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

时间:2015-05-30 23:49:40

标签: python sprite pyglet cocos2d-python

我正在尝试按下按键时移动精灵。我可以使用on_key_press()和on_key_release()来完成它,但是有了这些,我在向左移动时遇到问题,反之亦然。我想使用密钥轮询,并从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    

我似乎无法在cocos2d中实现这一点。一个简单的例子如下。它打印'按键!'很好,但如果我能把它打印成'太空!'当空格键被按下时,它会反复解决我的问题。

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()

为了完整性,这里是我的on_key_press(),on_key_release()代码。问题是如果我按下右键,按左键,释放左我的精灵将停止,因为on_key_release()将x速度设置为零。但是,我仍然按下右键,所以我想在按下并释放左后继续移动那些方向。

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])

1 个答案:

答案 0 :(得分:2)

来自pyglet guide

  

分别按下或释放键盘上的任何键时会触发Window.on_key_press和Window.on_key_release事件。 这些事件不受“密钥重复”的影响 - 一旦按下某个键,该密钥在被释放之前就不会再发生任何事件。

这意味着如果向右按,向左按,向左释放,但不向右释放,则在释放右键并再次按下之前不会发送新的on_key_press事件。

如果你保留了你的结构,我认为你必须检查self.keyson_key_release是否设置了key.RIGHT。但仅此一点是行不通的。使用当前代码,您keys[key.RIGHT]始终为False。我将解释其原因。

当您致电director.window.push_handlers(self.keys)时,您将KeyStateHandler自己的on_key_presson_key_release处理程序注册到您注册MyLayer相应处理程序的同一队列中。 KeyStateHandler的处理程序所做的是它们在keys dict中设置和取消设置键,以便您可以查询keys[key.SPACE]以查看空格键是否被按下。

代码的问题在于你在MyLayer的处理程序之前注册了KeyStateHandler的处理程序,这导致在KeyStateHandler的处理程序之前调用MyLayer的处理程序。因此,当您按空格并检查MyLayer.on_key_press keys[key.SPACE]是否为True时,它不是,因为KeyStateHandler尚未设置keys[key.SPACE]

要在MyLayer之前调用KeyStateHandler的处理函数,你不应该在MyLayer的构造函数中注册(= push)它们,而是在MyLayer的on_enter函数中这样:

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

如果你这样做,你可能还应该在MyLayer的on_exit函数中删除/取消注册这些处理程序。

如果您对代码段进行了此更改,则应打印“按键!”和'空间!'每次按空格键,但不重复,因为on_key_press事件仍然每按键一次只发送一次。

你可能已经使用CocosNode.schedule安排了一些功能,或者定义了一些使用self.player1.velocity移动你的精灵的动作(继承Move动作将是一个很好的方法) 。获得所需效果的一种方法是不定义自己的on_key_press和on_key_release处理函数,而是依赖KeyStateHandler。您可以像在代码片段中一样按下KeyStateHandler的处理函数,并在计划函数或操作步骤的开头读取keys dict,按下哪些键,并根据该值更新速度。

例如,打印'太空!'反复使用时间表:

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()

请注意,其工作方式是在KeyStateHandler的self.keys[key.SPACE]处理程序中将True设置为on_key_press,每次按键时只调用一次。释放密钥时,dict条目在KeyStateHandler的False处理程序中设置为on_key_release