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.
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.