key.get_pressed() loop Press and Hold question

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
Unin
Regular
Posts: 54
Joined: Wed Sep 01, 2010 8:08 pm
Location: Florida
Contact:

key.get_pressed() loop Press and Hold question

#1 Post by Unin » Tue Oct 28, 2014 10:53 pm

I'm attempting to get a displayable to rotate as the left or right arrow keys are HELD (not just single press)

Code: Select all

init python:
    import math
    import pygame
    test_image = Image("img.png")
  
    class KeyRoll(renpy.Displayable):
        def __init__(self,image):
            super(renpy.Displayable,self).__init__()
            self.start_image = image  
            self.rotation = 0
        
        def render(self,width,height,st,at):
            render = renpy.Render(0, 0)
            self.img = Transform(self.start_image, xanchor=0.5,yanchor=0.5,rotate=self.rotation)
            child_render = renpy.render(self.img, 0, 0, st, at)
            render.blit(child_render, (0,0))
            return render
 
        def event(self, ev, x, y, st):
            roll = {pygame.K_LEFT: -3, pygame.K_RIGHT: 3}
            pressed = pygame.key.get_pressed()
            while pygame.key.get_pressed == pygame.K_LEFT or pygame.key.get_pressed == pygame.K_RIGHT:
                for m in (roll[key] for key in roll if pressed[key]):
                    self.rotation += m
                    self.img = Transform(self.start_image, xanchor=0.5,yanchor=0.5,rotate=self.rotation)
                    renpy.redraw(self, 0)
                pygame.time.wait(33)
            
  
screen test:
    add KeyRoll(test_image):
        xanchor 0.5
        yanchor 0.5

label start:
    "before"
    call screen test
    "after"
    return
As is, it will display the image, but not rotate it.
Removing the while statement and dedenting accordingly will rotate the image per key press.
Replacing the while conditions with True ignores key input, gives zero rotation, and will eventually crash.

I strongly suspect my issue lies in my loop conditions, but despite my efforts, and half a dozen other people's threads on press-hold behavior, I cant seem to work it out. any suggestions?

neowired
Regular
Posts: 199
Joined: Mon Dec 01, 2008 2:33 pm
Contact:

Re: key.get_pressed() loop Press and Hold question

#2 Post by neowired » Thu Oct 30, 2014 6:11 am

I don't know how to do this in python.

In the screen language you should be able to do something like:

Code: Select all

key "x" action SetVariable('rotation',(rotation+1))
the key in this case will be read a globally defined amount of times per second, so if you keep it pressed it will add like 100 per second or however much it is
you can change that at init with

Code: Select all

config.key_repeat = (.3, .03)
Controls the rate of keyboard repeat. When key repeat is enabled, this should be a tuple. The first item in the tuple is the delay before the first repeat, and the second item is the delay between repeats. Both are in seconds. If None, keyboard repeat is disabled.
I think if you call the key from python it should have a similar effect.
Maybe what you need is to define the key_repeat?
Given that the key is already read a defined amount of times per second, you would not need to define any loop at all?

User avatar
PyTom
Ren'Py Creator
Posts: 15392
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
Contact:

Re: key.get_pressed() loop Press and Hold question

#3 Post by PyTom » Thu Oct 30, 2014 9:37 am

A CDD is the right idea, but you can't really use pygame directly like you do. Ren'Py displayables are event-driven, so you can't just block execution with a while statement, and expect it to work. What I like doing for something like this is to simply set flags when the KEYDOWN and KEYUP events occur, and then do all of the actual work inside the redraw method.

Here's how I would write KeyRoll.

Code: Select all

init python:
    import pygame

    class KeyRoll(renpy.Displayable):
        def __init__(self,image):
            super(renpy.Displayable,self).__init__()
            self.start_image = image
            self.rotation = 0
            self.rate = 0.0
            self.last_st = 0.0

        def render(self,width,height,st,at):
            self.rotation += self.rate * (st - self.last_st)
            self.last_st = st

            t = Transform(self.start_image, xanchor=0.5, yanchor=0.5, rotate=self.rotation)

            child_render = renpy.render(t, width, height, st, at)
            cw, ch = child_render.get_size()

            rv = renpy.Render(cw, ch)
            rv.blit(child_render, (0,0))

            if self.rate:
                renpy.redraw(self, 0)

            return rv

        def event(self, ev, x, y, st):

            # How fast we turn, in degrees per second.
            RATE = 90.0

            if ev.type == pygame.KEYDOWN:
                if ev.key == pygame.K_LEFT:
                    self.rate = -RATE
                    self.last_st = st
                    renpy.redraw(self, 0)
                    raise renpy.IgnoreEvent()

                elif ev.key == pygame.K_RIGHT:
                    self.rate = RATE
                    self.last_st = st
                    renpy.redraw(self, 0)
                    raise renpy.IgnoreEvent()

            elif ev.type == pygame.KEYUP:
                if ev.key == pygame.K_LEFT:
                    if self.rate == -RATE:
                        self.rate = 0
                        raise renpy.IgnoreEvent()

                elif ev.key == pygame.K_RIGHT:
                    if self.rate == RATE:
                        self.rate = 0
                        raise renpy.IgnoreEvent()

            return None

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 • https://www.patreon.com/renpytom

Unin
Regular
Posts: 54
Joined: Wed Sep 01, 2010 8:08 pm
Location: Florida
Contact:

Re: key.get_pressed() loop Press and Hold question

#4 Post by Unin » Thu Oct 30, 2014 5:31 pm

I swear... I knew KEYUP was a thing, and I knew it could be accomplished by rotating until a new event occurred... but the connection in my brain just never happened. :roll:
Thanks as always PyTom

Do you still accept paypal donations via your bishoujo.us address?

Post Reply

Who is online

Users browsing this forum: Google [Bot]