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