pymunk_demo_platformer_09.py Diff
pymunk_demo_platformer_09.py
--- /home/docs/checkouts/readthedocs.org/user_builds/arcade-library/checkouts/stable/doc/tutorials/pymunk_platformer/pymunk_demo_platformer_08.py
+++ /home/docs/checkouts/readthedocs.org/user_builds/arcade-library/checkouts/stable/doc/tutorials/pymunk_platformer/pymunk_demo_platformer_09.py
@@ -1,6 +1,8 @@
"""
Example of Pymunk Physics Engine Platformer
"""
+import math
+from typing import Optional
import arcade
@@ -64,12 +66,20 @@
# How many pixels to move before we change the texture in the walking animation
DISTANCE_TO_CHANGE_TEXTURE = 20
+# How much force to put on the bullet
+BULLET_MOVE_FORCE = 4500
+
+# Mass of the bullet
+BULLET_MASS = 0.1
+
+# Make bullet less affected by gravity
+BULLET_GRAVITY = 300
+
class PlayerSprite(arcade.Sprite):
- """Player Sprite"""
-
+ """ Player Sprite """
def __init__(self):
- """Init"""
+ """ Init """
# Let parent initialize
super().__init__(scale=SPRITE_SCALING_PLAYER)
@@ -84,7 +94,7 @@
# Load textures for idle, jump, and fall states
idle_texture = arcade.load_texture(f"{main_path}_idle.png")
jump_texture = arcade.load_texture(f"{main_path}_jump.png")
- fall_texture = arcade.load_texture(f"{main_path}_fall.png")
+ fall_texture = arcade.load_texture(f"{main_path}_fall.png")
# Make pairs of textures facing left and right
self.idle_texture_pair = idle_texture, idle_texture.flip_left_right()
self.jump_texture_pair = jump_texture, jump_texture.flip_left_right()
@@ -109,7 +119,7 @@
self.x_odometer = 0
def pymunk_moved(self, physics_engine, dx, dy, d_angle):
- """Handle being moved by the pymunk engine"""
+ """ Handle being moved by the pymunk engine """
# Figure out if we need to face left or right
if dx < -DEAD_ZONE and self.character_face_direction == RIGHT_FACING:
self.character_face_direction = LEFT_FACING
@@ -138,6 +148,7 @@
# Have we moved far enough to change the texture?
if abs(self.x_odometer) > DISTANCE_TO_CHANGE_TEXTURE:
+
# Reset the odometer
self.x_odometer = 0
@@ -149,22 +160,22 @@
class GameWindow(arcade.Window):
- """Main Window"""
+ """ Main Window """
def __init__(self, width, height, title):
- """Create the variables"""
+ """ Create the variables """
# Init the parent class
super().__init__(width, height, title)
# Player sprite
- self.player_sprite: PlayerSprite | None = None
+ self.player_sprite: PlayerSprite|None = None
# Sprite lists we need
- self.player_list: arcade.SpriteList | None = None
- self.wall_list: arcade.SpriteList | None = None
- self.bullet_list: arcade.SpriteList | None = None
- self.item_list: arcade.SpriteList | None = None
+ self.player_list: arcade.SpriteList|None = None
+ self.wall_list: arcade.SpriteList|None = None
+ self.bullet_list: arcade.SpriteList|None = None
+ self.item_list: arcade.SpriteList|None = None
# Track the current state of what key is pressed
self.left_pressed: bool = False
@@ -177,7 +188,7 @@
self.background_color = arcade.color.AMAZON
def setup(self):
- """Set up everything with the game"""
+ """ Set up everything with the game """
# Create the sprite lists
self.player_list = arcade.SpriteList()
@@ -218,7 +229,8 @@
gravity = (0, -GRAVITY)
# Create the physics engine
- self.physics_engine = arcade.PymunkPhysicsEngine(damping=damping, gravity=gravity)
+ self.physics_engine = arcade.PymunkPhysicsEngine(damping=damping,
+ gravity=gravity)
# Add the player.
# For the player, we set the damping to a lower value, which increases
@@ -230,15 +242,13 @@
# Friction is between two objects in contact. It is important to remember
# in top-down games that friction moving along the 'floor' is controlled
# by damping.
- self.physics_engine.add_sprite(
- self.player_sprite,
- friction=PLAYER_FRICTION,
- mass=PLAYER_MASS,
- moment_of_inertia=arcade.PymunkPhysicsEngine.MOMENT_INF,
- collision_type="player",
- max_horizontal_velocity=PLAYER_MAX_HORIZONTAL_SPEED,
- max_vertical_velocity=PLAYER_MAX_VERTICAL_SPEED,
- )
+ self.physics_engine.add_sprite(self.player_sprite,
+ friction=PLAYER_FRICTION,
+ mass=PLAYER_MASS,
+ moment_of_inertia=arcade.PymunkPhysicsEngine.MOMENT_INF,
+ collision_type="player",
+ max_horizontal_velocity=PLAYER_MAX_HORIZONTAL_SPEED,
+ max_vertical_velocity=PLAYER_MAX_VERTICAL_SPEED)
# Create the walls.
# By setting the body type to PymunkPhysicsEngine.STATIC the walls can't
@@ -247,20 +257,18 @@
# PymunkPhysicsEngine.KINEMATIC objects will move, but are assumed to be
# repositioned by code and don't respond to physics forces.
# Dynamic is default.
- self.physics_engine.add_sprite_list(
- self.wall_list,
- friction=WALL_FRICTION,
- collision_type="wall",
- body_type=arcade.PymunkPhysicsEngine.STATIC,
- )
+ self.physics_engine.add_sprite_list(self.wall_list,
+ friction=WALL_FRICTION,
+ collision_type="wall",
+ body_type=arcade.PymunkPhysicsEngine.STATIC)
# Create the items
- self.physics_engine.add_sprite_list(
- self.item_list, friction=DYNAMIC_ITEM_FRICTION, collision_type="item"
- )
+ self.physics_engine.add_sprite_list(self.item_list,
+ friction=DYNAMIC_ITEM_FRICTION,
+ collision_type="item")
def on_key_press(self, key, modifiers):
- """Called whenever a key is pressed."""
+ """Called whenever a key is pressed. """
if key == arcade.key.LEFT:
self.left_pressed = True
@@ -274,15 +282,69 @@
self.physics_engine.apply_impulse(self.player_sprite, impulse)
def on_key_release(self, key, modifiers):
- """Called when the user releases a key."""
+ """Called when the user releases a key. """
if key == arcade.key.LEFT:
self.left_pressed = False
elif key == arcade.key.RIGHT:
self.right_pressed = False
+ def on_mouse_press(self, x, y, button, modifiers):
+ """ Called whenever the mouse button is clicked. """
+
+ bullet = arcade.SpriteSolidColor(width=20, height=5, color=arcade.color.DARK_YELLOW)
+ self.bullet_list.append(bullet)
+
+ # Position the bullet at the player's current location
+ start_x = self.player_sprite.center_x
+ start_y = self.player_sprite.center_y
+ bullet.position = self.player_sprite.position
+
+ # Get from the mouse the destination location for the bullet
+ # IMPORTANT! If you have a scrolling screen, you will also need
+ # to add in self.view_bottom and self.view_left.
+ dest_x = x
+ dest_y = y
+
+ # Do math to calculate how to get the bullet to the destination.
+ # Calculation the angle in radians between the start points
+ # and end points. This is the angle the bullet will travel.
+ x_diff = dest_x - start_x
+ y_diff = dest_y - start_y
+ angle = math.atan2(y_diff, x_diff)
+
+ # What is the 1/2 size of this sprite, so we can figure out how far
+ # away to spawn the bullet
+ size = max(self.player_sprite.width, self.player_sprite.height) / 2
+
+ # Use angle to to spawn bullet away from player in proper direction
+ bullet.center_x += size * math.cos(angle)
+ bullet.center_y += size * math.sin(angle)
+
+ # Set angle of bullet
+ bullet.angle = math.degrees(angle)
+
+ # Gravity to use for the bullet
+ # If we don't use custom gravity, bullet drops too fast, or we have
+ # to make it go too fast.
+ # Force is in relation to bullet's angle.
+ bullet_gravity = (0, -BULLET_GRAVITY)
+
+ # Add the sprite. This needs to be done AFTER setting the fields above.
+ self.physics_engine.add_sprite(bullet,
+ mass=BULLET_MASS,
+ damping=1.0,
+ friction=0.6,
+ collision_type="bullet",
+ gravity=bullet_gravity,
+ elasticity=0.9)
+
+ # Add force to bullet
+ force = (BULLET_MOVE_FORCE, 0)
+ self.physics_engine.apply_force(bullet, force)
+
def on_update(self, delta_time):
- """Movement and game logic"""
+ """ Movement and game logic """
is_on_ground = self.physics_engine.is_on_ground(self.player_sprite)
# Update player forces based on keys pressed
@@ -312,16 +374,15 @@
self.physics_engine.step()
def on_draw(self):
- """Draw everything"""
+ """ Draw everything """
self.clear()
self.wall_list.draw()
self.bullet_list.draw()
self.item_list.draw()
self.player_list.draw()
-
def main():
- """Main function"""
+ """ Main function """
window = GameWindow(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
window.setup()
arcade.run()