pathfinding

main
Justus Jan Nico Wolff 2024-06-15 12:51:21 +02:00
parent 9502ee247e
commit 7c8e354103
5 changed files with 118 additions and 8 deletions

View File

@ -6,6 +6,7 @@ import time
import wave
import os
import math
import heapq
class stdrend:
def __init__(self, size, cam):
@ -151,7 +152,7 @@ def loadsound(path):
frames = fd.readframes(1000000000)
return frames
cammode = enum({"editable": 0, "follow": 1})
cammode = enum({"editable": 0, "follow": 1, "freecam": 2})
class event:
def __init__(self):
@ -197,9 +198,20 @@ class camera(obj):
self.touch = False
self.char = " "
def update(self):
def update(self, game):
"""
if char == "w": preview.camera.position += hashengine.vector2(y=1)
if char == "a": preview.camera.position += hashengine.vector2(x=1)
if char == "s": preview.camera.position -= hashengine.vector2(y=1)
if char == "d": preview.camera.position -= hashengine.vector2(x=1)
"""
if self.mode == cammode.follow and self.subject:
self.position = self.subject.position
if self.mode == cammode.freecam:
if game.isdown("w"): self.position += vector2(y=1)
if game.isdown("s"): self.position -= vector2(y=1)
if game.isdown("a"): self.position += vector2(x=1)
if game.isdown("d"): self.position -= vector2(x=1)
class seqobj:
def __init__(self, objects):
@ -334,6 +346,7 @@ class game:
for y in range(self._size[1]):
tochange.append((x, y))
#self._renderer.pix(x, y, " ", color3(255, 255, 255), color3(255, 255, 255))
self.camera.update(self)
for i in list(self._objects.values()):
if isinstance(i, obj):
pos = i.position + self.camera.position
@ -365,6 +378,80 @@ class game:
for i in self.currentsounds:
i.stop()
class pathfinding:
def __init__(self, grid_size, objects, game):
self.grid_size = grid_size
self.objects = objects
self._calculate_bounds()
self.grid = [[1 for _ in range(self.grid_width)] for _ in range(self.grid_height)]
self.game = game
self._init_grid()
def _init_grid(self):
for obj in self.objects:
if obj.collide:
x, y = int(obj.position.x) + self.offset_x, int(obj.position.y) + self.offset_y
if 0 <= x < self.grid_width and 0 <= y < self.grid_height:
self.grid[y][x] = 0
def _calculate_bounds(self):
min_x, max_x = 0, self.grid_size[0]
min_y, max_y = 0, self.grid_size[1]
for obj in self.objects:
if obj.collide:
min_x = min(min_x, int(obj.position.x))
max_x = max(max_x, int(obj.position.x))
min_y = min(min_y, int(obj.position.y))
max_y = max(max_y, int(obj.position.y))
self.grid_width = max_x - min_x + 1
self.grid_height = max_y - min_y + 1
self.offset_x = -min_x
self.offset_y = -min_y
def _heuristic(self, a, b):
return abs(a[0] - b[0]) + abs(a[1] - b[1])
def find_path(self, start, end):
self.objects = list(self.game._objects.values())
self._calculate_bounds()
self._init_grid()
start = (int(start.x) + self.offset_x, int(start.y) + self.offset_y)
end = (int(end.x) + self.offset_x, int(end.y) + self.offset_y)
open_set = []
heapq.heappush(open_set, (0, start))
came_from = {}
g_score = {start: 0}
f_score = {start: self._heuristic(start, end)}
while open_set:
_, current = heapq.heappop(open_set)
if math.dist(end, current) <= 1:
path = []
while current in came_from:
path.append(current)
current = came_from[current]
path.append(start)
path.reverse()
return [vector2(x - self.offset_x, y - self.offset_y) for x, y in path]
neighbors = [
(current[0] + dx, current[1] + dy)
for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]
if 0 <= current[0] + dx < self.grid_width and 0 <= current[1] + dy < self.grid_height
]
for neighbor in neighbors:
if self.grid[neighbor[1]][neighbor[0]] == 0:
continue
tentative_g_score = g_score[current] + 1
if neighbor not in g_score or tentative_g_score < g_score[neighbor]:
came_from[neighbor] = current
g_score[neighbor] = tentative_g_score
f_score[neighbor] = tentative_g_score + self._heuristic(neighbor, end)
heapq.heappush(open_set, (f_score[neighbor], neighbor))
return []
if __name__ == "__main__":
testgame = game(sounddir="testsound")
object = obj()

