如何在这个游戏中改变房间(街机Python)

How to change room in this game (arcade Python)

我正在使用 Python 的街机游戏库开发一个简单的平台游戏。我对此还是个新手,但我已尝试尽可能多地使用面向对象的编程。我已经成功设置了两个“房间”或游戏关卡。但是,我不知道如何在完成第一个房间后移动到第二个房间。这是我的代码:

import arcade
import os
import random

SPRITE_SCALING = 0.5
SPRITE_SCALING_COIN = 0.3
SPRITE_NATIVE_SIZE = 128
SPRITE_SIZE = int(SPRITE_NATIVE_SIZE * SPRITE_SCALING)

SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
SCREEN_TITLE = "Help Nick Adams!"

# Physics
MOVEMENT_SPEED = 5
JUMP_SPEED = 12
GRAVITY = 0.5


class Room:
    # Class to hold info about rooms/levels

    def __init__(self):
        self.wall_list = self.goal_list = self.enemy_list = self.victory_sprite = None
        self.collectedCoins = 0
        self.numCoins = 0


def setup_room_1():
    room = Room()
    room.wall_list = arcade.SpriteList(use_spatial_hash=True)
    room.enemy_list = arcade.SpriteList()
    room.goal_list = arcade.SpriteList(use_spatial_hash=True)
    room.victory_sprite = arcade.SpriteList(use_spatial_hash=True)

    # Draw platforms and ground
    for x in range(0, SCREEN_WIDTH, SPRITE_SIZE):
        wall = arcade.Sprite(":resources:images/tiles/grassMid.png", SPRITE_SCALING)

        wall.bottom = 0
        wall.left = x
        room.wall_list.append(wall)

    for x in range(SPRITE_SIZE * 3, SPRITE_SIZE * 8, SPRITE_SIZE):
        wall = arcade.Sprite(":resources:images/tiles/grassMid.png", SPRITE_SCALING)

        wall.bottom = SPRITE_SIZE * 3
        wall.left = x
        room.wall_list.append(wall)

    # Draw the crates
    for x in range(0, SCREEN_WIDTH, SPRITE_SIZE * 5):
        wall = arcade.Sprite(":resources:images/tiles/boxCrate_double.png", SPRITE_SCALING)

        wall.bottom = SPRITE_SIZE
        wall.left = x
        room.wall_list.append(wall)

    # Draw an enemy 1
    enemy = arcade.Sprite(":resources:images/enemies/wormGreen.png", SPRITE_SCALING)

    enemy.bottom = SPRITE_SIZE
    enemy.left = SPRITE_SIZE * 2

    enemy.change_x = 2
    room.enemy_list.append(enemy)

    # -- Draw enemy2 on the platform
    enemy = arcade.Sprite(":resources:images/enemies/wormGreen.png", SPRITE_SCALING)

    enemy.bottom = SPRITE_SIZE * 4
    enemy.left = SPRITE_SIZE * 4

    # Set boundaries for enemy
    enemy.boundary_right = SPRITE_SIZE * 8
    enemy.boundary_left = SPRITE_SIZE * 3
    enemy.change_x = 2
    room.enemy_list.append(enemy)

    # Set up coins
    for pos in [[128, 96], [418, 300], [670, 150]]:
        goal = arcade.Sprite(":resources:images/items/coinGold.png", SPRITE_SCALING)
        goal.center_x = pos[0]
        goal.center_y = pos[1]
        room.goal_list.append(goal)
        room.numCoins += 1

    # Set up checkpoint/level clear
    flag = arcade.Sprite(":resources:images/tiles/signExit.png", SPRITE_SCALING)
    flag.center_x = 770
    flag.center_y = 96
    room.victory_sprite.append(flag)

    # Load the background image for this level.
    room.background = arcade.load_texture(":resources:images/backgrounds/abstract_1.jpg")

    return room


