Moving Platforms#

sprite_moving_platforms.py#
  1"""
  2Sprite with Moving Platforms
  3
  4Artwork from https://kenney.nl
  5
  6If Python and Arcade are installed, this example can be run from the command line with:
  7python -m arcade.examples.sprite_moving_platforms
  8"""
  9from __future__ import annotations
 10
 11import arcade
 12from pyglet.math import Vec2
 13
 14SPRITE_SCALING = 0.5
 15
 16SCREEN_WIDTH = 1000
 17SCREEN_HEIGHT = 600
 18SCREEN_TITLE = "Sprite with Moving Platforms Example"
 19SPRITE_PIXEL_SIZE = 128
 20GRID_PIXEL_SIZE = (SPRITE_PIXEL_SIZE * SPRITE_SCALING)
 21
 22# How many pixels to keep as a minimum margin between the character
 23# and the edge of the screen.
 24VIEWPORT_MARGIN = SPRITE_PIXEL_SIZE * SPRITE_SCALING
 25RIGHT_MARGIN = 4 * SPRITE_PIXEL_SIZE * SPRITE_SCALING
 26
 27# Physics
 28MOVEMENT_SPEED = 10 * SPRITE_SCALING
 29JUMP_SPEED = 28 * SPRITE_SCALING
 30GRAVITY = .9 * SPRITE_SCALING
 31
 32# How fast the camera pans to the player. 1.0 is instant.
 33CAMERA_SPEED = 0.1
 34
 35
 36class MyGame(arcade.Window):
 37    """ Main application class. """
 38
 39    def __init__(self, width, height, title):
 40        """ Initializer """
 41
 42        # Call the parent init
 43        super().__init__(width, height, title)
 44
 45        # Sprite lists
 46
 47        # Drawing non-moving walls separate from moving walls improves performance.
 48        self.static_wall_list = None
 49        self.moving_wall_list = None
 50
 51        self.player_list = None
 52
 53        # Set up the player
 54        self.player_sprite = None
 55        self.physics_engine = None
 56        self.game_over = False
 57
 58        # Create the cameras. One for the GUI, one for the sprites.
 59        # We scroll the 'sprite world' but not the GUI.
 60        self.camera_sprites = arcade.SimpleCamera()
 61        self.camera_gui = arcade.SimpleCamera()
 62
 63        self.left_down = False
 64        self.right_down = False
 65
 66    def setup(self):
 67        """ Set up the game and initialize the variables. """
 68
 69        # Sprite lists
 70        self.static_wall_list = arcade.SpriteList()
 71        self.moving_wall_list = arcade.SpriteList()
 72        self.player_list = arcade.SpriteList()
 73
 74        # Set up the player
 75        self.player_sprite = arcade.Sprite(
 76            ":resources:images/animated_characters/female_person/femalePerson_idle.png",
 77            scale=SPRITE_SCALING,
 78        )
 79        self.player_sprite.center_x = 2 * GRID_PIXEL_SIZE
 80        self.player_sprite.center_y = 3 * GRID_PIXEL_SIZE
 81        self.player_list.append(self.player_sprite)
 82
 83        # Create floor
 84        for i in range(30):
 85            wall = arcade.Sprite(":resources:images/tiles/grassMid.png", scale=SPRITE_SCALING)
 86            wall.bottom = 0
 87            wall.center_x = i * GRID_PIXEL_SIZE
 88            self.static_wall_list.append(wall)
 89
 90        # Create platform side to side
 91        wall = arcade.Sprite(":resources:images/tiles/grassMid.png", scale=SPRITE_SCALING)
 92        wall.center_y = 3 * GRID_PIXEL_SIZE
 93        wall.center_x = 3 * GRID_PIXEL_SIZE
 94        wall.boundary_left = 2 * GRID_PIXEL_SIZE
 95        wall.boundary_right = 5 * GRID_PIXEL_SIZE
 96        wall.change_x = 2 * SPRITE_SCALING
 97        self.moving_wall_list.append(wall)
 98
 99        # Create platform side to side