23
main.py
View File

@ -476,10 +476,11 @@ def halatribute(event):
setattr(gamedata[currentobj]["args"][parent], name, new)
if "ID" in gamedata[currentobj]["args"]:
temp = preview.getobjbyid(gamedata[currentobj]["args"]["ID"])
setattr(temp, name, new)
setattr(getattr(temp, parent), name, new)
atritree.delete(*atritree.get_children())
objtree.focus("")
updselect(None)
preview.render()
def updatepreviewcam(char):
global cooldown
@ -707,9 +708,11 @@ def testing():
def APIGEN():
global APIPLUG
global maingame
API = {"print": log, "HASHBASE": hashengine}
API["HASHGAME"] = maingame
API["SOUND"] = lambda data: gsound(data, maingame)
API["PATHFIND"] = hashengine.pathfinding(maingame._size, list(maingame._objects.values()), maingame)
for i in APIPLUG:
exec(i, globals())
temp = globals()["PLUGINAPIFUNC"]()
@ -1083,7 +1086,6 @@ def GUIinit():
menu.add_cascade(label=LH.string("langs"), menu=langmenu)
for i in LH.getlangs():
langmenu.add_command(label=i, command=lambda i=i: selectlang(i))
loadplugins()
container.mainloop()
# attribute changers
@ -1163,6 +1165,7 @@ def aposx(old):
for i in str(tempvar):
if not i in numbers:
return old
if str(tempvar).split(".")[1] == "0": return int(tempvar)
return tempvar
def aposy(old):
@ -1190,6 +1193,7 @@ def aposy(old):
for i in str(tempvar):
if not i in numbers:
return old
if str(tempvar).split(".")[1] == "0": return int(tempvar)
return tempvar
def execgame(gametree, shouldlog=True, fAPIPLUG=[], fRUNPLUG=[]):
@ -1208,15 +1212,22 @@ def execgame(gametree, shouldlog=True, fAPIPLUG=[], fRUNPLUG=[]):
clog = shouldlog
run()
def execcmd(target):
try:
exec(target, globals())
except Exception as e:
return e
def cmd():
print(f"hashengine version: {version}")
print("CMD")
autoexecute = ["loadplugins()"]
for i in autoexecute:
print(f"> {i}")
execcmd(i)
while True:
cmd = input("> ")
try:
exec(cmd, globals())
except Exception as e:
print(e)
print(execcmd(cmd))
class rsound:
def __init__(self):

View File

