第4步-添加用户控件#

现在我们有了一个角色和一个供他们生存的世界,但如果你不能控制角色和移动,游戏还有什么意思呢?在本章中,我们将探索在Arade中添加键盘输入。

首先,在程序的顶部,我们想要添加一个新的常量,该常量控制每次更新角色移动的像素数:

PLAYER_MOVEMENT_SPEED = 5

为了处理键盘输入,我们需要向窗口类添加两个新函数, on_key_presson_key_release 。无论何时按下或松开键盘上的某个键,Arade都会自动调用这些函数。在这些功能中,根据按下或释放的键,我们将移动角色。

def on_key_press(self, key, modifiers):
    """Called whenever a key is pressed."""

    if key == arcade.key.UP or key == arcade.key.W:
        self.player_sprite.change_y = PLAYER_MOVEMENT_SPEED
    elif key == arcade.key.DOWN or key == arcade.key.S:
        self.player_sprite.change_y = -PLAYER_MOVEMENT_SPEED
    elif key == arcade.key.LEFT or key == arcade.key.A:
        self.player_sprite.change_x = -PLAYER_MOVEMENT_SPEED
    elif key == arcade.key.RIGHT or key == arcade.key.D:
        self.player_sprite.change_x = PLAYER_MOVEMENT_SPEED

def on_key_release(self, key, modifiers):
    """Called whenever a key is released."""

    if key == arcade.key.UP or key == arcade.key.W:
        self.player_sprite.change_y = 0
    elif key == arcade.key.DOWN or key == arcade.key.S:
        self.player_sprite.change_y = 0
    elif key == arcade.key.LEFT or key == arcade.key.A:
        self.player_sprite.change_x = 0
    elif key == arcade.key.RIGHT or key == arcade.key.D:
        self.player_sprite.change_x = 0

在这些框中,我们正在修改 change_xchange_y 我们的球员雪碧的属性。更改这些值实际上不会在精灵上执行移动。为了应用此更改,我们需要使用我们的Sprite创建一个物理引擎,并每帧更新一个物理引擎。然后,物理引擎将负责实际移动精灵。

我们之所以让物理引擎承担这一责任,而不是自己做,是因为我们可以让物理引擎进行碰撞检测,并根据结果允许/不允许移动。在后面的章节中,我们将使用更先进的物理引擎,它可以做一些事情,比如允许在重力下跳跃,或者爬梯子。

备注

这种跟踪玩家按键的速度的方法很简单,但并不完美。如果玩家同时按下左键和右键,然后松开左键,我们预计玩家会向右移动。此方法不支持这一点。如果需要稍微复杂一点的方法,请参见 更好地通过键盘移动

让我们在我们的 __init__ 功能。我们将通过向它传递我们的玩家Sprite和包含我们的墙的SpriteList来实现这一点。

self.physics_engine = arcade.PhysicsEngineSimple(
    self.player_sprite, self.wall_list
)

现在我们有了一个物理引擎,但我们仍然需要每一帧都更新它。为此,我们将向窗口类添加一个新函数,名为 on_update 。此函数类似于 on_draw ,它将被Arade以每秒60次的默认次数调用。它还将给我们带来一个 delta_time 参数,该参数告诉上次调用和当前调用之间的时间量。该值将在后续章节的某些计算中使用。在这个函数中,我们将更新我们的物理引擎。它将处理碰撞检测并根据它的 change_xchange_y 价值观。

def on_update(self, delta_time):
    """Movement and Game Logic"""

    self.physics_engine.update()

此时,您应该能够运行游戏,并使用键盘移动角色。如果物理引擎工作正常,角色应该不能在地面或盒子中移动。

有关本教程中使用的物理引擎的更多信息,请参阅 arcade.PhysicsEngineSimple

备注

可以有多个物理引擎,每个移动的精灵一个。这些都是非常简单但容易的物理引擎。看见 PyMunk平台 一个更先进的物理引擎。

备注

如果要查看如何检查冲突,请尝试使用 draw_hit_boxes() 中的播放器和WALL SpriteList的函数 on_draw 功能。这将向您展示物理引擎使用的点击框是什么样子的。

源代码#

