Page 1 of 1

[SOLVED] Creator Defined Displayable re-initializes when calling/invoking new context(I think?)

Posted: Sun Apr 18, 2021 4:58 pm
by vague_robot
So I've cobbled together a relatively simple isometric exploration CDD, based on a few different approaches I've found here on the forum. However I've noticed that whenever I either try to use the normal dialogue system or perform an action that creates a new context (Like opening the menu or the confirmation UI when you try to close the window I believe?), the CDD gets re-initialized and resets the character back to their start position. I'm not sure if the dialogue system also uses contexts or if that's actually a whole different issue, but based off what I've understood about creating new contexts at least, that doesn't seem like the intended effect. So I'm wondering if there may be something I've set up strangely or if I've fundamentally misunderstood how some part of this is supposed to work.

I've provided a stripped down version of the class working in a project since that's probably the quickest way to see what I mean. For the record, you use the arrow keys to move around and space to interact when the exclamation point is visible, with the interaction points being the red, green, and blue colored squares. You still have to click to progress through the interaction dialogue.

I also included an alternate script file in the root "test" folder, where I tried working around the issue by using a variable outside the class with position values that it would theoretically write to before the reset is triggered, and then use when it was re-initialized so nothing would appear to change. I couldn't seem to get that to work either though.

Here's the class specifically for ease of viewing. (Also excuse the code itself possibly still being a bit rough. I haven't quite gotten to the point of shoring things up yet. lol)

Code: Select all

