22. Sprites bewegen¶
Wie bringen wir Sprites dazu, sich zu bewegen?
Um das Verhalten unseres Sprites anzupassen, müssen wir unsere eigene Kindklasse von der Klasse Sprite
ableiten. Das ist einfach:
class Coin(arcade.Sprite):
Wir müssen jedem Sprite eine update
-Methode zur Verfügung stellen. Die Methode update
wird automatisch aufgerufen, um die Position des Sprites zu aktualisieren.
class Coin(arcade.Sprite):
def update(self):
# Code to move goes here
Warte! Wir haben eine neue Klasse namens Coin
, aber wir benutzen sie nicht. Suche in unserem Originalcode diese Zeile:
coin = arcade.Sprite("coin_01.png", COIN_SPRITE_SCALING)
Siehe, wie es ein Exemplar von Sprite
erstellt? Wir möchten stattdessen ein Exemplar unserer neuen Coin
-Klasse erstellen:
coin = Coin("coin_01.png", COIN_SPRITE_SCALING)
Wie bringen wir nun die Münze dazu, sich zu bewegen?
22.1. Sprites nach unten verschieben¶
Damit die Sprites auf dem Bildschirm „herunterfallen“, müssen wir ihre y-Position verkleinern. Das ist einfach. Überschreibe update
im Sprite und ziehe 1
von y
in jedem Frame ab:
class Coin(arcade.Sprite):
def update(self):
self.center_y -= 1
Als nächstes erstelle ein Exemplar der Klasse Coin
anstelle einer Klasse Sprite
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | """ Sprite Sample Program """
import random
import arcade
# --- Constants ---
SPRITE_SCALING_PLAYER = 0.5
SPRITE_SCALING_COIN = 0.2
COIN_COUNT = 50
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
class Coin(arcade.Sprite):
def update(self):
self.center_y -= 1
class MyGame(arcade.Window):
""" Our custom Window Class"""
def __init__(self):
""" Initializer """
# Call the parent class initializer
super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, "Sprite Example")
# Variables that will hold sprite lists
self.player_list = None
self.coin_list = None
# Set up the player info
self.player_sprite = None
self.score = 0
# Don't show the mouse cursor
self.set_mouse_visible(False)
arcade.set_background_color(arcade.color.AMAZON)
def setup(self):
""" Set up the game and initialize the variables. """
# Sprite lists
self.player_list = arcade.SpriteList()
self.coin_list = arcade.SpriteList()
# Score
self.score = 0
# Set up the player
# Character image from kenney.nl
self.player_sprite = arcade.Sprite("character.png", SPRITE_SCALING_PLAYER)
self.player_sprite.center_x = 50
self.player_sprite.center_y = 50
self.player_list.append(self.player_sprite)
# Create the coins
for i in range(COIN_COUNT):
# Create the coin instance
# Coin image from kenney.nl
coin = Coin("coin_01.png", SPRITE_SCALING_COIN)
# Position the coin
coin.center_x = random.randrange(SCREEN_WIDTH)
coin.center_y = random.randrange(SCREEN_HEIGHT)
# Add the coin to the lists
self.coin_list.append(coin)
def on_draw(self):
""" Draw everything """
arcade.start_render()
self.coin_list.draw()
self.player_list.draw()
# Put the text on the screen.
output = f"Score: {self.score}"
arcade.draw_text(output, 10, 20, arcade.color.WHITE, 14)
def on_mouse_motion(self, x, y, dx, dy):
""" Handle Mouse Motion """
# Move the center of the player sprite to match the mouse x, y
self.player_sprite.center_x = x
self.player_sprite.center_y = y
def update(self, delta_time):
""" Movement and game logic """
# Call update on all sprites (The sprites don't do much in this
# example though.)
self.coin_list.update()
# Generate a list of all sprites that collided with the player.
hit_list = arcade.check_for_collision_with_list(self.player_sprite,
self.coin_list)
# Loop through each colliding sprite, remove it, and add to the score.
for coin in hit_list:
coin.remove_from_sprite_lists()
self.score += 1
def main():
""" Main method """
window = MyGame()
window.setup()
arcade.run()
if __name__ == "__main__":
main()
|
Dadurch bewegen sich die Münzen nach unten. Sobald sie sich vom Bildschirm entfernen, begeben sie sich weiter in ein Land mit negativen Koordinaten. Wir können sie nicht mehr sehen. Traurig.