100        wall = arcade.Sprite(":resources:images/tiles/grassMid.png", scale=SPRITE_SCALING)
101        wall.center_y = 3 * GRID_PIXEL_SIZE
102        wall.center_x = 7 * GRID_PIXEL_SIZE
103        wall.boundary_left = 5 * GRID_PIXEL_SIZE
104        wall.boundary_right = 9 * GRID_PIXEL_SIZE
105        wall.change_x = -2 * SPRITE_SCALING
106        self.moving_wall_list.append(wall)
107
108        # Create platform moving up and down
109        wall = arcade.Sprite(":resources:images/tiles/grassMid.png", scale=SPRITE_SCALING)
110        wall.center_y = 5 * GRID_PIXEL_SIZE
111        wall.center_x = 5 * GRID_PIXEL_SIZE
112        wall.boundary_top = 8 * GRID_PIXEL_SIZE
113        wall.boundary_bottom = 4 * GRID_PIXEL_SIZE
114        wall.change_y = 2 * SPRITE_SCALING
115        self.moving_wall_list.append(wall)
116
117        # Create platform moving diagonally
118        wall = arcade.Sprite(":resources:images/tiles/grassMid.png", scale=SPRITE_SCALING)
119        wall.center_y = 5 * GRID_PIXEL_SIZE
120        wall.center_x = 8 * GRID_PIXEL_SIZE
121        wall.boundary_left = 7 * GRID_PIXEL_SIZE
122        wall.boundary_right = 9 * GRID_PIXEL_SIZE
123        wall.boundary_top = 8 * GRID_PIXEL_SIZE
124        wall.boundary_bottom = 4 * GRID_PIXEL_SIZE
125        wall.change_x = 2 * SPRITE_SCALING
126        wall.change_y = 2 * SPRITE_SCALING
127        self.moving_wall_list.append(wall)
128
129        # Create our physics engine
130        self.physics_engine = \
131            arcade.PhysicsEnginePlatformer(self.player_sprite,
132                                           [self.static_wall_list, self.moving_wall_list],
133                                           gravity_constant=GRAVITY)
134
135        # Set the background color
136        self.background_color = arcade.color.AMAZON
137
138        self.game_over = False
139
140    def on_draw(self):
141        """
142        Render the screen.
143        """
144
145        # This command has to happen before we start drawing
146        self.clear()
147
148        # Select the camera we'll use to draw all our sprites
149        self.camera_sprites.use()
150
151        # Draw the sprites.
152        self.static_wall_list.draw()
153        self.moving_wall_list.draw()
154        self.player_list.draw()
155
156        self.camera_gui.use()
157
158        # Put the text on the screen.
159        distance = self.player_sprite.right
160        output = f"Distance: {distance}"
161        arcade.draw_text(output, 10, 20, arcade.color.WHITE, 14)
162
163    def set_x_speed(self):
164        if self.left_down and not self.right_down:
165            self.player_sprite.change_x = -MOVEMENT_SPEED
166        elif self.right_down and not self.left_down:
167            self.player_sprite.change_x = MOVEMENT_SPEED
168        else:
169            self.player_sprite.change_x = 0
170
171    def on_key_press(self, key, modifiers):
172        """ Called whenever the mouse moves. """
173        if key == arcade.key.UP:
174            if self.physics_engine.can_jump():
175                self.player_sprite.change_y = JUMP_SPEED
176        elif key == arcade.key.LEFT:
177            self.left_down = True
178            self.set_x_speed()
179        elif key == arcade.key.RIGHT:
180            self.right_down = True
181            self.set_x_speed()
182
183    def on_key_release(self, key, modifiers):
184        """ Called when the user presses a mouse button. """
185        if key == arcade.key.LEFT:
186            self.left_down = False
187            self.set_x_speed()
188        elif key == arcade.key.RIGHT:
189            self.right_down = False
190            self.set_x_speed()
191
192    def on_update(self, delta_time):
193        """ Movement and game logic """
194
195        # Call update on all sprites
196        self.physics_engine.update()
197
198        # Scroll the screen to the player
199        self.scroll_to_player()
200
201    def scroll_to_player(self):
202        """
203        Scroll the window to the player.
204
205        if CAMERA_SPEED is 1, the camera will immediately move to the desired position.
206        Anything between 0 and 1 will have the camera move to the location with a smoother
207        pan.
208        """
209
210        position = Vec2(self.player_sprite.center_x - self.width / 2,
211                        self.player_sprite.center_y - self.height / 2)
212        self.camera_sprites.move_to(position, CAMERA_SPEED)
213
214
215def main():
216    """ Main function """
217    window = MyGame(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
218    window.setup()
219    arcade.run()
220
221
222if __name__ == "__main__":
223    main()