RGameLib.py source code
RGameLib.py
#----------------------------------
#----------------------------------
# Imports
#----------------------------------
#----------------------------------
import decimal
import math
from decimal import Decimal
#----------------------------------
#----------------------------------
# Vectors
#----------------------------------
#----------------------------------
class RG_Vector2D:
# ----------------------------------
# Variables:
# ----------------------------------
_length:Decimal = Decimal(0.0);
X:Decimal = Decimal(0.0);
Y:Decimal = Decimal(0.0);
# ----------------------------------
# Base Functions:
# ----------------------------------
# Constructor
def __init__(self, x:Decimal = Decimal(0.0), y:Decimal = Decimal(0.0)) -> None:
# Initializing X and Y.
self.X = Decimal(x);
self.Y = Decimal(y);
# Initializing the length.
self.GetLength();
pass;
# To String
def __str__(self) -> str:
return "Vector 2D: (X: "+str(self.X) + ", Y: " + str(self.Y) + ")"
# Equals
def __eq__(self, other) -> bool:
if(not type(other) is RG_Vector2D): return False;
return other.X == self.X and other.Y == self.Y;
#------------------------------------
# Functions:
# -----------------------------------
def ToVector(self):
return self
def ToVelocity(self):
return RG_Velocity2D(self.X, self.Y)
def GetLength(self) -> Decimal:
# Get length squared
LengthSqr = self.GetlengthSqr();
# Check if anything changedS
if(self._length * self._length == LengthSqr):
return self._length;
# Otherwise complete the square rooting of the length and store the result.
self._length = Decimal.sqrt(Decimal(LengthSqr));
return self._length;
def GetlengthSqr(self) -> Decimal:
return self.X * self.X + self.Y * self.Y;
def SetLength(self, newLength):
length = self.GetLength();
if(newLength == length):
return;
if(length == 0):
raise Exception("Cannot set the length of the 0 vector or a velocity with the speed of 0 to any other value than 0.")
self.NormalizeOpt(length);
h = self * newLength;
self.X = h.X;
self.Y = h.Y;
self._length = h._length;
pass;
def Normalize(self):
length = self.GetLength();
if(length == 0):
raise Exception("Cannot normalize the 0 vector or a velocity with the speed of 0.")
h = self / length;
self.X = h.X;
self.Y = h.Y;
pass;
def NormalizeOpt(self, length):
if(length == 0):
raise Exception("Cannot normalize the 0 vector or a velocity with the speed of 0.")
h = self / length;
self.X = h.X;
self.Y = h.Y;
pass
def DotProduct(self, other):
return other.X * self.X + other.Y * self.Y
# ----------------------------------
# Operator Overloading:
# ----------------------------------
# Plus: +
def __add__(self, Right):
self.Y = Decimal(self.Y)
self.X = Decimal(self.X)
# Get Type.
tp = type(Right);
# If point then return point
if(tp is RG_Point2D or tp is RG_Position2D):
x = self.X + Decimal(Right.X);
y = self.Y + Decimal(Right.Y);
return RG_Point2D(x, y);
# If vector then return vector.
elif(tp is RG_Vector2D or tp is RG_Velocity2D):
x = self.X + Decimal(Right.X);
y = self.Y + Decimal(Right.Y);
return RG_Vector2D(x, y);
# Otherwise it is not a compatible correct type so a type error will be raised:
raise TypeError("You can only add vectors with Points or other vectors (with the same number of dimensions)."+str(tp));
# Subtract: -
def __sub__(self, Right):
self.Y = Decimal(self.Y)
self.X = Decimal(self.X)
# Get Type.
tp = type(Right);
# If point then return point
if(tp is RG_Point2D):
x = self.X - Decimal(Right.X);
y = self.Y - Decimal(Right.Y);
return RG_Point2D(x, y);
# If vector then return vector.
elif(tp is RG_Vector2D):
x = self.X - Decimal(Right.X);
y = self.Y - Decimal(Right.Y);
return RG_Vector2D(x, y);
# Otherwise it is not a compatible correct type so a type error will be raised:
raise TypeError("You can only take away vectors with Points or other vectors (with the same number of dimensions).");
# Multiply: *
def __mul__(self, Right):
self.Y = Decimal(self.Y)
self.X = Decimal(self.X)
# Get Type.
tp = type(Right);
# If num then do num multiplication
if(tp is float or tp is int ):
x = self.X * Decimal(Right);
y = self.Y * Decimal(Right);
return RG_Vector2D(x, y);
if(tp is Decimal ):
x = self.X * Right;
y = self.Y * Right;
return RG_Vector2D(x, y);
# If vector then do vector multiplication
elif(tp is RG_Vector2D):
x = self.X * Decimal(Right.X);
y = self.Y * Decimal(Right.Y);
return RG_Vector2D(x, y);
# Otherwise it is not a compatible correct type so a type error will be raised:
raise TypeError("You can only multiply vectors by intigers, floats, Decimal, and other vectors (with the same number of dimensions)."+str(tp));
# Divide: /
def __truediv__(self, Right):
self.Y = Decimal(self.Y)
self.X = Decimal(self.X)
# Get Type.
tp = type(Right);
# If num then do num devision
if(tp is float or tp is int or tp is decimal.Decimal):
x = self.X / Decimal(Right);
y = self.Y / Decimal(Right);
return RG_Vector2D(x, y);
# If vector then do vector division
elif(tp is RG_Vector2D):
x = self.X / Decimal(Right.X);
y = self.Y / Decimal(Right.Y);
return RG_Vector2D(x, y);
# Otherwise it is not a compatible correct type so a type error will be raised:
raise TypeError("You can only divide vectors by intigers, floats, Decimal, and other vectors (with the same number of dimensions).");
# Floor Divide: //
def __floordiv__(self, Right):
self.Y = Decimal(self.Y)
self.X = Decimal(self.X)
# Get Type.
tp = type(Right);
# If num then do num floor division
if(tp is float or tp is int or tp is decimal.Decimal):
x = self.X // Decimal(Right);
y = self.Y // Decimal(Right);
return RG_Vector2D(x, y);
# If vector then do vector floor division
elif(tp is RG_Vector2D):
x = self.X // Decimal(Right.X);
y = self.Y // Decimal(Right.Y);
return RG_Vector2D(x, y);
# Otherwise it is not a compatible correct type so a type error will be raised:
raise TypeError("You can only floor divide vectors by integers, floats, Decimal, and other vectors (with the same number of dimensions).");
# Modulus: %
def __mod__(self, Right):
self.Y = Decimal(self.Y)
self.X = Decimal(self.X)
# Get Type.
tp = type(Right);
# If num then do num modulus
if(tp is float or tp is int or tp is decimal.Decimal):
x = self.X % Decimal(Right);
y = self.Y % Decimal(Right);
return RG_Vector2D(x, y);
# If vector then do vector modulus
elif(tp is RG_Vector2D):
x = self.X % Decimal(Right.X);
y = self.Y % Decimal(Right.Y);
return RG_Vector2D(x, y);
# Otherwise it is not a compatible correct type so a type error will be raised:
raise TypeError("You can only modulus vectors by integers, floats, Decimal and other vectors (with the same number of dimensions).");
pass;
class RG_Velocity2D(RG_Vector2D):
# ----------------------------------
# Base Functions:
# ----------------------------------
# Constructor
def __init__(self, x:Decimal = Decimal(0.0), y:Decimal = Decimal(0.0)):
super().__init__(x, y)
pass;
# To String
def __str__(self) -> str:
return "Velocity: (X: "+str(self.X) + ", Y: " + str(self.Y) + ")"
# Equals
def __eq__(self, other:RG_Vector2D) -> bool:
return other.X == self.X and other.Y == self.Y;
# ----------------------------------
# Wrappers:
# ----------------------------------
def SetSpeed(self, speed):
self.SetLength(Decimal(speed));
def GetSpeed(self):
return float(self.GetLength());
def ToVector(self):
return RG_Vector2D(self.X, self.Y);
def ToVelocity(self):
return self
def __add__(self, Right):
t = type(Right)
if(t is RG_Velocity2D):
Right = Right.ToVector()
if(t is RG_Position2D):
Right = Right.ToPoint()
vec = super().__add__(Right)
if (t is RG_Position2D):
return RG_Position2D(vec.X,vec.Y)
if (t is RG_Point2D):
return RG_Point2D(vec.X,vec.Y)
return RG_Velocity2D(vec.X,vec.Y)
def __sub__(self, Right):
t = type(Right)
if(t is RG_Velocity2D):
Right = Right.ToVector();
if(t is RG_Position2D):
Right = Right.ToPoint();
vec = super().__sub__(Right)
if (t is RG_Position2D):
return RG_Position2D(vec.X,vec.Y)
if (t is RG_Point2D):
return RG_Point2D(vec.X,vec.Y)
return RG_Velocity2D(vec.X,vec.Y)
def __mul__(self, Right):
vec = super().__mul__(Right)
return RG_Velocity2D(vec.X,vec.Y)
def __truediv__(self, Right):
vec = super().__truediv__(Right)
return RG_Velocity2D(vec.X,vec.Y)
def __floordiv__(self, Right):
vec = super().__floordiv__(Right)
return RG_Velocity2D(vec.X,vec.Y)
def __mod__(self, Right):
vec = super().__mod__(Right)
return RG_Velocity2D(vec.X,vec.Y)
pass;
#----------------------------------
#----------------------------------
# Points
#----------------------------------
#----------------------------------
class RG_Point2D:
# ----------------------------------
# Variables:
# ----------------------------------
X:Decimal = Decimal(0.0);
Y:Decimal = Decimal(0.0);
# ----------------------------------
# Base Functions:
# ----------------------------------
# Constructor
def __init__(self, x:Decimal = 0.0, y:Decimal = 0.0) -> None:
self.X = Decimal(x);
self.Y = Decimal(y);
pass;
# To String
def __str__(self) -> str:
return "Point: (X: "+str(self.X) + ", Y: " + str(self.Y) + ")"
# Equals
def __eq__(self, other) -> bool:
if(not type(other) is RG_Point2D): return False;
return other.X == self.X and other.Y == self.Y;
def ToPosition(self):
return RG_Position2D(self.X, self.Y);
def ToPoint(self):
return self;
# ----------------------------------
# Operator Overloading:
# ----------------------------------
# Plus: +
def __add__(self, Right):
self.Y = Decimal(self.Y)
self.X = Decimal(self.X)
# If not vector then throw error
if(not (type(Right) is RG_Vector2D or type(Right) is RG_Velocity2D)):
raise TypeError("You can only add vectors to points (with the same number of dimensions)."+str(type(Right)));
# Otherwise complete the addition
x = self.X + Decimal(Right.X);
y = self.Y + Decimal(Right.Y);
return RG_Point2D(x, y);
# Subtract: -
def __sub__(self, Right):
t = type(Right)
self.Y = Decimal(self.Y)
self.X = Decimal(self.X)
# If not point or vec then throw error
if(t is RG_Point2D):
x = self.X - Decimal(Right.X);
y = self.Y - Decimal(Right.Y);
return RG_Vector2D(x, y);
elif(t is RG_Vector2D):
x = self.X - Decimal(Right.X);
y = self.Y - Decimal(Right.Y);
return RG_Point2D(x, y);
else:
raise TypeError("You can only subtract points and vectors from other points (with the same number of dimensions).");
# Otherwise complete the subtraction
pass;
class RG_Position2D(RG_Point2D):
# ----------------------------------
# Base Functions:
# ----------------------------------
# Constructor
def __init__(self, x: Decimal = Decimal(0.0), y: Decimal = Decimal(0.0)) -> None:
super().__init__(x, y)
pass;
# To String
def __str__(self) -> str:
return "Position: (X: "+str(self.X) + ", Y: " + str(self.Y) + ")"
# Equals
def __eq__(self, other:RG_Point2D) -> bool:
return other.X == self.X and other.Y == self.Y;
# ----------------------------------
# Functions:
# ----------------------------------
def ToPosition(self):
return self;
def ToPoint(self):
return RG_Point2D(self.X, self.Y);
def Move(self, velocity:RG_Velocity2D):
newPos = velocity + self;
self.X = newPos.X;
self.Y = newPos.Y;
def VectorTo(self, other) -> RG_Vector2D:
return other - self;
def __add__(self, Right):
t = type(Right)
if(t is RG_Velocity2D):
Right = Right.ToVector();
vec = super().__add__(Right)
return RG_Position2D(vec.X,vec.Y)
def __sub__(self, Right):
t = type(Right)
if(t is RG_Velocity2D):
Right = Right.ToVector();
if(t is RG_Position2D):
Right = Right.ToPoint();
vec = super().__sub__(Right)
if (t is RG_Position2D):
return RG_Vector2D(vec.X,vec.Y)
if (t is RG_Point2D):
return RG_Vector2D(vec.X,vec.Y)
return RG_Position2D(vec.X,vec.Y)
pass;
import random;
#Random
def RandomInt(min:int = 0, max:int = 100):
random.seed();
return random.randint(min,max);
def RandomFloat(min:int = -1, max:int = 1):
random.seed();
if(min < 0 and max > 0):
val = random.random() * 2 -1;
elif(max < 1):
val = random.random() * -1;
else:
val = random.random();
if(not(min < -1 or max > 1)): return val;
intval = RandomInt(min,max);
return intval + val;
class ref:
Value = "Not Initialized"
def __init__(self, value) -> None:
self.Value = value;
pass
pass;
from ctypes import *
import time
class RG_Counter:
def __init__(self, trigger, recurring = False) -> None:
self._trigger = trigger;
self._recurring = recurring;
self._count = 0;
pass
@property
def Finished():
pass;
@Finished.getter
def Finished(self):
if(self._count == -1):return False;
self._count += 1;
if(self._count == self._trigger):
if(not self._recurring):
self._count = -1;
return True;
self._count = 0;
return True;
return False;
pass;
class RG_Timer:
def __init__(self,mainScript, done = None, trigger:int = 1) -> None:
self.Done = done;
self.MainScript = mainScript;
self._trigger = trigger;
self.Count = 0
self._id = 0
pass
def Tick(self,deltaTime):
self.Count += deltaTime * self.MainScript.MainPhysics.Interval;
if(self.Count >= self._trigger and self.Done != None):
self.Done();
self.UnSubscribe()
pass;
def Reset(self):
self.Count = 0
pass;
def Subscribe(self):
self.MainScript.MainPhysics.Add(self);
pass;
def UnSubscribe(self):
self.MainScript.MainPhysics.Remove(self);
del self;
pass;
pass;
def IsDefined():
global py
try:
a = py
except:
return False
return True
def TimeInit():
if(IsDefined()):
return
global tim;
global py;
try:
tim = cdll.LoadLibrary(__file__+"\\RGame\\Time.dll")
tim.Pause.argtypes = [c_double];
#tim.PauseUntil.argtypes = [c_void_p]
tim.Del_CRG_TimePoint.argtypes = [c_void_p]
tim.CRG_TimePoint_Difference.argtypes = [c_void_p,c_void_p]
tim.CRG_TimePoint_Difference.restype = c_double
tim.CRG_TimePoint_Increament.argtypes = [c_void_p,c_double]
tim.CRG_TimePoint_Decreament.argtypes = [c_void_p,c_double]
tim.CRG_Now.restype = c_void_p
py = False
except Exception as e:
tim = None
py = True
switchWarning = RG_FileExistsWarning(*e.args, "The Time.dll could not be loaded so automatically switching form C++ to Python code for time module")
Log(switchWarning.Message, switchWarning.Value, LogLevel.WARNING)
pass;
def Pause(length):
global tim;
global py;
if(length <= 0):return;
if(py):
time.sleep(length)
return
tim.Pause(length);
pass;
class RG_TimePoint:
Tis = None
pTis = None
def Now(self):
if not (IsDefined()):
TimeInit()
global tim
global py
if(py):
self.pTis = time.perf_counter_ns()/1000000000
return
self.Tis = tim.CRG_Now()
def Diff(self):
global tim
global py
if(py): return time.perf_counter_ns()/1000000000 - self.pTis
return tim.CRG_TimePoint_Difference(tim.CRG_Now(), self.Tis)
def __init__(self):
self.Now()
def __del__(self):
global tim
global py
if(py):return
tim.Del_CRG_TimePoint(self.Tis)
def __sub__(self, other):
global tim
global py
if(py):
if(other is RG_TimePoint):
return self.pTis - other.pTis
self.pTis -= other
return
if(other is RG_TimePoint):
return tim.CRG_TimePoint_Difference(self.Tis, other.Tis)
tim.CRG_TimePoint_Decreament(self.Tis, other)
def __add__(self, other):
global tim
global py
if(py):
self.pTis += other
return
tim.CRG_TimePoint_Increament(self.Tis, other)
import random
def RGBtoColor(r:int, g:int, b:int):
return "#%02x%02x%02x" % (r, g, b);
def RandomColor():
random.seed()
return "#%02x%02x%02x" % (random.randint(0,255), random.randint(0,255), random.randint(0,255));
def GetTypeStr(thing):
return thing.__class__.__name__
class RG_Exception(Exception):
Message:str = None
def __init__(self, message = None) -> None:
self.Message = message
pass
pass
class RG_Warning(RG_Exception):
pass
class RG_TypeError(TypeError,RG_Exception):
Message:str = "An error has ocurred."
Value = None
def __init__(self, value = None, message = None) -> None:
self.Message = message
self.Value = value
pass
pass
class RG_TypeWarning(TypeError,RG_Warning):
Message:str = "An error has ocurred."
Value = None
def __init__(self, value = None, message = None) -> None:
self.Message = message
self.Value = value
pass
pass
class RG_ValueError(ValueError,RG_Exception):
Message:str = "An error has ocurred."
Value = None
def __init__(self, value = None, message = None) -> None:
self.Message = message
self.Value = value
pass
pass
class RG_FileExistsError(FileExistsError,RG_Exception):
Message:str = "An error has ocurred."
Value = None
def __init__(self, value = None, message = None) -> None:
self.Message = message
self.Value = value
pass
pass
class RG_FileExistsWarning(FileExistsError,RG_Warning):
Message:str = "An error has ocurred."
Value = None
def __init__(self, value = None, message = None) -> None:
self.Message = message
self.Value = value
pass
pass
class RG_AccessError(RG_Exception):
Message:str = "An error has ocurred."
Value = None
def __init__(self, value = None, message = None) -> None:
self.Message = message
self.Value = value
pass
pass
class RG_AccessWarning(RG_Warning):
Message:str = "An error has ocurred."
Value = None
def __init__(self, value = None, message = None) -> None:
self.Message = message
self.Value = value
pass
pass
from enum import Enum
import traceback
class LogLevel(Enum):
FATAL = 5
ERROR = 4
WARNING = 3
MESSAGE = 2
DEBUG = 1
pass
def Log(message:str, value = None, level:LogLevel = LogLevel.DEBUG):
match level:
case LogLevel.FATAL:
LogFatal(message, value)
case LogLevel.ERROR:
LogError(message, value)
case LogLevel.WARNING:
LogWarning(message, value)
case LogLevel.MESSAGE:
LogMessage(message)
case LogLevel.DEBUG:
LogDebug(message, value)
case _:
LogMessage(message)
def LogFatal(message, value = None):
print()
print(f" {GetConsoleStyle(0,7,1)}>-------------------------Error-------------------------<{EndStyle()}")
print()
print(f" > Level: {GetConsoleStyle(0,7,1)}Fatal{EndStyle()}")
if not (value is None):
print(" > Value of cause: ", value)
print(" > Message:")
print(GetConsoleStyle(0,1,0))
print(message + EndStyle())
print()
print(" > Where the problem ocurred:")
print()
traceback.print_exc()
print()
print(f" {GetConsoleStyle(0,7,1)}>-------------------------------------------------------<{EndStyle()}")
print()
pass
def LogError(message, value = None):
print()
print(f" {GetConsoleStyle(0,1)}>-------------------------Error-------------------------<{EndStyle()}")
print()
print(f" > Level: {GetConsoleStyle(0,1)}Error{EndStyle()}")
if not (value is None):
print(" > Value of cause: ", value)
print(" > Message:")
print(GetConsoleStyle(3,1))
print(message,EndStyle())
print()
print(" > Where the problem ocurred:")
print()
traceback.print_exc()
print()
print(f" {GetConsoleStyle(0,1)}>-------------------------------------------------------<{EndStyle()}")
print()
pass
def LogWarning(message, value = None):
print()
print(f" {GetConsoleStyle(0,3)}>------------------------Warning------------------------<{EndStyle()}")
print()
print(f" > Level: {GetConsoleStyle(0,3)}Warning{EndStyle()}")
if not (value is None):
print(" > Value of cause: ", value)
print(" > Message:")
print(GetConsoleStyle(3,3))
print(message,EndStyle())
print()
print(" > Where the problem ocurred:")
print()
traceback.print_exc()
print()
print(f" {GetConsoleStyle(0,3)}>-------------------------------------------------------<{EndStyle()}")
print()
pass
def LogMessage(message):
print()
print(f" >------------------------Message------------------------<")
print(" > Message:")
print(GetConsoleStyle(3,0))
print(message,EndStyle())
print()
print(" >-------------------------------------------------------<")
print()
pass
def LogDebug(message, value = None):
print()
print(f" {GetConsoleStyle(0,4)}>------------------------Debug------------------------<{EndStyle()}")
print()
if not (value is None):
print(" > Value: ", value)
print(" > Message:")
print(GetConsoleStyle(3,4))
print(message,EndStyle())
print()
print(" > Where the message ocurred:")
print()
traceback.print_exc()
print()
print(f" {GetConsoleStyle(0,4)}>-------------------------------------------------------<{EndStyle()}")
print()
pass
def GetConsoleStyle(style:int = None, color:int = None, background:int = None):
if (style is None):
style = 0
elif not (type(style) is int):
raise RG_TypeError(style,
" The argument 'style' for function 'SDL.GetConsoleStyle' must only have int inputs.")
elif (style < 0 or style > 5):
raise RG_ValueError(style,
" The argument 'style' for function 'SDL.GetConsoleStyle' must only be from 0 - 5\n To see the styles available call 'PrintConsoleStyles' (any where)")
if (color is None):
color = 7
elif not (type(color) is int):
raise RG_TypeError(color,
" The argument 'color' for function 'SDL.GetConsoleStyle' must only have int inputs.")
elif (color < 0 or color > 7):
raise RG_ValueError(color,
" The argument 'color' for function 'SDL.GetConsoleStyle' must only be from 0 - 7\n To see the colors available call 'PrintConsoleStyles' (any where)")
if (background is None):
background = 0
elif not (type(background) is int):
raise RG_TypeError(background,
" The argument 'background' for function 'SDL.GetConsoleStyle' must only have int inputs.")
elif (background < 0 or background > 7):
raise RG_ValueError(background,
" The argument 'background' for function 'SDL.GetConsoleStyle' must only be from 0 - 7\n To see the background colors available call 'PrintConsoleStyles' (any where)")
escape = "\033["
color += 30
background += 40
return escape + str(style) + ";" + str(color) + ";" + str(background) + "m"
def EndStyle():
return "\033[0;37;40m"
def PrintConsoleStyles():
print(f" {GetConsoleStyle(4)}Styles:{EndStyle()}" +" "+ f"{GetConsoleStyle(0,6)}Colors:{EndStyle()}" + " " + f"{GetConsoleStyle(0,0,3)}Background:{EndStyle()}")
print(EndStyle())
print(" "+GetConsoleStyle(0)+"Normal: 0"+EndStyle() +" "+ f"{GetConsoleStyle(0,0,7)}Black: 0{EndStyle()}"+" "+ f"{GetConsoleStyle(0,7,0)}Black: 0{EndStyle()}")
print(" "+GetConsoleStyle(1)+"Bold: 1"+EndStyle() +" "+ f"{GetConsoleStyle(0,1,0)}Red: 1{EndStyle()}"+" "+ f"{GetConsoleStyle(0,7,1)}Red: 1{EndStyle()}")
print(" "+GetConsoleStyle(2)+"Light: 2"+EndStyle() +" "+ f"{GetConsoleStyle(0,2,0)}Green: 2{EndStyle()}"+" "+ f"{GetConsoleStyle(0,7,2)}Green: 2{EndStyle()}")
print(" "+GetConsoleStyle(3)+"Italicized: 3"+EndStyle() +" "+ f"{GetConsoleStyle(0,3,0)}Yellow: 3{EndStyle()}"+" "+ f"{GetConsoleStyle(0,7,3)}Yellow: 3{EndStyle()}")
print(" "+GetConsoleStyle(4)+"Underlined: 4"+EndStyle() +" "+ f"{GetConsoleStyle(0,4,0)}Blue: 4{EndStyle()}"+" "+ f"{GetConsoleStyle(0,7,4)}Blue: 4{EndStyle()}")
print(" "+GetConsoleStyle(5)+"Blink: 5"+EndStyle() +" "+ f"{GetConsoleStyle(0,5,0)}Purple: 5{EndStyle()}"+" "+ f"{GetConsoleStyle(0,7,5)}Purple: 5{EndStyle()}")
print(GetConsoleStyle(0)+" "+EndStyle() +" "+ f"{GetConsoleStyle(0,6,0)}Cyan: 6{EndStyle()}"+" "+ f"{GetConsoleStyle(0,7,6)}Cyan: 1{EndStyle()}")
print(GetConsoleStyle(0)+" "+EndStyle() +" "+ f"{GetConsoleStyle(0,7,0)}White: 7{EndStyle()}"+" "+ f"{GetConsoleStyle(0,0,7)}White: 1{EndStyle()}")
pass
class RG_MainScript:
def tick(self, deltatime:float):
pass
def PhysicsTick(self, deltatime:float):
pass
def Render(self):
pass
class RG_Script:
_id:int = 0
import abc
class RG_Physics(metaclass = abc.ABCMeta):
@classmethod
def __subclasshook__(cls, subclass):
return (hasattr(subclass, 'Start') and
callable(subclass.Start) and
hasattr(subclass, 'End') and
callable(subclass.End) and
hasattr(subclass, 'Add') and
callable(subclass.Add) and
hasattr(subclass, 'Exists') and
callable(subclass.Exists) and
hasattr(subclass, 'End') and
callable(subclass.End) and
hasattr(subclass, 'Remove') and
callable(subclass.Remove) and
hasattr(subclass, 'Interval') and
hasattr(subclass, 'FailedTickFailsafe') and
hasattr(subclass, 'Running') and
hasattr(subclass, 'Counter') and
hasattr(subclass, 'DeltaTime') and
hasattr(subclass, 'FailedTickCount') or
NotImplemented)
_interval:float = None
_failedTickCount:int = None
_failedTickFailsafe:ref = None
@abc.abstractmethod
def Start(self) -> None:
pass
@abc.abstractmethod
def End(self) -> None:
pass
@abc.abstractmethod
def Add(self, script:RG_Script) -> None:
pass
@abc.abstractmethod
def Exists(self, script:RG_Script) -> bool:
return False
@abc.abstractmethod
def Remove(self, script:RG_Script) -> None:
pass
@property
@abc.abstractmethod
def Interval(self) -> float:
return self._interval
@Interval.setter
@abc.abstractmethod
def Interval(self, newValue:float) -> None:
self._interval= newValue
@property
@abc.abstractmethod
def FailedTickFailsafe(self) -> int:
return self._failedTickFailsafe.Value
@FailedTickFailsafe.setter
@abc.abstractmethod
def FailedTickFailsafe(self, newValue:int) -> None:
self._failedTickFailsafe.Value = newValue
@property
@abc.abstractmethod
def Running(self) -> bool:
return self.C_Physics.CRG_Physics_Running(self.Tis)
@property
@abc.abstractmethod
def Counter(self) -> int:
return self.C_Physics.CRG_Physics_GetCounter(self.Tis)
@property
@abc.abstractmethod
def DeltaTime(self) -> float:
return self.C_Physics.CRG_Physics_GetDeltaTime(self.Tis)
@property
@abc.abstractmethod
def FailedTickCount(self) -> int:
return self._failedTickCount
@FailedTickCount.setter
@abc.abstractmethod
def FailedTickCount(self, newValue:int) -> int:
self._failedTickCount = newValue
from threading import Thread
from ctypes import*
class RG_CppPhysics(RG_Physics):
_tis = None
_scrCounter = 0
_interval = 0
_failedTickFailsafe = ref(3)
_failedTickCount = 0
_referenceKeeper = {}
def __init__(self, mainScript:RG_MainScript, interval:float) -> None:
self._mainScript = mainScript
mainScriptTick = self._mainScript.tick
self.C_Physics = cdll.LoadLibrary(__file__+"\\RGame\\Physics.dll");
self._interval = interval
self.MainScriptTick = CFUNCTYPE(None,c_double)(mainScriptTick);
self.C_Physics.New_CRG_Physics.argtypes = [CFUNCTYPE(None,c_double),c_double,c_char_p];
self.C_Physics.New_CRG_Physics.restype = c_void_p;
self.C_Physics.Del_CRG_Physics.argtypes = [c_void_p];
self.C_Physics.Del_CRG_Physics.restype = None;
self.C_Physics.CRG_Physics_Start.argtypes = [c_void_p];
self.C_Physics.CRG_Physics_Start.restype = None;
self.C_Physics.CRG_Physics_End.argtypes = [c_void_p];
self.C_Physics.CRG_Physics_End.restype = None;
self.C_Physics.CRG_Physics_SetInterval.argtypes = [c_void_p, c_double];
self.C_Physics.CRG_Physics_SetInterval.restype = None;
self.C_Physics.CRG_Physics_Add.argtypes = [c_void_p,CFUNCTYPE(None,c_double)];
self.C_Physics.CRG_Physics_Add.restype = None;
self.C_Physics.CRG_Physics_Remove.argtypes = [c_void_p,CFUNCTYPE(None,c_double)];
self.C_Physics.CRG_Physics_Remove.restype = None;
self.C_Physics.CRG_Physics_Exists.argtypes = [c_void_p,CFUNCTYPE(None,c_double)];
self.C_Physics.CRG_Physics_Exists.restype = c_bool;
self.C_Physics.CRG_Physics_Running.argtypes = [c_void_p];
self.C_Physics.CRG_Physics_Running.restype = c_bool;
self.C_Physics.CRG_Physics_GetCounter.argtypes = [c_void_p];
self.C_Physics.CRG_Physics_GetCounter.restype = c_longlong;
self.C_Physics.CRG_Physics_GetDeltaTime.argtypes = [c_void_p];
self.C_Physics.CRG_Physics_GetDeltaTime.restype = c_double;
name = "MainPhysicsThread"
self._tis = self.C_Physics.New_CRG_Physics(self.MainScriptTick,interval,c_char_p(name.encode('utf-8')))
pass;
def __del__(self):
if(self._tis == None):return
self.End()
self.C_Physics.Del_CRG_Physics(self._tis)
del self._tis
del self._referenceKeeper
del self.C_Physics
def Start(self):
try:
self.t = Thread(target=self.waiter, name="PhyThread")
self.t.start()
except Exception as e:
print(e)
pass;
def waiter(self):
while not self._mainScript.Started: pass
self.C_Physics.CRG_Physics_Start(self._tis)
def End(self):
self.C_Physics.CRG_Physics_End(self._tis);
pass;
def Add(self, script:RG_Script):
script._id = self._scrCounter
self._scrCounter += 1
self._referenceKeeper[script._id] = CFUNCTYPE(None,c_double)(script.Tick)
self.C_Physics.CRG_Physics_Add(self._tis, self._referenceKeeper[script._id])
def Exists(self, script:RG_Script) -> bool:
return script._id in self._referenceKeeper
def Remove(self, script:RG_Script):
try:
self.C_Physics.CRG_Physics_Remove(self._tis, self._referenceKeeper[script._id]);
except Exception as e:
if(e.args[0] != "invalid command name \".!canvas\""):
return
else: raise e
del self._referenceKeeper[script._id];
pass;
@property
def Interval(self):
return self._interval;
@Interval.setter
def Interval(self,newValue):
self.C_Physics.CRG_Physics_SetInterval(self._tis,newValue);
self._interval = newValue
pass
@property
def FailedTickFailsafe(self) -> int:
return self._failedTickFailsafe.Value
@FailedTickFailsafe.setter
def FailedTickFailsafe(self, newValue:int) -> None:
self._failedTickFailsafe.Value = newValue
@property
def Running(self):
return self.C_Physics.CRG_Physics_Running(self._tis)
@property
def Counter(self):
return self.C_Physics.CRG_Physics_GetCounter(self._tis);
@property
def DeltaTime(self):
return self.C_Physics.CRG_Physics_GetDeltaTime(self._tis);
@property
def DeltaTime(self):
return self.C_Physics.CRG_Physics_GetDeltaTime(self._tis);
@property
def FailedTickCount(self) -> int:
return self._failedTickCount
@FailedTickCount.setter
def FailedTickCount(self, newValue:int) -> int:
self._failedTickCount = newValue
from threading import Thread;
import time
from multiprocessing import*
class RG_PyPhysics(RG_Physics):
_mainScript:RG_MainScript = None
_interval:float = None
_referenceKeeper = None
_running:bool = False
_counter:int = None
_timePoint:int = None
_waitLimit:int = None
_failedTickCount:int = None
_failedTickFailsafe:ref = None
def __init__(self, mainScript:RG_MainScript, interval:float) -> None:
self._mainScript = mainScript
self._interval = interval
self._referenceKeeper = []
self._failedTickFailsafe = ref(3)
def Start(self):
self._pyThread = Thread(target=self.doStart)
self._pyThread.start()
def doStart(self):
self._running = True
self._counter = 0
self._timePoint = time.perf_counter_ns()
self._waitLimit = time.perf_counter_ns() - self._timePoint
self._failedTickCount = 0
while not self._mainScript.Started: pass
while self._running:
self.doTick()
def doTick(self):
self._counter += 1
self._mainScript.tick(self.DeltaTime)
for obj in self._referenceKeeper:
obj(self.DeltaTime)
self._timePoint = time.perf_counter_ns()
if(self._interval*(1-self.DeltaTime) > self._waitLimit/1000000000) :
Pause(self._interval*(1-self.DeltaTime))
def End(self):
self._running = False
def Add(self, script:RG_Script):
self._referenceKeeper.append(script.Tick)
def Remove(self, script):
if(len(self._referenceKeeper) == 0): return
self._referenceKeeper.remove(script.Tick)
def Exists(self, script) -> bool:
return 0 < self._referenceKeeper.count(script.PhysicsTick)
@property
def Interval(self) -> float:
return self._interval
@Interval.setter
def Interval(self, newValue:float):
self._interval = newValue
@property
def FailedTickFailsafe(self) -> int:
return self._failedTickFailsafe.Value
@FailedTickFailsafe.setter
def FailedTickFailsafe(self, newValue:int) -> None:
self._failedTickFailsafe.Value = newValue
@property
def Running(self) -> bool:
return self._running
@property
def Counter(self) -> int:
return self._counter
@property
def DeltaTime(self) -> float:
if(self._interval == 0): return time.perf_counter_ns()-self._timePoint
return (time.perf_counter_ns()-self._timePoint)/(self._interval*1000000000)
@property
def FailedTickCount(self) -> int:
return self._failedTickCount
@FailedTickCount.setter
def FailedTickCount(self, newValue:int) -> int:
self._failedTickCount = newValue
import enum
@enum.unique
class RG_PhysicsMode(enum.Enum):
CPP = 0
PYTHON = 1
pass
class RG_MainPhysics(RG_Physics):
_physicsMode:int = None
_PyPhysics:RG_Physics = None
_CppPhysics:RG_Physics = None
_started:bool = False
_autoSet:bool = False
@property
def PhysicsMode(self) -> RG_PhysicsMode:
return self._physicsMode
@PhysicsMode.setter
def PhysicsMode(self, newValue:RG_PhysicsMode) -> None:
if self._autoSet and newValue != RG_PhysicsMode.PYTHON:
switchWarning = RG_TypeWarning(newValue, "The value has already automatically been (due to some error) set to python mode permanently.")
Log(switchWarning.Message, switchWarning.Value, LogLevel.WARNING)
return
if self._started:
raise RG_AccessError(newValue, "You cannot change the Physics mode after starting the simulation.")
self._physicsMode = newValue
def getPhysics(self) -> RG_Physics:
match self.PhysicsMode:
case RG_PhysicsMode.PYTHON:
return self._PyPhysics
case RG_PhysicsMode.CPP:
return self._CppPhysics
case _:
accessError = RG_AccessError(None,
"You probably accessed a private member of RG_MainPhysics (set a private member to None/called the private function getPhysics too early)!")
raise accessError
def __init__(self, mainScript:RG_MainScript, interval:float) -> None:
if self.PhysicsMode == None:
self.PhysicsMode = RG_PhysicsMode.CPP
self._PyPhysics = RG_PyPhysics(mainScript, interval)
try:
self._CppPhysics = RG_CppPhysics(mainScript, interval)
except Exception as e:
switchWarning = RG_FileExistsWarning(*e.args, "The Physics.dll could not be loaded so automatically setting physics mode permanently to Python")
Log(switchWarning.Message, switchWarning.Value, LogLevel.WARNING)
self.PhysicsMode = RG_PhysicsMode.PYTHON
self._autoSet = True
def Start(self) -> None:
if self._started: return
self._started = True
self.getPhysics().Start()
def End(self) -> None:
self.getPhysics().End()
def Add(self, script:RG_Script) -> None:
self.getPhysics().Add(script)
def Exists(self, script: RG_Script) -> bool:
return self.getPhysics().Exists(script)
def Remove(self, script: RG_Script) -> None:
self.getPhysics().Remove(script)
@property
def Interval(self) -> float:
return self.getPhysics().Interval
@Interval.setter
def Interval(self, newValue:float) -> None:
self.getPhysics().Interval = newValue
@property
def FailedTickFailsafe(self) -> int:
return self.getPhysics().FailedTickFailsafe
@FailedTickFailsafe.setter
def FailedTickFailsafe(self, newValue:int) -> None:
self.getPhysics().FailedTickFailsafe = newValue
@property
def Running(self) -> bool:
return self.getPhysics().Running
@property
def Counter(self) -> int:
return self.getPhysics().Counter
@property
def DeltaTime(self) -> float:
return self.getPhysics().DeltaTime
@property
def FailedTickCount(self) -> int:
return self.getPhysics().FailedTickCount
@FailedTickCount.setter
def FailedTickCount(self, newValue:int) -> int:
self.getPhysics().FailedTickCount = newValue
from decimal import Decimal
class RG_Size:
_width:Decimal = 100;
_height:Decimal = 100;
@property
def Width(self):
return self._width;
@Width.setter
def Width(self,newVal):
self._width = Decimal(newVal);
pass;
@property
def Height(self):
return self._height;
@Height.setter
def Height(self,newVal):
self._height = Decimal(newVal);
pass
def __init__(self, width:Decimal | float = None, height:Decimal | float = None) -> None:
# width
if (width is None):
width = Decimal(25)
elif not ((type(width) is Decimal) or (type(width) is int)):
if(type(width) is float):
LogWarning(" Possible loss of data (converting 'float' to 'Decimal').\n For the argument 'width'(first argument) of the class 'RG_Size'")
width = Decimal(width)
else:
raise RG_TypeError(width,
" 'RG_Size' must have a 'Decimal' as the argument 'width' (first argument).")
# height
if (height is None):
height = Decimal(25)
elif not ((type(height) is Decimal) or (type(height) is int)):
if(type(height) is float):
LogWarning(" Possible loss of data (converting 'float' to 'Decimal').\n For the argument 'height'(second argument) of the class 'RG_Size'")
height = Decimal(height)
else:
raise RG_TypeError(height,
" 'RG_Size' must have a 'Decimal' as the argument 'height' (second argument).")
self.Width = width
self.Height = height
pass
def __eq__(self, other) -> bool:
if(not type(other) is RG_Size): return False;
return self.Width == other.Width and self.Height == other.Height;
def __str__(self) -> str:
return "Size: (Width: " + str(self.Width) + ", Height: " + str(self.Height) + ")";
pass;
class RG_SizeSquare(RG_Size):
@property
def Side(self):
return self.Width
@Side.setter
def Side(self,newVal):
self.Width = Decimal(newVal);
self.Height = Decimal(newVal);
pass;
def __init__(self, side:Decimal | float = None) -> None:
#side
if (side is None):
side = Decimal(25)
elif not ((type(side) is Decimal) or (type(side) is int)):
if(type(side) is float):
LogWarning(" Possible loss of data (converting 'float' to 'Decimal').\n For the argument 'side'(second argument) of the class 'RG_Size'")
side = Decimal(side)
else:
raise RG_TypeError(side,
" 'RG_SizeSquare' must have a 'Decimal' as the argument 'side' (second argument).")
self.Side = side
pass
def __eq__(self, other) -> bool:
if(not type(other) is RG_SizeSquare): return False;
return self.Side == other.Side
def __str__(self) -> str:
return "Square Size: (Size: " + str(self.RadiusX) + ")";
pass;
class RG_SizeEllipse(RG_Size):
@property
def RadiusX(self):
return self.Width / 2
@RadiusX.setter
def RadiusX(self,newVal):
self.Width = Decimal(newVal)*2
pass;
@property
def RadiusY(self):
return self.Height / 2
@RadiusY.setter
def RadiusY(self,newVal):
self.Height = Decimal(newVal)*2
pass;
def __init__(self, radiusX:Decimal | float = None, radiusY:Decimal | float = None) -> None:
# radius X
if (radiusX is None):
radiusX = Decimal(25)
elif not ((type(radiusX) is Decimal) or (type(radiusX) is int)):
if(type(radiusX) is float):
LogWarning(" Possible loss of data (converting 'float' to 'Decimal').\n For the argument 'radiusX'(first argument) of the class 'RG_Size'")
radiusX = Decimal(radiusX)
else:
raise RG_TypeError(radiusX,
" 'RG_SizeEllipse' must have a 'Decimal' as the argument 'radiusX' (first argument).")
self.RadiusX = radiusX;
# radius Y
if (radiusY is None):
radiusY = Decimal(25)
elif not ((type(radiusY) is Decimal) or (type(radiusY) is int)):
if(type(radiusY) is float):
LogWarning(" Possible loss of data (converting 'float' to 'Decimal').\n For the argument 'radiusY'(second argument) of the class 'RG_Size'")
radiusY = Decimal(radiusY)
else:
raise RG_TypeError(radiusY,
" 'RG_Size' must have a 'Decimal' as the argument 'radiusY' (second argument).")
self.RadiusY = radiusY;
pass
def __eq__(self, other) -> bool:
if(not type(other) is RG_SizeEllipse): return False;
return self.Width == other.Width and self.Height == other.Height;
def __str__(self) -> str:
return "Ellipse Size: (RadiusX: " + str(self.RadiusX) + ", RadiusY: " + str(self.RadiusY) + ")";
pass;
class RG_SizeCircle(RG_SizeEllipse):
@property
def Radius(self):
return self.RadiusX;
@Radius.setter
def Radius(self,newVal):
self.RadiusX = Decimal(newVal);
self.RadiusY = Decimal(newVal);
pass;
def __init__(self, radius:Decimal | float = None) -> None:
# radius
if (radius is None):
radius = Decimal(25)
elif not ((type(radius) is Decimal) or (type(radius) is int)):
if(type(radius) is float):
LogWarning(" Possible loss of data (converting 'float' to 'Decimal').\n For the argument 'radius'(second argument) of the class 'RG_Size'")
radiusY = Decimal(radius)
else:
raise RG_TypeError(radius,
" 'RG_SizeCircle' must have a 'Decimal' as the argument 'radius' (second argument).")
self.Radius = radius;
pass
def __eq__(self, other) -> bool:
if(not type(other) is RG_SizeCircle): return False;
return self.Radius == other.Radius;
def __str__(self) -> str:
return "Circle Size: (Radius: " + str(self.Radius) + ")";
pass;
from tkinter import*
#----------------------------------
#----------------------------------
# Appearance
#----------------------------------
#----------------------------------
class RG_AppearanceType:
# ----------------------------------
# Variables:
# ----------------------------------
_ended = True
_created:bool = False;
@property
def Created(self):
return self._created;
@Created.setter
def Created(self,new):
raise ValueError("Created is readonly.")
_canvasID:str = "";
OffSet:RG_Vector2D = RG_Vector2D(0,0);
_visible = True;
@property
def Visible(self):
return self._visible
@Visible.setter
def Visible(self, new):
if not (type(new) is bool): raise TypeError("Cannot set visible to a value that is not bool: " + str(new))
if(new):
self.Show()
else:
self.Hide()
Dimensions:object = None;
def __init__(self, canvas:Canvas, spritePosition:RG_Position2D) -> None:
self._screen:Canvas = canvas;
self.CreateGraphics(spritePosition)
pass;
def __del__(self):
self.DeleteGraphics()
# ----------------------------------
# Functions:
# ----------------------------------
def CreateGraphics(self):
if(self.Created):return;
self._visible = True;
self._created = True;
self._canvasID = self._createGfx( RG_Position2D(0,0) );
pass;
def _createGfx(self, spritePosition:RG_Position2D) -> str:
pass;
def _configureGfx(self):
pass;
def DeleteGraphics(self):
if not (self.Created): return;
self._created = False;
self._visible = False;
try:
self._screen.delete(self._canvasID);
except Exception as e:
if(e.args[0] == "invalid command name \".!canvas\""):
return
else:
raise e
self._canvasID = "";
pass;
def Hide(self):
try:
self._screen.itemconfigure(self._canvasID, state = "hidden");
except Exception as e:
if(e.args[0] == "invalid command name \".!canvas\""):
return
else:
raise e
self._visible = False;
pass;
def Show(self):
self._screen.itemconfigure(self._canvasID, state = "normal");
self._visible = True;
pass;
def MoveTo(self,x,y):
try:
self._screen.moveto(self._canvasID, int(x-self.OffSet.X), (int(self._screen.winfo_height()-y+self.OffSet.Y-self.Dimensions.Height)));
except Exception as e:
if(e.args[0] == "invalid command name \".!canvas\""):
return
else:
raise e
def Render(self):
if(not self.Created): self.CreateGraphics()
if(not self.Visible): return;
self._configureGfx()
pass;
pass;
from tkinter import*
import tkinter.font as tkFont
import os
import math
#----------------------------------
#----------------------------------
# Appearance
#----------------------------------
#----------------------------------
class RG_App_Label(RG_AppearanceType):
def GetFontTypes() -> tuple:
return tkFont.families()
# ----------------------------------
# Base Functions:
# ----------------------------------
# Constructor
def __init__(self, screen:Canvas = None, text:str = None, fontType:str = None, fontSize:int = None, fontColor:str = None, bold:bool = None, italic:bool = None, underline:bool = None, overstrike:bool = None, offset:RG_Vector2D = None) -> None:
#-----------defaults-----------
# screen
if not (type(screen) is Canvas):
raise RG_TypeError(screen,
" An 'RG_App_Label' must have 'self.MainWindow.Screen' as the argument 'screen' (first argument).")
self._screen = screen
# text
if (text is None):
text = "Label text."
elif not (type(text) is str):
raise RG_TypeError(text,
" 'RG_App_Label' must have a string as the argument 'text' (second argument).")
self.Text = text
# fontType
if (fontType is None):
fontType = "Calibri"
elif not (type(fontType ) is str):
raise RG_TypeError(fontType ,
" 'RG_App_Label' must have a string as the argument 'fontType' (third argument).")
elif not (fontType in tkFont.families()):
raise RG_ValueError(fontType,
" 'RG_App_Label' the argument 'fontType' (third argument) must be a font that exists.")
self.FontType = fontType
# fontSize
if (fontSize is None):
fontSize = 12
elif not (type(fontSize ) is int):
raise RG_TypeError(fontSize ,
" 'RG_App_Label' must have an int as the argument 'fontSize' (fourth argument).")
self.FontSize = fontSize
# fontColor
if (fontColor is None):
fontColor = "Black"
elif not (type(fontColor ) is str):
raise RG_TypeError(fontColor ,
" 'RG_App_Label' must have a str as the argument 'fontColor' (fifth argument).")
self.Color = fontColor
# Bold
if (bold is None):
bold = False
elif not (type(bold) is bool):
raise RG_TypeError(bold ,
" 'RG_App_Label' must have a bool as the argument 'bold' (sixth argument).")
self.Weight = bold
# Italic
if (italic is None):
italic = False
elif not (type(italic) is bool):
raise RG_TypeError(italic,
" 'RG_App_Label' must have a bool as the argument 'italic' (seventh argument).")
self.Slant = italic
# Underline
if (underline is None):
underline = False
elif not (type(underline) is bool):
raise RG_TypeError(underline,
" 'RG_App_Label' must have a bool as the argument 'underline' (eighth argument).")
self.Underline = underline
# Overstrike
if (overstrike is None):
overstrike = False
elif not (type(overstrike) is bool):
raise RG_TypeError(overstrike,
" 'RG_App_Label' must have a bool as the argument 'overstrike' (ninth argument).")
self.Overstrike = overstrike
#offset
if (offset is None):
offset = RG_Vector2D()
elif not (type(offset) is RG_Vector2D):
raise RG_TypeError(offset,
" 'RG_App_Label' must have an RG_Vector2D as the argument 'offset' (last argument).")
self.OffSet = offset
pass
# To String
def __str__(self) -> str:
return "Label: (ShapeID: " + str(self._canvasID) + ", Text: " + str(self.Text) + ", FontType: " + str(self.FontType) + ", FontColor: " + str(self.FontColor) + ")";
# ----------------------------------
# Functions:
# ----------------------------------
def MoveTo(self, x, y):
self._screen.moveto(self._canvasID, int(x-self.OffSet.X), (int(self._screen.winfo_height()-y+self.OffSet.Y)));
def _createGfx(self, spritePosition:RG_Position2D):
absolutePosition = spritePosition + self.OffSet
if(self.Weight):
weight = "bold"
else:
weight = "normal"
if(self.Slant):
slant = "italic"
else:
slant = "roman"
font = tkFont.Font(
family = str(self.FontType),
size = self.FontSize,
weight = weight,
slant = slant,
underline = self.Underline,
overstrike = self.Overstrike)
try:
ID = self._screen.create_text(
absolutePosition.X, absolutePosition.Y,
fill=self.Color,
font=font,
text= self.Text
)
except Exception as e:
LogError(" Could not create a label.")
return ID;
def _configureGfx(self):
if(self.Weight):
weight = "bold"
else:
weight = "normal"
if(self.Slant):
slant = "italic"
else:
slant = "roman"
font = tkFont.Font(
family = str(self.FontType),
size = self.FontSize,
weight = weight,
slant = slant,
underline = self.Underline,
overstrike = self.Overstrike)
self._screen.itemconfigure(self._canvasID,
fill=self.Color,
font=font,
text= self.Text)
pass
pass
class RG_App_Shape(RG_AppearanceType):
# ----------------------------------
# Variables:
# ----------------------------------
Color:str = "Black";
Dimensions:RG_Size = RG_Size(50,50);
# ----------------------------------
# Base Functions:
# ----------------------------------
# Constructor
def __init__(self,screen:Canvas, dimensions:RG_Size = None, color:str = None, outlineColor:str = None, outlineWidth:int = None, offset:RG_Vector2D = None) -> None:
#-----------defaults-----------
# screen
if not (type(screen) is Canvas):
raise RG_TypeError(screen,
" An 'RG_App_Shape' must have 'self.MainWindow.Screen' as the argument 'screen' (first argument).")
self._screen = screen
# dim
if (dimensions is None):
dimensions = RG_Size()
elif not (issubclass(type(dimensions ),RG_Size) or type(dimensions ) is RG_Size):
raise RG_TypeError(dimensions ,
" 'RG_App_Shape' must have a RG_Size as the argument 'dimensions' (second argument).")
self.Dimensions = dimensions
# Color
if (color is None):
color = "Black"
elif not (type(color ) is str):
raise RG_TypeError(color ,
" 'RG_App_Shape' must have a str as the argument 'color' (third argument).")
self.Color = color
# outlineColor
if (outlineColor is None):
outlineColor = "Black"
elif not (type(outlineColor ) is str):
raise RG_TypeError(outlineColor ,
" 'RG_App_Ellipse' must have a str as the argument 'outlineColor' (fifth argument).")
self.OutlineColor = outlineColor
# outlineWidth
if (outlineWidth is None):
outlineWidth = 0
elif not (type(outlineWidth ) is int):
raise RG_TypeError(outlineWidth ,
" 'RG_App_Ellipse' must have an int as the argument 'outlineWidth' (sixth argument).")
self.OutlineWidth = outlineWidth
#offset
if (offset is None):
offset = RG_Vector2D()
elif not (type(offset) is RG_Vector2D):
raise RG_TypeError(offset,
" 'RG_App_Shape' must have an RG_Vector2D as the argument 'offset' (last argument).")
self.OffSet = offset
pass;
# To String
def __str__(self) -> str:
return "Shape: (ShapeID: " + str(self._canvasID) + ", Dimensions: " + str(self.Dimensions) + ", Color: " + str(self.Color) + ", OffSet: " + str(self.OffSet) + ")";
# ----------------------------------
# Functions:
# ----------------------------------
def _createGfx(self, spritePosition:RG_Position2D):
absolutePosition = spritePosition + self.OffSet;
ID = self._screen.create_rectangle(
absolutePosition.X, self._screen.winfo_height()-absolutePosition.Y,
absolutePosition.X + self.Dimensions.Width, (self._screen.winfo_height()-absolutePosition.Y) - self.Dimensions.Height,
fill=self.Color,outline=self.OutlineColor,width=self.OutlineWidth
);
return ID;
def _configureGfx(self):
pos = self._screen.coords(self._canvasID)
self._screen.coords(self._canvasID,
pos[0],pos[1],
pos[0] + float(self.Dimensions.Width), pos[1] + float(self.Dimensions.Height))
self._screen.itemconfigure(self._canvasID,
fill=self.Color,outline=self.OutlineColor,width=self.OutlineWidth)
pass;
pass;
class RG_App_Rectangle(RG_App_Shape):
pass;
class RG_App_Line(RG_App_Shape):
# ----------------------------------
# Variables:
# ----------------------------------
Color:str = "Black";
# ----------------------------------
# Base Functions:
# ----------------------------------
# Constructor
def __init__(self,screen:Canvas, points:list[RG_Vector2D] = None, color:str = None, width:int = None, smooth:bool = None, resolution:int = None, offset:RG_Vector2D = None) -> None:
#-----------defaults-----------
# screen
if not (type(screen) is Canvas):
raise RG_TypeError(screen,
" An 'RG_App_Line' must have 'self.MainWindow.Screen' as the argument 'screen' (first argument).")
self._screen = screen
# dim
if (points is None):
points = [RG_Vector2D(25,25)]
elif not (type(points ) is list):
raise RG_TypeError(points ,
" 'RG_App_Line' must have a list of RG_Vector2Ds as the argument 'points' (second argument).")
self.Points2 = points
# Color
if (color is None):
color = "Black"
elif not (type(color ) is str):
raise RG_TypeError(color ,
" 'RG_App_Line' must have a str as the argument 'color' (third argument).")
self.Color = color
# Width
if (width is None):
width = 1
elif not (type(width ) is int):
raise RG_TypeError(width ,
" 'RG_App_Line' must have a int as the argument 'width' (fourth argument).")
self.Width = width
# Smooth
if (smooth is None):
smooth = False
elif not (type(smooth ) is bool):
raise RG_TypeError(smooth ,
" 'RG_App_Line' must have a bool as the argument 'smooth' (fifth argument).")
self.Smooth = smooth
# Resolution
if (resolution is None):
resolution = 12
elif not (type(resolution ) is int):
raise RG_TypeError(resolution ,
" 'RG_App_Line' must have a int as the argument 'resolution' (sixth argument).")
self.Resolution = resolution
#offset
if (offset is None):
offset = RG_Vector2D()
elif not (type(offset) is RG_Vector2D):
raise RG_TypeError(offset,
" 'RG_App_Line' must have an RG_Vector2D as the argument 'offset' (last argument).")
self.OffSet = offset
pass;
# To String
def __str__(self) -> str:
return "Line: (ShapeID: " + str(self._canvasID) + ", Color: " + str(self.Color) + ", OffSet: " + str(self.OffSet) + ")";
# ----------------------------------
# Functions:
# ----------------------------------
def _createGfx(self, spritePosition:RG_Position2D):
absolutePosition = spritePosition + self.OffSet;
res = [absolutePosition.X, self._screen.winfo_height()-absolutePosition.Y]
for point in self.Points2:
res.append(absolutePosition.X + point.X)
res.append(self._screen.winfo_height() - (absolutePosition.Y + point.Y))
ID = self._screen.create_line(
*res,
fill=self.Color,width =self.Width, smooth=self.Smooth, splinesteps=self.Resolution
);
return ID;
def _configureGfx(self):
pos = self._screen.coords(self._canvasID)
res = [pos[0], pos[1]]
for point in self.Points2:
res.append(pos[0] + float(point.X))
res.append(pos[1] - float(point.Y))
self._screen.coords(self._canvasID,
*res)
self._screen.itemconfigure(self._canvasID,
fill=self.Color,width =self.Width, smooth=self.Smooth, splinesteps=self.Resolution)
pass;
def MoveTo(self,x,y):
res = [x,self._screen.winfo_height()-int(y)]
for point in self.Points2:
res.append(x + int(point.X))
res.append(self._screen.winfo_height() - int(y) - int(point.Y))
self._screen.coords(self._canvasID,
*res)
pass
pass;
class RG_App_Polygon(RG_App_Shape):
# ----------------------------------
# Variables:
# ----------------------------------
Color:str = "Black";
Rotation = 0
# ----------------------------------
# Base Functions:
# ----------------------------------
# Constructor
def __init__(self,screen:Canvas, points:list[RG_Vector2D] = None, color:str = None, outlineColor:str = None, outlineWidth:int = None, smooth:bool = None, resolution:int = None, offset:RG_Vector2D = None) -> None:
#-----------defaults-----------
# screen
if not (type(screen) is Canvas):
raise RG_TypeError(screen,
" An 'RG_App_Polygon' must have 'self.MainWindow.Screen' as the argument 'screen' (first argument).")
self._screen = screen
# dim
if (points is None):
points = [RG_Vector2D(25,25)]
elif not (type(points ) is list):
raise RG_TypeError(points ,
" 'RG_App_Polygon' must have a list of RG_Vector2Ds as the argument 'points' (second argument).")
self.Points2 = points
# Color
if (color is None):
color = "Black"
elif not (type(color ) is str):
raise RG_TypeError(color ,
" 'RG_App_Polygon' must have a str as the argument 'color' (third argument).")
self.Color = color
# outlineColor
if (outlineColor is None):
outlineColor = "Black"
elif not (type(outlineColor ) is str):
raise RG_TypeError(outlineColor ,
" 'RG_App_Polygon' must have a str as the argument 'outlineColor' (fifth argument).")
self.OutlineColor = outlineColor
# outlineWidth
if (outlineWidth is None):
outlineWidth = 0
elif not (type(outlineWidth ) is int):
raise RG_TypeError(outlineWidth ,
" 'RG_App_Polygon' must have an int as the argument 'outlineWidth' (sixth argument).")
self.OutlineWidth = outlineWidth
# Smooth
if (smooth is None):
smooth = False
elif not (type(smooth ) is bool):
raise RG_TypeError(smooth ,
" 'RG_App_Polygon' must have a bool as the argument 'smooth' (fifth argument).")
self.Smooth = smooth
# Resolution
if (resolution is None):
resolution = 12
elif not (type(resolution ) is int):
raise RG_TypeError(resolution ,
" 'RG_App_Polygon' must have a int as the argument 'resolution' (sixth argument).")
self.Resolution = resolution
#offset
if (offset is None):
offset = RG_Vector2D()
elif not (type(offset) is RG_Vector2D):
raise RG_TypeError(offset,
" 'RG_App_Polygon' must have an RG_Vector2D as the argument 'offset' (last argument).")
self.OffSet = offset
pass;
# To String
def __str__(self) -> str:
return "Polygon: (ShapeID: " + str(self._canvasID) + ", Color: " + str(self.Color) + ", OffSet: " + str(self.OffSet) + ")";
# ----------------------------------
# Functions:
# ----------------------------------
def _createGfx(self, spritePosition:RG_Position2D):
absolutePosition = spritePosition + self.OffSet;
res = [absolutePosition.X, self._screen.winfo_height()-absolutePosition.Y]
c = Decimal(math.cos(self.Rotation))
s = Decimal(math.sin(self.Rotation))
for point in self.Points2:
temp = RG_Vector2D()
temp.X = point.X * c - point.Y * s
temp.Y = point.X * s + point.Y * c
res.append(absolutePosition.X + point.X)
res.append(self._screen.winfo_height() - (absolutePosition.Y + point.Y))
ID = self._screen.create_polygon(
*res,
fill=self.Color,width =self.OutlineWidth, outline= self.OutlineColor , smooth=self.Smooth, splinesteps=self.Resolution,
);
return ID;
def _configureGfx(self):
pos = self._screen.coords(self._canvasID)
self._screen.itemconfigure(self._canvasID,
fill=self.Color,width =self.OutlineWidth, outline= self.OutlineColor, smooth=self.Smooth, splinesteps=self.Resolution)
pass;
def MoveTo(self,x,y):
res = [x,self._screen.winfo_height()-int(y)]
c = Decimal(math.cos(self.Rotation))
s = Decimal(math.sin(self.Rotation))
for point in self.Points2:
temp = RG_Vector2D()
temp.X = point.X * c - point.Y * s
temp.Y = point.X * s + point.Y * c
res.append(x + int(temp.X))
res.append(self._screen.winfo_height() - int(y) - int(temp.Y))
self._screen.coords(self._canvasID,
*res)
pass
def Rotate(self, angle:float, centre:RG_Point2D, spritePosition:RG_Position2D, clockwise=True):
coef = -1
if not (clockwise):
coef = 1
c = Decimal(math.cos(angle*coef))
s = Decimal(math.sin(angle*coef))
spritePosition.X -= centre.X
spritePosition.Y -= centre.Y
x = spritePosition.X * c - spritePosition.Y * s
y = spritePosition.X * s + spritePosition.Y * c
spritePosition.X = x
spritePosition.Y = y
spritePosition.X += centre.X
spritePosition.Y += centre.Y
self.Rotation += angle*coef
return spritePosition
pass
class RG_App_Ellipse(RG_App_Shape):
# ----------------------------------
# Base Functions:
# ----------------------------------
# Constructor
def __init__(self,screen:Canvas, radiusX:Decimal | float = None, radiusY:Decimal | float = None, color:str = None, outlineColor:str = None, outlineWidth:int = None, offset: RG_Vector2D = None) -> None:
#-----------defaults-----------
# screen
if not (type(screen) is Canvas):
raise RG_TypeError(screen,
" An 'RG_App_Ellipse' must have 'self.MainWindow.Screen' as the argument 'screen' (first argument).")
self._screen = screen
# dim
self.Dimensions = RG_SizeEllipse(radiusX,radiusY)
# Color
if (color is None):
color = "Black"
elif not (type(color ) is str):
raise RG_TypeError(color ,
" 'RG_App_Ellipse' must have a str as the argument 'color' (fourth argument).")
self.Color = color
# outlineColor
if (outlineColor is None):
outlineColor = "Black"
elif not (type(outlineColor ) is str):
raise RG_TypeError(outlineColor ,
" 'RG_App_Ellipse' must have a str as the argument 'outlineColor' (fifth argument).")
self.OutlineColor = outlineColor
# outlineWidth
if (outlineWidth is None):
outlineWidth = 0
elif not (type(outlineWidth ) is int):
raise RG_TypeError(outlineWidth ,
" 'RG_App_Ellipse' must have an int as the argument 'outlineWidth' (sixth argument).")
self.OutlineWidth = outlineWidth
#offset
if (offset is None):
offset = RG_Vector2D()
elif not (type(offset) is RG_Vector2D):
raise RG_TypeError(offset,
" 'RG_App_Ellipse' must have an RG_Vector2D as the argument 'offset' (last argument).")
self.OffSet = offset
pass;
# To String
def __str__(self) -> str:
return "Ellipse: (ShapeID: " + str(self._canvasID) + ", Dimensions: " + str(self.Dimensions) + ", Color: " + str(self.Color) + ", OffSet: " + str(self.OffSet) + ")";
# ----------------------------------
# Functions:
# ----------------------------------
def _createGfx(self, spritePosition: RG_Position2D) -> str:
absolutePosition = spritePosition + self.OffSet;
ID = self._screen.create_oval(
absolutePosition.X, (self._screen.winfo_height()-absolutePosition.Y),
absolutePosition.X + Decimal(self.Dimensions.Width), (self._screen.winfo_height()-absolutePosition.Y) - Decimal(self.Dimensions.Width),
fill=self.Color,outline=self.OutlineColor,width=self.OutlineWidth
);
return ID;
def _configureGfx(self):
pos = self._screen.coords(self._canvasID)
self._screen.coords(self._canvasID,
pos[0],pos[1],
pos[0] + float(self.Dimensions.Width), pos[1] + float(self.Dimensions.Height),)
self._screen.itemconfigure(self._canvasID,
fill=self.Color,outline=self.OutlineColor,width=self.OutlineWidth)
pass;
pass;
class RG_App_Circle(RG_App_Ellipse):
# ----------------------------------
# Base Functions:
# ----------------------------------
# Constructor
def __init__(self,screen:Canvas, radius:Decimal | float = None, color: str = None, outlineColor:str = None, outlineWidth:int = None, offset: RG_Vector2D = None) -> None:
#-----------defaults-----------
# screen
if not (type(screen) is Canvas):
raise RG_TypeError(screen,
" An 'RG_App_Circle' must have 'self.MainWindow.Screen' as the argument 'screen' (first argument).")
self._screen = screen
# dim
self.Dimensions = RG_SizeCircle(radius)
# Color
if (color is None):
color = "Black"
elif not (type(color ) is str):
raise RG_TypeError(color ,
" 'RG_App_Circle' must have a str as the argument 'color' (third argument).")
self.Color = color
# outlineColor
if (outlineColor is None):
outlineColor = "Black"
elif not (type(outlineColor ) is str):
raise RG_TypeError(outlineColor ,
" 'RG_App_Ellipse' must have an int as the argument 'outlineColor' (fifth argument).")
self.OutlineColor = outlineColor
# outlineWidth
if (outlineWidth is None):
outlineWidth = 0
elif not (type(outlineWidth ) is int):
raise RG_TypeError(outlineWidth ,
" 'RG_App_Ellipse' must have a str as the argument 'outlineWidth' (sixth argument).")
self.OutlineWidth = outlineWidth
#offset
if (offset is None):
offset = RG_Vector2D()
elif not (type(offset) is RG_Vector2D):
raise RG_TypeError(offset,
" 'RG_App_Circle' must have an RG_Vector2D as the argument 'offset' (last argument).")
self.OffSet = offset
pass;
pass;
class RG_App_Shader(RG_AppearanceType):
_location:str = "RGame\\RGamePic.png"
@property
def Location(self):
return self._location
@Location.setter
def Location(self, fileLocation):
if (fileLocation is None):
fileLocation = "RGame\\RGamePic.png"
elif not (type(fileLocation) is str):
raise RG_TypeError(fileLocation ,
" 'RG_App_Shader' must have a string as the parameter 'fileLocation'.")
elif not (os.path.exists(fileLocation)):
raise RG_FileExistsError(fileLocation,
" 'RG_App_Shader' the parameter 'fileLocation' must be a file that exists.")
self._location = fileLocation
self.Image = PhotoImage(file = self.Location)
self.Dimensions = RG_Size(self.Image.width(),self.Image.height())
def __init__(self,screen:Canvas, fileLocation:str = None, offset: RG_Vector2D = None) -> None:
#-----------defaults-----------
# screen
if not (type(screen) is Canvas):
raise RG_TypeError(screen,
" An 'RG_App_Shader' must have 'self.MainWindow.Screen' as the argument 'screen' (first argument).")
self._screen = screen
self.Location = fileLocation
#offset
if (offset is None):
offset = RG_Vector2D()
elif not (type(offset) is RG_Vector2D):
raise RG_TypeError(offset,
" 'RG_App_Shader' must have an RG_Vector2D as the argument 'offset' (last argument).")
self.OffSet = offset
pass;
# To String
def __str__(self) -> str:
return "Shader: (ShaderID: " + str(self._canvasID) + ", File Location: " + str(self.Location) + ", OffSet: " + str(self.OffSet) + ")";
# ----------------------------------
# Functions:
# ----------------------------------
def _createGfx(self, spritePosition: RG_Position2D) -> str:
absolutePosition = spritePosition + self.OffSet;
ID = self._screen.create_image(
absolutePosition.X, (self._screen.winfo_height()-absolutePosition.Y),
image=self.Image
);
return ID;
def _configureGfx(self):
self._screen.itemconfigure(self._canvasID,
image=self.Image)
pass;
def Resize(self, x, y):
xst = str(x)
if not ("." in xst):
xz = x
xs = 1
else:
decs = xst.split(".")[1]
xs = 10**len(decs)
xz = xs*x
yst = str(y)
if not ("." in yst):
yz = y
ys = 1
else:
decs = yst.split(".")[1]
ys = 10**len(decs)
yz = ys*y
self.Image = self.Image.zoom(int(xz),int(yz))
self.Image = self.Image.subsample(int(xs),int(ys))
self._screen.itemconfigure(self._canvasID,
image=self.Image)
pass;
pass;
from tkinter import*
from threading import*
from multiprocessing import*
from concurrent.futures import ThreadPoolExecutor
class RG_RenderingManager:
# Variables
# window
Window:Tk = None;
Screen:Canvas = None;
#Frame rate
FrameRate:ref = ref(24);
_pause:float = 1/FrameRate.Value;
#Running
BlockRender:bool = False;
Run:bool = True
FailedRenderCount:int = 0;
Ended = False;
Exceptions = []
# Constructor (Where it starts)
def __init__(self, mainScript, window:Tk, frameRate:ref = ref(30), scripts:ref = ref([]), failedRenderFailsafe:ref = ref(10), width:int=600, height:int=400, backGround:ref = ref("Black"), appearances:ref = ref([])):
print("Main\\Init\\MainWindow> Started | creating -> Render");
print("\nMain\\Init\\MainWindow\\Render> Started | creating -> General Values");
try:
self._mainScript = mainScript;
self.Window = window;
self._renderList = scripts;
self._appearances = appearances;
self._width = width;
self._height = height;
self._backGround = backGround;
self._failedRenderFailsafe = failedRenderFailsafe;
except Exception as e:
print("Failed initializing general input variables.\n\n");
raise e;
print("Main\\Init\\MainWindow\\Render> Finished | creating -> General Values");
print("Main\\Init\\MainWindow\\Render> Started | setting -> Frame Rate ");
try:
self.FrameRate = frameRate;
self._oldFrameRate = self.FrameRate.Value;
self._pause = 1/frameRate.Value;
except Exception as e:
print("Failed to initialize frame rate.\n\n");
raise e;
print("Main\\Init\\MainWindow\\Render> Finished | setting -> Frame Rate ");
print("Main\\Init\\MainWindow\\Render> Started | creating -> Canvas");
try:
self.Screen = Canvas(self.Window, width = width, height = height, bg = backGround);
except Exception as e:
print("Failed to create Canvas.\n\n");
raise e;
print("Main\\Init\\MainWindow\\Render> Finished | creating -> Canvas");
print("Main\\Init\\MainWindow\\Render> Started | printing -> Canvas");
try:
self.Screen.pack();
except Exception as e:
print("Failed to put Canvas on window.\n\n");
raise e;
print("Main\\Init\\MainWindow\\Render> Finished | printing -> Canvas");
print("\nMain\\Init\\MainWindow> Finished | creating -> Render");
self.timer = RG_Timer(self._mainScript)
self.executor = ThreadPoolExecutor(cpu_count())
def StartRendering(self, width:int=600, height:int=400, backGround:ref = ref("Black")):
print("Main\\Start up\\MainWindow> Started | configuring -> Canvas");
self.Screen.config(width = width, height = height, bg = backGround);
print("Main\\Start up\\MainWindow> Finished | configuring -> Canvas");
print("Main\\Start up\\MainWindow> Starting | Render");
try:
self.p = Thread(target = self.StartRender);
self.p.start()
self.Window.protocol("WM_DELETE_WINDOW", self.End);
self.Window.mainloop()
except Exception as e:
print("Failed to start the rendering.\n\n");
raise e;
pass;
#Render
def StartRender(self):
print("Main\\Start up\\MainWindow> Started | Render");
print("\nMain\\Start up> Started | MainWindow");
print("\nMain> Finished | Start up\n");
self._mainScript.Started = True;
self.Render();
def Render(self):
self.timer.Subscribe()
while self.Run:
try:
if(self.Ended) : return;
Pause(self._pause-self.timer.Count);
self.timer.Reset()
self.DoRender()
except Exception as e:
if self.HandleExp(e): return
pass;
def HandleExp(self,e):
if(self.Ended) : return True;
print("Failed Render.");
if(not self.Run): return True;
if(issubclass(type(e),RG_Exception)):
LogError(e.Message,e.Value)
pass
elif(len(e.args)>0):LogError(e.args[0])
else:LogError("There was an exception raised without a message.")
self.FailedRenderCount += 1;
if(self.FailedRenderCount == self._failedRenderFailsafe.Value):
text = f" > Max Failed Render count surpassed. Current failsafe: {self._failedRenderFailsafe.Value}.\n > The error:\n\n"
if(issubclass(type(e),RG_Exception)):
LogFatal(text + e.Message,e.Value)
pass
elif(len(e.args)>0):LogFatal(text + e.args[0])
else:LogFatal(text + "There was an exception raised without a message.")
self.End()
def DoRender(self):
if(self.Ended) : return;
if(self._oldFrameRate != self.FrameRate.Value):
self._oldFrameRate = self.FrameRate.Value
self._pause = 1/self.FrameRate.Value
self._mainScript.render()
self.DoRend()
self.executor.map(self.Display, self._appearances.Value)
for e in self.Exceptions:
raise e
def DoRend(self):
if(self.Ended) : return
for Src in self._renderList.Value:
Src.Render()
pass
def Display(self,Src):
try:
Src.Appearance.Render()
except Exception as e:
self.Exceptions.append(e)
def End(self):
if(self.Ended) : return;
self.Ended = True;
self.Run = False;
print("\nMain> Started | Ending .")
print("Main\\Ending> Started | ending -> physics.")
self._mainScript.MainPhysics.End();
while self._mainScript.MainPhysics.Running:pass
print("Main\\Ending> Finished | ending -> physics.")
print("Main> Finished | Ending.")
self.Window.destroy()
async def des(self):
pass
pass;
from enum import Enum
from tkinter import*
from concurrent.futures import ThreadPoolExecutor
class RG_WindowMode(Enum):
TKINTER = 0
PYGAME = 0
class RG_MainWindow:
WindowTitle:str = "RGame"
WindowHeight:int = 500
WindowWidth:int = 800
WindowBackground:str = "White"
WindowIcon:str = None
FrameRate:ref = ref(30);
FailedRenderFailsafe:ref = ref(3)
RenderingManager:RG_RenderingManager = None
SpriteRender:ref = ref([])
Appearances:ref = ref([])
Activate:bool = True
def __init__(self, mainScr, frameRate = ref(30)):
if(mainScr == None) : return;
self.MainScript = mainScr;
self.FrameRate = frameRate;
print("Main\\Init\\MainWindow> Started | creating -> Window");
self.Window = Tk()
print("Main\\Init\\MainWindow> Finished | creating -> Window");
print("Main\\Init\\MainWindow> Started | creating -> Rendering");
try:
self.RenderingManager = RG_RenderingManager(
self.MainScript, self.Window,
self.FrameRate, self.SpriteRender, self.FailedRenderFailsafe,
self.WindowWidth, self.WindowHeight, self.WindowBackground,
self.Appearances
)
except Exception as e:
print("Failed to initialize RenderingManager.\n\n")
raise e;
print("Main\\Init\\MainWindow> Finished | creating -> Rendering");
self.Mouse = RG_Mouse(self.RenderingManager.HandleExp,self.WindowHeight)
self.Mouse.bindEvents(self.Window)
def Start(self):
print("Main\\Start up> starting | MainWindow")
if(not self.Activate):
print("Main\\Start up\\MainWindow> Report | MainWindow.Activate is set to False so window will not start)");
self.Window.after(1,self.Window.destroy)
mainloop()
print("Main> Finished | Start up");
return;
self.CreateWindow()
self.RenderingManager.StartRendering(self.WindowWidth, self.WindowHeight, self.WindowBackground);
pass;
def CreateWindow(self):
print("\nMain\\Start up\\MainWindow> Started | configuring -> Window\n");
print("Main\\Start up\\MainWindow\\configuring> Started | setting -> Title");
self.Window.title(self.WindowTitle);
print("Main\\Start up\\MainWindow\\configuring> Finished | setting -> Title");
#photo = PhotoImage(file = self.WindowIcon);
#self.MainWindow.iconphoto(False, photo);
print("Main\\Start up\\MainWindow\\configuring> Started | setting -> Icon");
if(self.WindowIcon != None):
self.Window.iconbitmap(self.WindowIcon);
print("Main\\Start up\\MainWindow\\configuring> Finished | setting -> Icon");
print("Main\\Start up\\MainWindow\\configuring> Started | setting -> Max Size (will be separate to min in a future update)");
self.Window.maxsize(self.WindowWidth,self.WindowHeight);
print("Main\\Start up\\MainWindow\\configuring> Finished | setting -> Max Size");
print("Main\\Start up\\MainWindow\\configuring> Started | setting -> Min Size");
self.Window.minsize(self.WindowWidth,self.WindowHeight);
print("Main\\Start up\\MainWindow\\configuring> Finished | setting -> Min Size");
print("\nMain\\Start up\\MainWindow> Finished | configuring -> Window");
pass;
def Add(self, script:RG_Script):
self.SpriteRender.Value.append(script)
self.Appearances.Value.append(script)
pass;
def Exists(self, script:RG_Script):
return 0 < self.SpriteRender.Value.count(script)
def Remove(self, script):
if(len(self.SpriteRender.Value) == 0): return
self.SpriteRender.Value.remove(script)
self.Appearances.Value.remove(script)
pass;
def Bind(self,BindKey, Bind):
self.Window.bind(BindKey,Bind)
@property
def Screen(self):
return self.RenderingManager.Screen
class RG_Mouse:
def __init__(self, handleExp, height):
self.winH = height
self._handleExp = handleExp
self.executor = ThreadPoolExecutor()
Left = False
Middle = False
Right = False
ScrollDelta = 0
DoubleClickDelta = 0.5
DoubleClickTimePoint = RG_TimePoint()
OnSecondClick = False
DragDeltaMovement = 3
Drag = False
def BindLeftDown(self, bind):
self._leftDown.append(bind)
def BindLeftUp(self, bind):
self._leftUp.append(bind)
def BindMiddleDown(self, bind):
self._middleDown.append(bind)
def BindMiddleUp(self, bind):
self._middleUp.append(bind)
def BindRightDown(self, bind):
self._rightDown.append(bind)
def BindRightUp(self, bind):
self._rightUp.append(bind)
def BindDoubleClick(self, bind):
self._doubleClick.append(bind)
def BindMove(self, bind):
self._move.append(bind)
def BindDrag(self, bind):
self._drag.append(bind)
def BindScroll(self, bind):
self._scroll.append(bind)
def bindEvents(self, window):
window.bind("<1>",self.leftDown)
window.bind("<ButtonRelease-1>",self.leftUp)
window.bind("<2>",self.middleDown)
window.bind("<ButtonRelease-2>",self.middleUp)
window.bind("<3>",self.rightDown)
window.bind("<ButtonRelease-3>",self.rightUp)
window.bind("<Motion>",self.move)
window.bind("<MouseWheel>",self.scroll)
_leftDown:list = []
def leftDown(self, args):
self.Left = True
for func in self._leftDown:
try:
if(func(args)):
break
except Exception as e:
if(self._handleExp(e)): return
_doubleClick:list = []
def doubleClick(self, args):
if not (self.OnSecondClick):
self.OnSecondClick = True
self.DoubleClickTimePoint.Now()
return
self.OnSecondClick = False
if (self.DoubleClickTimePoint.Diff() > self.DoubleClickDelta):
return
for func in self._doubleClick:
try:
if(func(args)):
break
except Exception as e:
if(self._handleExp(e)): return
_leftUp:list = []
def leftUp(self, args):
self.Left = False
self.Drag = False
self.executor.submit(self.doubleClick, args)
for func in self._leftUp:
try:
if(func(args)):
break
except Exception as e:
if(self._handleExp(e)): return
_middleDown:list = []
def middleDown(self, args):
self.Middle = True
for func in self._middleDown:
try:
if(func(args)):
break
except Exception as e:
if(self._handleExp(e)): return
_middleUp:list = []
def middleUp(self, args):
self.Middle = False
for func in self._middleUp:
try:
if(func(args)):
break
except Exception as e:
if(self._handleExp(e)): return
_rightDown:list = []
def rightDown(self, args):
self.Right = True
for func in self._rightDown:
try:
if(func(args)):
break
except Exception as e:
if(self._handleExp(e)): return
_rightUp:list = []
def rightUp(self, args):
self.Right = False
for func in self._rightUp:
try:
if(func(args)):
break
except Exception as e:
if(self._handleExp(e)): return
_drag:list = []
LastPos = RG_Position2D()
Position = RG_Position2D()
DeltaMovement = RG_Vector2D()
def drag(self, args):
if not (self.Left): return
if not(self.Drag):
if not (self.DeltaMovement.GetlengthSqr() > self.DragDeltaMovement*self.DragDeltaMovement): return
self.Drag = True
for func in self._drag:
try:
if(func(args)):
break
except Exception as e:
if(self._handleExp(e)): return
_move:list = []
def move(self, args):
self.LastPos = self.Position
self.Position = RG_Position2D(args.x, self.winH-args.y)
self.DeltaMovement = self.LastPos.VectorTo(self.Position)
self.drag(args)
for func in self._move:
try:
if(func(args)):
break
except Exception as e:
if(self._handleExp(e)): return
_scroll:list = []
def scroll(self, args):
self.ScrollDelta += args.delta
for func in self._scroll:
try:
if(func(args)):
break
except Exception as e:
if(self._handleExp(e)): return
#MainScr class
class RG_Script:
Activated = False;
Velocity:RG_Velocity2D = RG_Velocity2D(0,0);
Position:RG_Position2D = RG_Position2D(0,0);
Name:str = "Script";
_id = 0;
rending = True;
def __init__(self,mainScript, position:RG_Position2D = None, velocity:RG_Velocity2D = None, appearance:RG_AppearanceType = None, name:str = "Script") -> None:
self.Before();
#mainScript
self.MainScript = mainScript;
#pos
if (position is None):
position = RG_Position2D()
elif not (type(position) is RG_Position2D):
raise RG_TypeError(position,
" 'RG_Script' must have an RG_Position2D as the argument 'position' (second argument).")
self.Position = position;
#vel
if (velocity is None):
velocity = RG_Velocity2D()
elif not (type(velocity) is RG_Velocity2D):
raise RG_TypeError(velocity,
" 'RG_Script' must have an RG_Velocity2D as the argument 'velocity' (third argument).")
self.Velocity = velocity;
self.MainWindow = self.MainScript.MainWindow;
#appearance
if (appearance is None):
appearance = None
elif not issubclass(type(appearance), RG_AppearanceType):
raise RG_TypeError(appearance,
" 'RG_Script' must have an RG_AppearanceType the argument 'appearance' (fourth argument).")
self.Appearance = appearance;
#name
if (name is None):
name = "script"
elif not (type(name) is str):
raise RG_TypeError(name,
" 'RG_Script' must have a string as the argument 'name' (last argument).")
self.Name = name;
self.ScreenWidth = self.MainWindow.WindowWidth;
self.ScreenHeight = self.MainWindow.WindowHeight;
self.MainPhysics = self.MainScript.MainPhysics;
self.Start();
self.Activate()
pass
def MoveTo(self,x,y):
self.Position.X = x;
self.Position.Y = y;
if not (self.Appearance is None):
self.Appearance.MoveTo(x,y)
pass;
def Activate(self):
if(self.Activated): return
self.Activated = True;
if not (self.Appearance is None):
self.Appearance.Show();
self.MainWindow.Add(self);
self.MainPhysics.Add(self);
pass;
def Deactivate(self):
if not (self.Activated): return
self.Activated = False;
self.MainPhysics.Remove(self);
if not (self.Appearance is None):
self.Appearance.Hide();
self.MainWindow.Remove(self);
self.rending = False;
pass;
# ----------------------------------
# Bounce:
# ----------------------------------
def Bounce(self):
pos = self.Position - self.Appearance.OffSet;
bounced = False;
if(pos.X < 0 ):
self.Position.X += 0 - pos.X;
self.Velocity.X *= -1;
bounced = True;
if(pos.X + self.Appearance.Dimensions.Width > self.ScreenWidth):
self.Position.X += (self.ScreenWidth - self.Appearance.Dimensions.Width)-pos.X;
self.Velocity.X *= -1;
bounced = True;
if(pos.Y < 0):
self.Position.Y += 0 - pos.Y;
self.Velocity.Y *= -1;
bounced = True;
if( self.Appearance.Dimensions.Height + pos.Y > self.ScreenHeight):
self.Position.Y += (self.ScreenHeight - self.Appearance.Dimensions.Height)-pos.Y;
self.Velocity.Y *= -1;
bounced = True;
return bounced;
# axial bounce
def BounceY(self):
pos = self.Position + self.Appearance.OffSet;
bounced = False;
if(pos.Y < 0):
self.Position.Y = self.Appearance.OffSet.Y;
self.Velocity.Y *= -1;
bounced = True;
if(pos.Y >= self.ScreenHeight - self.Appearance.Dimensions.Height):
self.Position.Y = self.ScreenHeight + self.Appearance.Dimensions.Height + self.Appearance.OffSet.Y;
self.Velocity.Y *= -1;
bounced = True;
return bounced;
def BounceX(self):
pos = self.Position+ self.Appearance.OffSet;
bounced = False;
if(pos.X < 0 ):
self.Position.X = self.Appearance.OffSet.X;
self.Velocity.X *= -1;
bounced = True;
if(pos.X >= self.ScreenWidth - self.Appearance.Dimensions.Width):
self.Position.X = self.ScreenWidth - self.Appearance.Dimensions.Width + self.Appearance.OffSet.X;
self.Velocity.X *= -1;
bounced = True;
return bounced;
# sides bounce
def BounceRight(self):
pos = self.Position + self.Appearance.OffSet;
bounced = False;
if(pos.X >= self.ScreenWidth - self.Appearance.Dimensions.Width):
self.Position.X = self.ScreenWidth - self.Appearance.Dimensions.Width + self.Appearance.OffSet.X;
self.Velocity.X *= -1;
bounced = True;
return bounced;
def BounceLeft(self):
pos = self.Position + self.Appearance.OffSet;
bounced = False;
if(pos.X < 0 ):
self.Position.X = self.Appearance.OffSet.X;
self.Velocity.X *= -1;
bounced = True;
return bounced;
def BounceBottom(self):
pos = self.Position + self.Appearance.OffSet;
bounced = False;
if(pos.Y >= self.ScreenHeight - self.Appearance.Dimensions.Height):
self.Position.Y = self.ScreenHeight - self.Appearance.Dimensions.Height + self.Appearance.OffSet.Y;
self.Velocity.Y *= -1;
bounced = True;
return bounced;
def BounceTop(self):
pos = self.Position + self.Appearance.OffSet;
bounced = False;
if(pos.Y < 0):
self.Position.Y = self.Appearance.OffSet.Y;
self.Velocity.Y *= -1;
bounced = True;
return bounced;
def Before(self):
pass;
def Start(self):
pass;
def Tick(self,deltaTime):
if not (self.MainWindow.RenderingManager.Run):return
if not (self.MainPhysics.Running):return
vel = self.Velocity*deltaTime;
self.Position.Move(vel);
try:
self.PhysicsTick(self.MainPhysics.DeltaTime)
except Exception as e:
if(issubclass(type(e),RG_Exception)):
LogError(e.Message,e.Value)
pass
else:LogError(e.args[0])
self.MainPhysics.FailedTickCount += 1;
if(self.MainPhysics.FailedTickCount == self.MainPhysics.FailedTickFailsafe):
text = f" > Max Failed PhysicsTick count surpassed. Current failsafe: {self.MainPhysics.FailedTickFailsafe}.\n > The error:\n\n"
if(issubclass(type(e),RG_Exception)):
LogFatal(text + e.Message,e.Value)
pass
else:LogFatal(text + e.args[0])
self.MainWindow.RenderingManager.End()
if self.MainWindow.RenderingManager.Run:
self.MoveTo(self.Position.X,self.Position.Y)
pass;
def PhysicsTick(self,deltaTime):
pass;
def Render(self):
if not (self.Appearance is None):
self.Appearance.Render()
pass;
pass;
class RG_Circle(RG_Script):
def __init__(self, mainScript, position: RG_Position2D = None, velocity: RG_Velocity2D = None, radius:float = None, color:str = None, OffSet:RG_Vector2D = None, name: str = None ) -> None:
super().__init__(mainScript, position=position, velocity=velocity, appearance=RG_App_Circle(mainScript.MainWindow.Screen, radius, color,OffSet ), name=name)
class RG_Ellipse(RG_Script):
def __init__(self, mainScript, position: RG_Position2D = None, velocity: RG_Velocity2D = None, radiusX:float = None, radiusY:float = None, color:str = None, OffSet:RG_Vector2D = None, name: str = None ) -> None:
super().__init__(mainScript, position=position, velocity=velocity, appearance=RG_App_Ellipse(mainScript.MainWindow.Screen, radiusX, radiusY, color,offset=OffSet ), name=name)
class RG_Rectangle(RG_Script):
def __init__(self, mainScript, position: RG_Position2D = None, velocity: RG_Velocity2D = None, width:float = None, height:float = None, color:str = None, OffSet:RG_Vector2D = None, name: str = None) -> None:
super().__init__(mainScript, position=position, velocity=velocity, appearance=RG_App_Rectangle(mainScript.MainWindow.Screen, RG_Size(width, height), color ,offset=OffSet ), name=name)
class RG_Line(RG_Script):
def __init__(self, mainScript, position: RG_Position2D = None, velocity: RG_Velocity2D = None, points:list[RG_Vector2D] = None, color:str = None, width:int = None, smooth:bool = None, resolution:int = None, Offset:RG_Vector2D = None, name: str = None ) -> None:
super().__init__(mainScript, position=position, velocity=velocity, appearance=RG_App_Line(mainScript.MainWindow.Screen, points, color, width, smooth, resolution, Offset), name=name)
class RG_Label(RG_Script):
def __init__(self, mainScript, position: RG_Position2D = None, velocity: RG_Velocity2D = None, text:str = None, fontType:str = None, fontSize:int = None, fontColor:str = None, bold:bool = None, italic:bool = None, underline:bool = None, overstrike:bool = None, Offset:RG_Vector2D = None, name: str = None ) -> None:
super().__init__(mainScript, position=position, velocity=velocity, appearance=RG_App_Label(mainScript.MainWindow.Screen, text, fontType, fontSize,fontColor, bold, italic, underline, overstrike, Offset), name=name)
class RG_Image(RG_Script):
def __init__(self, mainScript, position: RG_Position2D = None, velocity: RG_Velocity2D = None, fileLocation:str = None, OffSet:RG_Vector2D = None, name: str = None ) -> None:
super().__init__(mainScript, position=position, velocity=velocity, appearance=RG_App_Shader(screen = mainScript.MainWindow.Screen,fileLocation= fileLocation,offset=OffSet ), name=name)
#MainScr class
class RG_MainScript:
_beforeOverride = False
_mainOverride = False
_physicsTickOverride = False
_renderOverride = False
def __init__(self, before = None, main = None, physicsTick = None, render = None) -> None:
if not before is None:
self.Before = before
self._beforeOverride = True
if not main is None:
self.Main = main
self._mainOverride = True
if not physicsTick is None:
self.PhysicsTick = physicsTick
self._physicsTickOverride = True
if not render is None:
self.Render = render
self._renderOverride = True
self.Started = False
self.Stop = False
def StartRGame(self):
TimeInit()
try:
if self._beforeOverride:
self.Before(self)
else: self.Before()
except Exception as e:
print("In Before - before everything.\n")
raise e
if(self.Stop):
return
self.Started = True
print("Main> Started | Init ( initialization - where things get first created )")
self.INIT()
print("Main> Finished | Init")
try:
if self._mainOverride:
self.Main(self)
else: self.Main()
except Exception as e:
print("In MainScript Main\n")
raise e;
print("Main> Started | Start up ( where physics and rendering are first started )")
self.Exp = None;
self.Start();
def INIT(self):
print()
# Intervals
# physics
self.TickInterval = 0.05;
print("Main\\Init> Done | setting -> Physics Tick Interval.")
# rendering
self.FrameRate = ref( 10 );
print("Main\\Init> Done | setting -> Frame Rate.")
# Managers
# physics
print("Main\\Init> Started | creating -> Main Physics");
self.MainPhysics = RG_MainPhysics(self, self.TickInterval);
print("Main\\Init> Finished | creating -> Main Physics")
# rendering
print("Main\\Init> Started | creating -> Main Window");
self.MainWindow = RG_MainWindow(self, self.FrameRate);
print("Main\\Init> Finished | creating -> Main Window");
print()
pass;
def Before(self):
pass;
def Main(self):
pass;
def Start(self):
self.MainPhysics.Interval = self.TickInterval;
print()
print("Main\\Start up> Starting | Main Physics Tick")
self.MainPhysics.Start()
print("Main\\Start up> Started | Main Physics Tick")
print("Main\\Start up> Starting | Main Window Rendering")
self.MainWindow.Start()
pass;
def tick(self, deltatime):
if not (self.MainPhysics.Running):return
try:
if self._physicsTickOverride:
self.PhysicsTick(self, deltatime)
else: self.PhysicsTick(deltatime)
except Exception as e:
if(issubclass(type(e),RG_Exception)):
LogError(e.Message,e.Value)
pass
else:LogError(e.args[0])
self.MainPhysics.FailedTickCount += 1
if(self.MainPhysics.FailedTickCount == self.MainPhysics.FailedTickFailsafe):
text = f" > Max Failed PhysicsTick count surpassed. Current failsafe: {self.MainPhysics.FailedTickFailsafe}.\n > The error:\n\n"
if(issubclass(type(e),RG_Exception)):
LogFatal(text + e.Message,e.Value)
pass
else:LogFatal(text + e.args[0])
self.MainWindow.RenderingManager.End()
def PhysicsTick(self,deltatime):
pass
def render(self):
if self._physicsTickOverride:
self.Render(self)
else: self.Render()
def Render(self):
pass;
def End(self):
self.MainWindow.RenderingManager.End()
pass;
class Run:
def __init__(self, main:RG_MainScript) -> None:
"""
Run is a functor which runs your program with your custom main class
:param main: Your Main class which derives from RG_MainScript
"""
import os
os.system("color 00")
try:
main.StartRGame()
print("Started | Main\n")
if(main.Started):
main.MainPhysics.End()
except RG_Exception as e:
if not (e.Value is None):
LogFatal(e.Message, e.Value)
else:
LogFatal(e.Message)
except Exception as e:
if(len(e.args)>0):
LogFatal(e.args[0])
input("\nFinished | Main (press enter to close window): ")