Using the Physics Engine
This time, we’ll introduce the physics engine.
By using it, you can apply movements based on physical laws to your sprites.
1. Creating a Physics Engine
First, create a physics engine using the arcade.PymunkPhysicsEngine() method.
The gravity argument represents gravity in the physics world.
# main.py (excerpt)
# Create a physics engine
self.physics = arcade.PymunkPhysicsEngine(damping=0.8, gravity=(0, -900))
2. Adding the Player
Use the add_sprite() method to add a sprite to the physics engine.
# main.py (excerpt)
# Add the player
self.physics.add_sprite(
self.player,
friction=1.0,
collision_type="player"
)
3. Adding Coins and Blocks
Using the same approach, add coins and blocks.
For body_type, specify either DYNAMIC or STATIC as shown below.
| Value | Meaning |
|---|---|
arcade.PymunkPhysicsEngine.DYNAMIC |
An object affected by physics (movable) |
arcade.PymunkPhysicsEngine.STATIC |
An object not affected by physics (immovable) |
Coins should be DYNAMIC, while blocks should be STATIC.
# main.py (excerpt)
# Add coins
for coin in self.coins:
self.physics.add_sprite(
coin,
friction=1.0,
collision_type="coin",
body_type=arcade.PymunkPhysicsEngine.DYNAMIC
)
# Add blocks
for block in self.blocks:
self.physics.add_sprite(
block,
friction=1.0,
collision_type="block",
body_type=arcade.PymunkPhysicsEngine.STATIC
)
Use the following image for blocks (roof tiles are perfect for a ninja game!).
| Image | File name |
|---|---|
![]() |
block_01.png |
4. Giving Velocity to the Player
In the on_key_press() method, we apply an instantaneous velocity to the player.
The first argument of self.physics.set_velocity() is the player sprite,
and the second argument is the velocity vector.
# main.py (excerpt)
PLAYER_JUMP_X = 60
PLAYER_JUMP_Y = 300
# ...
def on_key_press(self, key, key_modifiers):
# Move (WASD)
if key == arcade.key.W:
self.physics.set_velocity(self.player, (0, PLAYER_JUMP_Y))
if key == arcade.key.A:
self.physics.set_velocity(self.player, (-PLAYER_JUMP_X, PLAYER_JUMP_Y))
if key == arcade.key.S:
pass
if key == arcade.key.D:
self.physics.set_velocity(self.player, (PLAYER_JUMP_X, PLAYER_JUMP_Y))
5. Running the Physics Engine
Finally, step the physics engine inside the on_update() method.
# main.py (excerpt)
self.physics.step(delta_time) # Advance the physics engine
Complete Code
Below is the complete code implementing all the features above.
You can copy and run it as-is.
# sprite.py (complete code)
import arcade
import random
import math
class BaseSprite(arcade.Sprite):
def __init__(self, filename, x, y):
super().__init__(filename)
# Position
self.center_x = x
self.center_y = y
class Player(BaseSprite):
def __init__(self, filename, x, y):
super().__init__(filename, x, y)
class Coin(BaseSprite):
def __init__(self, filename, x, y):
super().__init__(filename, x, y)
class Block(BaseSprite):
def __init__(self, filename, x, y):
super().__init__(filename, x, y)
# main.py (complete code)
import arcade
import random
import sprite
PLAYER_JUMP_X = 60
PLAYER_JUMP_Y = 300
class GameView(arcade.View):
def __init__(self, window):
super().__init__()
self.window = window
self.w = self.window.width
self.h = self.window.height
self.background_color = arcade.color.PAYNE_GREY
# Camera
self.camera = arcade.Camera2D() # Player camera
self.camera_gui = arcade.Camera2D() # Fixed camera
# Player
self.players = arcade.SpriteList()
self.player = sprite.Player(
"images/ninja/front_01.png",
self.w / 2,
self.h / 2
)
self.players.append(self.player)
# Coins
self.coins = arcade.SpriteList()
for _ in range(10):
x = random.random() * self.w
y = self.h
coin = sprite.Coin("images/coin/coin_01.png", x, y)
self.coins.append(coin)
# Blocks
block_pad_x = 48
block_total = 8
block_x = self.w / 2 - block_pad_x * (block_total - 1) / 2
block_y = 30
self.blocks = arcade.SpriteList()
for i in range(block_total):
x = block_x + block_pad_x * i
y = block_y
block = sprite.Block("images/block/block_01.png", x, y)
self.blocks.append(block)
# Info
self.msg_info = arcade.Text(
"GAME",
self.w / 2,
self.h - 20,
arcade.color.WHITE,
12,
anchor_x="center",
anchor_y="top"
)
# Create physics engine
self.physics = arcade.PymunkPhysicsEngine(damping=0.8, gravity=(0, -900))
# Add player
self.physics.add_sprite(
self.player,
friction=1.0,
collision_type="player"
)
# Add coins
for coin in self.coins:
self.physics.add_sprite(
coin,
friction=1.0,
collision_type="wall",
body_type=arcade.PymunkPhysicsEngine.DYNAMIC
)
# Add blocks
for block in self.blocks:
self.physics.add_sprite(
block,
friction=1.0,
collision_type="wall",
body_type=arcade.PymunkPhysicsEngine.STATIC
)
def on_key_press(self, key, key_modifiers):
# Move (WASD)
if key == arcade.key.W:
self.physics.set_velocity(self.player, (0, PLAYER_JUMP_Y))
if key == arcade.key.A:
self.physics.set_velocity(self.player, (-PLAYER_JUMP_X, PLAYER_JUMP_Y))
if key == arcade.key.S:
pass
if key == arcade.key.D:
self.physics.set_velocity(self.player, (PLAYER_JUMP_X, PLAYER_JUMP_Y))
def on_update(self, delta_time):
# Step physics engine
self.physics.step(delta_time)
# Camera follow
self.camera.position = arcade.math.lerp_2d(
self.camera.position,
self.player.position,
0.1
)
def on_draw(self):
self.clear()
self.camera.use()
self.players.draw()
self.coins.draw()
self.blocks.draw()
self.camera_gui.use()
self.msg_info.draw()
def main():
"""Main entry point"""
window = arcade.Window(480, 320, "Hello, Arcade!!")
window.show_view(GameView(window))
arcade.run()
if __name__ == "__main__":
main()
The result looks like this:
Closing Thoughts
Thank you for reading!
I hope this series becomes a starting point for your own game development. ޱ(ఠ皿ఠ)ว👍


Top comments (0)