Hashengine-2.3/hashengine.py

366 lines
12 KiB
Python

import mtTkinter as tk
from HEMD import color3, vector2, event, NULL
import audiosys
from loadbar import loadbar
import random
import string
import math
import time
import threading
import pickle
from pathfinding import pathfinding
from keyboard import keyboard
#import itertools
#import multiprocessing
# designated graphics size pixel 5x5
__VERSION__ = "HE2.3-HASHENGINE-2.3"
class obj:
def __init__(self):
self.position = vector2()
self.collide = True
self.anchored = True
self.velocity = vector2()
self.acceleration = vector2()
self.id = NULL()
self.color = color3()
self.colliding = event()
self._parent = NULL()
self.children = []
self.ignorecollision = []
@property
def parent(self):
return self._parent
@parent.setter
def parent(self, value):
self._parent.children.remove(self)
self._parent = value
self._parent.children.append(self)
class folder:
def __init__(self):
self._parent = NULL()
self.children = []
@property
def parent(self):
return self._parent
@parent.setter
def parent(self, value):
self._parent.children.remove(self)
self._parent = value
self._parent.children.append(self)
class game:
def __init__(self, canvas: tk.Canvas, pixelsize=3):
self._canvas = canvas
self._height = int(canvas.winfo_reqheight()/pixelsize)
self._width = int(canvas.winfo_reqwidth()/pixelsize)
self._pixelsize = pixelsize
self._OAP = {}
self._objects = {}
self._visobjects = {}
self._camera = obj()
self._camera.zoom = pixelsize
self._OAPUPDATING = False
self._handler = audiosys.handler()
self._threads = []
self._root = obj()
self._scripts = []
self._keyboard = keyboard(self._canvas)
"""self._workers = []
self._processes = 2 # total number of processes.
for i in range(self._processes):
xresult = multiprocessing.Array("i")
yresult = multiprocessing.Array("i")
oresult = multiprocessing.Array("s")
temp = multiprocessing.Process()
temp.start()
self._workers.append({"process": temp, ""})""" # scraped idea, im keeping it in incase i ever decide to use it
def genid(self):
out = ""
for i in range(255):
out = out + random.choice(list(string.ascii_letters))
return out
def v2tuple(self, target: vector2):
return (target.x, target.y)
def tuple2v(self, target: tuple):
return vector2(target[0], target[1])
def addtooap(self, target: obj):
if self.v2tuple(target.position.__round__()) in self._OAP:
self._OAP[self.v2tuple(target.position.__round__())].append(target)
else:
self._OAP[self.v2tuple(target.position.__round__())] = [target]
def updateobjinoap(self, target: obj):
self.remfromoap(target)
self.addtooap(target)
def remfromoap(self, target: obj):
for i in self._OAP:
if target in self._OAP[i]:
self._OAP[i].remove(target)
if len(self._OAP[i]) == 0:
self._OAP.pop(i)
break
def getfromoap(self, target: vector2):
if self.v2tuple(target.__round__()) in self._OAP:
return self._OAP[self.v2tuple(target.__round__())]
else:
return []
def addobj(self, target: obj, physics=True, id=None):
if id == None: temp = self.genid()
else: temp = id
if physics: self._objects[temp] = target
self._visobjects[temp] = target
target.id = temp
target._parent = self._root
self._root.children.append(target)
self.addtooap(target)
def getobjbyid(self, id):
if not id in self._objects: raise TypeError(f"No object with id {id} was found")
return self._objects[id]
def removeobj(self, target: obj):
if target.id in self._visobjects: self._visobjects.pop(target.id)
if target.id in self._objects: self._objects.pop(target.id)
self.remfromoap(target)
def distance(self, pos1, pos2):
return math.dist(((pos1.x, pos1.y), (pos2.x, pos2.y)))
def getcolliding(self, target):
return self.getfromoap(target.position)
def handlecollision(self, obj1: obj, obj2: obj):
#False is blocked
#True is not blocked
#returns tuple like this (True, True)
xblock = False
yblock = False
obj1pos = obj1.position.__round__()
obj2pos = obj2.position.__round__()
if obj2.collide == False: return (xblock, yblock)
if obj2pos.x > obj1pos.x > obj2pos.x: xblock = True
if obj2pos.y > obj1pos.y > obj2pos.y: yblock = True
if obj2.anchored == True:
obj1.velocity = vector2()
else:
if xblock: obj1.velocity.x = obj1.velocity.x/2;obj2.velocity.x = obj2.velocity.x/2;obj2.position.x += obj2.velocity.x
if yblock: obj1.velocity.y = obj1.velocity.y/2;obj2.velocity.y = obj2.velocity.y/2;obj2.position.y += obj2.velocity.y
return (xblock, yblock)
def calcphysobj(self, target: obj):
if target.anchored: target.velocity=vector2();return
new = target.position + target.velocity
oldvel = target.velocity.__copy__()
if target.collide == True:
colliding = self.getfromoap(new)
if len(colliding) > 0: target.colliding.execute()
for i in colliding:
if i == target: continue
if i in target.ignorecollision or target in i.ignorecollision: continue
i.colliding.execute()
temp = self.handlecollision(target, i)
if temp[0] == False: target.position.x += oldvel.x
if temp[1] == False: target.position.y += oldvel.y
if len(colliding) <= 1: target.position += target.velocity
else:
target.position += target.velocity
target.velocity += target.acceleration
self.updateobjinoap(target)
def updallobjpositions(self):
self._OAPUPDATING = True
for i in self._visobjects.values():
try:
self.updateobjinoap(i)
except Exception as e:
pass
self._OAPUPDATING = False
def render(self):
if self._OAPUPDATING == False: threading.Thread(target=self.updallobjpositions).start()
self._canvas.delete(tk.ALL)
self._height = int(self._canvas.winfo_reqheight()/self._camera.zoom)
self._width = int(self._canvas.winfo_reqwidth()/self._camera.zoom)
self._pixelsize = self._camera.zoom
#for y in range(self._camera.position.y, self._height+self._camera.position.y):
#for x in range(self._camera.position.x, self._width+self._camera.position.x):
for y in range(self._height):
for x in range(self._width):
obj = self.getfromoap(vector2(x+self._camera.position.x, y+self._camera.position.y))
if len(obj) == 0: continue
obj = obj[0]
self._canvas.create_rectangle(x*self._pixelsize, y*self._pixelsize, x*self._pixelsize+self._pixelsize, y*self._pixelsize+self._pixelsize, fill=obj.color.__tohex__(), width=0)
def updobjs(self):
start = time.time()
for i in self._objects.values():
self.calcphysobj(i)
return time.time()-start
def savegame(self):
print("pickling root...")
outobjects = pickle.dumps(self._root)
print("copying scripts...")
outscripts = []
TLB = loadbar(20, len(self._scripts))
for i in self._scripts:
outscripts.append(i)
TLB.current += 1
TLB.render()
print("encoding sounds...")
outsounds = []
TLB = loadbar(20, len(self._handler.storage))
for i in self._handler.storage:
outsounds.append(self._handler.tostring(i))
TLB.current += 1
TLB.render()
return {"obj": outobjects, "scripts": outscripts, "sounds": outsounds}
def readdobj(self, target, TLB):
TLB.repeat += len(target)
TLB.steps = TLB.repeat/TLB.length
for i in target.copy():
self.addobj(i, True, i.id)
if len(i.children) > 0: self.readdobj(i.children, TLB)
TLB.current += 1
TLB.render()
def isdown(self, key):
temp = self._keyboard.getkeys()
if key in temp:
return temp[key]
def loadgame(self, target):
print("loading objects...")
self._root = pickle.loads(target["obj"])
print("loading scripts...")
self._scripts = []
TLB = loadbar(20, len(target["scripts"]))
for i in target["scripts"]:
self._scripts.append(i)
TLB.current += 1
TLB.render()
print()
print("loading sounds...")
self._handler.storage = {}
TLB = loadbar(20, len(target["sounds"]))
for i in target["sounds"]:
self._handler.loadfromstring(i)
TLB.current += 1
TLB.render()
print("readding objects...")
self._OAP = {}
self._objects = {}
self._visobjects = {}
TLB = loadbar(20, 0)
self.readdobj(self._root.children, TLB)
def APIGEN(self):
API = {}
API["HASHGAME"] = self
API["vector2"] = vector2
API["color3"] = color3
API["event"] = event
API["NULL"] = NULL
API["obj"] = obj
API["SOUND"] = self._handler
return API
def rungame(self):
# yields forever
print("preparing scripts")
for i in self._scripts:
self._threads.append(threading.Thread(target=lambda i: exec(i, self.APIGEN())))
print("starting scripts")
for i in self._threads:
i.start()
print("starting loop")
while True:
took = self.updallobjpositions()
self.render()
took = 0.1-took
if took > 0:
time.sleep(took)
if not "__CMD__" in globals():
from PIL import Image
from tkinter import filedialog
root = tk.Tk()
canvas = tk.Canvas(root)
canvas.grid()
temp = game(canvas)
tempimg = Image.open(filedialog.askopenfilename())
tempimg = tempimg.resize((temp._width, temp._height))
for y in range(temp._height):
for x in range(temp._width):
tempobj = obj()
tempobj.position = vector2(x, y)
tempcolor = tempimg.getpixel((x, y))
tempobj.color = color3(tempcolor[0], tempcolor[1], tempcolor[2])
temp.addobj(tempobj)
print(f"{y}/{temp._height}", end="\r", flush=True)
tempstate = temp.savegame()
print("resetting...")
temp.__init__(canvas)
input("press enter to reload state")
print("loading...")
temp.loadgame(tempstate)
temp.render()
root.update()
print()
input("press enter to exit.")
"""root = tk.Tk()
canvas = tk.Canvas(root)
canvas.grid()
temp = game(canvas)
temp._camera.position.x = -5
temp._camera.position.y = -10
pathfind = pathfinding(temp)
start = obj()
start.position = vector2(-3, -3)
start.color = color3(0, 255)
temp.addobj(start)
goal = obj()
goal.position = vector2(50, 80)
goal.color = color3(255)
temp.addobj(goal)
tempobjlist = []
out = pathfind.find_path(start.position, goal.position)
for i in out:
tempobj = obj()
tempobj.position = i
tempobjlist.append(tempobj)
temp.addobj(tempobj)
for i in range(50):
goal.position.y -= 1
for i in tempobjlist:
temp.removeobj(i)
#temp.updallobjpositions()
out = pathfind.find_path(start.position, goal.position)
for i in out:
tempobj = obj()
tempobj.position = i
temp.addobj(tempobj)
tempobjlist.append(tempobj)
temp.render()
root.update()
input("press enter to exit.")"""