第4步-添加用户控件#
现在我们有了一个角色和一个供他们生存的世界,但如果你不能控制角色和移动,游戏还有什么意思呢?在本章中,我们将探索在Arade中添加键盘输入。
首先,在程序的顶部,我们想要添加一个新的常量,该常量控制每次更新角色移动的像素数:
PLAYER_MOVEMENT_SPEED = 5
为了处理键盘输入,我们需要向窗口类添加两个新函数, on_key_press
和 on_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_x
和 change_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_x
和 change_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
功能。这将向您展示物理引擎使用的点击框是什么样子的。
源代码#
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