def setup_room_2():
    room = Room()
    room.wall_list = arcade.SpriteList(use_spatial_hash=True)
    room.enemy_list = arcade.SpriteList()
    room.goal_list = arcade.SpriteList(use_spatial_hash=True)
    room.victory_sprite = arcade.SpriteList(use_spatial_hash=True)

    # Set up walls
    for y in range(0, 800, 200):
        for x in range(100, 700, 64):
            wall = arcade.Sprite(":resources:images/tiles/boxCrate_double.png", SPRITE_SCALING)
            wall.center_x = x
            wall.center_y = y
            room.wall_list.append(wall)

    for pos in [[35, 40], [765, 80], [35, 280], [765, 480]]:
        wall = arcade.Sprite(":resources:images/tiles/grassHalf.png", SPRITE_SCALING)
        wall.center_x = pos[0]
        wall.center_y = pos[1]
        room.wall_list.append(wall)

    # Create the coins
    for i in range(50):

        # Create the coin instance
        # Coin image from kenney.nl
        goal = arcade.Sprite(":resources:images/items/coinGold.png", SPRITE_SCALING_COIN)

        # Boolean variable if we successfully placed the coin
        coin_placed_successfully = False

        # Keep trying until success
        while not coin_placed_successfully:
            # Position the coin
            goal.center_x = random.randrange(100, 700)
            goal.center_y = random.randrange(SCREEN_HEIGHT)

            # See if the coin is hitting a wall
            wall_hit_list = arcade.check_for_collision_with_list(goal, room.wall_list)

            # See if the coin is hitting another coin
            coin_hit_list = arcade.check_for_collision_with_list(goal, room.goal_list)

            if len(wall_hit_list) == 0 and len(coin_hit_list) == 0:
                coin_placed_successfully = True

        # Add the coin to the lists
        room.goal_list.append(goal)
        room.numCoins += 1

    # Draw an enemy1
    enemy = arcade.Sprite(":resources:images/enemies/fly.png", SPRITE_SCALING_COIN)

    enemy.bottom = SPRITE_SIZE
    enemy.left = SPRITE_SIZE * 2

    enemy.boundary_right = SPRITE_SIZE * 8 + 60
    enemy.boundary_left = SPRITE_SIZE * 1 + 60
    enemy.change_x = 3
    room.enemy_list.append(enemy)

    # Draw a enemy2
    enemy = arcade.Sprite(":resources:images/enemies/fly.png", SPRITE_SCALING_COIN)

    enemy.bottom = SPRITE_SIZE * 4
    enemy.left = SPRITE_SIZE * 4

    enemy.boundary_right = SPRITE_SIZE * 8
    enemy.boundary_left = SPRITE_SIZE * 3
    enemy.change_x = 4
    room.enemy_list.append(enemy)

    # Draw a enemy3
    enemy = arcade.Sprite(":resources:images/enemies/fly.png", SPRITE_SCALING_COIN)

    enemy.bottom = SPRITE_SIZE * 7.2
    enemy.left = SPRITE_SIZE * 4

    enemy.boundary_right = SPRITE_SIZE * 8 + 80
    enemy.boundary_left = SPRITE_SIZE * 3
    enemy.change_x = 4.8
    room.enemy_list.append(enemy)

    # Draw victory point
    flag = arcade.Sprite(":resources:images/tiles/signExit.png", SPRITE_SCALING)
    flag.center_x = 765
    flag.center_y = 545
    room.victory_sprite.append(flag)

    # Load the background image for this level.
    room.background = arcade.load_texture(":resources:images/backgrounds/abstract_1.jpg")

    return room


