-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathspaceship.py
169 lines (140 loc) · 6.31 KB
/
spaceship.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
"""Spaceship class for the Asteroids game."""
from typing import List, Tuple
import pygame
import math
import random
from pygame.locals import *
from constants import (
WIDTH, HEIGHT, WHITE, GRAY, ORANGE,
PLAYER_ACCELERATION, PLAYER_FRICTION,
PLAYER_ROTATION_SPEED, PLAYER_INVULNERABILITY_TIME
)
from particle import ParticleSystem
from utils import wrap_position
class Spaceship:
"""Player-controlled spaceship."""
def __init__(self):
"""Initialize the spaceship with default values."""
# Position and movement
self.position: List[float] = [WIDTH // 2, HEIGHT // 2]
self.velocity: List[float] = [0, 0]
self.acceleration: float = PLAYER_ACCELERATION
self.friction: float = PLAYER_FRICTION
self.rotation: float = 0
self.rotation_speed: float = PLAYER_ROTATION_SPEED
# Collision and gameplay
self.radius: float = 15
self.invulnerable: bool = False
self.invulnerable_timer: int = 0
self.invulnerable_max_time: int = PLAYER_INVULNERABILITY_TIME
# Visual effects
self.thruster_particles = ParticleSystem()
def draw(self, surface: pygame.Surface) -> None:
"""Draw the spaceship and its effects on the given surface.
Args:
surface: Pygame surface to draw on
"""
# Only draw if not invulnerable or blinking
if not self.invulnerable or pygame.time.get_ticks() % 200 < 100:
self._draw_ship(surface)
# Draw thruster particles even if not thrusting (for residual particles)
self.thruster_particles.draw(surface)
def _draw_ship(self, surface: pygame.Surface) -> None:
"""Draw the spaceship shape.
Args:
surface: Pygame surface to draw on
"""
# Calculate angles
angle_rad = math.radians(self.rotation)
cos_angle = math.cos(angle_rad)
sin_angle = math.sin(angle_rad)
# Main body coordinates (more complex shape)
nose_x = self.position[0] + self.radius * 2 * cos_angle
nose_y = self.position[1] + self.radius * 2 * sin_angle
rear_left_x = self.position[0] - self.radius * cos_angle + self.radius * 0.8 * sin_angle
rear_left_y = self.position[1] - self.radius * sin_angle - self.radius * 0.8 * cos_angle
rear_right_x = self.position[0] - self.radius * cos_angle - self.radius * 0.8 * sin_angle
rear_right_y = self.position[1] - self.radius * sin_angle + self.radius * 0.8 * cos_angle
# Indentation for the back of the ship
indent_x = self.position[0] - self.radius * 1.2 * cos_angle
indent_y = self.position[1] - self.radius * 1.2 * sin_angle
# Cockpit
cockpit_x = self.position[0] + self.radius * cos_angle
cockpit_y = self.position[1] + self.radius * sin_angle
# Wings (longer and angled)
left_wing_x = self.position[0] - self.radius * 0.2 * cos_angle + self.radius * 1.8 * sin_angle
left_wing_y = self.position[1] - self.radius * 0.2 * sin_angle - self.radius * 1.8 * cos_angle
right_wing_x = self.position[0] - self.radius * 0.2 * cos_angle - self.radius * 1.8 * sin_angle
right_wing_y = self.position[1] - self.radius * 0.2 * sin_angle + self.radius * 1.8 * cos_angle
# Draw main body (with indentation)
pygame.draw.polygon(surface, WHITE, [
(nose_x, nose_y),
(rear_left_x, rear_left_y),
(indent_x, indent_y),
(rear_right_x, rear_right_y)
])
# Draw cockpit
pygame.draw.circle(surface, GRAY, (int(cockpit_x), int(cockpit_y)), self.radius // 3)
# Draw wings
pygame.draw.line(surface, WHITE, (rear_left_x, rear_left_y), (left_wing_x, left_wing_y), 2)
pygame.draw.line(surface, WHITE, (rear_right_x, rear_right_y), (right_wing_x, right_wing_y), 2)
# Check for thruster
keys = pygame.key.get_pressed()
if keys[K_UP] or keys[K_w]:
# Thruster particle effect
particle_pos = (indent_x - self.radius * 0.5 * cos_angle, indent_y - self.radius * 0.5 * sin_angle)
particle_velocity = (-cos_angle * 5, -sin_angle * 5) # Opposite direction of ship
self.thruster_particles.emit(
particle_pos,
particle_velocity,
ORANGE,
3,
15,
count=3,
spread=0.4
)
def update(self) -> None:
"""Update spaceship position, rotation, and effects."""
self._handle_input()
self._update_position()
self._update_invulnerability()
self.thruster_particles.update()
def _handle_input(self) -> None:
"""Handle keyboard input for controlling the spaceship."""
keys = pygame.key.get_pressed()
# Rotation
if keys[K_LEFT] or keys[K_a]:
self.rotation = (self.rotation - self.rotation_speed) % 360
if keys[K_RIGHT] or keys[K_d]:
self.rotation = (self.rotation + self.rotation_speed) % 360
# Thrust
if keys[K_UP] or keys[K_w]:
angle_rad = math.radians(self.rotation)
self.velocity[0] += self.acceleration * math.cos(angle_rad)
self.velocity[1] += self.acceleration * math.sin(angle_rad)
def _update_position(self) -> None:
"""Update the spaceship's position based on velocity and apply friction."""
# Apply friction
self.velocity[0] *= (1 - self.friction)
self.velocity[1] *= (1 - self.friction)
# Update position
self.position[0] += self.velocity[0]
self.position[1] += self.velocity[1]
# Screen wrapping
wrap_position(self.position)
def _update_invulnerability(self) -> None:
"""Update invulnerability status and timer."""
if self.invulnerable:
self.invulnerable_timer += 1
if self.invulnerable_timer >= self.invulnerable_max_time:
self.invulnerable = False
self.invulnerable_timer = 0
def reset(self) -> None:
"""Reset the spaceship after losing a life."""
self.position = [WIDTH // 2, HEIGHT // 2]
self.velocity = [0, 0]
self.rotation = 0
self.invulnerable = True
self.invulnerable_timer = 0
# Clear any existing particles
self.thruster_particles.clear()