obj highlighting, bug fixes and pong :D

main
Justus Jan Nico Wolff 2024-05-27 20:51:43 +02:00
parent 19a78eb3bf
commit 1a5a1de960
14 changed files with 2036 additions and 39 deletions

View File

@ -0,0 +1,86 @@
import random
import time
global HASHGAME
global HASHBASE
global SOUND
global currentspeed
global debounce
global speedincrease
ball = HASHGAME.getobjbySID("jYFrLyJBVMJgBfPPalVcUImJLUbVmiNmtzHoZdGLPaTQvAVMAlSVMOlUtrWiFtSybxtdXrxqqiVSGMOFPBwltyqmpwEIFxwrnErQuLVnMCWtMHKqpzGohWKeylyVWlApeCtDKTuVwzqbYNleAtjYjVPqmXONSxPabToIiKzUVgmdJPgvERSVAkjqtHzbBPpTGdCvhzqbPUrILjSroXLJdtjXeNyAsGIxSTVITUawNpwhFsGwCXVphjHtzereFBd")
upperobj1 = HASHGAME.getobjbySID("OspxVXZmVoEVdlfswQNBRXEXAPrErOJXZRWfIQEmGziyXbzQXFmVgWJNLIzvgAjkQrZydGYkDFBVhrbciwOqzlFJWSOeAwcqmitVxfeUPuUIQralBzAfXeaVZzpUwhsWBKXPlhALyeByTaWcsDUITulskyqxcrYiLNNQGaEZJxyIAaxqnIMoktHvIkTmfGzXXeYAIkjyKEWjhkJzxxmMWJjCpPQkBJBLagKYTWDPUxXRxahljZCUpnVmqnOOUGQ")
lowerobj1 = HASHGAME.getobjbySID("lQwOxmoKQUhilJgPARdJEcJLwOgnHnyJDxiFBgBSNmQXWHzeDvgGUaTvnkIGlCHJkvOHOAQklmCfftvXmkBMbopIZJMLSdcYOuvFWPyaNVZqZRMNJKNyaPLAwHoFLtjQWSAJfZoZqbQknmwhOoMIZpaumDRYFSNzqTvOzklUlAbcLDMRialZTlAFQLLHxECQhxwwkTDinnkIExaOWMUzlrrNdGwNHTLGxcBvJkUWbZYkRGNwwoPMIykQIcwgybj")
upperobj2 = HASHGAME.getobjbySID("hwDoZwmJeGaHQZecyjBRNWcTJXyFbQexBygreLGQdikUVUldcHyLJChjClstfKWUfkmDVyuBLvWypGifxRsobJSEWkqySvkthlpaNuBgNsEHjBULHILeNythkyTyHRWODZfZYCWWFsQQssKjwQhvcnheiNogPtsNVmSXcRmHnSiklHAtFwdWUDgsguLuBExbMBxMSyVzKuzqeciQRxVpBooptDHBvjfEaBcZOrJMhnIhOovsJhcEJVVRAfrVEYl")
lowerobj2 = HASHGAME.getobjbySID("HbxiUvAmmJdipAAYBaQbwvxOhKQrlCMuOSikBrvCpeRxUBjzDDCxUGWYzlxJqtJtoCNhSKOREArHZwqobbdPjySAcvXJhBSKKZqZqspVggwXywXhRkhZGenYOiheNkFpMBpYOWODCMjifuRJIjYfNFFODKScnoxleYiMbtVkuCkGhWhLUffepdmZKaVxbtvLdOTyIamHTKYlwPrtenszbwzTohjELaiYGtFhSgZAShNqXRSvUwZQKJHMzDCIxaH")
hitsound = SOUND(HASHGAME.sounds["ponghit"])
wonsound = SOUND(HASHGAME.sounds["won"])
lowerbound = 0
upperbound = 9
player1border = 0
player2border = 19
speedincrease = 0.1
debounce = False
currentspeed = speedincrease
def init():
global currentspeed
currentspeed = speedincrease
ball.velocity = HASHBASE.vector2(0.1, random.uniform(-0.5, 0.5))
ball.position = HASHBASE.vector2(9, 4)
def handleplayerhit():
global currentspeed
global debounce
hitsound.stop()
hitsound.play()
if debounce == True: return
debounce = True
if currentspeed > 0:
ball.position.x = player2border-1
ball.velocity.x = -currentspeed
ball.velocity.y = random.uniform(-0.5, 0.5)
currentspeed = -currentspeed
#ball.position.x = player2border-1
else:
ball.position.x = player1border+1
ball.velocity.x = -currentspeed
ball.velocity.y = random.uniform(-0.5, 0.5)
currentspeed = -currentspeed
#ball.position.x = player1border+1
speedincreasefunc()
debounce = False
def speedincreasefunc():
global currentspeed
if currentspeed > 0:
ball.velocity.x = currentspeed+speedincrease
currentspeed += speedincrease
else:
ball.velocity.x = currentspeed-speedincrease
currentspeed -= speedincrease
#ball._touching.attach(handleplayerhit)
init()
while True:
if ball.position.y > upperbound:
hitsound.stop()
hitsound.play()
ball.velocity.y = -ball.velocity.y
ball.position.y = upperbound-1
speedincreasefunc()
if ball.position.y < lowerbound:
hitsound.stop()
hitsound.play()
ball.velocity.y = -ball.velocity.y
ball.position.y = lowerbound+1
speedincreasefunc()
if ball.position.x > player2border or ball.position.x < player1border:
if not HASHGAME.between(upperobj1.position.y, lowerobj1.position.y, ball.position.y) and not HASHGAME.between(upperobj2.position.y, lowerobj2.position.y, ball.position.y):
wonsound.stop()
wonsound.play()
ball.position = HASHBASE.vector2(99, 99)
ball.velocity = HASHBASE.vector2()
time.sleep(3)
init()
else:
handleplayerhit()
time.sleep(0.5)

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,391 @@
import tkinter as tk
import string
import random
import threading
import time
import wave
import os
import math
class stdrend:
def __init__(self, size, cam):
self._size = size
self._grid = {}
self._win = tk.Tk()
tkeys = list(string.ascii_letters)
self._keys = {}
for i in tkeys:
self._keys[i] = False
self._win.bind("<KeyPress>", self.keypupd)
self._win.bind("<KeyRelease>", self.keydupd)
for y in range(size[1]):
for x in range(size[0]):
temp = tk.Label(text=" ")
temp.grid(row=y, column=x)
self._win.update()
self._grid[f"{x}:{y}"] = temp
def keypupd(self, event):
event = event.char
if event in self._keys:
self._keys[event] = True
def keydupd(self, event):
event = event.char
if event in self._keys:
self._keys[event] = False
def getkeys(self):
return self._keys
def coltohex(self, target):
colors = []
target = [target.r, target.g, target.b]
for i in target:
colors.append(("0"*(2-len(hex(i)[2:])))+hex(i)[2:])
out = ""
for i in colors:
out = out + i
return "#"+out
def update(self):
self._win.update()
def pix(self, x, y, text, bcolor, fcolor):
if f"{x}:{y}" in self._grid:
self._grid[f"{x}:{y}"].config(text=text, bg=self.coltohex(bcolor), fg=self.coltohex(fcolor))
class color3:
def __init__(self, r=0, g=0, b=0):
self.r = r
self.g = g
self.b = b
self._type = "color3"
def __add__(self, v):
temp = color3(self.r+v.r, self.g+v.g, self.b+v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
def __sub__(self, v):
temp = color3(self.r-v.r, self.g-v.g, self.b-v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
def __mul__(self, v):
temp = color3(self.r*v.r, self.g*v.g, self.b*v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
def __iadd__(self, v):
temp = color3(self.r+v.r, self.g+v.g, self.b+v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
def __isub__(self, v):
temp = color3(self.r-v.r, self.g-v.g, self.b-v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
def __imul__(self, v):
temp = color3(self.r*v.r, self.g*v.g, self.b*v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
class vector2:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
self._type = "vector2"
def _magnitude(self):
return abs(self.x+self.y)
def __add__(self, v):
return vector2(self.x+v.x, self.y+v.y)
def __sub__(self, v):
return vector2(self.x-v.x, self.y-v.y)
def __mul__(self, v):
return vector2(self.x*v.x, self.y*v.y)
def __iadd__(self, v):
return vector2(self.x+v.x, self.y+v.y)
def __isub__(self, v):
return vector2(self.x-v.x, self.y-v.y)
def __imul__(self, v):
return vector2(self.x*v.x, self.y*v.y)
class NULL:
def __init__(self):
return None
class enum:
def __init__(self, sel):
self._sel = dict(sel)
for i in self._sel:
setattr(self, i, self._sel[i])
def getposssel(self):
return list(self._sel.keys())
def loadsound(path):
with wave.open(path) as fd:
frames = fd.readframes(1000000000)
return frames
cammode = enum({"editable": 0, "follow": 1})
class event:
def __init__(self):
self._attached = []
def execute(self):
threads = []
for i in self._attached:
temp = threading.Thread(target=i)
temp.start()
threads.append(temp)
return threads
def attach(self, target):
self._attached.append(target)
class obj:
def __init__(self):
self.position = vector2()
self.char = " "
self.ID = 0
self.gravity = 0
self.acceleration = vector2()
self.velocity = vector2()
self.friction = 0
self.collide = True
self.anchored = False
self.bcolor = color3(255, 255, 255)
self.fcolor = color3()
self._touching = event()
class model:
def __init__(self, objects):
self._objects = objects
self.ID = 0
class camera(obj):
def __init__(self):
super().__init__()
self.mode = cammode.editable
self.subject = None
self.collide = False
self.touch = False
self.char = " "
def update(self):
if self.mode == cammode.follow and self.subject:
self.position = self.subject.position
class seqobj:
def __init__(self, objects):
self._objects = objects
def moveby(self, pos):
for i in self._objects:
i.position += pos
class game:
def __init__(self, size=[10, 10], renderer=stdrend, sounddir=""):
if renderer == None: raise TypeError("Renderer class needed!")
self.sounds = {}
self.currentsounds = []
for i in os.listdir(sounddir):
if not "." in i: continue
if i.split(".")[1] != "wav": continue
self.sounds[i.split(".")[0]] = loadsound(sounddir+"/"+i)
self._size = size
self._objects = {}
self._SIDS = {}
self._SEQSIDS = {}
self.camera = camera()
self._renderer = renderer(size, self.camera)
self._threads = []
def getobjbySID(self, target):
return self._objects[self._SIDS[target]]
def getobjseqbySID(self, target):
out = []
for i in self._SEQSIDS[target]:
out.append(self._objects[i])
return seqobj(out)
def isdown(self, key):
temp = self._renderer.getkeys()
if key in temp:
return temp[key]
def collidingpos(self, pos, ignore):
out = []
for i in self._objects:
i = self._objects[i]
if i.ID in ignore: continue
if math.dist([i.position.x, i.position.y], [pos.x, pos.y]) < 1 and i.collide == True:
out.append(i)
return out
def colliding(self, target):
out = []
if target.collide == False: return []
out = self.collidingpos(target.position, [target.ID,])
return out
def handlecollision(self, target: obj, target2: obj):
if target2.anchored == True:
target.velocity = vector2()
else:
xtrue = False
ytrue = False
if target.velocity.x > 0:
xtrue = True
if target.velocity.y > 0:
ytrue = True
half = vector2(abs(target.velocity.x)/2, abs(target.velocity.y)/2)
if not xtrue:
half = vector2(-abs(half.x), half.y)
if not ytrue:
half = vector2(half.x, -abs(half.y))
target.velocity = vector2(half.x, half.y)
target2.velocity = half
self._threads.extend(target._touching.execute())
self._threads.extend(target2._touching.execute())
def calcphysobj(self, target: obj):
opos = vector2(target.position.x, target.position.y)
collide = False
if target.anchored == True: return [opos, collide]
if target.collide == True:
colliding = self.collidingpos(target.position+target.velocity, [target.ID,])
for i in colliding:
target._touching.execute()
i._touching.execute()
self.handlecollision(target, i)
collide = True
target.position += target.velocity
target.velocity += vector2(0, target.gravity)
target.velocity += target.acceleration
temp = 2
if target.friction != 0:
temp = 2 / target.friction
else:
temp = 1
x = target.velocity.x
y = target.velocity.y
if x != 0:
x = x/temp
if y != 0:
y = y/temp
target.velocity = vector2(x, y)
return [opos, collide]
def calcphysmodel(self, target: model):
for i in target._objects:
self.calcphysobj(i)
def addobj(self, obj):
id = ""
for i in range(256):
id = id + random.choice(list(string.ascii_letters))
obj.ID = id
self._objects[id] = obj
def removeobj(self, obj):
self._objects.pop(obj.ID)
obj.ID = NULL()
def removeobjbyid(self, id):
self._objects.pop(id).ID = NULL()
def between(self, min, max, target):
if min < target < max: return True
return False
def getobjbyid(self, id):
return self._objects[id]
def render(self):
tochange = []
for x in range(self._size[0]):
for y in range(self._size[1]):
tochange.append((x, y))
#self._renderer.pix(x, y, " ", color3(255, 255, 255), color3(255, 255, 255))
for i in list(self._objects.values()):
if isinstance(i, obj):
pos = i.position + self.camera.position
if not self.between(-1, self._size[0], pos.x) or not self.between(-1, self._size[1], pos.y): continue#
pos = vector2(round(pos.x), round(pos.y))
self._renderer.pix(pos.x, pos.y, i.char, i.bcolor, i.fcolor)
if (pos.x, pos.y) in tochange: tochange.remove((pos.x, pos.y))
if isinstance(i, model):
for tobj in i._objects:
pos = tobj.position + self.camera.position
if not self.between(-1, self._size[0], pos.x) or not self.between(-1, self._size[1], pos.y): continue#
pos = vector2(round(pos.x), round(pos.y))
self._renderer.pix(pos.x, pos.y, tobj.char, tobj.bcolor, tobj.fcolor)
if (pos.x, pos.y) in tochange: tochange.remove((pos.x, pos.y))
for i in tochange:
self._renderer.pix(i[0], i[1], " ", color3(255, 255, 255), color3(255, 255, 255))
self._renderer.update()
def startscript(self, target):
temp = threading.Thread(target=target)
temp.start()
self._threads.append(temp)
def stopscripts(self):
for i in self._threads:
i.join(.0)
def stopsounds(self):
for i in self.currentsounds:
i.stop()
if __name__ == "__main__":
testgame = game(sounddir="testsound")
object = obj()
object.char = "#"
object.anchored = False
object.position = vector2(5, 5)
object.gravity = 1
floor = obj()
floor.char = "#"
floor.anchored = True
floor.position = vector2(5, 9)
floor.gravity = 0
floor.bcolor = color3(255, 255, 255)
testgame.addobj(object)
testgame.addobj(floor)
testgame.render()
print(object.ID)
while True:
testgame.calcphysobj(object)
testgame.calcphysobj(floor)
testgame.render()
time.sleep(0)

View File

@ -0,0 +1,7 @@
import player
import ast
file = open("game.HEGF", 'r')
file = file.read()
file = ast.literal_eval(file)
player.execgame(file)

View File

@ -0,0 +1,230 @@
'''Thread-safe version of tkinter.
Copyright (c) 2014, Andrew Barnert
Based on mtTkinter (for Python 2.x), copyright (c) 2009, Allen B. Taylor
This module is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser Public License for more details.
You should have received a copy of the GNU Lesser Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Usage:
import mttkinter as tkinter
# Use "t." as usual.
or
from mtt import *
# Use tkinter module definitions as usual.
This module modifies the original tkinter module in memory, making all
functionality thread-safe. It does this by wrapping the Tk class' tk
instance with an object that diverts calls through an event queue when
the call is issued from a thread other than the thread in which the Tk
instance was created. The events are processed in the creation thread
via an 'after' event.
The modified Tk class accepts two additional keyword parameters on its
__init__ method:
mtDebug:
0 = No debug output (default)
1 = Minimal debug output
...
9 = Full debug output
mtCheckPeriod:
Amount of time in milliseconds (default 100) between checks for
out-of-thread events when things are otherwise idle. Decreasing
this value can improve GUI responsiveness, but at the expense of
consuming more CPU cycles.
Note that, because it modifies the original tkinter module (in memory),
other modules that use tkinter (e.g., Pmw) reap the benefits automagically
as long as mttkinter is imported at some point before extra threads are
created.
Author: Allen B. Taylor, a.b.taylor@gmail.com
'''
import sys
import threading
if sys.version_info[0] == 2:
# Python 2
from Tkinter import *
import Queue as queue
else:
# Python 3
from tkinter import *
import queue
class _Tk(object):
"""Wrapper for underlying attribute tk of class Tk"""
def __init__(self, tk, mt_debug=0, mt_check_period=10):
"""
:param tk: Tkinter.Tk.tk Tk interpreter object
:param mt_debug: Determines amount of debug output.
0 = No debug output (default)
1 = Minimal debug output
...
9 = Full debug output
:param mt_check_period: Amount of time in milliseconds (default
10) between checks for out-of-thread events when things are
otherwise idle. Decreasing this value can improve GUI
responsiveness, but at the expense of consuming more CPU
cycles.
# TODO: Replace custom logging functionality with standard
# TODO: logging.Logger for easier access and standardization
"""
self._tk = tk
# Create the incoming event queue
self._event_queue = queue.Queue(1)
# Identify the thread from which this object is being created
# so we can tell later whether an event is coming from another
# thread.
self._creation_thread = threading.current_thread()
# Create attributes for kwargs
self._debug = mt_debug
self._check_period = mt_check_period
# Destroying flag to be set by the .destroy() hook
self._destroying = False
def __getattr__(self, name):
"""
Diverts attribute accesses to a wrapper around the underlying tk
object.
"""
return _TkAttr(self, getattr(self._tk, name))
class _TkAttr(object):
"""Thread-safe callable attribute wrapper"""
def __init__(self, tk, attr):
self._tk = tk
self._attr = attr
def __call__(self, *args, **kwargs):
"""
Thread-safe method invocation. Diverts out-of-thread calls
through the event queue. Forwards all other method calls to the
underlying tk object directly.
"""
# Check if we're in the creation thread
if threading.current_thread() == self._tk._creation_thread:
# We're in the creation thread; just call the event directly
if self._tk._debug >= 8 or \
self._tk._debug >= 3 and self._attr.__name__ == 'call' and \
len(args) >= 1 and args[0] == 'after':
print('Calling event directly:', self._attr.__name__, args, kwargs)
return self._attr(*args, **kwargs)
else:
if not self._tk._destroying:
# We're in a different thread than the creation thread;
# enqueue the event, and then wait for the response.
response_queue = queue.Queue(1)
if self._tk._debug >= 1:
print('Marshalling event:', self._attr.__name__, args, kwargs)
self._tk._event_queue.put((self._attr, args, kwargs, response_queue), True, 1)
is_exception, response = response_queue.get(True, None)
# Handle the response, whether it's a normal return value or
# an exception.
if is_exception:
ex_type, ex_value, ex_tb = response
raise ex_type(ex_value, ex_tb)
return response
def _Tk__init__(self, *args, **kwargs):
"""
Hook for Tkinter.Tk.__init__ method
:param self: Tk instance
:param args, kwargs: Arguments for Tk initializer
"""
# We support some new keyword arguments that the original __init__ method
# doesn't expect, so separate those out before doing anything else.
new_kwnames = ('mt_check_period', 'mt_debug')
new_kwargs = {
kw_name: kwargs.pop(kw_name) for kw_name in new_kwnames
if kwargs.get(kw_name, None) is not None
}
# Call the original __init__ method, creating the internal tk member.
self.__original__init__mtTkinter(*args, **kwargs)
# Replace the internal tk member with a wrapper that handles calls from
# other threads.
self.tk = _Tk(self.tk, **new_kwargs)
# Set up the first event to check for out-of-thread events.
self.after_idle(_check_events, self)
# Define a hook for class Tk's destroy method.
def _Tk_destroy(self):
self.tk._destroying = True
self.__original__destroy()
def _check_events(tk):
"""Checks events in the queue on a given Tk instance"""
used = False
try:
# Process all enqueued events, then exit.
while True:
try:
# Get an event request from the queue.
method, args, kwargs, response_queue = tk.tk._event_queue.get_nowait()
except queue.Empty:
# No more events to process.
break
else:
# Call the event with the given arguments, and then return
# the result back to the caller via the response queue.
used = True
if tk.tk._debug >= 2:
print('Calling event from main thread:', method.__name__, args, kwargs)
try:
response_queue.put((False, method(*args, **kwargs)))
except SystemExit:
raise # Raises original SystemExit
except Exception:
# Calling the event caused an exception; return the
# exception back to the caller so that it can be raised
# in the caller's thread.
from sys import exc_info # Python 2 requirement
ex_type, ex_value, ex_tb = exc_info()
response_queue.put((True, (ex_type, ex_value, ex_tb)))
finally:
# Schedule to check again. If we just processed an event, check
# immediately; if we didn't, check later.
if used:
tk.after_idle(_check_events, tk)
else:
tk.after(tk.tk._check_period, _check_events, tk)
"""Perform in-memory modification of Tkinter module"""
# Replace Tk's original __init__ with the hook.
Tk.__original__init__mtTkinter = Tk.__init__
Tk.__init__ = _Tk__init__
# Replace Tk's original destroy with the hook.
Tk.__original__destroy = Tk.destroy
Tk.destroy = _Tk_destroy

File diff suppressed because it is too large Load Diff

1
games/pong/main 100644

File diff suppressed because one or more lines are too long

Binary file not shown.

BIN
games/pong/won.wav 100644

Binary file not shown.

View File

@ -5,6 +5,7 @@ import threading
import time import time
import wave import wave
import os import os
import math
class stdrend: class stdrend:
def __init__(self, size, cam): def __init__(self, size, cam):
@ -110,7 +111,7 @@ class vector2:
self.x = x self.x = x
self.y = y self.y = y
self._type = "vector2" self._type = "vector2"
def _magnitude(self): def _magnitude(self):
return abs(self.x+self.y) return abs(self.x+self.y)
@ -243,22 +244,32 @@ class game:
out = [] out = []
for i in self._objects: for i in self._objects:
i = self._objects[i] i = self._objects[i]
if i in ignore: continue if i.ID in ignore: continue
if (i.position-pos)._magnitude() < 1 and i.collide == True: if math.dist([i.position.x, i.position.y], [pos.x, pos.y]) < 1 and i.collide == True:
out.append(i) out.append(i)
return out return out
def colliding(self, target): def colliding(self, target):
out = [] out = []
if target.collide == False: return [] if target.collide == False: return []
out = self.collidingpos(target.position, [target,]) out = self.collidingpos(target.position, [target.ID,])
return out return out
def handlecollision(self, target: obj, target2: obj): def handlecollision(self, target: obj, target2: obj):
if target2.anchored == True: if target2.anchored == True:
target.velocity = vector2() target.velocity = vector2()
else: else:
half = vector2(target.velocity.x/2, target.velocity.y/2) xtrue = False
ytrue = False
if target.velocity.x > 0:
xtrue = True
if target.velocity.y > 0:
ytrue = True
half = vector2(abs(target.velocity.x)/2, abs(target.velocity.y)/2)
if not xtrue:
half = vector2(-abs(half.x), half.y)
if not ytrue:
half = vector2(half.x, -abs(half.y))
target.velocity = vector2(half.x, half.y) target.velocity = vector2(half.x, half.y)
target2.velocity = half target2.velocity = half
self._threads.extend(target._touching.execute()) self._threads.extend(target._touching.execute())
@ -269,7 +280,7 @@ class game:
collide = False collide = False
if target.anchored == True: return [opos, collide] if target.anchored == True: return [opos, collide]
if target.collide == True: if target.collide == True:
colliding = self.collidingpos(target.position+target.velocity, [target,]) colliding = self.collidingpos(target.position+target.velocity, [target.ID,])
for i in colliding: for i in colliding:
target._touching.execute() target._touching.execute()
i._touching.execute() i._touching.execute()
@ -281,6 +292,8 @@ class game:
temp = 2 temp = 2
if target.friction != 0: if target.friction != 0:
temp = 2 / target.friction temp = 2 / target.friction
else:
temp = 1
x = target.velocity.x x = target.velocity.x
y = target.velocity.y y = target.velocity.y
if x != 0: if x != 0:

View File

@ -38,4 +38,7 @@
"import": "Importieren", "import": "Importieren",
"clog": "Logs erstellen", "clog": "Logs erstellen",
"copied": "Kopiert!", "copied": "Kopiert!",
"settings": "Einstellungen",
"gamex": "Spiel x Groesse",
"gamey": "Spiel y Groesse",
} }

View File

@ -38,4 +38,7 @@
"import": "Import", "import": "Import",
"clog": "Create logs", "clog": "Create logs",
"copied": "Copied!", "copied": "Copied!",
"settings": "Einstellungen",
"gamex": "Game x size",
"gamey": "Game y size",
} }

170
main.py
View File

@ -94,7 +94,7 @@ def prepspecified(target):
temp["args"] = tempargs temp["args"] = tempargs
out.append(temp) out.append(temp)
tempwin.destroy() tempwin.destroy()
return [out, modellist] return [out, modellist, gamexsize, gameysize]
class script: class script:
def __init__(self): def __init__(self):
@ -140,6 +140,10 @@ class previewrend:
self._posframe.grid() self._posframe.grid()
self._frame.grid() self._frame.grid()
def destroy(self):
self._posframe.destroy()
self._frame.destroy()
def keypupd(self, event): def keypupd(self, event):
event = event.char event = event.char
if event in self._keys: if event in self._keys:
@ -166,6 +170,14 @@ class previewrend:
def update(self): def update(self):
self._win.update() self._win.update()
def select(self, x, y):
if f"{x}:{y}" in self._grid:
self._grid[f"{x}:{y}"].config(background="cyan")
def deselect(self, x, y):
if f"{x}:{y}" in self._grid:
self._grid[f"{x}:{y}"].config(background="white")
def pix(self, x, y, text, bcolor, fcolor): def pix(self, x, y, text, bcolor, fcolor):
self._xcam.config(text=LH.string("xcam")+str(self._cam.position.x)) self._xcam.config(text=LH.string("xcam")+str(self._cam.position.x))
self._ycam.config(text=LH.string("ycam")+str(self._cam.position.y)) self._ycam.config(text=LH.string("ycam")+str(self._cam.position.y))
@ -333,7 +345,7 @@ def HMPC(event):
if not "ID" in gamedata[i]["args"]: continue if not "ID" in gamedata[i]["args"]: continue
setattr(gamedata[i]["args"]["position"], name, getattr(gamedata[i]["args"]["position"], name)+back) setattr(gamedata[i]["args"]["position"], name, getattr(gamedata[i]["args"]["position"], name)+back)
setattr(preview.getobjbyid(gamedata[i]["args"]["ID"]).position, name, getattr(preview.getobjbyid(gamedata[i]["args"]["ID"]).position, name)+back) setattr(preview.getobjbyid(gamedata[i]["args"]["ID"]).position, name, getattr(preview.getobjbyid(gamedata[i]["args"]["ID"]).position, name)+back)
preview.render() updselect(None)
def changemodelpos(event): def changemodelpos(event):
atritree.delete(*atritree.get_children()) atritree.delete(*atritree.get_children())
@ -390,36 +402,39 @@ def halatribute(event):
target = atritree.focus() target = atritree.focus()
name = atritree.item(target, "text") name = atritree.item(target, "text")
parent = atritree.parent(target) parent = atritree.parent(target)
currentobj = currentat
if name in valtypes: if name in valtypes:
if parent == "": if parent == "":
new = valtypes[name](gamedata[currentat]["args"][name]) new = valtypes[name](gamedata[currentobj]["args"][name])
gamedata[currentat]["args"][name] = new gamedata[currentobj]["args"][name] = new
if "ID" in gamedata[currentat]["args"]: if "ID" in gamedata[currentobj]["args"]:
temp = preview.getobjbyid(gamedata[currentat]["args"]["ID"]) temp = preview.getobjbyid(gamedata[currentobj]["args"]["ID"])
setattr(temp, name, new) setattr(temp, name, new)
if not name in DCTE: atritree.item(target, values=(new)) atritree.delete(*atritree.get_children())
if name in DCTE: atritree.item(target, values=("<DCTE>")) objtree.focus("")
else: else:
parent = atritree.item(parent, "text") parent = atritree.item(parent, "text")
new = valtypes[name](getattr(gamedata[currentat]["args"][parent], name)) new = valtypes[name](getattr(gamedata[currentobj]["args"][parent], name))
setattr(gamedata[currentat]["args"][parent], name, new) setattr(gamedata[currentobj]["args"][parent], name, new)
if "ID" in gamedata[currentat]["args"]: if "ID" in gamedata[currentobj]["args"]:
temp = preview.getobjbyid(gamedata[currentat]["args"]["ID"]) temp = preview.getobjbyid(gamedata[currentobj]["args"]["ID"])
setattr(temp, name, new) setattr(temp, name, new)
if not name in DCTE: atritree.item(target, values=(new)) atritree.delete(*atritree.get_children())
if name in DCTE: atritree.item(target, values=("<DCTE>")) objtree.focus("")
preview.render() updselect(None)
def updatepreviewcam(char): def updatepreviewcam(char):
global cooldown global cooldown
if cooldown == True: return if cooldown == True: return
cooldown = True cooldown = True
char = char.char char = char.char
allowed = ["w", "a", "s", "d"]
if not char in allowed: return
if char == "w": preview.camera.position += hashengine.vector2(y=1) if char == "w": preview.camera.position += hashengine.vector2(y=1)
if char == "a": preview.camera.position += hashengine.vector2(x=1) if char == "a": preview.camera.position += hashengine.vector2(x=1)
if char == "s": preview.camera.position -= hashengine.vector2(y=1) if char == "s": preview.camera.position -= hashengine.vector2(y=1)
if char == "d": preview.camera.position -= hashengine.vector2(x=1) if char == "d": preview.camera.position -= hashengine.vector2(x=1)
preview.render() updselect(None)
time.sleep(.0) time.sleep(.0)
cooldown = False cooldown = False
@ -497,7 +512,7 @@ def load(cleargame=True, GUI=True, path="", override=False):
clear() clear()
if len(target) == 0: return if len(target) == 0: return
if not isinstance(target[0], list): if not isinstance(target[0], list):
#old save file #very old save file
count = 1 count = 1
bar = tkk.Progressbar(tempwin, maximum=len(target)) bar = tkk.Progressbar(tempwin, maximum=len(target))
bar.place(width=200) bar.place(width=200)
@ -510,8 +525,8 @@ def load(cleargame=True, GUI=True, path="", override=False):
count += 1 count += 1
tempwin.destroy() tempwin.destroy()
preview.render() preview.render()
else: elif len(target) < 3:
#new save file #old save file
count = 1 count = 1
bar = tkk.Progressbar(tempwin, maximum=len(target)) bar = tkk.Progressbar(tempwin, maximum=len(target))
bar.place(width=200) bar.place(width=200)
@ -537,6 +552,38 @@ def load(cleargame=True, GUI=True, path="", override=False):
models.append(temp) models.append(temp)
tempwin.destroy() tempwin.destroy()
preview.render() preview.render()
else:
#new save file
global gamexsize
global gameysize
count = 1
bar = tkk.Progressbar(tempwin, maximum=len(target))
bar.place(width=200)
ids = {}
for i in target[0]:
ptext.config(text="Current: "+i["name"])
bar.step()
stat.config(text=f"Object {count}/{len(target)}")
tempwin.update()
id = importobj(i)
if id:
ids[count-1] = id
count += 1
for i in target[1]:
tempid = genid()
if GUIe == True: objtree.insert("", tk.END, text=i, image=icons["model"], iid=tempid, tags=("HASHMODEL",))
temp = []
for f in target[1][i]:
if GUIe == True:
objtree.detach(ids[f])
objtree.move(ids[f], tempid, "end")
temp.append(ids[f])
models.append(temp)
tempwin.destroy()
gamexsize = target[2]
gameysize = target[3]
if GUIe == True: initpreview()
preview.render()
def export(): def export():
temp = objtree.selection() temp = objtree.selection()
@ -598,8 +645,13 @@ def testing():
testproc = multiprocessing.Process(target=execgame, args=(prepspecified(gamedata), clog.get())) testproc = multiprocessing.Process(target=execgame, args=(prepspecified(gamedata), clog.get()))
testproc.start() testproc.start()
def APIGEN():
API = {"print": log, "HASHBASE": hashengine}
API["HASHGAME"] = maingame
API["SOUND"] = lambda data: gsound(data, maingame)
return API
def run(): def run():
print("preparing log file...")
global logfile global logfile
global maingame global maingame
global window global window
@ -607,18 +659,14 @@ def run():
logfile = "" logfile = ""
for i in temp: for i in temp:
logfile = logfile + "S" + str(i) logfile = logfile + "S" + str(i)
print("done")
log("Log file start!") log("Log file start!")
log(f"date: year: {temp[0]} month: {temp[1]} day: {temp[2]} hour: {temp[3]} min.: {temp[4]}, sec.: {temp[5]}") log(f"date: year: {temp[0]} month: {temp[1]} day: {temp[2]} hour: {temp[3]} min.: {temp[4]}, sec.: {temp[5]}")
log(f"Version: {version}") log(f"Version: {version}")
log("Preparing API...") log("Preparing API...")
API = {"print": log, "HASHBASE": hashengine}
log("Done!") log("Done!")
window = tk.Tk() window = tk.Tk()
window.protocol("WM_DELETE_WINDOW", NULL) window.protocol("WM_DELETE_WINDOW", NULL)
maingame = hashengine.game(renderer=lambda size, cam: render(size, cam, window, [0, 0]), sounddir="/") maingame = hashengine.game(renderer=lambda size, cam: render(size, cam, window, [0, 0]), sounddir="/", size=[gamexsize, gameysize])
API["HASHGAME"] = maingame
API["SOUND"] = lambda data: gsound(data, maingame)
log("main game initalised!") log("main game initalised!")
log("copying sounds...") log("copying sounds...")
for i in gamedata: for i in gamedata:
@ -672,11 +720,11 @@ while True:
""" """
gameloopsc = script() gameloopsc = script()
gameloopsc.code = gamescript gameloopsc.code = gamescript
maingame.startscript(lambda: gameloopsc.execute(API, log)) maingame.startscript(lambda: gameloopsc.execute(APIGEN(), log))
log("game test started!!!") log("game test started!!!")
log("---------------------") log("---------------------")
for i in scripts: for i in scripts:
maingame.startscript(lambda: i.execute(API, log)) maingame.startscript(lambda: i.execute(APIGEN(), log))
window.mainloop() window.mainloop()
def muladd(target): def muladd(target):
@ -780,16 +828,62 @@ def COBS(target: str, offset=hashengine.vector2(), ignore=[" ",]):
gamedata[temp]["args"]["collide"] = True gamedata[temp]["args"]["collide"] = True
setattr(preview.getobjbyid(gamedata[temp]["args"]["ID"]), "collide", True) setattr(preview.getobjbyid(gamedata[temp]["args"]["ID"]), "collide", True)
#preview.render() #preview.render()
preview.render() updselect(None)
tempwin.destroy() tempwin.destroy()
def updselect(event):
preview.render()
selection = objtree.selection()
for selected in selection:
if "objsel" in objtree.item(selected, "tags"):
if gamedata[selected]["id"] == "obj":
preview._renderer.select(gamedata[selected]["args"]["position"].x+preview.camera.position.x, gamedata[selected]["args"]["position"].y+preview.camera.position.y)
if "HASHMODEL" in objtree.item(selected, "tags"):
for i in objtree.get_children(selected):
if "objsel" in objtree.item(i, "tags"):
if gamedata[i]["id"] == "obj":
preview._renderer.select(gamedata[i]["args"]["position"].x+preview.camera.position.x, gamedata[i]["args"]["position"].y+preview.camera.position.y)
def changegamex():
global gamexsize
gamexsize = int(aposx(gamexsize))
initpreview()
def changegamey():
global gameysize
gameysize = int(aposy(gameysize))
initpreview()
def initpreview():
global preview
objs = {}
try:
objs = preview._objects
preview._renderer.destroy()
ungridobjtrees()
except:
pass
preview = hashengine.game(renderer=lambda size, cam: previewrend(size, cam, container=container, offset=[0, 0]), sounddir="/", size=[gamexsize, gameysize])
preview._objects = objs
try:
gridobjtrees()
except NameError:
pass
def gridobjtrees():
objtree.grid(row=1, column=0)
atritree.grid(row=2, column=0)
def ungridobjtrees():
objtree.grid_remove()
atritree.grid_remove()
def GUIinit(): def GUIinit():
global container global container
global objtree global objtree
global rmenu global rmenu
global atritree global atritree
global currentat global currentat
global preview
global GUIe global GUIe
global clog global clog
global models global models
@ -805,13 +899,14 @@ def GUIinit():
icons[i.split(".")[0]] = tk.PhotoImage(file=f"icons/{i}") icons[i.split(".")[0]] = tk.PhotoImage(file=f"icons/{i}")
#preview init #preview init
preview = hashengine.game(renderer=lambda size, cam: previewrend(size, cam, container=container, offset=[0, 0]), sounddir="/") initpreview()
#tree init #tree init
objtree = tkk.Treeview(container, columns=("-")) objtree = tkk.Treeview(container, columns=("-"))
objtree.heading("#0", text=LH.string("objs")) objtree.heading("#0", text=LH.string("objs"))
objtree.tag_bind("objsel", "<<TreeviewSelect>>", updatribute) objtree.tag_bind("objsel", "<<TreeviewSelect>>", updatribute)
objtree.tag_bind("HASHMODEL", "<<TreeviewSelect>>", changemodelpos) objtree.tag_bind("HASHMODEL", "<<TreeviewSelect>>", changemodelpos)
objtree.bind("<<TreeviewSelect>>", updselect, add="+")
objtree.grid(row=1, column=0) objtree.grid(row=1, column=0)
#attribute tree init #attribute tree init
@ -868,6 +963,11 @@ def GUIinit():
menu.add_cascade(label=LH.string("building"), menu=buildmenu) menu.add_cascade(label=LH.string("building"), menu=buildmenu)
buildmenu.add_command(label=LH.string("build"), command=build, image=icons["build"], compound="left") buildmenu.add_command(label=LH.string("build"), command=build, image=icons["build"], compound="left")
settings = tk.Menu(menu)
menu.add_cascade(label=LH.string("settings"), menu=settings)
settings.add_command(label=LH.string("gamex"), command=changegamex)
settings.add_command(label=LH.string("gamey"), command=changegamey)
langmenu = tk.Menu(menu) langmenu = tk.Menu(menu)
menu.add_cascade(label=LH.string("langs"), menu=langmenu) menu.add_cascade(label=LH.string("langs"), menu=langmenu)
for i in LH.getlangs(): for i in LH.getlangs():
@ -932,7 +1032,7 @@ def aposx(old):
wait = True wait = True
temp = tk.Toplevel() temp = tk.Toplevel()
butframe = tk.Frame(temp) butframe = tk.Frame(temp)
currentvar = tk.IntVar(temp, value=old) currentvar = tk.DoubleVar(temp, value=old)
current = tk.Entry(temp, textvariable=currentvar) current = tk.Entry(temp, textvariable=currentvar)
current.grid(row=0) current.grid(row=0)
b1 = tk.Button(butframe, image=icons["ar-left"], command=lambda: currentvar.set(currentvar.get()-1)) b1 = tk.Button(butframe, image=icons["ar-left"], command=lambda: currentvar.set(currentvar.get()-1))
@ -948,6 +1048,7 @@ def aposx(old):
temp.destroy() temp.destroy()
numbers = list(string.digits) numbers = list(string.digits)
numbers.append("-") numbers.append("-")
numbers.append(".")
for i in str(tempvar): for i in str(tempvar):
if not i in numbers: if not i in numbers:
return old return old
@ -958,7 +1059,7 @@ def aposy(old):
wait = True wait = True
temp = tk.Toplevel() temp = tk.Toplevel()
butframe = tk.Frame(temp) butframe = tk.Frame(temp)
currentvar = tk.IntVar(temp, value=old) currentvar = tk.DoubleVar(temp, value=old)
current = tk.Entry(temp, textvariable=currentvar) current = tk.Entry(temp, textvariable=currentvar)
current.grid(row=0) current.grid(row=0)
b1 = tk.Button(butframe, image=icons["ar-up"], command=lambda: currentvar.set(currentvar.get()-1)) b1 = tk.Button(butframe, image=icons["ar-up"], command=lambda: currentvar.set(currentvar.get()-1))
@ -974,6 +1075,7 @@ def aposy(old):
temp.destroy() temp.destroy()
numbers = list(string.digits) numbers = list(string.digits)
numbers.append("-") numbers.append("-")
numbers.append(".")
for i in str(tempvar): for i in str(tempvar):
if not i in numbers: if not i in numbers:
return old return old
@ -1008,6 +1110,10 @@ global extypes
global attypes global attypes
global crucial global crucial
global DCTE global DCTE
global gamexsize
global gameysize
gamexsize = 10
gameysize = 10
crucial = ["obj"] crucial = ["obj"]
types = hashengine.enum({"obj": hashengine.obj, "script": script, "rawsound": rsound, "sound": lambda: sound(apath("", [("Wave files", ".wave .wav")]))}) types = hashengine.enum({"obj": hashengine.obj, "script": script, "rawsound": rsound, "sound": lambda: sound(apath("", [("Wave files", ".wave .wav")]))})
ignoreat = ["ID", "execute", "sdata"] ignoreat = ["ID", "execute", "sdata"]

View File

@ -19,7 +19,7 @@ To create objects in the game, use HASHBASE.obj().
No optional arguments. No optional arguments.
events are used to execute one or more scripts when it is executed. events are used to execute one or more scripts when it is executed.
normal use cases of events are in objects._touched and all scripts attached to that event normal use cases of events are in objects. the event \<OBJECT>._touching and all scripts attached to that event
get executed once that object is colliding with something. get executed once that object is colliding with something.
to attach to an event use \<EVENT>.attach(\<FUNCTION>). to attach to an event use \<EVENT>.attach(\<FUNCTION>).
to create your own event use HASHBASE.event(), you can execute the event with \<EVENT>.execute() which will return a list of created threads where the executed functions run in. to create your own event use HASHBASE.event(), you can execute the event with \<EVENT>.execute() which will return a list of created threads where the executed functions run in.