class MainGame(arcade.Window):

    def __init__(self):
        super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)

        file_path = os.path.dirname(os.path.abspath(__file__))
        os.chdir(file_path)

        # Sprites and set up player
        self.player_list = self.rooms = self.player_sprite = self.physics_engine = None
        self.current_room = self.view_left = self.view_bottom = self.collectedCoins = 0
        self.game_over = False

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

    def setup(self):
        """ Set up the game and initialize the variables. """

        # -- Set up the player
        self.player_sprite = arcade.Sprite(":resources:images/animated_characters/female_person/femalePerson_idle.png",
                                           SPRITE_SCALING)

        # list of rooms
        self.rooms = []

        # Create the rooms
        room = setup_room_1()
        self.rooms.append(room)

        room = setup_room_2()
        self.rooms.append(room)

        # Starting room number
        self.current_room = 0
        
        # Player start position according to room number
        if self.current_room == 0:
            self.player_sprite.center_x = 64
            self.player_sprite.center_y = 270
        elif self.current_room == 1:
            self.player_sprite.center_x = 35
            self.player_sprite.center_y = 55
        self.player_list = arcade.SpriteList()
        self.player_list.append(self.player_sprite)

        # Create a physics engine
        self.physics_engine = arcade.PhysicsEnginePlatformer(self.player_sprite, self.rooms[self.current_room].wall_list
                                                             )

        # Set the background color
        arcade.set_background_color(arcade.color.AMAZON)

    def on_draw(self):
       
        arcade.start_render()

        self.rooms[self.current_room].wall_list.draw()
        self.rooms[self.current_room].goal_list.draw()
        self.rooms[self.current_room].enemy_list.draw()
        self.rooms[self.current_room].victory_sprite.draw()

        # Draw all the sprites.
        self.player_list.draw()

    def on_key_press(self, key, modifiers):
        if key == arcade.key.UP:
            if self.physics_engine.can_jump():
                self.player_sprite.change_y = JUMP_SPEED
        elif key == arcade.key.LEFT:
            self.player_sprite.change_x = -MOVEMENT_SPEED
        elif key == arcade.key.RIGHT:
            self.player_sprite.change_x = MOVEMENT_SPEED

    def on_key_release(self, key, modifiers):
        if key == arcade.key.LEFT or key == arcade.key.RIGHT:
            self.player_sprite.change_x = 0

    def on_update(self, delta_time):
        
        if not self.game_over:
            # Move the enemies
            self.rooms[self.current_room].enemy_list.update()

            # Check each enemy
            for enemy in self.rooms[self.current_room].enemy_list:
                # If the enemy hit a wall, reverse
                if len(arcade.check_for_collision_with_list(enemy, self.rooms[self.current_room].wall_list)) > 0:
                    enemy.change_x *= -1
                # If the enemy hit the left boundary, reverse
                elif enemy.boundary_left is not None and enemy.left < enemy.boundary_left:
                    enemy.change_x *= -1
                # If the enemy hit the right boundary, reverse
                elif enemy.boundary_right is not None and enemy.right > enemy.boundary_right:
                    enemy.change_x *= -1

            # Update the player using the physics engine
            self.physics_engine.update()

            # See if we hit any coins
            goal_hit_list = arcade.check_for_collision_with_list(self.player_sprite,
                                                                 self.rooms[self.current_room].goal_list)

            # Loop through each coin we hit (if any) and remove it
            for goal in goal_hit_list:
                # Remove the coin
                goal.remove_from_sprite_lists()
                # Play a sound
                arcade.play_sound(self.collect_goal_sound)
                # Count number of coins collected
                self.collectedCoins += 1

            if self.player_sprite.center_x <= -10 or self.player_sprite.center_x >= 800:
                self.player_sprite.change_x = 0
                self.player_sprite.change_y = 0
                self.player_sprite.center_x = 64
                self.player_sprite.center_y = 270

            # See if the player hit a worm
            if len(arcade.check_for_collision_with_list(self.player_sprite,
                                                        self.rooms[self.current_room].enemy_list)) > 0:
                self.game_over = True

            # See if the player hit the flag. If so, progress to round 2 ??????
            if arcade.check_for_collision_with_list(self.player_sprite,
                                                    self.rooms[
                                                        self.current_room].victory_sprite) and self.collectedCoins == \
                    self.rooms[self.current_room].numCoins:
                self.game_over = True
                self.current_room += 1


