Tutorial: A Jump`n Run with the Physic-Engine
Contents
Tutorial: A Jump`n Run with the Physic-Engine#
In this chapter we will build a Jump`n run with the physics engine. You will learn the following:
How do I use the physics engine?
How do I implement a camera that follows the player?
How do I use sensors to check if a player is on the “ground”. if is located:
How do I create animations for different situations (walking, jumping, standing, …)
WARNING: Simulation the physics of a plattformer with a physics-engine may not be the best solution and can lead to many unexpected side-effects.
First steps: The Board#
Create a Physicsboard:
from miniworldmaker import *
...
b = PhysicsBoard(400, 400)
#b.debug = True # If you set b.debug to True, you'll see what the physics-engine is "seeing"
b.run()
Create a Token#
Now you must create your first token:
import math
...
class Player(Rectangle):
def on_setup(self):
self.direction = "right"
self.size = (80,80)
self.physics.size = (0.8, 0.8)
self.physics.density = 1
self.physics.max_velocity_x = 200 # don't run faster than this
self.physics.friction = 0.7
self.moment = math.inf # do not rotate
With self.physics
, you can define object attributes like density or friction. With self.physics.size
you can scale
down the object for the physics-engine. (In the Physicsengine the token will have the size (80 * 0.8, 80 * 0,8) ).
Add events#
You can add events to the different buttons. Add these methods to your class:
def on_key_pressed_d(self):
self.physics.force_in_direction(90,1000)
def on_key_pressed_a(self):
self.physics.force_in_direction(-90,1000)
def on_key_down_w(self):
if self.sensor.detect():
self.physics.force_in_direction(0,15000)
This will applice a force, if you press a or d or an impulse if you jump. You will need to experience the values for the force. These depend on the mass of your body which is calculated by its size and density.
Add some objects#
Add some objects to play your game (After the definition of your class and before b.run()
)
c = Rectangle((0,300),400, 4)
c.physics.simulation = "manual"
c2 = Rectangle((400,360),400, 4)
c2.direction = 10
c2.physics.simulation = "manual"
c2.friction = 1
c3 = Rectangle((400,220),80, 4)
c3.direction = 10
c3.physics.simulation = "manual"
p = Player((20,220))
The sensor#
Jumping should only be allowed, if the player is standing on the ground. A sensor can help to detect this.
A sensor is an object attached to a Token, which can detect tokens.
Expand the on_setup
-Method:
def on_setup(self):
self.direction = "right"
self.size = (80,80)
self.physics.size = (0.8, 0.8)
self.physics.density = 1
self.physics.max_velocity_x = 200 # don't run faster than this
self.physics.friction = 0.7
self.moment = math.inf # do not rotate
self.sensor = Sensor(self, (0, 40))
self.sensor.size = (40, 20)
self.sensor.visible = False
self.standing_costume = self.add_costume("images/alien_stand.png")
The sensor ist set to visible
for demonstration and debugging purposes - You can delete this line later.
The player should only be able to jump when the sensor touches a token. Extend the event method for this:
def on_key_down_w(self):
if self.sensor.detect():
self.physics.force_in_direction(0,10000)
Animations#
You need to access the current state
of the token and detect state-changes. When the state of the token changes
(e.g.: It switches from “standing” to “walking” or “walking” to “jumping” ), the costume will be changed.
First, add some costumes in on_setup
and add variables to access the current state:
def on_setup(self):
self.direction = "right"
self.size = (80,80)
self.physics.size = (0.8, 0.8)
self.physics.density = 1
self.physics.max_velocity_x = 200 # don't run faster than this
self.physics.friction = 0.7
self.moment = math.inf # do not rotate
self.sensor = Sensor(self, (0, 40))
self.sensor.size = (40, 20)
self.sensor.visible = False
self.standing_costume = self.add_costume("images/alien_stand.png")
self.walking_costume = self.add_costume(["images/alien_walk1.png","images/alien_walk2.png"])
self.jumping_costume = self.add_costume("images/alien_jump.png")
self.old_velocity_x = 0
self.was_standing = False
self.was_jumping = False
self.was_walking = False
Now you must add some methods do detect the current state:
def is_standing(self):
return abs(self.physics.velocity_x) < 5 and self.sensor.detect()
def is_walking(self):
return abs(self.physics.velocity_x) > 5 and self.sensor.detect()
def is_jumping(self):
return not self.sensor.detect()
def started_jumping(self):
return (not self.was_jumping) and self.is_jumping()
def started_standing(self):
return (not self.was_standing) and self.is_standing()
def started_walking(self):
return (not self.was_walking) and self.is_walking()
def has_changed_direction(self):
if self.old_velocity_x >= -5 and self.physics.velocity_x < 0:
return True
elif self.old_velocity_x <= 5 and self.physics.velocity_x > 0:
return True
else:
return False
Now you can use this to write the act()
- Method, which will be called, every frame. The act()-Method
calls the corresponding methods, if a state has changed.
Flips the character, if he changes his direction.
Saves the current state of velcotiy ans state into variables for the next call of act().
def act(self):
changed_state = False # ...is false until a state change was detected in current frame.
# select costume
if self.started_standing():
self.start_standing()
changed_state = True
elif self.started_walking():
self.start_walking()
changed_state = True
elif self.started_jumping():
self.start_jumping()
changed_state = True
if changed_state or not self.is_standing():
if self.physics.velocity_x < 1:
self.is_flipped = True
else:
self.is_flipped = False
# safe current state for next act
self.old_velocity_x = self.physics.velocity_x
self.was_jumping = self.is_jumping()
self.was_standing = self.is_standing()
self.was_walking = self.is_walking()
…and add methods to start jumping/walking/standing, …:
def start_standing(self):
self.switch_costume(self.standing_costume)
self.costume.is_rotatable = False
def start_walking(self):
self.switch_costume(self.walking_costume)
self.costume.is_rotatable = False
self.costume.animate(loop = True)
def start_jumping(self):
self.switch_costume(self.jumping_costume)
self.costume.is_rotatable = False
The camera#
If you want the player to move through a scrolling world you need a camera.
Set boundaries for your board:
b = PhysicsBoard(400, 400)
b.boundary_x = 1200
b.boundary_y = 450
…and attach the camera to your token:
def act(self):
self.board.camera.from_token(self)
...
Now you’re ready: