Player
game/player.py defines the Player class, a pygame.sprite.Sprite that handles movement input, screen-boundary clamping, motion trail rendering, and health state.
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
image | pygame.Surface | 32×32 SRCALPHA | Neon-green rounded rectangle sprite. Outer border (0, 255, 150), inner fill (0, 100, 50). |
rect | pygame.Rect | Centred at (x, y) | Collision and positioning rect derived from image. |
pos | pygame.Vector2 | (x, y) | Sub-pixel position used for all movement calculations. |
trail_positions | list[tuple[float, float]] | [] | Ring buffer of the last 10 positions, newest first. |
speed | int | 6 | Movement speed in pixels per frame (applied after normalisation). |
health | int | 100 | Current health. Decremented by 15 on enemy contact. |
max_health | int | 100 | Maximum health. Used by the HUD to calculate the health bar fill ratio. |
__init__(x, y)
Horizontal spawn position in screen coordinates. Typically
width // 2.Vertical spawn position in screen coordinates. Typically
height // 2.pos and rect, and initialises all attributes to their defaults. The sprite image is a 32×32 surface with pygame.SRCALPHA, drawn with two rounded rectangles to create a glowing terminal-cursor look.
handle_input()
Reads the current keyboard state and moves the player. Called internally by update().
Supported keys
| Action | Keys |
|---|---|
| Move up | W, ↑ |
| Move down | S, ↓ |
| Move left | A, ← |
| Move right | D, → |
update(screen_width, screen_height)
Called once per frame by the game loop via player.update(width, height).
Current screen width in pixels. Used as the right boundary for clamping.
Current screen height in pixels. Used as the bottom boundary for clamping.
Clamp to screen bounds
Ensures the player sprite centre never gets closer than 16 px to any screen edge:The 16 px margin equals half the sprite width/height, so the player is fully visible at all times.
Wall collision is handled in the main game loop after
player.update() returns. If the player’s rect overlaps a wall rect, player.pos is reset to its pre-update value.draw(screen)
Renders the motion trail and the player sprite.
The active Pygame display surface.
Trail rendering
Iterates overtrail_positions from newest (index 0) to oldest (index 9). Each ghost frame is a semi-transparent cyan rectangle that shrinks and fades with age:
| Frame index | Alpha | Size (px) |
|---|---|---|
| 0 (newest) | 150 | 32 |
| 1 | 135 | 30 |
| 2 | 120 | 28 |
| … | … | … |
| 9 (oldest) | 15 | 14 |
Sprite rendering
After the trail, the player’s ownimage is blitted at self.rect:
draw() is called directly by the main loop and does not use the shake offset, so the player sprite stays visually stable while the world shakes around it.