Is there a way to create an object timer property in python? Like own[‘delay’].timerProperty?
I don’t believe you can, as it doesn’t belong to the default python types.
You could easily create a class instance with a property that updates when called. Using the get() method, every time you call
time = myclass.timer_prop_1
it would update the value. Bare in mind you’d need both the container class as well as the timer property class.
Otherwise, you could write a class with methods like get_time, or a property decorated function that returns the time.
Here is an example of a descriptor version (hacky)
from time import time, sleep
def unbind(function):
try:
return function.__func__
except AttributeError:
raise Exception("Function is not bound")
def is_bound(function):
return hasattr(function, "__self__")
class SpecialProperty(object):
"Emulate PyProperty_Type() in Objects/descrobject.c"
def __init__(self, fget=None, fset=None, fdel=None, doc=None):
self.fget = fget
self.fset = fset
self.fdel = fdel
if is_bound(self.fget):
self.fget = unbind(self.fget)
if is_bound(self.fset):
self.fset = unbind(self.fset)
if is_bound(self.fdel):
self.fdel = unbind(self.fdel)
self.__doc__ = doc
def __get__(self, obj, objtype=None):
if obj is None:
return self
if self.fget is None:
raise AttributeError("unreadable attribute")
return self.fget(obj)
def __set__(self, obj, value):
if self.fset is None:
raise AttributeError("can't set attribute")
self.fset(obj, value)
def __delete__(self, obj):
if self.fdel is None:
raise AttributeError("can't delete attribute")
self.fdel(obj)
def setter(self, func):
if is_bound(func):
func = unbind(func)
self.fset = func
return self
class InstanceDescriptor:
def __getattribute__(self, name):
value = object.__getattribute__(self, name)
if hasattr(value, "__get__"):
return value.__get__(self, self.__class__)
return value
def __setattr__(self, name, value):
try:
obj = object.__getattribute__(self, name)
except AttributeError:
pass
else:
if hasattr(obj, '__set__'):
return obj.__set__(self, value)
return object.__setattr__(self, name, value)
class Timer:
def __init__(self):
self.time = time()
def __get__(self, inst, typ):
if inst is None: return self
return time() - self.time
def __set__(self, inst, value):
if inst is None: return
self.time = time() - value
class ExampleClass(InstanceDescriptor):
def __init__(self):
self.timer = Timer()
a = ExampleClass()
print(a.timer)
sleep(1)
print(a.timer)
a.timer = 0.0
time.sleep(1)
print(a.timer)
Here is a simple property version, but less hidden
from time import time
class ExampleClass:
def __init__(self):
self._time = time()
@property
def timer(self):
return time() - self._time
@timer.setter
def timer(self, value):
self._time = time() - value
That’s a to bad you cant use properties in that way. It would be very useful.
you mean a object that keep the time for all objects of the scene ?
if so, you can make a obj that keep the time, call it Time or something .
with a script that run every frame(and calculate the time)
then , from other obj , you call this obj from the scene , and read the time .
objTime = scene.objects[“Time”]
time = objTime[“time”]
I would have liked each object to work independently on its own properties, but it will work.
Thanks =D
Since you took the time to create these I decided to try them out and, it works great! Thanks! I like to look over the code and try to figure out how it works so at first it looked a little intimidating. Still does kinda. I’m still learning how classes work.
Thank you for your help! Thank you for creating these!
That’s kind of you to try them, although I really wanted to see how easy it was. Fundamentally you can never trick C++ into thinking a PyObject isn’t a PyObject unless you explicitly try to do so, so that would always be an issue with debug properties and logic bricks. I wouldn’t try and understand the classes too badly; they’re non-conventional hacking. I took the concept of descriptors, then allowed them to work with instances (using the InstancedDescriptor base class) and then I overwrote the property access mechanism on the game object to call any descriptors if they existed before reading the property.
It is pretty simple. I added the script to my addons folder so all I have to do is import “from timer_lib import Timer, ObjectPatch”
set own = ObjectPatch(own) and your good to go!
import bge
from timer_lib import Timer, ObjectPatch
def main(cont):
own = cont.owner
own = ObjectPatch(own)
if not "timer" in own:
own['timer'] = Timer()
print(own['timer'])
Do you need to use this?
if not isinstance(own, ObjectPatch):
own = ObjectPatch(own)
Yes. That is the only part you “need”. It only needs to (and should only) be run once to setup the object.