def main():
    window = MainGame()
    window.setup()
    arcade.run()


if __name__ == "__main__":
    main()

如果我从 def 更新中删除 self.gameover= True,程序会转换到房间 2,但精灵未正确加载且玩家位置未重置。

  • self.game_over = True替换为self.setup()
  • 将房间创建从 setup 移至 __init__

更新的脚本:

import arcade
import os
import random

SPRITE_SCALING = 0.5
SPRITE_SCALING_COIN = 0.3
SPRITE_NATIVE_SIZE = 128
SPRITE_SIZE = int(SPRITE_NATIVE_SIZE * SPRITE_SCALING)

SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
SCREEN_TITLE = "Help Nick Adams!"

# Physics
MOVEMENT_SPEED = 5
JUMP_SPEED = 12
GRAVITY = 0.5


class Room:
    # Class to hold info about rooms/levels

    def __init__(self):
        self.wall_list = self.goal_list = self.enemy_list = self.victory_sprite = None
        self.collectedCoins = 0
        self.numCoins = 0


def setup_room_1():
    room = Room()
    room.wall_list = arcade.SpriteList(use_spatial_hash=True)
    room.enemy_list = arcade.SpriteList()
    room.goal_list = arcade.SpriteList(use_spatial_hash=True)
    room.victory_sprite = arcade.SpriteList(use_spatial_hash=True)

    # Draw platforms and ground
    for x in range(0, SCREEN_WIDTH, SPRITE_SIZE):
        wall = arcade.Sprite(":resources:images/tiles/grassMid.png", SPRITE_SCALING)

        wall.bottom = 0
        wall.left = x
        room.wall_list.append(wall)

    for x in range(SPRITE_SIZE * 3, SPRITE_SIZE * 8, SPRITE_SIZE):
        wall = arcade.Sprite(":resources:images/tiles/grassMid.png", SPRITE_SCALING)

        wall.bottom = SPRITE_SIZE * 3
        wall.left = x
        room.wall_list.append(wall)

    # Draw the crates
    for x in range(0, SCREEN_WIDTH, SPRITE_SIZE * 5):
        wall = arcade.Sprite(":resources:images/tiles/boxCrate_double.png", SPRITE_SCALING)

        wall.bottom = SPRITE_SIZE
        wall.left = x
        room.wall_list.append(wall)

    # Draw an enemy 1
    enemy = arcade.Sprite(":resources:images/enemies/wormGreen.png", SPRITE_SCALING)

    enemy.bottom = SPRITE_SIZE
    enemy.left = SPRITE_SIZE * 2

    enemy.change_x = 2
    room.enemy_list.append(enemy)

    # -- Draw enemy2 on the platform
    enemy = arcade.Sprite(":resources:images/enemies/wormGreen.png", SPRITE_SCALING)

    enemy.bottom = SPRITE_SIZE * 4
    enemy.left = SPRITE_SIZE * 4

    # Set boundaries for enemy
    enemy.boundary_right = SPRITE_SIZE * 8
    enemy.boundary_left = SPRITE_SIZE * 3
    enemy.change_x = 2
    room.enemy_list.append(enemy)

    # Set up coins
    for pos in [[128, 96], [418, 300], [670, 150]]:
        goal = arcade.Sprite(":resources:images/items/coinGold.png", SPRITE_SCALING)
        goal.center_x = pos[0]
        goal.center_y = pos[1]
        room.goal_list.append(goal)
        room.numCoins += 1

    # Set up checkpoint/level clear
    flag = arcade.Sprite(":resources:images/tiles/signExit.png", SPRITE_SCALING)
    flag.center_x = 770
    flag.center_y = 96
    room.victory_sprite.append(flag)

    # Load the background image for this level.
    room.background = arcade.load_texture(":resources:images/backgrounds/abstract_1.jpg")

    return room