@ -70,3 +70,10 @@ Hashengine supports audio playback. As previously said, HASHBASE.loadsound(\<PAT
to play a sound use SOUND(HASHGAME.sounds[\<Target sound name>]) or if youre using loadsound then SOUND(loadsound(\<PATH>)). this will return a **SOUND** Class which can playback the sound. to play the sound use \<sound>.play().
to stop the sound use \<sound>.stop() and to yield until the sound is done playing sue \<sound>.wait()
## PATHFIND
### Hashengine provides you with built-in pathfinding
Hashengine has an built pathfinding system (A*). to use it, use PATHFIND.find_path(\<start vector2>, \<end vector2>).
it returns an list of vector2's representing every single waypoint.

View File

@ -0,0 +1,4 @@
B #
#
#
A

View File

@ -0,0 +1 @@
[[{'id': 'obj', 'name': 'B', 'SID': 'TqykIpLtCKwtqAdSrksOjKtUmNXVMkXPEnNKVYAjnCbhDGwNbiefXdeJhMxBeNOTWfRCHZWOtdMxmHlcCDPdEXOzGmhuXTQyaVywRqwWOxdVioLSUAZkpivegeBalvtkgfVkIVlaJUGJLHLiOCdncxyNGkciReWUntWGjfQTuIeZSGwWtpakiQQgCZCFpkPUUWYlvLNADLvmCOzKwGQCIMnaVavcHYDEhJStHnzPlYIgASEBDMywrmZeUxtrOlO', 'args': {'anchored': True, 'char': 'B', 'collide': True, 'friction': 0, 'gravity': 0, 'acceleration': {'x': 0, 'y': 0, 'ARGID': 'vector2'}, 'bcolor': {'b': 255, 'g': 255, 'r': 255, 'ARGID': 'color3'}, 'fcolor': {'b': 0, 'g': 0, 'r': 0, 'ARGID': 'color3'}, 'position': {'x': 0, 'y': 0, 'ARGID': 'vector2'}, 'velocity': {'x': 0, 'y': 0, 'ARGID': 'vector2'}}}, {'id': 'obj', 'name': '#', 'SID': 'TZIeEulKFDdSyFercdukmdlaWqXJtxCNsYUJRehtpqWXtqNrCRIQppHJlLHYlxmOfzSJwjGOMFhOGWFRybutzbfWmxBuuThfZKRaeHqqqdocjkfPxfBVZsqZFTgKYQXcUXtXpXnkSUYZqGZGztgeuOJXyKwTJTLaGMtMfvXmmNXviOlnmBlTbdzgZQoJLTPJqTkmavOKepbCcrzcjDUuCZpfnOaTuehRnyPHFcXbiPIOFRmsqpWfXKwWzREsfyV', 'args': {'anchored': True, 'char': '#', 'collide': True, 'friction': 0, 'gravity': 0, 'acceleration': {'x': 0, 'y': 0, 'ARGID': 'vector2'}, 'bcolor': {'b': 255, 'g': 255, 'r': 255, 'ARGID': 'color3'}, 'fcolor': {'b': 0, 'g': 0, 'r': 0, 'ARGID': 'color3'}, 'position': {'x': 5, 'y': 0, 'ARGID': 'vector2'}, 'velocity': {'x': 0, 'y': 0, 'ARGID': 'vector2'}}}, {'id': 'obj', 'name': '#', 'SID': 'HtBTelOcoHVYzWzpvfwphPDTJCUQgZjmOXomRObTJkhMuefWHbCZPQWSeaGZOcbWXknUYaerTNDmsNOhwAOQZJpHxwrAwtBbyLWuQwggXUXKgWDyUzCNaMLeVaWDEIXRXdWVxmRObSotLnIUDfqByenIsHpitNcMWXCqGpLTzApWHKzhMfIoFoswtqrPydSOOqAWXWLyVhNlhIPjqTUqOyxhBtxJoouAZWfsLBriRwCYQJIsPmFUsWTEZLUzqJi', 'args': {'anchored': True, 'char': '#', 'collide': True, 'friction': 0, 'gravity': 0, 'acceleration': {'x': 0, 'y': 0, 'ARGID': 'vector2'}, 'bcolor': {'b': 255, 'g': 255, 'r': 255, 'ARGID': 'color3'}, 'fcolor': {'b': 0, 'g': 0, 'r': 0, 'ARGID': 'color3'}, 'position': {'x': 5, 'y': 1, 'ARGID': 'vector2'}, 'velocity': {'x': 0, 'y': 0, 'ARGID': 'vector2'}}}, {'id': 'obj', 'name': '#', 'SID': 'rpmRdCpAZzcbSvkgQKCOzzeUnFahtWUVmoEJuXVlVejBTMumOrRRLDLjnpuMkkoztSOaLTVGGEgYzTdAJJXcwfJPXemlENOQFlItDHRojMUmZAlPeCdawyaLqkhHPJPJRVUZCHQOJYlixucjpuqyhcorIUKnzxNYWdQSCIOyHHOIyHMAzZEQLrlwBsCgKAXwTMhNqNXGAEscABPlgvULVegLIbqdVRlQAiQTMbhArjOGxtJhBORsAIUDkrRrViz', 'args': {'anchored': True, 'char': '#', 'collide': True, 'friction': 0, 'gravity': 0, 'acceleration': {'x': 0, 'y': 0, 'ARGID': 'vector2'}, 'bcolor': {'b': 255, 'g': 255, 'r': 255, 'ARGID': 'color3'}, 'fcolor': {'b': 0, 'g': 0, 'r': 0, 'ARGID': 'color3'}, 'position': {'x': 5, 'y': 2, 'ARGID': 'vector2'}, 'velocity': {'x': 0, 'y': 0, 'ARGID': 'vector2'}}}, {'id': 'obj', 'name': 'A', 'SID': 'kZbEQPYcJFNelliPHswwvvDVeiYGLXYeYvAGHdmDmxdIAFqWlkAFPxNCBlVRXgofJIaBBQaOMUHcnAyFmsHaorUhFIlblXHSdLFsRtLWmkMpPnBmpHrJZhkNCmNEvaZdCtNWnbJfAWdaFOlfHSYNIbenaNQhLXUntneNdMIlpEgWrCVhaOimAcXRDtMwusYibgkCZIIPLnsHtXWcSjjskdzylorzBNCNOJwnLqFLkDLbbeiaoKcqhfdsdMwPNzn', 'args': {'anchored': True, 'char': 'A', 'collide': True, 'friction': 0, 'gravity': 0, 'acceleration': {'x': 0, 'y': 0, 'ARGID': 'vector2'}, 'bcolor': {'b': 255, 'g': 255, 'r': 255, 'ARGID': 'color3'}, 'fcolor': {'b': 0, 'g': 0, 'r': 0, 'ARGID': 'color3'}, 'position': {'x': -2, 'y': -2, 'ARGID': 'vector2'}, 'velocity': {'x': 0, 'y': 0, 'ARGID': 'vector2'}}}, {'id': 'script', 'name': 'Skript', 'SID': 'jjlcqqosdzDsDAjdUlAzeudsNiDEfggOTzGZZdhYPUtMzWPDEnsAgaOpiEeZofjivwPOkkLejUqHRJzIaUwdcNCkeuoEzRyMsLLxoIzzAJbWxlNIcmayhgZDTPAHAEKalgBYizLaxhXISElzdxcaJdoqfAgHJGDkRlvpPPNHoTnizOrVUNcnVpEncJUuOwBevnNRoHhptbJoKRHHsINkJXtkGxIrOVBObXGHlEbXQKyJKSisqvedYtazodZoXUJ', 'args': {'code': 'start = HASHGAME.getobjbySID("TqykIpLtCKwtqAdSrksOjKtUmNXVMkXPEnNKVYAjnCbhDGwNbiefXdeJhMxBeNOTWfRCHZWOtdMxmHlcCDPdEXOzGmhuXTQyaVywRqwWOxdVioLSUAZkpivegeBalvtkgfVkIVlaJUGJLHLiOCdncxyNGkciReWUntWGjfQTuIeZSGwWtpakiQQgCZCFpkPUUWYlvLNADLvmCOzKwGQCIMnaVavcHYDEhJStHnzPlYIgASEBDMywrmZeUxtrOlO")\nend = HASHGAME.getobjbySID("kZbEQPYcJFNelliPHswwvvDVeiYGLXYeYvAGHdmDmxdIAFqWlkAFPxNCBlVRXgofJIaBBQaOMUHcnAyFmsHaorUhFIlblXHSdLFsRtLWmkMpPnBmpHrJZhkNCmNEvaZdCtNWnbJfAWdaFOlfHSYNIbenaNQhLXUntneNdMIlpEgWrCVhaOimAcXRDtMwusYibgkCZIIPLnsHtXWcSjjskdzylorzBNCNOJwnLqFLkDLbbeiaoKcqhfdsdMwPNzn")\nHASHGAME.camera.mode = 2\npath = PATHFIND.find_path(start.position, end.position)\nfor i in path:\n\ttemp = HASHBASE.obj()\n\ttemp.position = i\n\ttemp.char = "-"\n\ttemp.anchored = True\n\tHASHGAME.addobj(temp)'}}], {'Erstellte Objekte': [0, 1, 2, 3, 4]}, 10, 10]