Page 1 of 1

CDD Child Anchors and Layering Issues

Posted: Wed Oct 24, 2018 8:33 pm
by Nisshou
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

Re: CDD Child Anchors and Layering Issues

Posted: Wed Oct 24, 2018 9:34 pm
by PyTom

Code: Select all

                    renderWindow.blit(projectileRender, (projectile.projectileXpos, projectile.projectileYpos))
Blit ignores things like the anchors. If you want to use them, use Render.place instead. You can find it documented at:

https://www.renpy.org/doc/html/udd.html ... nder.place

Re: CDD Child Anchors and Layering Issues

Posted: Thu Oct 25, 2018 5:26 pm
by Nisshou
Awesome! The anchor component is working now after using Render.place. 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.

Re: CDD Child Anchors and Layering Issues

Posted: Thu Oct 25, 2018 7:40 pm
by Remix
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):

or

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

Re: CDD Child Anchors and Layering Issues

Posted: Fri Oct 26, 2018 8:12 am
by Nisshou
Looks like that did it! Thanks so much for your help, Remix!
You are all awesome.