Münzen bewegen sich nach unten¶
22.1.1. Nach oben zurücksetzen¶
Wir können das umgehen, indem wir die Münzen wieder nach oben setzen. So wird es gemacht:
class Coin(arcade.Sprite):
def update(self):
self.center_y -= 1
# See if we went off-screen
if self.center_y < 0:
self.center_y = SCREEN_HEIGHT
Das ist aber nicht perfekt. Denn wenn Ihre Augen schnell sind, können Sie sehen, wie die Münze beim Berühren des unteren Rands plötzlich verschwindet und oben herein ploppt. Es läuft nicht glatt ab. Dies liegt daran, dass wir sie nach oben verschieben, wenn sich die Mitte der Münze am unteren Rand befindet. Nicht die Oberseite der Münze ist herausgerutscht.
Es gibt ein paar Möglichkeiten, wie wir das erreichen können. Hier ist eine. Wir werden bei -20 anstelle von 0 prüfen. Solange der Münzradius 20 oder weniger beträgt, passt das.
class Coin(arcade.Sprite):
def update(self):
self.center_y -= 1
# See if we went off-screen
if self.center_y < -20:
self.center_y = SCREEN_HEIGHT + 20
Es geht auch anders. Neben center_y
haben Sprites andere Attribute, die in diesen Fällen nützlich sind. Das sind top
, bottom
, left
und right
. Also können wir das so umsetzen:
class Coin(arcade.Sprite):
def update(self):
self.center_y -= 1
# See if we went off-screen
if self.top < 0:
self.bottom = SCREEN_HEIGHT
Auf diese Weise können die Münzen flüssig auf dem Bildschirm verschoben werden. Aber da sie oben an der gleichen x-Position wieder auftauchen, wiederholen sich die Muster. Siehe die Abbildung unten:

Münzen, die sich in einem Muster wiederholen¶
Stattdessen können wir es ein wenig zufälliger gestalten:
def update(self):
# Move the coin
self.center_y -= 1
# See if the coin has fallen off the bottom of the screen.
# If so, reset it.
if self.top < 0:
# Reset the coin to a random spot above the screen
self.center_y = random.randrange(SCREEN_HEIGHT + 20,
SCREEN_HEIGHT + 100)
self.center_x = random.randrange(SCREEN_WIDTH)
22.1.2. Nie endende Münzen¶
Das funktioniert, aber wenn wir alle Münzen eingesammelt haben, sind wir fertig. Was wäre, wenn es ein nie endender Strom von Münzen wäre? Anstatt die Münze zu „vernichten“, setzen wir sie auf den oberen Bildschirmrand zurück.
def update(self, delta_time):
""" Movement and game logic """
self.coin_list.update()
hit_list = arcade.check_for_collision_with_list(self.player_sprite, self.coin_list)
for coin in hit_list:
self.score += 1
# Reset the coin to a random spot above the screen
coin.center_y = random.randrange(SCREEN_HEIGHT + 20,
SCREEN_HEIGHT + 100)
coin.center_x = random.randrange(SCREEN_WIDTH)
Wir können sogar diesen gemeinsamen Code nehmen und ihn in eine Methode verschieben. Hier ist das vollständiges Beispiel:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | """ Sprite Sample Program """
import random
import arcade
# --- Constants ---
SPRITE_SCALING_PLAYER = 0.5
SPRITE_SCALING_COIN = 0.2
COIN_COUNT = 50
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
class Coin(arcade.Sprite):
"""
This class represents the coins on our screen. It is a child class of
the arcade library's "Sprite" class.
"""
def reset_pos(self):
# Reset the coin to a random spot above the screen
self.center_y = random.randrange(SCREEN_HEIGHT + 20,
SCREEN_HEIGHT + 100)
self.center_x = random.randrange(SCREEN_WIDTH)
def update(self):
# Move the coin
self.center_y -= 1
# See if the coin has fallen off the bottom of the screen.
# If so, reset it.
if self.top < 0:
self.reset_pos()
class MyGame(arcade.Window):
""" Our custom Window Class"""
def __init__(self):
""" Initializer """
# Call the parent class initializer
super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, "Sprite Example")
# Variables that will hold sprite lists
self.player_list = None
self.coin_list = None
# Set up the player info
self.player_sprite = None
self.score = 0
# Don't show the mouse cursor
self.set_mouse_visible(False)
arcade.set_background_color(arcade.color.AMAZON)
def setup(self):
""" Set up the game and initialize the variables. """
# Sprite lists
self.player_list = arcade.SpriteList()
self.coin_list = arcade.SpriteList()
# Score
self.score = 0
# Set up the player
# Character image from kenney.nl
self.player_sprite = arcade.Sprite("character.png", SPRITE_SCALING_PLAYER)
self.player_sprite.center_x = 50
self.player_sprite.center_y = 50
self.player_list.append(self.player_sprite)
# Create the coins
for i in range(COIN_COUNT):
# Create the coin instance
# Coin image from kenney.nl
coin = Coin("coin_01.png", SPRITE_SCALING_COIN)
# Position the coin
coin.center_x = random.randrange(SCREEN_WIDTH)
coin.center_y = random.randrange(SCREEN_HEIGHT)
# Add the coin to the lists
self.coin_list.append(coin)
def on_draw(self):
""" Draw everything """
arcade.start_render()
self.coin_list.draw()
self.player_list.draw()
# Put the text on the screen.
output = f"Score: {self.score}"
arcade.draw_text(output, 10, 20, arcade.color.WHITE, 14)
def on_mouse_motion(self, x, y, dx, dy):
""" Handle Mouse Motion """
# Move the center of the player sprite to match the mouse x, y
self.player_sprite.center_x = x
self.player_sprite.center_y = y
def update(self, delta_time):
""" Movement and game logic """
# Call update on all sprites (The sprites don't do much in this
# example though.)
self.coin_list.update()
# Generate a list of all sprites that collided with the player.
hit_list = arcade.check_for_collision_with_list(self.player_sprite,
self.coin_list)
# Loop through each colliding sprite, remove it, and add to the score.
for coin in hit_list:
coin.reset_pos()
self.score += 1
def main():
""" Main method """
window = MyGame()
window.setup()
arcade.run()
if __name__ == "__main__":
main()
|
22.2. Abprallende Münzen¶
Anstatt immer eins von y-Koordinate abzuziehen und die Sprites nach unten zu bewegen, können wir einen Richtungsvektor mit change_x
und change_y
beibehalten. Mit diesem können wir das Sprite über den Bildschirm springen lassen:

Herum hüpfende Münzen¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | """ Sprite Sample Program """
import random
import arcade
# --- Constants ---
SPRITE_SCALING_PLAYER = 0.5
SPRITE_SCALING_COIN = 0.2
COIN_COUNT = 50
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
class Coin(arcade.Sprite):
def __init__(self, filename, sprite_scaling):
super().__init__(filename, sprite_scaling)
self.change_x = 0
self.change_y = 0
def update(self):
# Move the coin
self.center_x += self.change_x
self.center_y += self.change_y
# If we are out-of-bounds, then 'bounce'
if self.left < 0:
self.change_x *= -1
if self.right > SCREEN_WIDTH:
self.change_x *= -1
if self.bottom < 0:
self.change_y *= -1
if self.top > SCREEN_HEIGHT:
self.change_y *= -1
class MyGame(arcade.Window):
""" Our custom Window Class"""
def __init__(self):
""" Initializer """
# Call the parent class initializer
super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, "Sprite Example")
# Variables that will hold sprite lists
self.player_list = None
self.coin_list = None
# Set up the player info
self.player_sprite = None
self.score = 0
# Don't show the mouse cursor
self.set_mouse_visible(False)
arcade.set_background_color(arcade.color.AMAZON)
def setup(self):
""" Set up the game and initialize the variables. """
# Sprite lists
self.player_list = arcade.SpriteList()
self.coin_list = arcade.SpriteList()
# Score
self.score = 0
# Set up the player
# Character image from kenney.nl
self.player_sprite = arcade.Sprite("character.png", SPRITE_SCALING_PLAYER)
self.player_sprite.center_x = 50
self.player_sprite.center_y = 50
self.player_list.append(self.player_sprite)
# Create the coins
for i in range(COIN_COUNT):
# Create the coin instance
# Coin image from kenney.nl
coin = Coin("coin_01.png", SPRITE_SCALING_COIN)
# Position the coin
coin.center_x = random.randrange(SCREEN_WIDTH)
coin.center_y = random.randrange(SCREEN_HEIGHT)
coin.change_x = random.randrange(-3, 4)
coin.change_y = random.randrange(-3, 4)
# Add the coin to the lists
self.coin_list.append(coin)
def on_draw(self):
""" Draw everything """
arcade.start_render()
self.coin_list.draw()
self.player_list.draw()
# Put the text on the screen.
output = f"Score: {self.score}"
arcade.draw_text(output, 10, 20, arcade.color.WHITE, 14)
def on_mouse_motion(self, x, y, dx, dy):
""" Handle Mouse Motion """
# Move the center of the player sprite to match the mouse x, y
self.player_sprite.center_x = x
self.player_sprite.center_y = y
def update(self, delta_time):
""" Movement and game logic """
# Call update on all sprites (The sprites don't do much in this
# example though.)
self.coin_list.update()
# Generate a list of all sprites that collided with the player.
hit_list = arcade.check_for_collision_with_list(self.player_sprite,
self.coin_list)
# Loop through each colliding sprite, remove it, and add to the score.
for coin in hit_list:
coin.remove_from_sprite_lists()
self.score += 1
def main():
""" Main method """
window = MyGame()
window.setup()
arcade.run()
if __name__ == "__main__":
main()
|
TODO: Put in some text about spawning a sprite too close to the edge. Also make a refer to it from the final project.
Nimm, was du aus dem obigen Beispiel gelernt hast, und prüfe, ob die folgenden Abläufe reproduzieren kannst:

Testmuster¶
22.3. Münzen, die sich in Kreisen bewegen¶

Münzen, die sich im Kreis bewegen¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | import random
import arcade
import math
SPRITE_SCALING = 0.5
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
class Coin(arcade.Sprite):
def __init__(self, filename, sprite_scaling):
""" Constructor. """
# Call the parent class (Sprite) constructor
super().__init__(filename, sprite_scaling)
# Current angle in radians
self.circle_angle = 0
# How far away from the center to orbit, in pixels
self.circle_radius = 0
# How fast to orbit, in radians per frame
self.circle_speed = 0.008
# Set the center of the point we will orbit around
self.circle_center_x = 0
self.circle_center_y = 0
def update(self):
""" Update the ball's position. """
# Calculate a new x, y
self.center_x = self.circle_radius * math.sin(self.circle_angle) \
+ self.circle_center_x
self.center_y = self.circle_radius * math.cos(self.circle_angle) \
+ self.circle_center_y
# Increase the angle in prep for the next round.
self.circle_angle += self.circle_speed
class MyGame(arcade.Window):
""" Main application class. """
def __init__(self, width, height):
super().__init__(width, height)
# Sprite lists
self.player_list = None
self.coin_list = None
# Set up the player
self.score = 0
self.player_sprite = None
def start_new_game(self):
""" Set up the game and initialize the variables. """
# Sprite lists
self.player_list = arcade.SpriteList()
self.coin_list = arcade.SpriteList()
# Set up the player
self.score = 0
# Character image from kenney.nl
self.player_sprite = arcade.Sprite("character.png", SPRITE_SCALING)
self.player_sprite.center_x = 50
self.player_sprite.center_y = 70
self.player_list.append(self.player_sprite)
for i in range(50):
# Create the coin instance
# Coin image from kenney.nl
coin = Coin("coin_01.png", SPRITE_SCALING / 3)
# Position the center of the circle the coin will orbit
coin.circle_center_x = random.randrange(SCREEN_WIDTH)
coin.circle_center_y = random.randrange(SCREEN_HEIGHT)
# Random radius from 10 to 200
coin.circle_radius = random.randrange(10, 200)
# Random start angle from 0 to 2pi
coin.circle_angle = random.random() * 2 * math.pi
# Add the coin to the lists
self.coin_list.append(coin)
# Don't show the mouse cursor
self.set_mouse_visible(False)
# Set the background color
arcade.set_background_color(arcade.color.AMAZON)
def on_draw(self):
# This command has to happen before we start drawing
arcade.start_render()
# Draw all the sprites.
self.coin_list.draw()
self.player_list.draw()
# Put the text on the screen.
output = "Score: " + str(self.score)
arcade.draw_text(output, 10, 20, arcade.color.WHITE, 14)
def on_mouse_motion(self, x, y, dx, dy):
self.player_sprite.center_x = x
self.player_sprite.center_y = y
def update(self, delta_time):
""" Movement and game logic """
# Call update on all sprites (The sprites don't do much in this
# example though.)
self.coin_list.update()
# Generate a list of all sprites that collided with the player.
hit_list = arcade.check_for_collision_with_list(self.player_sprite,
self.coin_list)
# Loop through each colliding sprite, remove it, and add to the score.
for coin in hit_list:
self.score += 1
coin.remove_from_sprite_lists()
def main():
window = MyGame(SCREEN_WIDTH, SCREEN_HEIGHT)
window.start_new_game()
arcade.run()
if __name__ == "__main__":
main()
|
22.4. Rotating Sprites¶
Sprites können einfach gedreht werden, indem das Attribut angle
gesetzt wird. Winkel werden in Grad angegeben. Das Folgende wird die Spielfigur auf den Kopf stellen:
self.player_sprite.angle = 180
Wenn du dies in die Methode update
der Münze einfügst, werden die Münzen gedreht:
self.angle += 1
# If we rotate past 360, reset it back a turn.
if self.angle > 359:
self.angle -= 360