0

我试图在按下一个键时移动一个精灵。我可以使用 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])
4

1 回答 1

2

来自pyglet 指南

Window.on_key_press 和 Window.on_key_release 事件分别在键盘上的任何键被按下或释放时触发。这些事件不受“键重复”的影响——一旦按下一个键,该键就没有更多的事件,直到它被释放。

这意味着如果你按下右,按下左,释放左,但不释放右,那么新的 on_key_press 事件在你释放右并再次按下之前不会被调度。

如果您保留现有结构,我认为您必须检查 key.RIGHT 是否设置在self.keys, inside 中on_key_release。但仅凭这一点是行不通的。使用当前代码,您总是会keys[key.RIGHT]得到False. 接下来我会解释为什么会这样。

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

代码的问题是您在 MyLayer 的处理程序之前注册 KeyStateHandler 的处理程序,这导致 MyLayer 的处理程序在 KeyStateHandler 的处理程序之前被调用。因此,当您按空格并检查MyLayer.on_key_press是否为时,它不是,因为 KeyStateHandler 尚未keys[key.SPACE]设置。Truekeys[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函数中删除/取消注册这些处理程序。

如果您对代码片段进行此更改,它应该打印“Key press!” 和“空间!” 每次按空格键时,但不会重复,因为 on_key_press 事件在每次按键时仍然只调度一次。

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

例如,打印“空格!” 重复使用时间表:

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]中设置为,每次按键仅调用一次。当您释放键时,dict 条目在 KeyStateHandler 的处理程序中设置为。Trueon_key_pressFalseon_key_release

于 2015-05-31T15:13:39.407 回答