Game freezes when I attempt to run main game loop method?

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
cdra
Newbie
Posts: 5
Joined: Mon Sep 09, 2013 6:43 am
Contact:

Game freezes when I attempt to run main game loop method?

#1 Post by cdra » Wed Sep 11, 2013 12:33 am

Now that I've got some things cleared up in this game, I've reached a very frustrating issue. The game builds, but when it calls this method, it freezes up and becomes unresponsive. Augh.

A little background: I'm working on a VN/adventure game hybrid and trying to write a fairly simple movement engine for top-down exploration. I'm using pygame keyboard events to handle the movement. I wrote the engine in pygame (outside of renpy) originally, then learned from the game designer that I needed the map to be displayable behind the ren'py screens. I wrote a very silly roundabout system of return methods to get around this while calling the original movement engine script through renpygame, then realized that I would much rather implement it properly in ren'py than import it like that, since I want to integrate it more closely with the script.

Anyhow, I've tracked down that somehow the freeze is occurring during this loop.

Code: Select all

#main game loop
while not goOn:
    ui.clear() # clear layer to start
    # handle events
    for event in pygame.event.get():
        if (event.type == pygame.MOUSEBUTTONDOWN and event.button == 1) or (event.type == KEYDOWN and event.key == K_SPACE):
            interactSprite = self.checkInteraction() # checks if there are any sprites in reach that the player can interact with
            if interactSprite != None:
                investigateReturn = interactSprite.message # sprite has a "message" if it can be interacted with
                if investigateReturn != None:
                    goOn = investigateReturn() # return True if we want to close the movement engine
        # handle player movement
        else:
            self.getMoveDirKeys(event) # method to collect keydown and keyup events and update moveDir appropriately
    
    # move the player if there are no collisions in the direction given
    moveDirTrans = translateDirect(self.moveDir) # makes moveDir more readable for the program
    newpos = self.calculateNewPos() # calculates player's theoretical new position
    if (moveDirTrans is not STILL) and (self.inBounds(newpos)): # ensures that the player is inside the map bounds
        collide = checkCollision(newpos) # looks to see if the player will collide with any sprite obstacles
        if collide:
            if sprite.isDoor: # if you collide with a door, walk through it. doors should be set as "obstacles" though they can be walked through obviously
                self.player.move(newpos) # make it appear as if the player is walking into the door as it implements stuff
                self.player.updateFacing(moveDirTrans)
                investigateReturn = sprite.message # this isn't fully implemented, but you can walk through a door to automatically call their method
                goOn = investigateReturn
        else: 
            self.player.move(newpos)
            self.player.updateFacing(moveDirTrans)
    collide = False # reset collision flag for next game loop
    self.showMap(self.player.loc, self.player.facing) # finally display updated map
For a little relevant background, this is a selection from the enableMovement() method for a moveEngine class I've written--in essence, this is the main game loop. I know that the showMap() method works to just display the relevant images; the key is somewhere in this game loop that lets the player actually move around. The goOn flag should be tripped to True by the sprite.message method (which calls relevant dialogue for inspecting that sprite) if the movement engine should close after calling that method.

Some of the other methods in here are fairly simple and hopefully are self-explanatory. I can post the code snippets for those if you're curious.

I'm hoping someone has an idea of what could be going on here, because I'm rather baffled. Sorry for such a long post!

Elmiwisa
Veteran
Posts: 476
Joined: Sun Jul 21, 2013 8:08 am
Contact:

Re: Game freezes when I attempt to run main game loop method

#2 Post by Elmiwisa » Wed Sep 11, 2013 3:49 am

Why are you using your own loop when Ren'Py already have its own loop? :shock:
And...do you actually redraw the window at any points in this loop? :cry: showMap sounds like it almost do it but doesn't actually do it (this bit of information might be of interest). If you do not redraw the window, then this is basically an infinite loop that the game got stuck in.
Anyway, you might want to look at an example on this page which would help you understand the way keyboard event can be handled (funnily I just found that obscure page yesterday, and it already managed to answer someone's thread and now it come up again; what's the odd? :shock: ). There is also this documentation that provide a more Ren'Py-centric approach to handle the same problem. And then there is also this page which provide an alternative to using Ren'Py screen language directly. Then there is this page that handle the redraw part for you, though it is probably unnecessary since screen already do the same thing very well, and it is unlikely that you need a customized displayable.
Oh I almost forgot this but it is probably overkill.

