第11步-使用场景#

到目前为止,我们的游戏中有三个SpriteList。一个给我们的玩家,一个给我们的墙(地面和盒子),一个给我们的硬币。这仍然是可控的,但随着我们游戏的发展呢?你也许可以想象,一场比赛可能会有数百名SpriteList。仅使用我们当前的方法,我们就必须跟踪每个变量,并确保以正确的顺序绘制它们。

Arade提供了一种更好的方法来处理此问题, arcade.Scene 班级。这个类将为我们保存所有的精灵列表,允许我们创建新的精灵列表,更改它们被吸引的顺序,等等。在后面的章节中,我们将使用一个特殊的函数从地图编辑器工具中加载地图,并根据地图自动创建场景。

在本章结束时,您将得到与之前相同的结果,但使用场景对象的代码将略有不同。

首先,我们可以将所有SpriteList变量从 __init__ 并将它们替换为On变量以保存场景对象:

self.scene = None

现在在我们的最顶端 setup 函数,我们可以通过执行以下操作来初始化场景:

self.scene = arcade.Scene()

接下来,我们将删除中的行 setup 它初始化了我们的球员精灵列表,该行看起来是这样的:

self.player_list = arcade.SpriteList()

然后,不是使用以下命令将我们的播放器添加到SpriteList self.player_sprite.append() 。我们会将玩家直接添加到场景中:

self.player_sprite = arcade.Sprite(self.player_texture)
self.player_sprite.center_x = 64
self.player_sprite.center_y = 128
self.scene.add_sprite("Player", self.player_sprite)

让我们分析一下当我们这样做时会发生什么 arcade.Scene.add_sprite() 。它的第一个参数是一个字符串,它定义了我们要向其添加Sprite的层的名称。这可以是现有的层,也可以是新的层。如果层已经存在,精灵将被添加到它,如果它不存在,场景将自动创建它。在引擎盖下,层只是一个带有名称的SpriteList。因此,当我们指定 Player 作为我们的一层。场景正在创建一个新的SpriteList,给它命名,然后将我们的球员Sprite添加到其中。

接下来,我们将用以下函数替换WALL和COUNT SpriteList的初始化:

self.scene.add_sprite_list("Walls", use_spatial_hash=True)
self.scene.add_sprite_list("Coins", use_spatial_hash=True)

在这里,我们采取的方法与我们对我们的 Player 一层。对于我们的球员,我们只是直接添加了一杯雪碧。这里我们初始化了新的空层,名为 WallsCoins 。这种方法的优点是,我们可以指定该层应该使用空间散列,就像我们之前为那些SpriteList指定的那样。

现在,当我们使用 add_sprite 函数之后,这些精灵将被添加到这些现有的层中。

为了将Sprite添加到这些组件中,让我们修改 self.wall_list.append() For循环中的函数,用于将我们的墙和硬币放置在 setup 功能。我们实际上更改这些循环的唯一部分是将其添加到SpriteList的最后一行,但我已经包括了这些循环,这样您就可以看到它应该在哪里更改。

# Create the ground
for x in range(0, 1250, 64):
    wall = arcade.Sprite(":resources:images/tiles/grassMid.png", scale=TILE_SCALING)
    wall.center_x = x
    wall.center_y = 32
    self.scene.add_sprite("Walls", wall)

# Putting Crates on the Ground
coordinate_list = [[512, 96], [256, 96], [768, 96]]

for coordinate in coordinate_li
    wall = arcade.Sprite(
        ":resources:images/tiles/boxCrate_double.png", scale=TILE_SCALING
    )
    wall.position = coordinate
    self.scene.add_sprite("Walls", wall)

# Add coins to the world
for x in range(128, 1250, 256):
    coin = arcade.Sprite(":resources:images/items/coinGold.png", scale=COIN_SCALING)
    coin.center_x = x
    coin.center_y = 96
    self.scene.add_sprite("Coins", coin)