def setup_room_2():
    room = Room()
    room.wall_list = arcade.SpriteList(use_spatial_hash=True)
    room.enemy_list = arcade.SpriteList()
    room.goal_list = arcade.SpriteList(use_spatial_hash=True)
    room.victory_sprite = arcade.SpriteList(use_spatial_hash=True)

    # Set up walls
    for y in range(0, 800, 200):
        for x in range(100, 700, 64):
            wall = arcade.Sprite(":resources:images/tiles/boxCrate_double.png", SPRITE_SCALING)
            wall.center_x = x
            wall.center_y = y
            room.wall_list.append(wall)

    for pos in [[35, 40], [765, 80], [35, 280], [765, 480]]:
        wall = arcade.Sprite(":resources:images/tiles/grassHalf.png", SPRITE_SCALING)
        wall.center_x = pos[0]
        wall.center_y = pos[1]
        room.wall_list.append(wall)

    # Create the coins
    for i in range(50):

        # Create the coin instance
        # Coin image from kenney.nl
        goal = arcade.Sprite(":resources:images/items/coinGold.png", SPRITE_SCALING_COIN)

        # Boolean variable if we successfully placed the coin
        coin_placed_successfully = False

        # Keep trying until success
        while not coin_placed_successfully:
            # Position the coin
            goal.center_x = random.randrange(100, 700)
            goal.center_y = random.randrange(SCREEN_HEIGHT)

            # See if the coin is hitting a wall
            wall_hit_list = arcade.check_for_collision_with_list(goal, room.wall_list)

            # See if the coin is hitting another coin
            coin_hit_list = arcade.check_for_collision_with_list(goal, room.goal_list)

            if len(wall_hit_list) == 0 and len(coin_hit_list) == 0:
                coin_placed_successfully = True

        # Add the coin to the lists
        room.goal_list.append(goal)
        room.numCoins += 1

    # Draw an enemy1
    enemy = arcade.Sprite(":resources:images/enemies/fly.png", SPRITE_SCALING_COIN)

    enemy.bottom = SPRITE_SIZE
    enemy.left = SPRITE_SIZE * 2

    enemy.boundary_right = SPRITE_SIZE * 8 + 60
    enemy.boundary_left = SPRITE_SIZE * 1 + 60
    enemy.change_x = 3
    room.enemy_list.append(enemy)

    # Draw a enemy2
    enemy = arcade.Sprite(":resources:images/enemies/fly.png", SPRITE_SCALING_COIN)

    enemy.bottom = SPRITE_SIZE * 4
    enemy.left = SPRITE_SIZE * 4

    enemy.boundary_right = SPRITE_SIZE * 8
    enemy.boundary_left = SPRITE_SIZE * 3
    enemy.change_x = 4
    room.enemy_list.append(enemy)

    # Draw a enemy3
    enemy = arcade.Sprite(":resources:images/enemies/fly.png", SPRITE_SCALING_COIN)

    enemy.bottom = SPRITE_SIZE * 7.2
    enemy.left = SPRITE_SIZE * 4

    enemy.boundary_right = SPRITE_SIZE * 8 + 80
    enemy.boundary_left = SPRITE_SIZE * 3
    enemy.change_x = 4.8
    room.enemy_list.append(enemy)

    # Draw victory point
    flag = arcade.Sprite(":resources:images/tiles/signExit.png", SPRITE_SCALING)
    flag.center_x = 765
    flag.center_y = 545
    room.victory_sprite.append(flag)

    # Load the background image for this level.
    room.background = arcade.load_texture(":resources:images/backgrounds/abstract_1.jpg")

    return room


