简体   繁体   English

使用cocos2d-python和pyglet进行键轮询

[英]Key polling with cocos2d-python and pyglet

I'm trying to move a sprite while a key is pressed. 我正在尝试在按下键的同时移动精灵。 I can do it with on_key_press() and on_key_release(), but with these I run into problems with moving right while holding left and vice versa. 我可以使用on_key_press()和on_key_release()来做到这一点,但是通过这些我遇到了在向左移动的同时向右移动的问题,反之亦然。 I'd like to use key polling and found this from the pyglet documentation. 我想使用键轮询,并从pyglet文档中找到了它。

from pyglet.window import key

window = pyglet.window.Window()
keys = key.KeyStateHandler()
window.push_handlers(keys)

# Check if the spacebar is currently pressed:
if keys[key.SPACE]:
    pass    

I don't seem to be able to implement this in cocos2d. 我似乎无法在cocos2d中实现此功能。 A simple example is below. 下面是一个简单的示例。 It prints 'Key Press!' 打印“按键!” just fine, but if I could get it to print 'Space!' 很好,但是如果我能打印“太空!” repeatedly when the space key is pressed it would solve my problem. 反复按空格键可以解决我的问题。

from cocos.director import director
from cocos.layer import *
from cocos.scene import Scene
from pyglet.window import key
from pyglet.window.key import KeyStateHandler

class MyLayer(Layer):
    is_event_handler = True

    def __init__(self):
        super(MyLayer, self).__init__()
        self.keys = KeyStateHandler()
        director.window.push_handlers(self.keys)

    def on_key_press(self, symbol, modifiers):
        print('Key press!')
        if self.keys[key.SPACE]:
            print('Space!')

def main():
    director.init(resizable=False, width=1024, height=786)
    title_scene = Scene(MyLayer())
    director.run(title_scene)

if __name__ == '__main__':
    main()

For completeness here is my on_key_press(), on_key_release() code. 为了完整起见,这里是我的on_key_press()和on_key_release()代码。 The problem is that if I press Right, press Left, release Left my Sprite will be stopped since the on_key_release() sets the x velocity to zero. 问题是,如果我按向右,按向左,释放左,由于on_key_release()将x速度设置为零,我的Sprite将停止。 But, I'm still pressing Right so I want to continue moving that directions after pressing and releasing Left. 但是,我仍要按向右,因此我想在按住并释放向左后继续沿该方向移动。

def on_key_press(self, symbol, modifiers):
    if symbol == key.LEFT:
        self.player1.velocity = (-self.player1.speed, self.player1.velocity[1])
    if symbol == key.RIGHT:
        self.player1.velocity = (self.player1.speed, self.player1.velocity[1])

def on_key_release(self, symbol, modifiers):
    if symbol == key.LEFT:
        self.player1.velocity = (0, self.player1.velocity[1])
    if symbol == key.RIGHT:
        self.player1.velocity = (0, self.player1.velocity[1])

From pyglet guide : 来自pyglet指南

The Window.on_key_press and Window.on_key_release events are fired when any key on the keyboard is pressed or released, respectively. 当分别按下或释放键盘上的任何键时,将触发Window.on_key_press和Window.on_key_release事件。 These events are not affected by "key repeat" -- once a key is pressed there are no more events for that key until it is released. 这些事件不受“键重复”的影响-按下某个键后,在释放该键之前不会再有其他事件。

This means that if you press right, press left, release left, but don't release right, then new on_key_press events won't be dispatched before you release right and press it again. 这意味着,如果您按向右,按向左,向左释放,但不向右释放,那么在释放并再次按它之前,将不会调度新的on_key_press事件。

If you keep the structure you have, I think you have to check if key.RIGHT is set in self.keys , inside on_key_release . 如果保留现有结构,我认为您必须检查self.keys内部的on_key_release是否设置了on_key_release But that alone wouldn't work. 但是,仅此一项是行不通的。 With the current code you would always get that keys[key.RIGHT] is False . 使用当前代码,您将始终获得keys[key.RIGHT]False I'll explain next why this is. 接下来,我将解释为什么。