接下来我们需要做的是修复我们的物理引擎。如果您还记得在第4章,我们添加了一个物理引擎,并将我们的WALL精灵列表发送到 walls 参数。

我们需要将PhysicsEngPlatformer初始化修改为:

self.physics_engine = arcade.PhysicsEnginePlatformer(
    self.player_sprite, walls=self.scene["Walls"], gravity_constant=GRAVITY
)

这与以前基本相同,但我们从场景中删除了墙SpriteList。如果您熟悉Python词典,请参阅 arcade.Scene 类可以以非常类似的方式进行交互。通过将名称放在方括号中传递给场景,可以获取场景中的任何特定SpriteList。

我们还需要更改我们的 arcade.check_for_collision_with_list() 中的函数 on_update 我们用它来获得我们命中的硬币来使用这个新语法。

coin_hit_list = arcade.check_for_collision_with_list(
    self.player_sprite, self.scene["Coins"]
)

我们需要做的最后一件事是更新我们的 on_draw 功能。在这里,我们将删除所有SpriteList绘制,并用绘制我们的场景的一行代替它们。

self.scene.draw()

备注

确保在我们的世界摄像头被激活之后和我们的图形用户界面摄像头被激活之前保存它。如果在激活图形用户界面摄像头的情况下绘制场景,则以播放器为中心和滚动将不起作用。

源代码#