User avatar
xela
Lemma-Class Veteran
Posts: 2481
Joined: Sun Sep 18, 2011 10:13 am
Contact:

Re: Game freezes when I attempt to run main game loop method

#3 Post by xela » Wed Sep 11, 2013 7:16 am

Yeap, not a bad idea to push your code to higher level, but why don't you simply use logging to see where the loop hangs?
Like what we're doing? Support us at:
Image

cdra
Newbie
Posts: 5
Joined: Mon Sep 09, 2013 6:43 am
Contact:

Re: Game freezes when I attempt to run main game loop method

#4 Post by cdra » Wed Sep 11, 2013 3:26 pm

Elmiwisa wrote:Why are you using your own loop when Ren'Py already have its own loop? :shock:
And...do you actually redraw the window at any points in this loop? :cry: showMap sounds like it almost do it but doesn't actually do it (this bit of information might be of interest). If you do not redraw the window, then this is basically an infinite loop that the game got stuck in.
Anyway, you might want to look at an example on this page which would help you understand the way keyboard event can be handled (funnily I just found that obscure page yesterday, and it already managed to answer someone's thread and now it come up again; what's the odd? :shock: ). There is also this documentation that provide a more Ren'Py-centric approach to handle the same problem. And then there is also this page which provide an alternative to using Ren'Py screen language directly. Then there is this page that handle the redraw part for you, though it is probably unnecessary since screen already do the same thing very well, and it is unlikely that you need a customized displayable.
Oh I almost forgot this but it is probably overkill.
I'm not sure about the fact that I'm using my own loop--it may be totally unnecessary, and I just don't quite understand how to do it otherwise. omo The reason I was doing it was basically to pause the script until you're done with the exploration for that scene (you investigate the thing that returns true). Are you suggesting I make a new screen to show the map? I'm working on implementing the map using a screen now, and thus far it's working reasonably well... Except that my keyboard controls don't seem to be working and the rest of the game doesn't want to stop for the map screen to do its thing. It skips completely over letting you move around. I'll keep working at it and report back if I figure something more specific out about it.

showMap() should redraw the window (I hope?)--I can execute showMap() in isolation to just display the map (with all the sprites on it) behind text. I'm still using it with my screen language implementation, just because it's a simple series of ui.add calls. I did check out that Konami code documentation, though perhaps I didn't quite understand it? I'll try using a more similar syntax to get my keyboard events and see if that helps... but right now, that's not really working.

Keymaps won't work (best as I can tell) because I need to be able to interpret both KEYUP and KEYDOWN events for continuous movement.
xela wrote:Yeap, not a bad idea to push your code to higher level, but why don't you simply use logging to see where the loop hangs?
Yeah, I'll give that a shot. Is there a debug-type mode where I can log things like this? See, the problem (and why I'm having so much trouble debugging) is that when this method is called, the program stops responding and doesn't display anything at all--it just freezes in the last place before the method call (whether that's on the main menu after clicking 'start game' or after some text in the game). I have to end it from the task manager. @_@ If there's a way to log outside of this, I'd love to know about it.

User avatar
xela
Lemma-Class Veteran
Posts: 2481
Joined: Sun Sep 18, 2011 10:13 am
Contact:

Re: Game freezes when I attempt to run main game loop method

#5 Post by xela » Wed Sep 11, 2013 4:32 pm

"logging" is a python module...

Codesnip from my project:

Code: Select all

import logging

