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

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
Message
Author
vague_robot
Newbie
Posts: 2
Joined: Sun Apr 18, 2021 1:04 am
Contact:

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

#1 Post 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!
Attachments
test_project.zip
(777.33 KiB) Downloaded 11 times
Last edited by vague_robot on Sun Apr 18, 2021 10:49 pm, edited 1 time in total.

User avatar
Ocelot
Lemma-Class Veteran
Posts: 2400
Joined: Tue Aug 23, 2016 10:35 am
Github: MiiNiPaa
Discord: MiiNiPaa#4384
Contact:

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

#2 Post 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
< < insert Rick Cook quote here > >

vague_robot
Newbie
Posts: 2
Joined: Sun Apr 18, 2021 1:04 am
Contact:

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

#3 Post 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!

Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Google [Bot]