使用场景#
  1"""
  2Platformer Game
  3
  4python -m arcade.examples.platform_tutorial.11_scene
  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
 15COIN_SCALING = 0.5
 16
 17# Movement speed of player, in pixels per frame
 18PLAYER_MOVEMENT_SPEED = 5
 19GRAVITY = 1
 20PLAYER_JUMP_SPEED = 20
 21
 22
 23class MyGame(arcade.Window):
 24    """
 25    Main application class.
 26    """
 27
 28    def __init__(self):
 29
 30        # Call the parent class and set up the window
 31        super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
 32
 33        # Variable to hold our texture for our player
 34        self.player_texture = None
 35
 36        # Separate variable that holds the player sprite
 37        self.player_sprite = None
 38
 39        # Replacing all of our SpriteLists with a Scene variable
 40        self.scene = None
 41
 42        # A variable to store our camera object
 43        self.camera = None
 44
 45        # A variable to store our gui camera object
 46        self.gui_camera = None
 47
 48        # This variable will store our score as an integer.
 49        self.score = 0
 50
 51        # This variable will store the text for score that we will draw to the screen.
 52        self.score_text = None
 53
 54        # Load sounds
 55        self.collect_coin_sound = arcade.load_sound(":resources:sounds/coin1.wav")
 56        self.jump_sound = arcade.load_sound(":resources:sounds/jump1.wav")
 57
 58    def setup(self):
 59        """Set up the game here. Call this function to restart the game."""
 60        self.scene = arcade.Scene()
 61
 62        self.player_texture = arcade.load_texture(":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png")
 63
 64        self.player_sprite = arcade.Sprite(self.player_texture)
 65        self.player_sprite.center_x = 64
 66        self.player_sprite.center_y = 128
 67        self.scene.add_sprite("Player", self.player_sprite)
 68
 69        self.scene.add_sprite_list("Walls", use_spatial_hash=True)
 70        self.scene.add_sprite_list("Coins", use_spatial_hash=True)
 71
 72        # Create the ground
 73        # This shows using a loop to place multiple sprites horizontally
 74        for x in range(0, 1250, 64):
 75            wall = arcade.Sprite(":resources:images/tiles/grassMid.png", scale=TILE_SCALING)
 76            wall.center_x = x
 77            wall.center_y = 32
 78            self.scene.add_sprite("Walls", wall)
 79
 80        # Put some crates on the ground
 81        # This shows using a coordinate list to place sprites
 82        coordinate_list = [[512, 96], [256, 96], [768, 96]]
 83
 84        for coordinate in coordinate_list:
 85            # Add a crate on the ground
 86            wall = arcade.Sprite(
 87                ":resources:images/tiles/boxCrate_double.png", scale=TILE_SCALING
 88            )
 89            wall.position = coordinate
 90            self.scene.add_sprite("Walls", wall)
 91
 92        # Add coins to the world
 93        for x in range(128, 1250, 256):
 94            coin = arcade.Sprite(":resources:images/items/coinGold.png", scale=COIN_SCALING)
 95            coin.center_x = x
 96            coin.center_y = 96
 97            self.scene.add_sprite("Coins", coin)
 98
 99        # Create a Platformer Physics Engine, this will handle moving our
100        # player as well as collisions between the player sprite and
101        # whatever SpriteList we specify for the walls.
102        # It is important to supply static to the walls parameter. There is a
103        # platforms parameter that is intended for moving platforms.
104        # If a platform is supposed to move, and is added to the walls list,
105        # it will not be moved.
106        self.physics_engine = arcade.PhysicsEnginePlatformer(
107            self.player_sprite, walls=self.scene["Walls"], gravity_constant=GRAVITY
108        )
109
110        # Initialize our camera, setting a viewport the size of our window.
111        self.camera = arcade.camera.Camera2D()
112
113        # Initialize our gui camera, initial settings are the same as our world camera.
114        self.gui_camera = arcade.camera.Camera2D()
115
116        # Reset our score to 0
117        self.score = 0
118
119        # Initialize our arcade.Text object for score
120        self.score_text = arcade.Text(f"Score: {self.score}", x=0, y=5)
121
122        self.background_color = arcade.csscolor.CORNFLOWER_BLUE
123
124    def on_draw(self):
125        """Render the screen."""
126
127        # Clear the screen to the background color
128        self.clear()
129
130        # Activate our camera before drawing
131        self.camera.use()
132
133        # Draw our Scene
134        self.scene.draw()
135
136        # Activate our GUI camera
137        self.gui_camera.use()
138
139        # Draw our Score
140        self.score_text.draw()
141
142    def on_update(self, delta_time):
143        """Movement and Game Logic"""
144
145        # Move the player using our physics engine
146        self.physics_engine.update()
147
148        # See if we hit any coins
149        coin_hit_list = arcade.check_for_collision_with_list(
150            self.player_sprite, self.scene["Coins"]
151        )
152
153        # Loop through each coin we hit (if any) and remove it
154        for coin in coin_hit_list:
155            # Remove the coin
156            coin.remove_from_sprite_lists()
157            arcade.play_sound(self.collect_coin_sound)
158            self.score += 75
159            self.score_text.text = f"Score: {self.score}"
160
161        # Center our camera on the player
162        self.camera.position = self.player_sprite.position
163
164    def on_key_press(self, key, modifiers):
165        """Called whenever a key is pressed."""
166
167        if key == arcade.key.ESCAPE:
168            self.setup()
169
170        if key == arcade.key.UP or key == arcade.key.W:
171            if self.physics_engine.can_jump():
172                self.player_sprite.change_y = PLAYER_JUMP_SPEED
173                arcade.play_sound(self.jump_sound)
174
175        if key == arcade.key.LEFT or key == arcade.key.A:
176            self.player_sprite.change_x = -PLAYER_MOVEMENT_SPEED
177        elif key == arcade.key.RIGHT or key == arcade.key.D:
178            self.player_sprite.change_x = PLAYER_MOVEMENT_SPEED
179
180    def on_key_release(self, key, modifiers):
181        """Called whenever a key is released."""
182
183        if key == arcade.key.LEFT or key == arcade.key.A:
184            self.player_sprite.change_x = 0
185        elif key == arcade.key.RIGHT or key == arcade.key.D:
186            self.player_sprite.change_x = 0
187
188
189def main():
190    """Main function"""
191    window = MyGame()
192    window.setup()
193    arcade.run()
194
195
196if __name__ == "__main__":
197    main()

运行本章#

python -m arcade.examples.platform_tutorial.11_scene