Code: Select all

    config.reject_backslash = False
    
    gamedir = os.path.normpath(config.gamedir)


    # setting the window on center
    # useful if game is launched in the window mode
    os.environ['SDL_VIDEO_CENTERED'] = '1'

    sys.setdefaultencoding('utf-8')

    # To lazy to write out Capitals
    true = True
    false = False
    none = None

    result = True
    
    Error = Exception

    # Game may bug out on saving, in such case, comment should be removed
    # config.use_cpickle = False
    
    
    # enable logging via the 'logging' module
    logging.basicConfig(level=logging.DEBUG, format='%(levelname)-8s %(name)-15s %(message)s')
    devlog = logging.getLogger("my project")
    devlogfile = logging.FileHandler(os.path.join(gamedir, "devlog.txt"))
    devlogfile.setLevel(logging.DEBUG)
    devlog.addHandler(devlogfile)
    devlog.critical("\n--- launch game ---")
    fm = logging.Formatter('%(levelname)-8s %(name)-15s %(message)s')
    devlogfile.setFormatter(fm)
    del fm
    devlog.info("game directory: %s" % gamedir)
You can readup on the module in python documentation. Otherwise just use logging.info() or similar method to log every step of your loop into devlog.txt and look at the file to find out where you game breaks.

Much simpler solution might be to use RenPy's internal logging system: http://www.renpy.org/wiki/renpy/doc/ref ... /renpy.log It is a lot simpler to figure out.
Like what we're doing? Support us at:
Image

Elmiwisa
Veteran
Posts: 476
Joined: Sun Jul 21, 2013 8:08 am
Contact:

Re: Game freezes when I attempt to run main game loop method

#6 Post by Elmiwisa » Wed Sep 11, 2013 4:58 pm

Here is an example of controlling with keyboard using mainly Python and Ren'Py screen language. You need to define some image with the name "hamster loc" to make it work though, just put in any small image. I put in extensive comments to make it easier to understand. This example use Ren'Py's engine feature as much as possible cut down size. It looks long but only because most of them are comments.

Code: Select all

init -2 python:
    class Coordinate:#this one is to manage the hamster's location on the screen
        def __init__(self,x,y,xmin,ymin,xmax,ymax):
            #self explanatory
            self.x,self.y,self.xmin,self.ymin,self.xmax,self.ymax=x,y,xmin,ymin,xmax,ymax
            #whenever possible, xoffset and yoffset will be added to x and y
            #these offset variable are needed because Ren'Py lack Action
            #that let you add to variable
            self.xoffset,self.yoffset=0,0
            return
        #this transform method will be called every few milisecond
        #argument d is the object this transform will act on
        #ignore the time arguments for now, we don't need them
        def transform(self,d,show_time,animate_time):
            #add offset to x and y
            #once added, make these offset 0 again so we don't add multiple times
            self.x+=self.xoffset
            self.y+=self.yoffset
            self.xoffset,self.yoffset=0,0
            #check for boundary
            if self.x<self.xmin:
                self.x=self.xmin
            if self.y<self.ymin:
                self.y=self.ymin
            if self.x>self.xmax:
                self.x=self.xmax
            if self.y>self.ymax:
                self.y=self.ymax
            #finally, set the position of the object
            d.pos=(self.x,self.y)
            #return 0 to ensure that the function is called whenever possible
            return 0
    #create an object to manage out hamster's location
    hamster_coordinate=Coordinate(0.5,0.5,0.05,0.05,0.95,0.95)

#this screen show a hamster and you can move them in 4 direction with arrow key
screen hamster_cage:
    #first we add the image of the hamster to the screen
    #an image named "hamster loc" must be defined of course
    #anchor (0.5,0.5) ensure that we will set the value of d.pos above
    #the coordinate will refer to the position of the exact centre of the image
    #at Transform(function=hamster_coordinate.transform) will make
    #the function hamster_coordinate.transform responsible for
    #various properties of the image "hamster loc"
    #these properties are passed in through the d argument
    #this function will be called every few milisecond

    add "hamster loc" anchor (0.5,0.5) at Transform(function=hamster_coordinate.transform)
    
    #now we add in all the keyboard control
    #here the higher-level keymap is used instead of listening to arrow button directly
    #because some device don't technically have arrow key, such as joystick
    #so instead of "K_LEFT" we use "focus_left" for example
    #we give each of these key event the appropriate Action
    #for example, for left button, we want to set the field
    #hamster_coordinate.xoffset to a negative number
    #SetField do exactly that job

    key "focus_left" action SetField(hamster_coordinate,"xoffset",-0.005)
    key "focus_right" action SetField(hamster_coordinate,"xoffset",+0.005)
    key "focus_up" action SetField(hamster_coordinate,"yoffset",-0.005)
    key "focus_down" action SetField(hamster_coordinate,"yoffset",+0.005)

    #"dismiss" is a whole collection of keys that are use to read dialogue
    #such as spacebar and enter key
    #action Return is use to quit this screen, without it you cannot quit
    #the argument for Return can be anything, it will be return to whatever call the screen

    key "dismiss" action Return("hamster")
