Arcade官方教程解析9 Add Ladders, Properties, and a Moving Platform

"""
Platformer Game
"""
import os

import arcade

# Constants
SCREEN_WIDTH = 1000
SCREEN_HEIGHT = 650
SCREEN_TITLE = "Platformer"

# Constants used to scale our sprites from their original size
CHARACTER_SCALING = 1
TILE_SCALING = 0.5
COIN_SCALING = 0.5
SPRITE_PIXEL_SIZE = 128
GRID_PIXEL_SIZE = SPRITE_PIXEL_SIZE * TILE_SCALING

# Movement speed of player, in pixels per frame
PLAYER_MOVEMENT_SPEED = 7
GRAVITY = 1.5
PLAYER_JUMP_SPEED = 30

PLAYER_START_X = 64
PLAYER_START_Y = 256

# Layer Names from our TileMap
LAYER_NAME_MOVING_PLATFORMS = "Moving Platforms"
LAYER_NAME_PLATFORMS = "Platforms"
LAYER_NAME_COINS = "Coins"
LAYER_NAME_BACKGROUND = "Background"
LAYER_NAME_LADDERS = "Ladders"


class MyGame(arcade.Window):
    """
    Main application class.
    """

    def __init__(self):
        """
        Initializer for the game
        """

        # Call the parent class and set up the window
        super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)

        # Set the path to start with this program
        file_path = os.path.dirname(os.path.abspath(__file__))
        os.chdir(file_path)

        # Our TileMap Object
        self.tile_map = None

        # Our Scene Object
        self.scene = None

        # Separate variable that holds the player sprite
        self.player_sprite = None

        # Our 'physics' engine
        self.physics_engine = None

        # A Camera that can be used for scrolling the screen
        self.camera = None

        # A Camera that can be used to draw GUI elements
        self.gui_camera = None

        self.end_of_map = 0

        # Keep track of the score
        self.score = 0

        # Load sounds
        self.collect_coin_sound = arcade.load_sound(":resources:sounds/coin1.wav")
        self.jump_sound = arcade.load_sound(":resources:sounds/jump1.wav")
        self.game_over = arcade.load_sound(":resources:sounds/gameover1.wav")

    def setup(self):
        """Set up the game here. Call this function to restart the game."""

        # Set up the Cameras
        self.camera = arcade.Camera(self.width, self.height)
        self.gui_camera = arcade.Camera(self.width, self.height)

        # Map name
        map_name = ":resources:tiled_maps/map_with_ladders.json"

        # Layer Specific Options for the Tilemap
        layer_options = {
            LAYER_NAME_PLATFORMS: {
                "use_spatial_hash": True,
            },
            LAYER_NAME_MOVING_PLATFORMS: {
                "use_spatial_hash": False,
            },
            LAYER_NAME_LADDERS: {
                "use_spatial_hash": True,
            },
            LAYER_NAME_COINS: {
                "use_spatial_hash": True,
            },
        }

        # Load in TileMap
        self.tile_map = arcade.load_tilemap(map_name, TILE_SCALING, layer_options)

        # Initiate New Scene with our TileMap, this will automatically add all layers
        # from the map as SpriteLists in the scene in the proper order.
        self.scene = arcade.Scene.from_tilemap(self.tile_map)

        # Keep track of the score
        self.score = 0

        # Set up the player, specifically placing it at these coordinates.
        image_source = ":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png"
        self.player_sprite = arcade.Sprite(image_source, CHARACTER_SCALING)
        self.player_sprite.center_x = PLAYER_START_X
        self.player_sprite.center_y = PLAYER_START_Y
        self.scene.add_sprite("Player", self.player_sprite)

        # Calculate the right edge of the my_map in pixels
        self.end_of_map = self.tile_map.width * GRID_PIXEL_SIZE

        # --- Other stuff
        # Set the background color
        if self.tile_map.background_color:
            arcade.set_background_color(self.tile_map.background_color)

        # Create the 'physics engine'
        self.physics_engine = arcade.PhysicsEnginePlatformer(
            self.player_sprite,
            platforms=self.scene[LAYER_NAME_MOVING_PLATFORMS],
            gravity_constant=GRAVITY,
            ladders=self.scene[LAYER_NAME_LADDERS],
            walls=self.scene[LAYER_NAME_PLATFORMS]
        )

    def on_draw(self):
        """Render the screen."""
        # Clear the screen to the background color
        self.clear()

        # Activate the game camera
        self.camera.use()

        # Draw our Scene
        self.scene.draw()

        # Activate the GUI camera before drawing GUI elements
        self.gui_camera.use()

        # Draw our score on the screen, scrolling it with the viewport
        score_text = f"Score: {self.score}"
        arcade.draw_text(
            score_text,
            10,
            10,
            arcade.csscolor.BLACK,
            18,
        )

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

        if key == arcade.key.UP or key == arcade.key.W:
            if self.physics_engine.is_on_ladder():
                self.player_sprite.change_y = PLAYER_MOVEMENT_SPEED
            elif self.physics_engine.can_jump():
                self.player_sprite.change_y = PLAYER_JUMP_SPEED
                arcade.play_sound(self.jump_sound)
        elif key == arcade.key.DOWN or key == arcade.key.S:
            if self.physics_engine.is_on_ladder():
                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 when the user releases a key."""

        if key == arcade.key.UP or key == arcade.key.W:
            if self.physics_engine.is_on_ladder():
                self.player_sprite.change_y = 0
        elif key == arcade.key.DOWN or key == arcade.key.S:
            if self.physics_engine.is_on_ladder():
                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

    def center_camera_to_player(self):
        screen_center_x = self.player_sprite.center_x - (self.camera.viewport_width / 2)
        screen_center_y = self.player_sprite.center_y - (
            self.camera.viewport_height / 2
        )
        if screen_center_x < 0:
            screen_center_x = 0
        if screen_center_y < 0:
            screen_center_y = 0
        player_centered = screen_center_x, screen_center_y

        self.camera.move_to(player_centered, 0.2)

    def update(self, delta_time):
        """Movement and game logic"""
        # Move the player with the physics engine
        self.physics_engine.update()

        # Update animations
        self.scene.update_animation(
            delta_time, [LAYER_NAME_COINS, LAYER_NAME_BACKGROUND]
        )

        # Update walls, used with moving platforms
        self.scene.update([LAYER_NAME_MOVING_PLATFORMS])

        # See if we hit any coins
        coin_hit_list = arcade.check_for_collision_with_list(
            self.player_sprite, self.scene[LAYER_NAME_COINS]
        )

        # Loop through each coin we hit (if any) and remove it
        for coin in coin_hit_list:

            # Figure out how many points this coin is worth
            if "Points" not in coin.properties:
                print("Warning, collected a coin without a Points property.")
            else:
                points = int(coin.properties["Points"])
                self.score += points

            # Remove the coin
            coin.remove_from_sprite_lists()
            arcade.play_sound(self.collect_coin_sound)

        # Position the camera
        self.center_camera_to_player()


def main():
    """Main function"""
    window = MyGame()
    window.setup()
    arcade.run()


if __name__ == "__main__":
    main()

这是一个基于arcade库创建的平台游戏。代码主要通过使用TileMap来生成游戏场景和精灵,并通过arcade.PhysicsEnginePlatformer实现玩家角色的移动。以下是对代码的逐行描述:

  1. 导入所需的库和模块:

    • os:用于处理文件路径和当前工作目录。
    • arcade:用于创建游戏窗口、精灵和场景等。
  2. 设置游戏窗口的常量:

    • SCREEN_WIDTH:窗口的宽度。
    • SCREEN_HEIGHT:窗口的高度。
    • SCREEN_TITLE:窗口的标题。
  3. 定义一个名为MyGame的类,继承自arcade.Window。这是主应用程序类。

  4. 在MyGame类的构造函数中,调用父类的构造函数并设置窗口的大小和标题。然后初始化一些变量。

  5. 设置游戏的初始设置。

  6. 创建一个名为setup的方法,用于设置游戏的初始状态。这个方法会在开始游戏和重新开始游戏时调用。

34-42. 设置摄像机对象,用于控制屏幕的滚动和绘制GUI元素。

  1. 设置地图的名称。

48-57. 定义一个字典,存储各个图层的设置选项。

  1. 使用arcade库的load_tilemap方法加载地图。

  2. 使用从tilemap创建场景对象。

  3. 初始化分数变量。

69-73. 设置玩家精灵的图像和初始位置。

  1. 计算地图右边缘的像素位置。

  2. 设置背景颜色。

  3. 创建一个物理引擎,用于处理玩家精灵与平台和梯子的碰撞。

  4. 创建一个名为on_draw的方法,用于绘制屏幕。

92-93. 清空屏幕,并设置背景颜色。

96-99. 切换到游戏摄像机,并绘制场景。

102-104. 切换到GUI摄像机,并绘制分数。

  1. 创建一个名为on_key_press的方法,用于处理按键按下事件。

110-111. 检查玩家是否在梯子上,如果是,则改变竖直速度。如果可以跳跃,则进行跳跃操作。

115-116. 检查玩家是否在梯子上,如果是,则改变竖直速度。

118-119. 修改玩家横向速度。

122-123. 修改玩家横向速度。

  1. 创建一个名为on_key_release的方法,用于处理按键释放事件。

130-131. 检查玩家是否在梯子上,如果是,则将竖直速度设为0。

133-134. 检查玩家是否在梯子上,如果是,则将竖直速度设为0。

136-137. 将玩家横向速度设为0。

139-140. 将玩家横向速度设为0。

143-145. 将摄像机的位置设置为以玩家为中心。

  1. 创建一个名为update的方法,用于更新游戏逻辑和精灵的移动。

  2. 使用物理引擎更新玩家精灵的位置。

  3. 使用scene对象的update_animation方法更新动画。

  4. 使用scene对象的update方法更新墙壁。

162-169. 检查玩家是否与硬币精灵碰撞,并根据硬币的属性增加得分,并移除硬币精灵。

  1. 更新相机的位置。

  2. 创建一个名为main的方法。

180-182. 创建MyGame对象并调用setup方法。

  1. 启动游戏循环。

  2. 检查脚本是否作为主程序运行,如果是,则调用main方法。

相关推荐

  1. Arcade官方教程解析8 Multiple Levels and Other Layers

    2024-03-16 06:32:03       20 阅读
  2. CMake官方教程9--打包文件

    2024-03-16 06:32:03       19 阅读
  3. CMake官方教程4--使用表达式生成器

    2024-03-16 06:32:03       20 阅读
  4. CMake官方教程11--加入导出设置

    2024-03-16 06:32:03       16 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-16 06:32:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-16 06:32:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-16 06:32:03       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-16 06:32:03       20 阅读

热门阅读

  1. hive行转列函数stack(int n, v_1, v_2, ..., v_k)

    2024-03-16 06:32:03       19 阅读
  2. WPF实现拖动控件功能(类似从工具箱拖出工具)

    2024-03-16 06:32:03       20 阅读
  3. C++中using 和 typedef 的区别

    2024-03-16 06:32:03       18 阅读
  4. 半监督学习--一起学习吧之人工智能

    2024-03-16 06:32:03       23 阅读
  5. 相机学习的知识积累

    2024-03-16 06:32:03       23 阅读