【问题标题】:How to handle multiple keyboard inputs in kivy?如何在kivy中处理多个键盘输入?
【发布时间】:2021-11-13 12:29:24
【问题描述】:

所以我正在开发这个游戏,它是一个平台游戏,所以我现在正在研究动作,问题是:

我可以将玩家左右移动,我也可以跳跃,但是我不能同时移动和跳跃,例如,当我向前移动时,我希望能够向前跳跃,那会要求我按前进和向上按钮。 我已经尝试了很多方法来解决这个问题,但没有成功,我还没有发现这个问题在谷歌上搜索,所以......这是帮助解决问题的最小代码。 问题是玩家要么跳跃要么移动,当我按下向上和前进键时它不会同时进行。

main.py

from kivy.core.window import Window
from kivymd.app import MDApp
from kivymd.uix.screen import MDScreen
from kivymd.uix.floatlayout import MDFloatLayout
from kivy.properties import Clock

from Player import PlayerImage

class LevelOneLayout(MDFloatLayout):
    pass


class LevelOne(MDScreen):
    from PlayerAction import _keyboard_closed, _on_keyboard_down, _on_keyboard_up

    gravity_force = 1800

    def __init__(self, **kwargs):
        super().__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)
        Clock.schedule_once(self.setup, 1/60)


    def setup(self, dt):

    self.player_image = PlayerImage()
    self.add_widget(self.player_image)


    Clock.schedule_interval(self.game_gravity, 1/30)


    def game_gravity(self, dt):
        if self.player_image.on_air:
            self.player_image.player_gravity_vel -= self.gravity_force * 1/30
            self.player_image.y += self.player_image.player_gravity_vel * 1/30 

        if self.player_image.y <= 60:
            self.player_image.y = 60
            self.player_image.player_gravity_vel = 0
            self.player_image.on_air = False


class MainApp(MDApp):
    def build(self):
        self.theme_cls.theme_style = "Dark"
        self.theme_cls.primary_palette = "Red"

        return


MainApp().run()

Main.kv

LevelOne:

    LevelOneLayout:


<LevelOneLayout>:


<PlayerImage>:
    source: "player_77x100.png"
    size_hint: None, None
    size: "77dp", "100dp"
    x: "0dp"
    y: "50dp"

播放器.py

from kivy.uix.image import Image
from kivy.animation import Animation
from kivymd.uix.floatlayout import MDFloatLayout


class PlayerImage(Image):

    texture_side = "right"

    def __init__(self):
        super().__init__()

        self.velx = 20

        self.player_gravity_vel = 0
        self.on_air = False


    def move_left(self, state, *args):
        if state: 
            self.x -= self.velx
            self.texture_left()
            self.forced_dash = False
        else:
            return None


    def move_right(self, state, *args):
        if state:
            self.x += self.velx
            self.texture_right()
            self.forced_dash = False
        else:
            return None


    def jump(self, state, *args):
        if not self.on_air and state:
            self.player_gravity_vel = 830
            self.on_air = True
        else:
            return None



    def texture_left(self):
        if self.texture.tex_coords[0] == 0: 
            self.texture.flip_horizontal()
            self.texture.ask_update(self.update_texture)
            self.texture_side = "left"


    def texture_right(self):
        if self.texture.tex_coords[0] == 1: 
            self.texture.flip_horizontal()
            self.texture.ask_update(self.update_texture)
            self.texture_side = "right"


    def update_texture(self, texture):
        self.texture = None
        self.texture = texture

PlayerAction.py

key_state = True


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


def _on_keyboard_down(self, keyboard, keycode, *args):

    if keycode[1] == "up":
        self.player_image.jump(key_state)

    if keycode[1] == "left":
        self.player_image.move_left(key_state)

    elif keycode[1] == "right":
        self.player_image.move_right(key_state)

    return True


def _on_keyboard_up(self, keyboard, keycode, *args):

    key_state = False

    if keycode[1] == "up":
        self.player_image.jump(key_state)

    if keycode[1] == "left":
        self.player_image.move_left(key_state)

    elif keycode[1] == "right":
        self.player_image.move_right(key_state)

    return True