Add the above code to screens.rpy.

To use it, put this somewhere in your script after the start label:

Code: Select all

call screen hamster_cage
Now back to your concern:

Loop:
cdra wrote:I'm not sure about the fact that I'm using my own loop--it may be totally unnecessary, and I just don't quite understand how to do it otherwise. omo The reason I was doing it was basically to pause the script until you're done with the exploration for that scene (you investigate the thing that returns true).
Ren'Py have already have its own loop to handle user-input. This loop is triggered by ui.interact(), though you probably should not use it directly. In the example above, I use

Code: Select all

call screen hamster_cage
. This display the screen and then call ui.interact() automatically, which cause the game to enter its own loop waiting for user-input. A lot of statement such as various other ui function and show statement do NOT enter this loop. If you use them, the game will run them, but then will move on immediately to the next part. ui.interact() do a lot more, which ensure all event are properly processed, rather than obsessed with just single one. In fact, if you used it you won't even have to stop the game using Task Manager, since it also process event such as clicking the close button.

Redraw the window:
cdra wrote:showMap() should redraw the window (I hope?)--I can execute showMap() in isolation to just display the map (with all the sprites on it) behind text. I'm still using it with my screen language implementation, just because it's a simple series of ui.add calls.
ui.add do NOT redraw the window. Almost every function that supposedly show something on the screen do not do it. In fact, I do not know what function do it, because it is too deep into the engine details. All these method that looks like it draw something onto the screen actually just mark stuff as supposed to be on the screen, and left the actual drawing to whatever function that redraw the window. The window is redraw constantly as part of the ui.interact() loop above, hence more reason to use it. So yes, your loop really did not redraw the window at all. showMap work in isolation because there are many many thing that automatically call ui.interact(); however none of these are in your loop.

Keymap:
Check the code above to see if it is good enough for you. If that is not enough, then you might need to go back to the Konami Code example. There are various other key configuration possible too.

Log:
Logging anything would probably make things worse, considering you are in an infinite loop and all. There is the log method to automatically log stuff to a log file. Check out the configuration variable too.
There appeared to be some sort of console too, but I can't figure out how to activate them. They are listed in the feature list however.

I hope this address all of your concern. :D

cdra
Newbie
Posts: 5
Joined: Mon Sep 09, 2013 6:43 am
Contact:

Re: Game freezes when I attempt to run main game loop method

#7 Post by cdra » Wed Sep 11, 2013 7:16 pm

Woah, that's quite an answer, thanks! I had a feeling ui.interact() had something to do with this, but I wasn't about to touch it given that I have no idea what it actually does... and since I shouldn't be calling it, I'm glad I didn't touch it owo; I'm working on getting this translated into screen language and it's almost there--I'm not totally happy with the controls because it takes a second to get the player moving, but at least I have something to work off of. I mostly have to figure out how to handle the interactables, which should be easy enough with the Return call you mentioned. Thanks for the help!

I did figure out how to do the logging on my own shortly after making that post ^^; Good to know, though! I imported the logging module so I can check things out when I have problems in the future.

Elmiwisa
Veteran
Posts: 476
Joined: Sun Jul 21, 2013 8:08 am
Contact:

Re: Game freezes when I attempt to run main game loop method

#8 Post by Elmiwisa » Wed Sep 11, 2013 7:54 pm

cdra wrote:it takes a second to get the player moving
:idea:

