nodes/ground.pyΒΆ
Part of Clumsy Bird.
1"""Scrolling ground: two side-by-side ground sprites that loop, plus a
2solid collision strip the bird crashes into."""
3
4from config import (
5 ASSETS,
6 GROUND_HEIGHT,
7 GROUND_SCROLL_SPEED,
8 GROUND_Y,
9 WIDTH,
10)
11
12from simvx.core import CharacterBody2D, Node2D, RectangleShape2D, Sprite2D, Vec2
13
14
15class Ground(Node2D):
16 """Visual + collision ground strip.
17
18 Two ground sprites tile horizontally; when one scrolls past the left edge
19 it teleports to the right of the other for a seamless loop. A single
20 static CharacterBody2D in the middle of the strip handles bird-vs-ground
21 collisions (the strip never moves, only the visuals scroll).
22 """
23
24 def __init__(self, **kwargs):
25 super().__init__(**kwargs)
26 self.add_to_group("ground")
27
28 # Two scrolling ground sprites: sprite.position is its centre.
29 self._sprites = [
30 self.add_child(
31 Sprite2D(
32 texture=str(ASSETS / "ground.png"),
33 width=WIDTH,
34 height=GROUND_HEIGHT,
35 position=Vec2(WIDTH / 2, GROUND_Y + GROUND_HEIGHT / 2),
36 name="GroundA",
37 )
38 ),
39 self.add_child(
40 Sprite2D(
41 texture=str(ASSETS / "ground.png"),
42 width=WIDTH,
43 height=GROUND_HEIGHT,
44 position=Vec2(WIDTH * 1.5, GROUND_Y + GROUND_HEIGHT / 2),
45 name="GroundB",
46 )
47 ),
48 ]
49
50 # Static collision body covering the ground strip; never moves.
51 self.collider = self.add_child(
52 CharacterBody2D(
53 shape=RectangleShape2D(half_extents=Vec2(WIDTH * 2, GROUND_HEIGHT / 2)),
54 position=Vec2(WIDTH / 2, GROUND_Y + GROUND_HEIGHT / 2),
55 name="GroundCollider",
56 )
57 )
58 self.collider.add_to_group("ground_collider")
59
60 def on_update(self, dt: float):
61 for spr in self._sprites:
62 spr.position.x -= GROUND_SCROLL_SPEED * dt
63 if spr.position.x < -WIDTH / 2:
64 spr.position.x += WIDTH * 2