CDD Child Anchors and Layering Issues

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Post Reply
Posts: 3
Joined: Tue Sep 18, 2018 7:39 am

CDD Child Anchors and Layering Issues

#1 Post by Nisshou » Wed Oct 24, 2018 8:33 pm

Hey Everyone,

I am creating a CDD that displays multiple projectiles flying towards the screen in sequence. Each projectile should spin and grow larger over time to imitate a first-person perspective of having something thrown at you. I've provided the code I've written so far at the bottom of this post.

However, I have an issue where instead of the projectiles zooming and rotating in place, they all fly off towards the bottom-right corner of the screen. I assume this is due to the anchor point of the children being set to (0, 0) rather than (0.5, 0.5). I attempted to change this in the Transform properties with no result.

There is also an issue where newly drawn projectiles will be drawn on top of older projectiles, which doesn't make sense visually as newer projectiles should be further away from the player, hidden behind closer incoming projectiles.

My questions are:

1. How can I set the anchor points of the CDD's children? Will this anchor point be affected by the actively changing zoom and rotation transformations?
2. How can I make it so that the oldest child displayed will always be the drawn closest to the player?

Any other feedback is also welcome.
Thank you for your help in advance.

Code: Select all

init python:
    fireball = renpy.image("fireball", "fireball.png")

init python:
    class Projectile(object):
        def __init__(self, projectileImage, projectileAppearanceTime, projectileZoom, projectileRotation, projectileXpos, projectileYpos):
            self.projectileImage = projectileImage
            self.projectileAppearanceTime = projectileAppearanceTime
            self.projectileZoom = projectileZoom
            self.projectileRotation = projectileRotation
            self.projectileXpos = projectileXpos
            self.projectileYpos = projectileYpos

    class MagicBattle(renpy.Displayable):
        def __init__(self, fullProjectileList, **kwargs):

            super(MagicBattle, self).__init__(**kwargs)

            # List of projectile objects that will be used to control projectile appearance
            self.fullProjectileList = fullProjectileList

        # Processes active projectiles and draws the screen
        def render(self, width, height, st, at):

            # The main render object that will be drawn into
            renderWindow = renpy.Render(width, height)

            # Loop that will be handling drawing of multiple projectiles at once by looking through the projectile list
            for projectile in self.fullProjectileList:
                if projectile.projectileAppearanceTime <= st:

                    # Creating the zoom and rotate transform to be applied to the projectile image
                    projectileTransform = Transform(child=projectile.projectileImage, anchor=(0.5, 0.5), zoom=projectile.projectileZoom, rotate=projectile.projectileRotation)

                    # Create a render of the projectile image using the transform above
                    projectileRender = renpy.render(projectileTransform, width, height, st, at)

                    # Draw the render above into the main render window
                    renderWindow.blit(projectileRender, (projectile.projectileXpos, projectile.projectileYpos))

                    # Change rotation and zoom of the projectile for the next render frame to emulate an incoming projectile
                    projectile.projectileRotation -= 30
                    projectile.projectileZoom += 0.05

            renpy.redraw(self, 0)

            return renderWindow

    # Create a list of projectiles to pass into the MagicBattle class for testing
    testProjectileList = [
    Projectile("fireball", 1.0, 0.2, 0, 0, 0),
    Projectile("fireball", 1.2, 0.2, 0, 0, 0),
    Projectile("fireball", 1.4, 0.2, 0, 200, 0),
    Projectile("fireball", 1.8, 0.2, 0, 400, 0),
    Projectile("fireball", 2.0, 0.2, 0, 600, 0),
    Projectile("fireball", 2.2, 0.2, 0, 800, 0)

screen battle():

    default battle = MagicBattle(testProjectileList)

    add battle

label start:

    "The magic battle test is starting."

    window hide
    $ quick_menu = False

    call screen battle

User avatar
Ren'Py Creator
Posts: 15474
Joined: Mon Feb 02, 2004 10:58 am
Completed: Moonlight Walks
Projects: Ren'Py
IRC Nick: renpytom
Github: renpytom
itch: renpytom
Location: Kings Park, NY

Re: CDD Child Anchors and Layering Issues

#2 Post by PyTom » Wed Oct 24, 2018 9:34 pm

Code: Select all

                    renderWindow.blit(projectileRender, (projectile.projectileXpos, projectile.projectileYpos))
Blit ignores things like the anchors. If you want to use them, use instead. You can find it documented at: ...
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom
"Silly and fun things are important." - Elon Musk
Software > Drama •

Posts: 3
Joined: Tue Sep 18, 2018 7:39 am

Re: CDD Child Anchors and Layering Issues

#3 Post by Nisshou » Thu Oct 25, 2018 5:26 pm

Awesome! The anchor component is working now after using Thanks so much, PyTom!

Regarding ordering images within the CDD, how could I go about controlling how images appear on top of each other?
I assume it would be related to manipulating the zorder values of each image depending on their appearance time, but I can't figure out how to do it within the context of a CDD.

User avatar
Eileen-Class Veteran
Posts: 1441
Joined: Tue May 30, 2017 6:10 am
Completed: None... yet (as I'm still looking for an artist)
Projects: An un-named anime based trainer game

Re: CDD Child Anchors and Layering Issues

#4 Post by Remix » Thu Oct 25, 2018 7:40 pm

I think blitting is a first-come-first-served, so maybe just reverse the list:

for projectile in sorted(self.fullProjectileList, key=lambda proj_obj: proj_obj.projectileAppearanceTime, reverse=True):


for projectile in sorted(self.fullProjectileList, key=lambda proj_obj: -proj_obj.projectileAppearanceTime):
Frameworks & Scriptlets:

Posts: 3
Joined: Tue Sep 18, 2018 7:39 am

Re: CDD Child Anchors and Layering Issues

#5 Post by Nisshou » Fri Oct 26, 2018 8:12 am

Looks like that did it! Thanks so much for your help, Remix!
You are all awesome.

Post Reply

Who is online

Users browsing this forum: Google [Bot]