【问题标题】:Python Kivy - How to react on multiple key downs?Python Kivy - 如何对多个按键做出反应?
【发布时间】:2017-04-22 22:23:56
【问题描述】:

所以我读了这篇 SO 帖子: How to handle several keys pressed at the same time in Kivy?

我根据 Kivy 网站 (http://kivy.org/docs/tutorials/pong.html) 上的教程实现了 Pong 游戏。 我的 PongGame Widget 有以下方法:

def __init__(self):
    super(PongGame, self).__init__()
    self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
    self._keyboard.bind(on_key_down = self._on_keyboard_down)
    self._keyboard.bind(on_key_up = self._on_keyboard_up)

def _keyboard_closed (self):
    self._keyboard.unbind(on_key_down=self._on_keyboard_down)
    self._keyboard = None

def _on_keyboard_down (self, keyboard, keycode, text, modifiers):
    print('### ----------------------------------- ###')
    print('The keys', keycode, 'have been pressed down')
    print('You pressed the key', keycode[1], '.', sep=' ', end='\n')
    #print(' - text is %r' % text)
    print(' - modifiers are %r' % modifiers)

    if keycode[1] == 'w':
        if self.player1.center_y + 20 < self.height-85:
            self.player1.center_y += 20
    elif keycode[1] == 's':
        self.player1.center_y -= 20
    elif keycode[1] == 'up':
        self.player2.center_y += 20
    elif keycode[1] == 'down':
        self.player2.center_y -= 20

    return True
"""
def _on_keyboard_up (self, keyboard, keycode, text, modifiers):
    print('### ----------------------------------- ###')
    print('The keys', keycode, 'have been released.')
    print('You pressed the key', keycode[1], '.', sep=' ', end='\n')
    #print(' - text is %r' % text)
    print(' - modifiers are %r' % modifiers)

    return True
"""

def _on_keyboard_up(self, *args):
    print('up', args)

有了这个,我可以使用“w”、“s”、“up”和“down”来控制两个玩家。但是,仅执行最后按下按钮的操作。这是一个问题,因为当其他玩家想要移动他们的桨时,玩家可能会通过一直按下按钮来干扰彼此的输入。

我将如何实现,让两个玩家同时控制,这样他们就不会互相妨碍,除非键盘不能再按下任何按键(硬件限制)?

我目前想用 Kivy 开发桌面游戏,而不是智能手机,所以我想用真正的键盘来控制角色。

【问题讨论】:

    标签: python kivy keyboard-events keydown


    【解决方案1】:

    我的解决方案非常相似,但更短。 这是使用 set() 作为活动按钮列表的简单示例。

    因此,如果您不想在我的解决方案中添加其他操作,您只需将条目添加到 self.pressed_actions 字典,格式为 'button_character':lambda 函数,它将使用参数运行您的函数。

    此示例将向控制台提示在每一帧中哪些按钮处于活动状态。

    请随意使用。

    *set 就像一个列表,但没有重复。所以你不必担心同一个按钮的更多条目。

    from kivy.app import App
    from kivy.uix.widget import Widget
    from kivy.core.window import Window
    from kivy.clock import Clock
    
    class Basic(Widget):
    
        pFrame = 0
    
        def __init__(self, **kwargs):
            super(Basic, self).__init__(**kwargs)
            self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
            self._keyboard.bind(on_key_down=self._on_keyboard_down)
            self._keyboard.bind(on_key_up=self._on_keyboard_up)
    
            self.pressed_keys = set()
    
            self.pressed_actions = {
                'w': lambda: self.text_example('w pressed'),
                's': lambda: self.text_example('s pressed'),
                'a': lambda: self.text_example('a pressed'),
                'd': lambda: self.text_example('d pressed'),
            }
    
        def _keyboard_closed(self):
            self._keyboard.unbind(on_key_down=self._on_keyboard_down)
            self._keyboard.unbind(on_key_up=self._on_keyboard_down)
            self._keyboard = None
    
        def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
            self.pressed_keys.add(keycode[1])
    
        def _on_keyboard_up(self, keyboard, keycode):
            self.pressed_keys.remove(keycode[1])
    
        def text_example(self, text):
            print('Frame: %s Key %s' % (self.pFrame, text))
    
        def update(self, dt):
            for key in self.pressed_keys:
                try:
                    self.pressed_actions[key]()
                except KeyError:
                    print("Frame: %s Key %s. Omitted" % (self.pFrame, key))
    
            self.pFrame += 1
    
    class MyApp(App):
    
        def build(self):    
            basic = Basic() 
            Clock.schedule_interval(basic.update, 1.0 / 2.0)
            return basic
    
    if __name__ == '__main__':
        try:
            MyApp().run()
        except KeyboardInterrupt:
            print('App has been closed by ^C')
    

    【讨论】:

    • 此解决方案更好,因为它克服了原始 Pong 示例中明显的“滞后”。任何玩过演示的人都知道第一次按键会滞后,然后,拨片会移动。该解决方案获得丝滑运动。谢谢@Vermibus!
    【解决方案2】:

    我现在找到了解决方案,但我不知道这是否是我们可以拥有的最佳解决方案。 以下是pong应用程序的完整代码,让玩家可以独立移动自己的球拍。

    from random import randint
    from kivy.app import App
    from kivy.core.window import Window
    from kivy.uix.widget import Widget
    from kivy.properties import NumericProperty, ReferenceListProperty, ObjectProperty
    from kivy.vector import Vector
    from kivy.clock import Clock
    
    
    class PongPaddle(Widget):
        score = NumericProperty(0)
    
    
        def bounce_ball (self, ball):
            if self.collide_widget(ball):
                vx, vy = ball.velocity
                offset = (ball.center_y - self.center_y) / (self.height / 2)
                bounced = Vector(-1 * vx, vy)
                vel = bounced * 1.1
                ball.velocity = vel.x, vel.y + offset
    
    
    class PongBall(Widget):
        velocity_x = NumericProperty(0)
        velocity_y = NumericProperty(0)
        velocity = ReferenceListProperty(velocity_x, velocity_y)
    
    
        def move (self):
            self.pos = Vector(*self.velocity) + self.pos
    
    
    class PongGame(Widget):
        ball = ObjectProperty(None)
        player1 = ObjectProperty(None)
        player2 = ObjectProperty(None)
    
        pressed_keys = {
            'w': False,
            's': False,
            'up': False,
            'down': False
        }
    
    
        def __init__(self):
            super(PongGame, self).__init__()
            self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
            self._keyboard.bind(on_key_down = self._on_keyboard_down)
            self._keyboard.bind(on_key_up = self._on_keyboard_up)
    
    
        def _keyboard_closed (self):
            self._keyboard.unbind(on_key_down=self._on_keyboard_down)
            self._keyboard = None
    
    
        def _on_keyboard_down (self, keyboard, keycode, text, modifiers):
            #pressed_key = self._keyboard.keycode_to_string(keycode) # this does not work somehow
            pressed_key = keycode[1]
            print('You pressed the key', pressed_key, '.', sep=' ', end='\n')
    
            self.pressed_keys[pressed_key] = True
    
            return True
    
    
        def _on_keyboard_up (self, keyboard, keycode):
            released_key = keycode[1]
            print('You released the key', released_key, '.', sep=' ', end='\n')
            self.pressed_keys[released_key] = False
            return True
    
    
        def serve_ball (self, vel=(4, 0)):
            self.ball.center = self.center
            self.ball.velocity = Vector(vel).rotate(randint(0, 360))
    
    
        def update (self, dt):
            self.ball.move()
    
            # bounce of paddles
            self.player1.bounce_ball(self.ball)
            self.player2.bounce_ball(self.ball)
    
            # bounce ball off bottom or top
            if (self.ball.y < self.y) or (self.ball.top > self.top):
                self.ball.velocity_y *= -1
    
            # went of to a side to score point?
            if self.ball.x < self.x:
                self.player2.score += 1
                self.serve_ball(vel=(4, 0))
    
            if self.ball.x > self.width:
                self.player1.score += 1
                self.serve_ball(vel=(-4, 0))
    
            # actions for keys pressed
            if self.pressed_keys['w']:
                if self.player1.center_y + 20 < self.height:
                    self.player1.center_y += 20
    
            if self.pressed_keys['s']:
                if self.player1.center_y + 20 > 0:
                    self.player1.center_y -= 20
    
            if self.pressed_keys['up']:
                if self.player2.center_y + 20 < self.height:
                    self.player2.center_y += 20
    
            if self.pressed_keys['down']:
                if self.player2.center_y + 20 > 0:
                    self.player2.center_y -= 20
    
    
        def on_touch_move (self, touch):
            if touch.x < self.width / 3:
                self.player1.center_y = touch.y
            if touch.x > self.width - self.width / 3:
                self.player2.center_y = touch.y
    
    
    class PongApp(App):
        def build (self):
            game = PongGame()
            game.serve_ball()
            Clock.schedule_interval(game.update, 1.0 / 60.0)
            return game
    
    
    if __name__ == '__main__':
        PongApp().run()
    

    如果您知道更好的方法,或者更类似于 Kivy 的方法,请发布答案:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-27
      • 2015-01-27
      • 1970-01-01
      • 2021-09-10
      • 1970-01-01
      • 2013-01-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多