class ExplorationScreen(renpy.Displayable):
    def __init__(self):
        renpy.log('Initializing ExplorationScreen!')
        super(renpy.Displayable, self).__init__()
        # sprite setup
        self.sprite = front
        self.bang = 'images/bang.png'
        # bg
        self.iso = 'images/iso.png'
        self.iso_map = renpy.load_surface('images/iso.png')

        self.pause_input = False
        self.orientation = 1
        self.direction = ''
        self.pos_x = 640
        self.pos_y = 360
        self.dpos_x = 0.5
        self.dpos_y = 0.5
        self.speed_x = 0.0
        self.speed_y = 0.0
        self.last_st = None
        self.last_x = 0
        self.last_y = 0

    def get_map_color(self, x, y):
        try:
            pos_color = self.iso_map.get_at((x,y)) [:3]
        except IndexError:
            pos_color = -1
        finally:
            return pos_color

    def check_map(self, x, y):
        pos_color = self.get_map_color(x, y)

        new_x = x
        new_y = y
        if pos_color != -1:
            if pos_color == (0, 0, 0):
                if self.direction == 'l':
                    if self.get_map_color(self.last_x - 1, self.last_y + 1) != (0, 0, 0):
                        new_x = self.last_x - 1
                        new_y = self.last_y + 1
                    else:
                        new_x = self.last_x
                        new_y = self.last_y
                elif self.direction == 'u':
                    if self.get_map_color(self.last_x - 1, self.last_y - 1) != (0, 0, 0):
                        new_x = self.last_x - 1
                        new_y = self.last_y - 1
                    else:
                        new_x = self.last_x
                        new_y = self.last_y
                elif self.direction == 'd':
                    if self.get_map_color(self.last_x + 1, self.last_y + 1) != (0, 0, 0):
                        new_x = self.last_x + 1
                        new_y = self.last_y + 1
                    else:
                        new_x = self.last_x
                        new_y = self.last_y
                elif self.direction == 'r':
                    if self.get_map_color(self.last_x + 1, self.last_y - 1) != (0, 0, 0):
                        new_x = self.last_x + 1
                        new_y = self.last_y - 1
                    else:
                        new_x = self.last_x
                        new_y = self.last_y
        else:
            new_x = self.last_x
            new_y = self.last_y

        return new_x, new_y

    def check_interact(self, x, y):
        pos_color = self.get_map_color(x, y)

        if pos_color == (255, 0, 0):
            renpy.log('Starting Interaction 1!')
            renpy.jump('interaction_1')
        elif pos_color == (0, 255, 0):
            renpy.log('Starting Interaction 2!')
            renpy.jump('interaction_2')
        elif pos_color == (0, 0, 255):
            renpy.log('Starting Ending Interaction!')
            renpy.jump('interaction_end')


    def render(self, width, height, st, at):
        base = renpy.displayable(self.iso)
        r = renpy.render(base, width, height, st, at)

        if self.last_st is None:
            self.last_st = st

        dtime = st - self.last_st
        self.last_st = st
        self.last_x = self.pos_x
        self.last_y = self.pos_y

        move_x = dtime * self.speed_x
        move_y = dtime * self.speed_y

        self.pos_x += self.dpos_x * move_x
        self.pos_y += self.dpos_y * move_y

        map_check_results = self.check_map(self.pos_x, self.pos_y)
        self.pos_x = map_check_results[0]
        self.pos_y = map_check_results[1]

        char = Transform(self.sprite, xanchor=0.5, yanchor=0.75, xzoom=self.orientation)
        r.place(char, self.pos_x, self.pos_y)

        pos_color = self.get_map_color(self.pos_x, self.pos_y)
        if  pos_color == (255, 0, 0):
            bang = Transform(self.bang, xanchor=0.5, yanchor=1.0)
            r.place(bang, self.pos_x, self.pos_y)
        elif  pos_color == (0, 255, 0):
            bang = Transform(self.bang, xanchor=0.5, yanchor=1.0)
            r.place(bang, self.pos_x, self.pos_y)
        elif  pos_color == (0, 0, 255):
            bang = Transform(self.bang, xanchor=0.5, yanchor=1.0)
            r.place(bang, self.pos_x, self.pos_y)
        renpy.redraw(self, 0)
        return r

    def event(self, ev, x, y, st):
        rate_x = 400.0
        rate_y = 200.0
        if not self.pause_input:
            if ev.type == pygame.KEYDOWN:
                if ev.key == pygame.K_LEFT:
                    self.sprite = back
                    self.orientation = 1
                    self.direction = 'l'
                    self.speed_x = -rate_x
                    self.speed_y = -rate_y
                    renpy.redraw(self, 0)
                    raise renpy.IgnoreEvent()

                elif ev.key == pygame.K_RIGHT:
                    self.sprite = front
                    self.orientation = -1
                    self.direction = 'r'
                    self.speed_x = rate_x
                    self.speed_y = rate_y
                    renpy.redraw(self, 0)
                    raise renpy.IgnoreEvent()

                elif ev.key == pygame.K_UP:
                    self.sprite = back
                    self.orientation = -1
                    self.direction = 'u'
                    self.speed_x = rate_x
                    self.speed_y = -rate_y
                    renpy.redraw(self, 0)
                    raise renpy.IgnoreEvent()

                elif ev.key == pygame.K_DOWN:
                    self.sprite = front
                    self.orientation = 1
                    self.direction = 'd'
                    self.speed_x = -rate_x
                    self.speed_y = rate_y
                    renpy.redraw(self, 0)
                    raise renpy.IgnoreEvent()
                elif ev.key == pygame.K_SPACE:
                    self.check_interact(self.pos_x, self.pos_y)
                    raise renpy.IgnoreEvent()

            elif ev.type == pygame.KEYUP:
                if ev.key == pygame.K_LEFT:
                    self.sprite = back
                    self.orientation = 1
                    self.speed_x = 0
                    self.speed_y = 0
                    raise renpy.IgnoreEvent()

                elif ev.key == pygame.K_RIGHT:
                    self.sprite = front
                    self.orientation = -1
                    self.speed_x = 0
                    self.speed_y = 0
                    raise renpy.IgnoreEvent()

                elif ev.key == pygame.K_UP:
                    self.sprite = back
                    self.orientation = -1
                    self.speed_x = 0
                    self.speed_y = 0
                    raise renpy.IgnoreEvent()

                elif ev.key == pygame.K_DOWN:
                    self.sprite = front
                    self.orientation = 1
                    self.speed_x = 0
                    self.speed_y = 0
                    raise renpy.IgnoreEvent()

        return None
Any guidance on how to potentially correct or work around this behavior would be greatly appreciated!

Re: Creator Defined Displayable re-initializes when calling/invoking new context(I think?)

Posted: Sun Apr 18, 2021 5:09 pm
by Ocelot
add ExplorationScreen() This will create a new ExplorationScreen every time screen is reevaluated. Which is at least every time interaction is triggered and might be even more often (not to mention, it will create it several times before screen is shown as part of screen prediction). You want to store ExplorationScreen in variable which won't reset every time.

Quick fix:

Code: Select all

screen iso_mode:
    default e_screen = ExplorationScreen()
    $ renpy.log('Initializing iso_mode screen!')
    add e_screen

Re: Creator Defined Displayable re-initializes when calling/invoking new context(I think?)

Posted: Sun Apr 18, 2021 5:23 pm
by vague_robot
Ah, of course it would be something as simple as that. :oops: That makes perfect sense now that you explain it too. Thank you for the clarification!