第12步-从地图编辑器加载地图#

在本章中,我们将开始使用一个名为 Tiled 。平铺是一个流行的2D地图编辑器,它可以与任何游戏引擎一起使用,但Arade有专门的集成来处理平铺。

在本教程中,我们将探讨如何使用Arade的内置功能从切片加载地图 arcade.TileMap 使用Arade附带的内置资源中的一些地图来初始化。我们不会在本教程中介绍如何实际构建地图,但如果您想了解更多有关切片的信息,请查看以下资源:

实际上,您不需要平铺即可继续学习本教程。我们将使用Arade附带的所有预建地图。然而,如果你想尝试自己的地图或改变事物,我建议你去拼贴并熟悉它,它是一个非常有用的2D游戏开发工具。

首先,我们将删除一些代码。也就是说,我们将移除我们的地面、盒子和硬币精灵的创造(我们将留给玩家一个)。继续,并从 setup 功能。

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

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)

coordinate_list = [[512, 96], [256, 96], [768, 96]]

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

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)

一旦我们开始加载 Mapfile ,这些事情现在将由我们的 Mapfile 自动处理。

为了加载地图,我们将首先在中为其创建一个变量 __init__

self.tile_map = None

接下来,我们将把地图加载到 setup 函数,然后使用Arade提供的内置函数从该函数创建场景。这将给我们一个完全基于 Mapfile 自动绘制的场景。此代码将全部放在 setup 功能。

确保替换设置为 self.scene 下面是新的。

layer_options = {
    "Platforms": {
        "use_spatial_hash": True
    }
}

self.tile_map = arcade.load_tilemap(
    ":resources:tiled_maps/map.json",
    scaling=TILE_SCALING,
    layer_options=layer_options
)

self.scene = arcade.Scene.from_tilemap(self.tile_map)

这段代码将加载到我们的内置平铺地图中,并自动从它构建场景。这个阶段的场景已经准备好可以绘制了,我们不需要对它做任何其他操作(除了添加我们的球员)。

备注

是什么 layer_options 而这些价值观又从何而来呢?

layer_options is a special dictionary that can be provided to the load_tilemap function. This will send special options for each layer into the map loader. In this example our map has a layer called Platforms, and we want to enable spatial hashing on it. Much like we did for our wall SpriteList before. For more info on the layer options dictionary and the available keys, check out :class`arcade.TileMap`

在这一点上,我们只剩下一段代码需要更改。在切换到我们的新地图时,您可能已经注意到 layer_options 字典,我们现在有一个名为 Platforms 。在我们之前的场景中,我们将这一层称为 Walls 。在创建物理引擎时,我们需要更新该引用。

setup 函数更新物理引擎创建以使用新的 Platforms 层:

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

源代码#

