Python Kivy - 如何对多个关键点做出反应?

时间:2015-07-13 00:03:54

标签: python kivy keyboard-events keydown

所以我读了这篇帖子: 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开发桌面游戏,而不是智能手机,所以我想使用真正的键盘来控制角色。

2 个答案:

答案 0 :(得分:3)

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

所以,如果你不想在我的解决方案中添加另一个动作,你只需要在格式&#39; button_character&#39;:lambda函数中添加一个self.pressed_actions dict的条目,它将运行你的函数参数。

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

随意使用。

* 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')

答案 1 :(得分:2)

我现在找到了一个解决方案,但我不知道这是否是我们能做到的最好的解决方案。 以下是乒乓应用程序的完整代码,使玩家能够独立移动他们的桨。

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的方式,请发表回答:)