第3步-多款雪碧和SpriteList#

到目前为止,我们的游戏进行得很顺利,我们有一个角色出现在屏幕上!如果我们的角色有一个可以生活的世界,那不是很好吗?为了做到这一点,我们需要画更多的精灵。在本章中,我们将探索SpriteList,这是Arade提供的一次绘制大量Sprite的类。

最后,我们会得到这样的结果:

../../_images/title_03.png

SpriteList#

arcade.SpriteList 存在以一次绘制所有精灵的集合。例如,假设您要绘制100,000个长方体雪碧。如果没有SpriteList,您将不得不将所有Sprite放到一个列表中,然后对调用 draw() 在每一个精灵身上。

这种方法表现得极为糟糕。相反,您可以将所有框添加到 arcade.SpriteList 然后绘制SpriteList。这样做,您可以绘制所有100,000个精灵,其成本与绘制一个精灵的成本大致相同。

备注

这是因为Arade是一个大量基于GPU的库。GPU真的很擅长分批处理。这意味着我们可以将有关精灵的所有信息发送到GPU,然后告诉它一次绘制所有精灵。然而,如果我们一次只画一个精灵,那么我们每次都必须从我们的CPU到我们的GPU进行往返。

即使只绘制一个Sprite,也应该为其创建SpriteList。除了小调试之外,绘制单个Sprite永远不会比将其添加到SpriteList更好。事实上,打电话给 draw() 在Sprite上,只需在内部创建一个SpriteList来绘制该Sprite。

让我们继续为我们的玩家在我们的 __init__ 函数,并将玩家添加到其中。

self.player_list = arcade.SpriteList()
self.player_list.append(self.player_sprite)

然后在我们的 on_draw 函数,我们可以为角色绘制SpriteList,而不是直接绘制Sprite:

self.player_list.draw()

现在,让我们尝试为我们的角色构建一个世界。为此,我们将为要绘制的对象创建一个新的SpriteList,我们可以在 __init__ 功能。

self.wall_list = arcade.SpriteList(use_spatial_hash=True)

在这段代码中有一些需要解包的地方。让我们来解决每个问题:

  1. 为什么不使用与我们的播放器相同的SpriteList,为什么将其命名为WALLS?

    最终,我们需要在角色和这些对象之间进行碰撞检测。除了绘制之外,SpriteList还用作碰撞检测的实用程序。例如,您可以检查两个SpriteList之间的冲突,或将SpriteList传递到几个物理引擎中。我们将在后面的章节中探讨这些主题。

  2. 是什么 use_spatial_hash

    这也用于碰撞检测。空间散列是一种特殊的算法,它将使其性能更高,代价是移动精灵的成本更高。您经常会在预计不会移动太多的SpriteList上看到此选项,例如墙或楼板。

使用新创建的SpriteList,让我们继续向其中添加一些对象。我们可以将这些行添加到我们的 __init__ 功能。

for x in range(0, 1250, 64):
    wall = arcade.Sprite(":resources:images/tiles/grassMid.png", TILE_SCALING)
    wall.center_x = x
    wall.center_y = 32
    self.wall_list.append(wall)

coordinate_list = [[512, 96], [256, 96], [768, 96]]
for coordinate in coordinate_list:
    wall = arcade.Sprite(
        ":resources:images/tiles/boxCrate_double.png", scale=0.5
    )
    wall.position = coordinate
    self.wall_list.append(wall)

在这些行中,我们将一些草和一些板条箱添加到SpriteList中。

对于地面,我们使用的是Python的 range 函数在X位置列表上迭代,这将给我们一条水平线的Sprite。对于这些框,我们将它们插入列表中的指定坐标。

我们还在做一些新的事情 arcade.Sprite 创造。首先,我们直接传递图像文件,而不是首先创建纹理。这最终是做同样的事情,我们只是不是自己管理纹理,而是让Arade来处理它。我们还为这些精灵增加了一个比例。为了好玩,你可以去掉刻度,看看图像会变得更大。

最后,为了绘制我们的新世界,我们所需要做的就是绘制墙的SpriteList on_draw

self.wall_list.draw()

源代码#

03_More_Sprite-带有SpriteList的多个Sprite#
 1"""
 2Platformer Game
 3
 4python -m arcade.examples.platform_tutorial.03_more_sprites
 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
17class MyGame(arcade.Window):
18    """
19    Main application class.
20    """
21
22    def __init__(self):
23
24        # Call the parent class and set up the window
25        super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
26
27        # Variable to hold our texture for our player
28        self.player_texture = arcade.load_texture(":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png")
29
30        # Separate variable that holds the player sprite
31        self.player_sprite = arcade.Sprite(self.player_texture)
32        self.player_sprite.center_x = 64
33        self.player_sprite.center_y = 128
34
35        # SpriteList for our player
36        self.player_list = arcade.SpriteList()
37        self.player_list.append(self.player_sprite)
38
39        # SpriteList for our boxes and ground
40        # Putting our ground and box Sprites in the same SpriteList
41        # will make it easier to perform collision detection against
42        # them later on. Setting the spatial hash to True will make
43        # collision detection much faster if the objects in this
44        # SpriteList do not move.
45        self.wall_list = arcade.SpriteList(use_spatial_hash=True)
46
47        # Create the ground
48        # This shows using a loop to place multiple sprites horizontally
49        for x in range(0, 1250, 64):
50            wall = arcade.Sprite(":resources:images/tiles/grassMid.png", scale=0.5)
51            wall.center_x = x
52            wall.center_y = 32
53            self.wall_list.append(wall)
54
55        # Put some crates on the ground
56        # This shows using a coordinate list to place sprites
57        coordinate_list = [[512, 96], [256, 96], [768, 96]]
58
59        for coordinate in coordinate_list:
60            # Add a crate on the ground
61            wall = arcade.Sprite(
62                ":resources:images/tiles/boxCrate_double.png", scale=0.5
63            )
64            wall.position = coordinate
65            self.wall_list.append(wall)
66
67        self.background_color = arcade.csscolor.CORNFLOWER_BLUE
68
69    def setup(self):
70        """Set up the game here. Call this function to restart the game."""
71        pass
72
73    def on_draw(self):
74        """Render the screen."""
75
76        # Clear the screen to the background color
77        self.clear()
78
79        # Draw our sprites
80        self.player_list.draw()
81        self.wall_list.draw()
82
83
84def main():
85    """Main function"""
86    window = MyGame()
87    window.setup()
88    arcade.run()
89
90
91if __name__ == "__main__":
92    main()

备注

一旦您准备好并运行了代码,请尝试以下操作:

  • 看看是否可以使用SpriteList更改所有框和地面的颜色

  • 尝试使SpriteList不可见

运行本章#

python -m arcade.examples.platform_tutorial.03_more_sprites