【问题讨论】:

  • 看起来您的代码依赖于这样一个事实,即当您按住某个键时,您会反复从该键获取新的按键事件。但是,当您按住一个键然后按另一个键时,第二个键会覆盖该键。相反,您不应该依赖它并在程序中处理按键向上/向下状态:在keyboard_down 事件存储某处的“左键按下”状态,并在keyboard_up 事件中清除该状态。然后 Clock.schedule_interval 一个函数“update_character”,如果左键向下,则向左移动,如果右键向下则向右移动,如果跳转键向下,则跳转等。
  • 感谢您的帮助 Mr.inclement,我在 kivy 小组支持中提出了这个问题,在 Mr.ElliotG 的帮助下,您的一切正常,我会在这里发布我的解决方案以防其他人偶然发现这个问题,再次感谢您的帮助。

标签: python python-3.x kivy kivy-language kivymd


【解决方案1】:

因此,对于管理多个按键的示例,我推荐此链接: https://groups.google.com/g/kivy-users/c/b0Qmv160GBk

这是我在 kivy 组支持中提出的这个问题的答案,所以我对代码进行了一些更改以适应我的代码,并在 Mr.inclements 的帮助下做到了这一点: 我已将更改放在引用中。

Main.py 文件:

from kivy.core.window import Window
from kivymd.app import MDApp
from kivymd.uix.screen import MDScreen
from kivymd.uix.floatlayout import MDFloatLayout
from kivy.properties import Clock

from Player import PlayerImage

class LevelOneLayout(MDFloatLayout):
    pass


class LevelOne(MDScreen):
    from PlayerAction import _keyboard_closed, _on_keyboard_down, _on_keyboard_up, """process_keys"""

    gravity_force = 1800

    def __init__(self, **kwargs):
        super().__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)
        Clock.schedule_once(self.setup, 1/60)


    def setup(self, dt):

        self.player_image = PlayerImage()
        self.add_widget(self.player_image)


        Clock.schedule_interval(self.game_gravity, 1/30)
        """Clock.schedule_interval(self.process_keys, 1/30)"""


    def game_gravity(self, dt):
        if self.player_image.on_air:
            self.player_image.player_gravity_vel -= self.gravity_force * 1/30
            self.player_image.y += self.player_image.player_gravity_vel * 1/30 

        if self.player_image.y <= 60:
            self.player_image.y = 60
            self.player_image.player_gravity_vel = 0
            self.player_image.on_air = False


class MainApp(MDApp):
    def build(self):
        self.theme_cls.theme_style = "Dark"
        self.theme_cls.primary_palette = "Red"

        return


MainApp().run()

PlayerAction.py 文件:

"""pressed_keys = set()"""


def _keyboard_closed(self):

    self._keyboard.unbind(on_key_down = self._on_keyboard_down)

    """self._keyboard.unbind(on_key_up = self._on_keyboard_up)"""

    self._keyboard = None


def _on_keyboard_down(self, keyboard, keycode, *args):    

    """pressed_keys.add(keycode[1])"""

    return True


def _on_keyboard_up(self, keyboard, keycode, *args): 

    """pressed_keys.remove(keycode[1])"""    

    return True

"""
def process_keys(self, dt):

    if pressed_keys.issuperset({'up', 'right'}):

        self.player_image.jump()

        self.player_image.move_right()


    elif pressed_keys.issuperset({'up', 'left'}):

        self.player_image.jump()

        self.player_image.move_left()


    elif pressed_keys.issuperset({'left', 'up'}):

        self.player_image.move_left()

        self.player_image.up()


    elif pressed_keys.issuperset({'right', 'up'}):

        self.player_image.move_right()

        self.player_image.up()


    elif pressed_keys.issuperset({'up'}):

        self.player_image.jump()


    elif pressed_keys.issuperset({'left'}):

        self.player_image.move_left()


    elif pressed_keys.issuperset({'right'}):

        self.player_image.move_right()
"""

Player.py 文件:

在 player.py 文件中,我刚刚从“jump”、“move_left”和“move_right”方法中删除了“state”参数,因为我已经从 PlayerAction.py 文件中删除了“key_state”变量,我这里不需要“state”参数。

请注意,在 kivy 支持组中提供的多次按键示例并没有使用 Clock 来调用“process_key”方法,而是仅从“_on_keyboard_down”方法调用,但是这样做仍然会让您感觉像第二个key 覆盖了第一个,所以我在这里尝试使用 Mr.inclement 的答案,方法是使用 Clock 调用“process_key”方法,它可以工作。就是它。

【讨论】:

    猜你喜欢
    • 2020-10-26
    • 1970-01-01
    • 1970-01-01
    • 2018-04-07
    • 1970-01-01
    • 2010-09-23
    • 1970-01-01
    • 2010-09-28
    • 1970-01-01
    相关资源
    最近更新 更多