Teenagers in Pygrr - setting up parenting

 Parenting is a pretty useful thing when it comes to game development. It allows you to link objects together, so that they'll inherit movement and everything. It's basically like sticking two or more objects together. 

The structure of families in coding is referred to as a "hierarchy", as there can be multiply levels of children, starting from the "root" object. For example, I'm going to use indentation to show you an example of a hierarchy.

Root object
First child
Grandchild
Another grandchild!
Second child
Third child

If I move an object left, all of the objects underneath it in the hierarchy (that is, successors of that object) will also move left by the same amount. Change travels down in a hierarchy, applying to all of the object's children, and then their children, and so on and so forth.

It should be pretty simple to code this... spoiler: it wasn't

Well, movement was quite easy to code, just rotation was the thing that was... Interesting! As you can see here, I've hooked up a gun to the player, and when the player moves, so does the gun! Awesome stuff...

import pygrr


pygrr.create_window()


player = pygrr.Polygon(model=pygrr.Model.rectangle(50, 100), outline_width=5, tag="Player")


gun_model = pygrr.Model.from_file("gun_new.pygrr", scale=4.5)

gun = pygrr.Polygon(model=gun_model, parent=player, tag="Gun")

gun.set_outlinewidth(5)


bullet_model = pygrr.Model.rectangle(2, 4)


while True:  # game loop!

    player_speed = 50 * pygrr.deltatime


    for obj in pygrr.objects:

        if obj.get_tag() == "Bullet":

            obj.move_forward(500 * pygrr.deltatime)


    if pygrr.Input.key("left"):

        player.move_left(player_speed)

    if pygrr.Input.key("right"):

        player.move_right(player_speed)

    if pygrr.Input.key("up"):

        player.move_up(player_speed)

    if pygrr.Input.key("down"):

        player.move_down(player_speed)


    gun.point_towards(pygrr.Input.mouse_x(), pygrr.Input.mouse_y())


    if pygrr.Input.mouse_down("left"):

        bullet = pygrr.Polygon(position=gun.get_position(), model=bullet_model, fill_color="black", tag="Bullet", rotation=gun.get_rotation())

        bullet.move_forward(55)

        gun.rotate_left(5)


    pygrr.next_frame()

Here's the code for that. Pretty simple stuff! You might have noticed, but I've adding a new structure to Pygrr - tags and objects. You can tag an object, and then in the game loop, iterate through (scan through) all objects, applying change to some object if it's tag is what you want, or anything like that.

The code in there that does this is:

for obj in pygrr.objects:

    if obj.get_tag() == "Bullet":

        obj.move_forward(500 * pygrr.deltatime)

Cool stuff! Now, let's do the rotation.

Well, I'm an idiot. I need to add a function "rotate_around", so that they rotate around their parent's anchor!

Here's the moment when I spent ages getting so many errors, spending hours rewriting this new function... Here's a compilation of some bugs!

4 hours, 5 rewrites later, I found myself at a stopping point. There was no reason my code shouldn't work! Then I read it all through again, and realised. I missed a single minus symbol. One single symbol, that's all it was! Fun(!)...

Well, here we go, it works now!

Only a few functions left to add here! Added to get:

obj.get_localposition()

obj.get_localx()

obj.get_localy()

obj.get_localrotation()

These just return the values in relation to their parent! Also, in every function such as "move", there is an optional parameter defaulted to True called "inherit". This chooses whether or not to apply the change to the children!

We've also added:

obj.apply_position(inherit=True, inherit_level=1)

obj.apply_rotation(inherit=True, inherit_level=1)

obj.apply_visibility(inherit_level=255)

obj.apply_all(inherit_level, inherit) # calls all of the above functions

Parameter "inherit_level" states how many levels of children to apply change to.

Parameter "inherit" states whether or not to inherit change in children below inherit_level (like normal inherit parameter!).

Now, this is all well and good, but how do I actually parent objects to one another? I'm glad you asked!

When you create an object, you can pass in the optional "parent" parameter, to set parent, or the optional "children" array, to add children. If you want to do it later on, there's a few functions to help you out!

obj.get_parent() # returns object's parent

obj.get_children() # returns object's children

obj.unchild() # removes object from their parent

obj.add_child(new_child) # adds child to object

obj.remove_child(child) # removes child from object

obj.set_parent(new_parent) # sets object's parent

And that's done! All we need now is collision and documentation, and the alpha is ready to go!

Isaac, over and out...

Popular posts from this blog

Messing around with procedural art - Turtle graphics

The fossils of Morocco | Mosasaurus beaugei

Blog post #0 - Hello, world!