class MainGame(arcade.Window):

    def __init__(self):
        super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)

        file_path = os.path.dirname(os.path.abspath(__file__))
        os.chdir(file_path)

        # Sprites and set up player
        self.player_list = self.rooms = self.player_sprite = self.physics_engine = None
        self.current_room = self.view_left = self.view_bottom = self.collectedCoins = 0
        self.game_over = False

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

        # Starting room number
        self.current_room = 0

        # list of rooms
        self.rooms = []

        # Create the rooms
        room = setup_room_1()
        self.rooms.append(room)

        room = setup_room_2()
        self.rooms.append(room)

    def setup(self):
        """ Set up the game and initialize the variables. """

        # -- Set up the player
        self.player_sprite = arcade.Sprite(":resources:images/animated_characters/female_person/femalePerson_idle.png", SPRITE_SCALING)

        # Player start position according to room number
        if self.current_room == 0:
            self.player_sprite.center_x = 64
            self.player_sprite.center_y = 270
        elif self.current_room == 1:
            self.player_sprite.center_x = 35
            self.player_sprite.center_y = 55
        self.player_list = arcade.SpriteList()
        self.player_list.append(self.player_sprite)

        # Create a physics engine
        self.physics_engine = arcade.PhysicsEnginePlatformer(self.player_sprite, self.rooms[self.current_room].wall_list)

        # Set the background color
        arcade.set_background_color(arcade.color.AMAZON)

    def on_draw(self):

        arcade.start_render()

        self.rooms[self.current_room].wall_list.draw()
        self.rooms[self.current_room].goal_list.draw()
        self.rooms[self.current_room].enemy_list.draw()
        self.rooms[self.current_room].victory_sprite.draw()

        # Draw all the sprites.
        self.player_list.draw()

    def on_key_press(self, key, modifiers):
        if key == arcade.key.UP:
            if self.physics_engine.can_jump():
                self.player_sprite.change_y = JUMP_SPEED
        elif key == arcade.key.LEFT:
            self.player_sprite.change_x = -MOVEMENT_SPEED
        elif key == arcade.key.RIGHT:
            self.player_sprite.change_x = MOVEMENT_SPEED

    def on_key_release(self, key, modifiers):
        if key == arcade.key.LEFT or key == arcade.key.RIGHT:
            self.player_sprite.change_x = 0

    def on_update(self, delta_time):

        if not self.game_over:
            # Move the enemies
            self.rooms[self.current_room].enemy_list.update()

            # Check each enemy
            for enemy in self.rooms[self.current_room].enemy_list:
                # If the enemy hit a wall, reverse
                if len(arcade.check_for_collision_with_list(enemy, self.rooms[self.current_room].wall_list)) > 0:
                    enemy.change_x *= -1
                # If the enemy hit the left boundary, reverse
                elif enemy.boundary_left is not None and enemy.left < enemy.boundary_left:
                    enemy.change_x *= -1
                # If the enemy hit the right boundary, reverse
                elif enemy.boundary_right is not None and enemy.right > enemy.boundary_right:
                    enemy.change_x *= -1

            # Update the player using the physics engine
            self.physics_engine.update()

            # See if we hit any coins
            goal_hit_list = arcade.check_for_collision_with_list(self.player_sprite, self.rooms[self.current_room].goal_list)

            # Loop through each coin we hit (if any) and remove it
            for goal in goal_hit_list:
                # Remove the coin
                goal.remove_from_sprite_lists()
                # Play a sound
                arcade.play_sound(self.collect_goal_sound)
                # Count number of coins collected
                self.collectedCoins += 1

            if self.player_sprite.center_x <= -10 or self.player_sprite.center_x >= 800:
                self.player_sprite.change_x = 0
                self.player_sprite.change_y = 0
                self.player_sprite.center_x = 64
                self.player_sprite.center_y = 270

            # See if the player hit a worm
            if len(arcade.check_for_collision_with_list(self.player_sprite, self.rooms[self.current_room].enemy_list)) > 0:
                self.game_over = True

            # See if the player hit the flag. If so, progress to round 2 ??????
            if arcade.check_for_collision_with_list(self.player_sprite, self.rooms[self.current_room].victory_sprite) and self.collectedCoins == self.rooms[self.current_room].numCoins:
                # self.game_over = True
                self.current_room += 1
                self.setup()


def main():
    window = MainGame()
    window.setup()
    arcade.run()


if __name__ == "__main__":
    main()