04_USER_Contro.py-用户控件#
  1"""
  2Platformer Game
  3
  4python -m arcade.examples.platform_tutorial.04_user_control
  5"""
  6import arcade
  7
  8# Constants
  9SCREEN_WIDTH = 800
 10SCREEN_HEIGHT = 600
 11SCREEN_TITLE = "Platformer"
 12
 13# Constants used to scale our sprites from their original size
 14TILE_SCALING = 0.5
 15
 16# Movement speed of player, in pixels per frame
 17PLAYER_MOVEMENT_SPEED = 5
 18
 19
 20class MyGame(arcade.Window):
 21    """
 22    Main application class.
 23    """
 24
 25    def __init__(self):
 26
 27        # Call the parent class and set up the window
 28        super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
 29
 30        # Variable to hold our texture for our player
 31        self.player_texture = arcade.load_texture(":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png")
 32
 33        # Separate variable that holds the player sprite
 34        self.player_sprite = arcade.Sprite(self.player_texture)
 35        self.player_sprite.center_x = 64
 36        self.player_sprite.center_y = 128
 37
 38        # SpriteList for our player
 39        self.player_list = arcade.SpriteList()
 40        self.player_list.append(self.player_sprite)
 41
 42        # SpriteList for our boxes and ground
 43        # Putting our ground and box Sprites in the same SpriteList
 44        # will make it easier to perform collision detection against
 45        # them later on. Setting the spatial hash to True will make
 46        # collision detection much faster if the objects in this
 47        # SpriteList do not move.
 48        self.wall_list = arcade.SpriteList(use_spatial_hash=True)
 49
 50        # Create the ground
 51        # This shows using a loop to place multiple sprites horizontally
 52        for x in range(0, 1250, 64):
 53            wall = arcade.Sprite(":resources:images/tiles/grassMid.png", scale=TILE_SCALING)
 54            wall.center_x = x
 55            wall.center_y = 32
 56            self.wall_list.append(wall)
 57
 58        # Put some crates on the ground
 59        # This shows using a coordinate list to place sprites
 60        coordinate_list = [[512, 96], [256, 96], [768, 96]]
 61
 62        for coordinate in coordinate_list:
 63            # Add a crate on the ground
 64            wall = arcade.Sprite(
 65                ":resources:images/tiles/boxCrate_double.png", scale=TILE_SCALING
 66            )
 67            wall.position = coordinate
 68            self.wall_list.append(wall)
 69
 70        # Create a Simple Physics Engine, this will handle moving our
 71        # player as well as collisions between the player sprite and
 72        # whatever SpriteList we specify for the walls.
 73        self.physics_engine = arcade.PhysicsEngineSimple(
 74            self.player_sprite, self.wall_list
 75        )
 76
 77        self.background_color = arcade.csscolor.CORNFLOWER_BLUE
 78
 79    def setup(self):
 80        """Set up the game here. Call this function to restart the game."""
 81        pass
 82
 83    def on_draw(self):
 84        """Render the screen."""
 85
 86        # Clear the screen to the background color
 87        self.clear()
 88
 89        # Draw our sprites
 90        self.player_list.draw()
 91        self.wall_list.draw()
 92
 93    def on_update(self, delta_time):
 94        """Movement and Game Logic"""
 95
 96        # Move the player using our physics engine
 97        self.physics_engine.update()
 98
 99    def on_key_press(self, key, modifiers):
100        """Called whenever a key is pressed."""
101
102        if key == arcade.key.UP or key == arcade.key.W:
103            self.player_sprite.change_y = PLAYER_MOVEMENT_SPEED
104        elif key == arcade.key.DOWN or key == arcade.key.S:
105            self.player_sprite.change_y = -PLAYER_MOVEMENT_SPEED
106        elif key == arcade.key.LEFT or key == arcade.key.A:
107            self.player_sprite.change_x = -PLAYER_MOVEMENT_SPEED
108        elif key == arcade.key.RIGHT or key == arcade.key.D:
109            self.player_sprite.change_x = PLAYER_MOVEMENT_SPEED
110
111    def on_key_release(self, key, modifiers):
112        """Called whenever a key is released."""
113
114        if key == arcade.key.UP or key == arcade.key.W:
115            self.player_sprite.change_y = 0
116        elif key == arcade.key.DOWN or key == arcade.key.S:
117            self.player_sprite.change_y = 0
118        elif key == arcade.key.LEFT or key == arcade.key.A:
119            self.player_sprite.change_x = 0
120        elif key == arcade.key.RIGHT or key == arcade.key.D:
121            self.player_sprite.change_x = 0
122
123
124def main():
125    """Main function"""
126    window = MyGame()
127    window.setup()
128    arcade.run()
129
130
131if __name__ == "__main__":
132    main()

运行本章#

python -m arcade.examples.platform_tutorial.04_user_control