Platformer¶
Demonstrates: CharacterBody2D, CollisionShape2D, move_and_slide, is_on_floor, gravity, input actions, platform collision. Controls: A/D or Left/Right = move, Space = jump. Run: python packages/graphics/examples/platformer_demo.py
Source Code¶
1#!/usr/bin/env python3
2"""Platformer demo -- CharacterBody2D with gravity, jump, and platforms.
3
4Demonstrates: CharacterBody2D, CollisionShape2D, move_and_slide, is_on_floor,
5 gravity, input actions, platform collision.
6Controls: A/D or Left/Right = move, Space = jump.
7Run: python packages/graphics/examples/platformer_demo.py
8"""
9
10from simvx.core import CharacterBody2D, Input, InputMap, Key, Node2D, Property, Vec2
11from simvx.graphics import App
12
13WIDTH, HEIGHT = 800, 600
14GRAVITY = 800.0
15
16
17class Platform(CharacterBody2D):
18 """Static platform that other bodies collide with."""
19
20 w = Property(120.0, range=(20, 400))
21 h = Property(16.0, range=(8, 60))
22
23 def __init__(self, w: float = 120, h: float = 16, **kwargs):
24 super().__init__(collision=Vec2(w / 2, h / 2), **kwargs)
25 self.w = w
26 self.h = h
27
28 def draw(self, renderer):
29 x = self.position.x - self.w / 2
30 y = self.position.y - self.h / 2
31 renderer.draw_rect(x, y, self.w, self.h, colour=(0.39, 0.71, 0.31, 1.0))
32
33
34class Player(CharacterBody2D):
35 speed = Property(250.0, range=(100, 500))
36 jump_force = Property(450.0, range=(200, 800))
37
38 def __init__(self, **kwargs):
39 super().__init__(collision=12, **kwargs)
40 self.can_jump = True
41
42 def process(self, dt: float):
43 # Horizontal movement
44 self.velocity.x = (Input.get_strength("right") - Input.get_strength("left")) * self.speed
45
46 # Gravity
47 self.velocity.y += GRAVITY * dt
48
49 # Jump
50 if Input.is_action_just_pressed("jump") and self.is_on_floor():
51 self.velocity.y = -self.jump_force
52
53 self.move_and_slide(dt)
54
55 # Reset if fallen off screen
56 if self.position.y > HEIGHT + 50:
57 self.position = Vec2(WIDTH / 2, 100)
58 self.velocity = Vec2()
59
60 def draw(self, renderer):
61 renderer.draw_rect(self.position.x - 10, self.position.y - 14, 20, 28, colour=(0.24, 0.55, 1.0, 1.0))
62 # Eyes
63 renderer.draw_rect(self.position.x - 5, self.position.y - 10, 4, 4, colour=(1.0, 1.0, 1.0, 1.0))
64 renderer.draw_rect(self.position.x + 1, self.position.y - 10, 4, 4, colour=(1.0, 1.0, 1.0, 1.0))
65
66
67class PlatformerDemo(Node2D):
68 def ready(self):
69 InputMap.add_action("left", [Key.A, Key.LEFT])
70 InputMap.add_action("right", [Key.D, Key.RIGHT])
71 InputMap.add_action("jump", [Key.SPACE])
72
73 self.add_child(Player(name="Player", position=Vec2(WIDTH / 2, 100)))
74
75 # Ground
76 self.add_child(Platform(name="Ground", w=WIDTH, h=20, position=Vec2(WIDTH / 2, HEIGHT - 10)))
77
78 # Platforms
79 platforms = [
80 (200, 450, 150),
81 (400, 350, 120),
82 (600, 450, 150),
83 (300, 250, 100),
84 (500, 250, 100),
85 (150, 150, 130),
86 (650, 150, 130),
87 ]
88 for i, (x, y, w) in enumerate(platforms):
89 self.add_child(Platform(name=f"Plat{i}", w=w, position=Vec2(x, y)))
90
91 def draw(self, renderer):
92 renderer.draw_text("Platformer Demo", (10, 10), scale=2, colour=(1.0, 1.0, 1.0))
93 renderer.draw_text("A/D: move SPACE: jump", (10, 35), scale=1, colour=(0.71, 0.71, 0.71))
94
95
96if __name__ == "__main__":
97 App(title="Platformer Demo", width=WIDTH, height=HEIGHT).run(PlatformerDemo())