从地图编辑器加载地图#
  1"""
  2Platformer Game
  3
  4python -m arcade.examples.platform_tutorial.12_tiled
  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        # Variable to hold our Tiled Map
 40        self.tile_map = None
 41
 42        # Replacing all of our SpriteLists with a Scene variable
 43        self.scene = None
 44
 45        # A variable to store our camera object
 46        self.camera = None
 47
 48        # A variable to store our gui camera object
 49        self.gui_camera = None
 50
 51        # This variable will store our score as an integer.
 52        self.score = 0
 53
 54        # This variable will store the text for score that we will draw to the screen.
 55        self.score_text = None
 56
 57        # Load sounds
 58        self.collect_coin_sound = arcade.load_sound(":resources:sounds/coin1.wav")
 59        self.jump_sound = arcade.load_sound(":resources:sounds/jump1.wav")
 60
 61    def setup(self):
 62        """Set up the game here. Call this function to restart the game."""
 63        layer_options = {
 64            "Platforms": {
 65                "use_spatial_hash": True
 66            }
 67        }
 68
 69        # Load our TileMap
 70        self.tile_map = arcade.load_tilemap(":resources:tiled_maps/map.json", scaling=TILE_SCALING, layer_options=layer_options)
 71
 72        # Create our Scene Based on the TileMap
 73        self.scene = arcade.Scene.from_tilemap(self.tile_map)
 74
 75        self.player_texture = arcade.load_texture(":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png")
 76
 77        self.player_sprite = arcade.Sprite(self.player_texture)
 78        self.player_sprite.center_x = 128
 79        self.player_sprite.center_y = 128
 80        self.scene.add_sprite("Player", self.player_sprite)
 81
 82        # Create a Platformer Physics Engine, this will handle moving our
 83        # player as well as collisions between the player sprite and
 84        # whatever SpriteList we specify for the walls.
 85        # It is important to supply static to the walls parameter. There is a
 86        # platforms parameter that is intended for moving platforms.
 87        # If a platform is supposed to move, and is added to the walls list,
 88        # it will not be moved.
 89        self.physics_engine = arcade.PhysicsEnginePlatformer(
 90            self.player_sprite, walls=self.scene["Platforms"], gravity_constant=GRAVITY
 91        )
 92
 93        # Initialize our camera, setting a viewport the size of our window.
 94        self.camera = arcade.camera.Camera2D()
 95
 96        # Initialize our gui camera, initial settings are the same as our world camera.
 97        self.gui_camera = arcade.camera.Camera2D()
 98
 99        # Reset our score to 0
100        self.score = 0
101
102        # Initialize our arcade.Text object for score
103        self.score_text = arcade.Text(f"Score: {self.score}", x=0, y=5)
104
105        self.background_color = arcade.csscolor.CORNFLOWER_BLUE
106
107    def on_draw(self):
108        """Render the screen."""
109
110        # Clear the screen to the background color
111        self.clear()
112
113        # Activate our camera before drawing
114        self.camera.use()
115
116        # Draw our Scene
117        self.scene.draw()
118
119        # Activate our GUI camera
120        self.gui_camera.use()
121
122        # Draw our Score
123        self.score_text.draw()
124
125    def on_update(self, delta_time):
126        """Movement and Game Logic"""
127
128        # Move the player using our physics engine
129        self.physics_engine.update()
130
131        # See if we hit any coins
132        coin_hit_list = arcade.check_for_collision_with_list(
133            self.player_sprite, self.scene["Coins"]
134        )
135
136        # Loop through each coin we hit (if any) and remove it
137        for coin in coin_hit_list:
138            # Remove the coin
139            coin.remove_from_sprite_lists()
140            arcade.play_sound(self.collect_coin_sound)
141            self.score += 75
142            self.score_text.text = f"Score: {self.score}"
143
144        # Center our camera on the player
145        self.camera.position = self.player_sprite.position
146
147    def on_key_press(self, key, modifiers):
148        """Called whenever a key is pressed."""
149
150        if key == arcade.key.ESCAPE:
151            self.setup()
152
153        if key == arcade.key.UP or key == arcade.key.W:
154            if self.physics_engine.can_jump():
155                self.player_sprite.change_y = PLAYER_JUMP_SPEED
156                arcade.play_sound(self.jump_sound)
157
158        if key == arcade.key.LEFT or key == arcade.key.A:
159            self.player_sprite.change_x = -PLAYER_MOVEMENT_SPEED
160        elif key == arcade.key.RIGHT or key == arcade.key.D:
161            self.player_sprite.change_x = PLAYER_MOVEMENT_SPEED
162
163    def on_key_release(self, key, modifiers):
164        """Called whenever a key is released."""
165
166        if key == arcade.key.LEFT or key == arcade.key.A:
167            self.player_sprite.change_x = 0
168        elif key == arcade.key.RIGHT or key == arcade.key.D:
169            self.player_sprite.change_x = 0
170
171
172def main():
173    """Main function"""
174    window = MyGame()
175    window.setup()
176    arcade.run()
177
178
179if __name__ == "__main__":
180    main()