[SOLVED] Scene Update for all gameobjects help
Just gave the metaclass direction and no success. i was able to easily control exec order for
start()though the metaclass would always make a new scene loop fore each subclass.
one of the attempts
class meta(type): @classmethod def awake(cls): return @classmethod def start(cls): return @classmethod def update(cls, dt): return @classmethod def __prepare__(metacls, name, bases, **kwds): class GameLoop (Scene): def setup(self): pass def update(self): metacls.update(self.dt) run(GameLoop()) return collections.OrderedDict() def __new__(cls, name, bases, namespace, **kwds): result = type.__new__(cls, name, bases, dict(namespace)) result.awake() ...some attr... result.start() return result class Core(metaclass=meta): def __init__(self): pass def update(self, dt): pass
I feel like there is a simple aproch to doing this but its just out of reach..
mikael last edited by
@stephen, sorry for being slow, but I do not yet quite get what you are trying to accomplish. Don’t the Nodes already support defining update methods that run in sync, without needing to be explicitly called?
@mikael well 😶 i actually have not tried let me run a quick test.
but to answer your question..
yes im wanting to have a single loop that EVERY GameObject that gets created inherits.
@mikael No Sir they do not automatically link. i even tried subclassing EffectsNode.
mikael last edited by mikael
@stephen, can you please reiterate the design goal? Is it that you need to:
a) explicitly control the order every game object gets updated in
b) have global awake, stop methods affecting all objects
c) all objects to have access to the same core configuration
What do you exactly mean by ”need to have all objects have the same timing”?
JonB last edited by
I was saying you simply have something like this
def update(self): for node in self.children: if hasattr(node, 'update') and callable(node.update): node.update()
You could actually do something like this via a class decorator
def auto_update_children(cls): originalupdate = cls.__dict__.get('update') # Possibly None. def update(self): for node in self.children: if hasattr(node, 'update') and callable(node.update): node.update() #finally, if the class already had an update... call it. so you can define classes with an update method, it will update children, then call your specific code.. if callable(originalupdate): originalupdate(self) setattr(cls, 'update',update) return cls @auto_update_children class Game(Scene): def update(self): #do any specific game logic... children have all been update'd when this gets called check_collsitions() etc() #...
Likewise, you could then use said decorator on different "layers" that manage their own game state and children.
The other approach is that you don't have to literally call update on every object. You probably have classes of objects -- player, enemy, projectiles, powerups, whatever.
Keep those as lists inside your scene, and then loop through the lists.
The advantage of that is you can do things like check collisions of every enemy with player, or projectiles with player.
def add_enemy(self): enemy = EnemyNode(....) # ... some code to add a random enemy... self.enemies.append(enemy) self.add_child(enemy) def add_projectile(self, initial_position, initial_velocity): projectile = Projectile(initial_position, initial_velocity) self.projectiles.append(projectile) self.add_child(projectile) def update(self): for enemy in self.enemies: enemy.update() player.update() for projectile in self.projectiles: projectile.update() if projectile.bbox.intersects(player.bbox): #kill player, ...
So, you don't have to have a separate named object for everything in your scene, you have categories of objects that get added so that they can start being updated.
I would be happy to 😀
ill draw out a mini-version.
class Core: def __init__(self, *args, **kwargs): self.awake() self.w, self.h=get_screen_size() self.screenScale=get_screen_scale() ...and so on... self.start() def awake(self): pass # exec before any attrs are set def start(self): pass # exec afer attrs but before returned def update(self): pass # needs to update from here for all gameobjects class GameObject(Core): def __init__(self, id=None *args, **kwargs): Core.__init__(self, *args, **kwargs) self.id=id class Actor(GameObject): def __init__(self, isHostile=False, speed=30, id=None, *args, **kwargs): GameObject.__init__(self, id=id, *args, **kwargs) self.isHostile=isHostile self.speed=speed self.position=(0,0) class Deer(Actor): def __init__(self, loot=, isHostile=False, speed=50, id=100, *args, **kwargs): Actor.__init__(self, isHostile=isHostile, speed=speed, id=id, *args, **kwargs) self.loot_inventory=loot self.spawn_location=None self.health_points=None def awake(self): self.spawn_location=(456, 987) def start(self): self.health_points=100 def update(self): self.position=(...)
###In the example
- Core holds the initial
awake()is called before any base Attributes are set.
start()is called after all base attributes are set but before Instance is returned
update()needs to provide loop for All Subclasses of Core.. so all GameObjects.
- now we work our way down to
Deer()where we use the exec timing methods to set everything as needed.
I know i can just drop ref to every object in the Scene subclass but im trying to find a way to do this implicitly at
ive tried A handfull of approches including metaclass and nothing seems to do this other than manually placing hundreds+objects in the
update()of Scene subclass.
I will be more than happy to give any information to help, been on this solo project for nearly a year now and im at a stand still till i get this resolved.
- Core holds the initial
Now thats what im talking bout!
i believe i shale give a combination of entity goups and Cls decorater..
i will be sure to post wether this solves my issue!
JonB last edited by
Rereading your question ... I guess maybe I read more into your question than you originally wanted...
class GameLoop(Scene): def __init__(self): self.go_list = ; def add_gameobject(self, go): self.go_list.append(go) self.add_child(go) def remove_gameobject(self,go): #... remove from go_list and remove_child def setup(self): for i in range(40): self.add_gameobject( GameObject() ) def update(self): for go in self.go_list: go.update()
Doesn't something like this accomplish what you are after, without a lot of muss & fuss?
Now, I think you could accomplish various types of physics behaviours using decorators -- for instance, you could have a projectile decorator which simply takes current velocity and adjusts position. Then, you could have a affected_by_gravity decorator which adjusts velocity in each time step by g*dt in y. A bouncy decorator that looks for collisions and then inverts velocity, etc. Each decorator would have the form
def affected_by_gravity(cls): originalupdate = cls.__dict__.get('update) def update(self, dt): self.velocity = self.parent.gravity * dt if callable(originalupdate): originalupdate(self,dt) setattr(cls,'update',update) return cls
then you could have
@affected_by_gravity @projectile_physics @bouncy class Ball(ShapeNode): def __init__(self): pass
i feel you first example hold the solution but i do know i will be looking into these decorators more. ive always went around them cuz thry feel uncomfortable. i normaly only programmed in .net on platforms like unity and unreal.
mikael last edited by
@JonB, agree on the first half of your post. Thanks for taking the time to make examples.
Regarding bullet physics and all that, would seem like recreating SpriteKit.
Thank you!! i REALLY appreciate the effort! 👏🏻👏🏻
this community has always got me in the right direction. hopefully this rpg will be play-test ready in roughly 6-8 months (im doing everything alone art, story, coding... so bare with me lol) and as it moves along ill try to post updates and functional "builds" that way you all can throw some input in. when it is fully completed i plan to host it on app store but i will be providing copies for group of you that have been aiding me along the way with python. i never thought i would be able to do this level of coding on a mobile device. lol thank you again and again @omz amazing work on Pythonista!