User avatar
MilywayObree
Newbie
Posts: 17
Joined: Sun Jan 28, 2018 11:24 am
Completed: None so far, pending to be exact
Projects: DDLC, The notebook and other secret projects
Organization: Vocastin/Oriaa Pro-Creations
Deviantart: MexicoRPelino
Github: HizashiroTakahashi
Skype: PixelMINEGaming
Location: Philippines
Contact:

Re: Game freezes when I attempt to run main game loop method?

#9 Post by MilywayObree » Thu Mar 29, 2018 7:54 am

Hello I have modified your code to make a 4 point walking position but got me really stuck with how you can add a walking animation.... and I also added some speed to the walking so it wouldn't take too much time to get from one point to another.

Code: Select all

init python:
    class Coordinate:
        def __init__(self,x,y,xmin,ymin,xmax,ymax):

            self.x,self.y,self.xmin,self.ymin,self.xmax,self.ymax=x,y,xmin,ymin,xmax,ymax

            self.xoffset,self.yoffset=0,0
            return

        def transform(self,d,show_time,animate_time):

            self.x+=self.xoffset
            self.y+=self.yoffset
            self.xoffset,self.yoffset=0,0

            if self.x<self.xmin:
                self.x=self.xmin
            if self.y<self.ymin:
                self.y=self.ymin
            if self.x>self.xmax:
                self.x=self.xmax
            if self.y>self.ymax:
                self.y=self.ymax

            d.pos=(self.x,self.y)

            return 0

    sprite_coordinate=Coordinate(0.5,0.5,0.05,0.05,0.95,0.95)
image sprite_left = "test_spriteleft.png"
image sprite_right = "test_spriteright.png"
image sprite_front = "test_spritefront.png"
image sprite_back = "test_spriteback.png"

screen left():
    #timer 2.0/30.0 repeat True action #[ Function('hide_right'), Function('hide_up'), Function('hide_down') ]
    #timer 2.0/30.0 repeat True action [ Hide('right'), Hide('up'), Hide('down') ]
    add "sprite_left" anchor (0.5,0.5) at Transform(function=sprite_coordinate.transform)
screen right():
    #timer 2.0/30.0 repeat True action #[ Function('hide_left'), Function('hide_up'), Function('hide_down') ]
    #timer 2.0/30.0 repeat True action [ Hide('left'), Hide('up'), Hide('down') ]
    add "sprite_right" anchor (0.5,0.5) at Transform(function=sprite_coordinate.transform)
screen up():
    #timer 2.0/30.0 repeat True action #[ Function('hide_right'), Function('hide_left'), Function('hide_down') ]
    #timer 2.0/30.0 repeat True action [ Hide('left'), Hide('right'), Hide('down') ]
    add "sprite_back" anchor (0.5,0.5) at Transform(function=sprite_coordinate.transform)
screen down():
    #timer 2.0/30.0 repeat True action #[ Function('hide_right'), Function('hide_up'), Function('hide_left') ]
    #timer 2.0/30.0 repeat True action [ Hide('left'), Hide('up'), Hide('right') ]
    add "sprite_front" anchor (0.5,0.5) at Transform(function=sprite_coordinate.transform)
screen sprite_move():


    #add "hamster loc" anchor (0.5,0.5) at Transform(function=hamster_coordinate.transform)


    key "focus_left" action [ SetField(sprite_coordinate,"xoffset",-0.020), Show('left'), Hide('right'), Hide('up'), Hide('down') ]
    key "focus_right" action [ SetField(sprite_coordinate,"xoffset",+0.020), Show('right'), Hide('left'), Hide('up'), Hide('down') ]
    key "focus_up" action [ SetField(sprite_coordinate,"yoffset",-0.020), Show('up'), Hide('left'), Hide('right'), Hide('down') ]
    key "focus_down" action [ SetField(sprite_coordinate,"yoffset",+0.020), Show('down'), Hide('left'), Hide('up'), Hide('right') ]


    key "dismiss" action Return("hamster")
Just Monika.

Post Reply

Who is online

Users browsing this forum: Google [Bot]