2024-08-16 12:04:12 +02:00
import sys
sys . dont_write_bytecode = True
2024-07-03 18:22:50 +02:00
import mtTkinter as tk
2024-07-06 15:21:14 +02:00
from HEMD import color3 , vector2 , event , NULL
import audiosys
from loadbar import loadbar
2024-07-04 15:23:29 +02:00
import random
import string
import math
2024-07-04 20:26:48 +02:00
import time
2024-07-05 15:27:31 +02:00
import threading
2024-07-06 15:21:14 +02:00
import pickle
2024-07-06 16:32:26 +02:00
from pathfinding import pathfinding
2024-07-07 12:27:18 +02:00
from keyboard import keyboard
2024-08-14 22:28:51 +02:00
import copy
import ast
import os
import shutil
2024-07-03 19:07:33 +02:00
#import itertools
#import multiprocessing
2024-07-03 18:22:50 +02:00
# designated graphics size pixel 5x5
__VERSION__ = " HE2.3-HASHENGINE-2.3 "
2024-07-03 19:07:33 +02:00
2024-07-04 15:23:29 +02:00
class obj :
2024-07-03 19:07:33 +02:00
def __init__ ( self ) :
2024-07-04 15:23:29 +02:00
self . position = vector2 ( )
self . collide = True
self . anchored = True
self . velocity = vector2 ( )
self . acceleration = vector2 ( )
self . id = NULL ( )
self . color = color3 ( )
self . colliding = event ( )
2024-07-06 15:21:14 +02:00
self . _parent = NULL ( )
2024-07-04 15:23:29 +02:00
self . children = [ ]
2024-07-04 20:26:48 +02:00
self . ignorecollision = [ ]
2024-07-25 22:17:48 +02:00
self . type = " OBJ "
self . name = " object "
2024-07-03 19:07:33 +02:00
2024-07-06 15:21:14 +02:00
@property
def parent ( self ) :
return self . _parent
@parent.setter
def parent ( self , value ) :
2024-07-26 13:09:38 +02:00
if hasattr ( self . _parent , " children " ) : self . _parent . children . remove ( self )
2024-07-06 15:21:14 +02:00
self . _parent = value
2024-07-26 13:09:38 +02:00
if hasattr ( self . _parent , " children " ) : self . _parent . children . append ( self )
2024-07-06 15:21:14 +02:00
2024-07-07 17:32:02 +02:00
class folder :
def __init__ ( self ) :
self . _parent = NULL ( )
self . children = [ ]
2024-07-25 22:17:48 +02:00
self . type = " FOLD "
self . name = " folder "
self . id = NULL ( )
2024-07-07 17:32:02 +02:00
2024-08-02 19:30:35 +02:00
def move ( self , target : vector2 ) :
2024-08-14 22:28:51 +02:00
""" move the children of the folder to an specified position
"""
2024-08-02 19:30:35 +02:00
temp = [ ]
for i in self . children :
temp . append ( i . position )
temp = target . __getdiff__ ( temp , True )
target - = temp
for i in self . children :
i . position + = target
2024-07-07 17:32:02 +02:00
@property
def parent ( self ) :
return self . _parent
@parent.setter
def parent ( self , value ) :
2024-07-25 22:17:48 +02:00
if hasattr ( self . _parent , " children " ) : self . _parent . children . remove ( self )
2024-07-07 17:32:02 +02:00
self . _parent = value
2024-07-26 13:09:38 +02:00
if hasattr ( self . _parent , " children " ) : self . _parent . children . append ( self )
2024-07-07 17:32:02 +02:00
2024-07-03 19:07:33 +02:00
class game :
2024-08-16 12:04:12 +02:00
def __init__ ( self , canvas : tk . Canvas , win , pixelsize = 3 , chunksize = 10 ) :
2024-07-03 19:07:33 +02:00
self . _canvas = canvas
2024-07-04 20:26:48 +02:00
self . _height = int ( canvas . winfo_reqheight ( ) / pixelsize )
self . _width = int ( canvas . winfo_reqwidth ( ) / pixelsize )
self . _pixelsize = pixelsize
2024-07-03 19:07:33 +02:00
self . _OAP = { }
self . _objects = { }
self . _visobjects = { }
2024-07-04 20:26:48 +02:00
self . _camera = obj ( )
self . _camera . zoom = pixelsize
2024-07-05 15:27:31 +02:00
self . _OAPUPDATING = False
2024-07-06 15:21:14 +02:00
self . _handler = audiosys . handler ( )
self . _threads = [ ]
self . _root = obj ( )
2024-07-25 22:17:48 +02:00
self . _scripts = { }
2024-07-28 16:43:05 +02:00
self . _keyboard = keyboard ( win )
2024-07-25 22:17:48 +02:00
self . _things = { }
2024-07-26 17:17:19 +02:00
self . _win = win
2024-08-16 12:04:12 +02:00
self . _chunksize = chunksize
self . _globalvars = { }
2024-07-03 19:07:33 +02:00
""" 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 ( )
2024-07-04 20:26:48 +02:00
self . _workers . append ( { " process " : temp , " " } ) """ # scraped idea, im keeping it in incase i ever decide to use it
2024-08-02 19:30:35 +02:00
2024-08-14 22:28:51 +02:00
def cloneobj ( self , target ) :
return copy . deepcopy ( target )
2024-08-16 12:04:12 +02:00
def getchunkbypos ( self , position : vector2 ) :
return vector2 ( int ( position . x / self . _chunksize ) , int ( position . y / self . _chunksize ) )
def getposbychunk ( self , chunk : vector2 ) :
return vector2 ( int ( chunk . x * self . _chunksize ) , int ( chunk . y * self . _chunksize ) )
2024-07-04 15:23:29 +02:00
def genid ( self ) :
out = " "
for i in range ( 255 ) :
out = out + random . choice ( list ( string . ascii_letters ) )
return out
2024-07-04 20:26:48 +02:00
def v2tuple ( self , target : vector2 ) :
return ( target . x , target . y )
def tuple2v ( self , target : tuple ) :
return vector2 ( target [ 0 ] , target [ 1 ] )
2024-07-04 15:23:29 +02:00
def addtooap ( self , target : obj ) :
2024-08-16 12:04:12 +02:00
if self . v2tuple ( self . getchunkbypos ( target . position . __round__ ( ) ) ) in self . _OAP :
self . _OAP [ self . v2tuple ( self . getchunkbypos ( target . position . __round__ ( ) ) ) ] . append ( target )
2024-07-04 15:23:29 +02:00
else :
2024-08-16 12:04:12 +02:00
self . _OAP [ self . v2tuple ( self . getchunkbypos ( target . position . __round__ ( ) ) ) ] = [ target ]
2024-07-04 20:26:48 +02:00
def updateobjinoap ( self , target : obj ) :
self . remfromoap ( target )
self . addtooap ( target )
2024-07-04 15:23:29 +02:00
def remfromoap ( self , target : obj ) :
2024-07-04 20:26:48 +02:00
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
2024-07-04 15:23:29 +02:00
def getfromoap ( self , target : vector2 ) :
2024-08-16 12:04:12 +02:00
if self . v2tuple ( self . getchunkbypos ( target . __round__ ( ) ) ) in self . _OAP :
return self . _OAP [ self . v2tuple ( self . getchunkbypos ( target . __round__ ( ) ) ) ]
2024-07-04 15:23:29 +02:00
else :
return [ ]
2024-07-25 22:17:48 +02:00
def addobj ( self , target : obj , physics = True , id = None , parent = None ) :
2024-07-05 15:27:31 +02:00
if id == None : temp = self . genid ( )
else : temp = id
2024-07-04 15:23:29 +02:00
if physics : self . _objects [ temp ] = target
2024-07-25 22:17:48 +02:00
if parent == None : parent = self . _root
2024-07-04 15:23:29 +02:00
self . _visobjects [ temp ] = target
2024-07-04 20:26:48 +02:00
target . id = temp
2024-07-26 13:09:38 +02:00
target . parent = parent
2024-07-25 22:17:48 +02:00
self . _things [ temp ] = target
2024-07-04 15:23:29 +02:00
self . addtooap ( target )
2024-07-25 22:17:48 +02:00
def addfold ( self , target : folder , id = None , parent = None ) :
if id == None : temp = self . genid ( )
else : temp = id
if parent == None : parent = self . _root
target . id = temp
target . parent = parent
self . _things [ temp ] = target
2024-07-06 16:32:26 +02:00
def getobjbyid ( self , id ) :
if not id in self . _objects : raise TypeError ( f " No object with id { id } was found " )
return self . _objects [ id ]
2024-07-25 22:17:48 +02:00
def getglobalthing ( self , id ) :
if not id in self . _things : raise TypeError ( f " No thing with id { id } was found " )
return self . _things [ id ]
2024-07-27 12:21:27 +02:00
def recursiverem ( self , target , TLB : loadbar ) :
TLB . repeat + = len ( target . children )
TLB . steps = TLB . repeat / TLB . length
count = 0
2024-07-27 12:53:00 +02:00
#overflow = int(len(target.children)/10)
overflow = 1000000 # whoever deletes one million objects is not human anymore.
2024-07-27 12:21:27 +02:00
for i in target . children . copy ( ) :
2024-07-26 13:09:38 +02:00
self . INROBJ ( i )
2024-07-27 12:21:27 +02:00
self . recursiverem ( i , TLB )
TLB . current + = 1
TLB . render ( )
count + = 1
if count > overflow :
count = 0
self . render ( )
self . _win . update ( )
2024-08-16 12:04:12 +02:00
messagebox . showinfo ( " why " , " just why, one million objects, seriously??? " )
2024-07-26 13:09:38 +02:00
def INROBJ ( self , target ) :
2024-07-06 16:32:26 +02:00
if target . id in self . _visobjects : self . _visobjects . pop ( target . id )
if target . id in self . _objects : self . _objects . pop ( target . id )
2024-07-26 13:09:38 +02:00
if target . id in self . _things : self . _things . pop ( target . id )
if target . type == " OBJ " : self . remfromoap ( target )
target . parent = NULL ( )
def removeobj ( self , target : obj ) :
self . INROBJ ( target )
2024-07-27 12:21:27 +02:00
TLB = loadbar ( 20 , 1 )
self . recursiverem ( target , TLB )
2024-07-04 15:23:29 +02:00
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 )
2024-07-04 20:26:48 +02:00
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 :
2024-07-05 15:27:31 +02:00
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
2024-07-04 20:26:48 +02:00
return ( xblock , yblock )
def calcphysobj ( self , target : obj ) :
if target . anchored : target . velocity = vector2 ( ) ; return
2024-07-25 22:17:48 +02:00
if target . type == " FOLD " : return
2024-07-04 20:26:48 +02:00
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
2024-07-05 15:27:31 +02:00
if len ( colliding ) < = 1 : target . position + = target . velocity
2024-07-04 20:26:48 +02:00
else :
target . position + = target . velocity
target . velocity + = target . acceleration
self . updateobjinoap ( target )
2024-07-05 15:27:31 +02:00
def updallobjpositions ( self ) :
2024-07-26 17:17:19 +02:00
otime = time . time ( )
2024-07-05 15:27:31 +02:00
self . _OAPUPDATING = True
for i in self . _visobjects . values ( ) :
try :
self . updateobjinoap ( i )
except Exception as e :
pass
self . _OAPUPDATING = False
2024-07-26 17:17:19 +02:00
return time . time ( ) - otime
2024-07-05 15:27:31 +02:00
2024-07-04 20:26:48 +02:00
def render ( self ) :
2024-08-16 12:04:12 +02:00
#if self._OAPUPDATING == False: self.updallobjpositions()
2024-07-04 20:26:48 +02:00
self . _canvas . delete ( tk . ALL )
2024-07-06 16:32:26 +02:00
self . _height = int ( self . _canvas . winfo_reqheight ( ) / self . _camera . zoom )
self . _width = int ( self . _canvas . winfo_reqwidth ( ) / self . _camera . zoom )
2024-07-04 20:26:48 +02:00
self . _pixelsize = self . _camera . zoom
2024-07-06 16:32:26 +02:00
#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):
2024-08-16 12:04:12 +02:00
for y2 in range ( int ( self . _height / self . _chunksize + 1 ) ) :
for x2 in range ( int ( self . _width / self . _chunksize + 1 ) ) :
obj = self . getfromoap ( self . getposbychunk ( vector2 ( x2 + self . getchunkbypos ( self . _camera . position ) . x , y2 + self . getchunkbypos ( self . _camera . position ) . y ) ) )
2024-07-04 20:26:48 +02:00
if len ( obj ) == 0 : continue
2024-08-16 12:04:12 +02:00
for i in obj :
x = i . position . x - self . _camera . position . x
y = i . position . y - self . _camera . position . y
self . _canvas . create_rectangle ( x * self . _pixelsize , y * self . _pixelsize , x * self . _pixelsize + self . _pixelsize , y * self . _pixelsize + self . _pixelsize , fill = i . color . __tohex__ ( ) , width = 0 )
2024-07-04 20:26:48 +02:00
def updobjs ( self ) :
2024-07-05 15:27:31 +02:00
start = time . time ( )
2024-07-04 20:26:48 +02:00
for i in self . _objects . values ( ) :
self . calcphysobj ( i )
2024-07-05 15:27:31 +02:00
return time . time ( ) - start
2024-07-04 15:23:29 +02:00
2024-07-06 15:21:14 +02:00
def savegame ( self ) :
print ( " pickling root... " )
outobjects = pickle . dumps ( self . _root )
print ( " copying scripts... " )
2024-07-26 13:09:38 +02:00
outscripts = { }
2024-07-06 15:21:14 +02:00
TLB = loadbar ( 20 , len ( self . _scripts ) )
for i in self . _scripts :
2024-07-26 13:09:38 +02:00
outscripts [ i ] = self . _scripts [ i ]
2024-07-06 15:21:14 +02:00
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 ( )
2024-07-25 22:17:48 +02:00
print ( )
print ( " done. " )
2024-07-06 15:21:14 +02:00
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 ( ) :
2024-07-25 22:17:48 +02:00
if i . type == " OBJ " : self . addobj ( i , True , i . id , i . parent )
if i . type == " FOLD " : self . addfold ( i , i . id , i . parent )
2024-07-06 15:21:14 +02:00
if len ( i . children ) > 0 : self . readdobj ( i . children , TLB )
TLB . current + = 1
TLB . render ( )
2024-07-07 12:27:18 +02:00
def isdown ( self , key ) :
temp = self . _keyboard . getkeys ( )
if key in temp :
return temp [ key ]
2024-07-06 15:21:14 +02:00
def loadgame ( self , target ) :
print ( " loading objects... " )
self . _root = pickle . loads ( target [ " obj " ] )
print ( " loading scripts... " )
2024-07-26 13:09:38 +02:00
self . _scripts = { }
2024-07-06 15:21:14 +02:00
TLB = loadbar ( 20 , len ( target [ " scripts " ] ) )
for i in target [ " scripts " ] :
2024-07-26 13:09:38 +02:00
self . _scripts [ i ] = target [ " scripts " ] [ i ]
2024-07-06 15:21:14 +02:00
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 )
2024-07-25 22:17:48 +02:00
print ( )
print ( " done. " )
2024-07-06 15:21:14 +02:00
2024-07-07 12:27:18 +02:00
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
2024-07-26 17:17:19 +02:00
API [ " PATHFIND " ] = pathfinding ( self )
2024-08-16 12:04:12 +02:00
API [ " GLOBAL " ] = self . _globalvars
2024-07-07 12:27:18 +02:00
return API
def rungame ( self ) :
2024-07-26 17:17:19 +02:00
""" warning, yields forever!
"""
2024-07-07 12:27:18 +02:00
print ( " preparing scripts " )
2024-07-25 22:17:48 +02:00
for i in list ( self . _scripts . values ( ) ) :
2024-07-26 17:17:19 +02:00
self . _threads . append ( threading . Thread ( target = lambda i = i : exec ( i , self . APIGEN ( ) ) ) )
2024-07-07 12:27:18 +02:00
print ( " starting scripts " )
for i in self . _threads :
i . start ( )
print ( " starting loop " )
while True :
2024-08-16 12:04:12 +02:00
took = self . updobjs ( )
took + = self . updallobjpositions ( )
2024-07-07 12:27:18 +02:00
self . render ( )
2024-07-26 17:17:19 +02:00
self . _win . update ( )
2024-08-16 12:04:12 +02:00
took = 0.01 - took
2024-07-07 12:27:18 +02:00
if took > 0 :
time . sleep ( took )
2024-08-14 22:28:51 +02:00
def build ( self , targetdir = " out " ) :
os . makedirs ( targetdir , exist_ok = True )
shutil . copyfile ( " hashengine.py " , targetdir + " /main.py " )
shutil . copyfile ( " mtTkinter.py " , targetdir + " /mtTkinter.py " )
file = open ( targetdir + " /game.HEGF " , ' w ' )
file . write ( str ( self . savegame ( ) ) )
file . close ( )
2024-07-20 19:06:03 +02:00
if not " __CMD__ " in globals ( ) and __name__ == " __main__ " :
2024-07-04 15:23:29 +02:00
root = tk . Tk ( )
canvas = tk . Canvas ( root )
2024-08-14 22:28:51 +02:00
#load game file
if not os . path . exists ( " game.HEGF " ) : from tkinter import messagebox ; messagebox . showerror ( " ERROR " , " Hashengine was unable to find the game.HEGF file! Hashengine will be closing now " ) ; exit ( )
file = open ( " game.HEGF " , ' r ' )
gafi = ast . literal_eval ( file . read ( ) )
file . close ( )
gamec = game ( canvas , root , 3 )
gamec . loadgame ( gafi )
2024-07-06 15:21:14 +02:00
root . update ( )
2024-08-14 22:28:51 +02:00
gamec . rungame ( )