When you call director.window.push_handlers(self.keys) , you register KeyStateHandler's own on_key_press and on_key_release handlers to the same queue you register MyLayer's corresponding handlers. 调用director.window.push_handlers(self.keys) ,会将KeyStateHandler自己的on_key_presson_key_release处理程序注册到注册MyLayer相应处理程序的同一队列中。 What the KeyStateHandler's handlers do is that they set and unset keys in keys dict so that you can for example query keys[key.SPACE] to see if space key is being held down. KeyStateHandler的处理程序所做的是,它们在keys dict中设置和取消设置键,以便您可以例如查询keys[key.SPACE]以查看是否按住了空格键。

The problem with the code is that you register KeyStateHandler's handlers before MyLayer's handlers, which causes MyLayer's handlers to be called before those of KeyStateHandler. 该代码的问题是,您在MyLayer的处理程序之前注册了KeyStateHandler的处理程序,这导致MyLayer的处理程序在KeyStateHandler的处理程序之前被调用。 So when you press space and check in MyLayer.on_key_press whether keys[key.SPACE] is True , it is not, since KeyStateHandler hasn't set keys[key.SPACE] yet. 因此,当您按空格keys[key.SPACE]并检查MyLayer.on_key_press keys[key.SPACE]是否为True ,则不是,因为KeyStateHandler尚未设置keys[key.SPACE]

To call KeyStateHandler's handler functions before those of MyLayer, you shouldn't register (=push) them in MyLayer's constructor, but in MyLayer's on_enter function like this: 要在MyLayer的那些函数之前调用KeyStateHandler的处理函数,您不应在MyLayer的构造函数中注册(=推动)它们,而应在MyLayer的on_enter函数中进行如下注册:

def on_enter(self):
    super(MyLayer, self).on_enter()
    director.window.push_handlers(self.keys)

If you do this, you should probably also remove/deregister those handler's in MyLayer's on_exit function. 如果这样做,您可能还应该在MyLayer的on_exit函数中删除/注销那些处理程序。

If you make this change to your code snippet, it should print 'Key press!' 如果您对代码段进行了更改,则应打印“按键!”。 and 'Space!' 和“太空!” every time you press space, but not repeatedly since on_key_press event is still dispatched only once per key press. 每次您按空格键时,但不会重复,因为on_key_press事件仍然每次按键仅调度一次。

You probably have scheduled some function with CocosNode.schedule , or defined some Action that uses self.player1.velocity to move your Sprite (inheriting from the Move action would be a good way to do this). 您可能已经通过CocosNode.schedule安排了一些功能,或者定义了一些使用self.player1.velocity来移动Sprite的Action(继承自Move动作将是一个很好的方法)。 One way to get the effect you want is to not define your own on_key_press and and on_key_release handler functions, but to rely on KeyStateHandler. 获得所需效果的一种方法是不定义自己的on_key_press和on_key_release处理函数,而是依赖KeyStateHandler。 You push the KeyStateHandler's handler functions as in your code snippet, and in the beginning of your scheduled function or Action step you read from keys dict, which keys are being pressed, and update the velocity based on that. 你推KeyStateHandler的处理功能,如在您的代码段,并在预定的功能或操作步骤开始您读取keys快译通,它正在按键,并更新基础上的速度。

For example, to print 'Space!' 例如,要打印“ Space!” repeatedly using schedule: 重复使用时间表:

from cocos.director import director
from cocos.layer import *
from cocos.scene import Scene
from pyglet.window import key
from pyglet.window.key import KeyStateHandler

class MyLayer(Layer):

    def __init__(self):
        super(MyLayer, self).__init__()
        self.keys = KeyStateHandler()
        director.window.push_handlers(self.keys)
        self.schedule(self.act_on_input)

    def act_on_input(self, dt):
        if self.keys[key.SPACE]:
            print('Space!')

def main():
    director.init(resizable=False, width=1024, height=786)
    title_scene = Scene(MyLayer())
    director.run(title_scene)

if __name__ == '__main__':
    main()

Note that the way this works is that self.keys[key.SPACE] is set to True in KeyStateHandler's on_key_press handler, which is called only once per key press. 请注意,此方法的工作方式是在KeyStateHandler的on_key_press处理程序self.keys[key.SPACE]设置为True ,每次按键仅调用一次。 When you release the key, the dict entry is set to False in KeyStateHandler's on_key_release handler. 释放键时,dict条目在KeyStateHandler的on_key_release处理程序中设置为False

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM