Asteroids
https://simplegametutorials.github.io/pygamezero/
asteroids.py
1import os
2os.environ['SDL_video_window_pos'] = '%d,%d' % (20, 100)
3import pgzrun
4import math
5import random
6
7WIDTH = 800
8HEIGHT = 600
9PLAYER_R = 30
10
11C_BACKGROUND = (0, 16, 0)
12C_PLAYER_FILL = (0, 32, 0)
13C_PLAYER_STROKE = (0, 255, 0)
14C_BULLET = C_PLAYER_STROKE
15C_ASTEROID_FILL = (0, 24, 8)
16C_ASTEROID_STROKE = (0, 196, 64)
17C_ASTEROID_STROKE_COLLISION = (255, 0, 0)
18TURN_ANGLE = 10
19BULLET_SPEED = 500
20BULLET_RADIUS = 3
21
22
23
24def reset(): # {{{
25 global ship_x, ship_y
26 global ship_speed_x, ship_speed_y
27 global ship_angle
28 global bullet_timer
29 global bullets
30 global asteroids
31 global asteroid_stages
32 global bullet_timer, bullet_timer_limit
33
34
35 ship_x = WIDTH/2
36 ship_y = HEIGHT/2
37 ship_angle = 0
38 ship_speed_x = 0
39 ship_speed_y = 0
40 bullets = []
41 bullet_timer_limit = 0.005
42 bullet_timer = bullet_timer_limit
43 asteroid_radius = 88
44
45
46 asteroids = [ # {{{
47 {
48 'x': 100,
49 'y': 100,
50 },
51
52 {
53 'x': WIDTH - 100,
54 'y': 100,
55 },
56
57 {
58 'x': WIDTH / 2,
59 'y': HEIGHT - 100,
60 },
61 ] # }}}
62 asteroid_stages = [ # {{{
63 { 's': 120, 'r': 15 },
64 { 's': 70, 'r': 30 },
65 { 's': 50, 'r': 50 },
66 { 's': 20, 'r': 80 },
67 ]
68 # }}}
69 for asteroid in asteroids:
70 asteroid['angle'] = random.random() * 2 * math.pi
71 asteroid['c'] = C_ASTEROID_STROKE
72 asteroid['stage'] = len(asteroid_stages) -1
73 # }}}
74def are_circles_intersecting(ax,ay,ar,bx,by,br): # {{{
75 return (ax-bx)**2 + (ay-by)**2 <=(ar+br)**2
76# }}}
77def point_on_circle(x, y, r, a): # {{{
78 px = x + math.cos(a) * (r-5)
79 py = y + math.sin(a) * (r-5)
80 return (px, py)
81# }}}
82def update(dt): # {{{
83 global ship_angle
84 global ship_x, ship_y
85 global ship_speed_x, ship_speed_y
86 global bullet_timer
87
88 if len(asteroids) == 0: reset()
89
90 for asteroid in asteroids:
91 asteroid_speed = asteroid_stages[asteroid['stage']]['s']
92 asteroid['x'] += math.cos(asteroid['angle']) * asteroid_speed * dt
93 asteroid['y'] += math.sin(asteroid['angle']) * asteroid_speed * dt
94 asteroid['x'] %= WIDTH
95 asteroid['y'] %= HEIGHT
96 if are_circles_intersecting(
97 ship_x,ship_y, PLAYER_R,
98 asteroid['x'], asteroid['y'], asteroid_stages[asteroid['stage']]['r']
99 ):
100 # asteroid['c'] = C_ASTEROID_STROKE_COLLISION
101 reset()
102 else: asteroid['c'] = C_ASTEROID_STROKE
103
104
105 if keyboard.D: ship_angle += TURN_ANGLE * dt
106 elif keyboard.A: ship_angle -= TURN_ANGLE * dt
107 elif keyboard.W:
108 ship_speed = 100
109 ship_speed_x += math.cos(ship_angle) * ship_speed * dt
110 ship_speed_y += math.sin(ship_angle) * ship_speed * dt
111
112 ship_x += ship_speed_x * dt
113 ship_y += ship_speed_y * dt
114 ship_x %= WIDTH
115 ship_y %= HEIGHT
116 ship_angle %= 2*math.pi
117
118 bullet_timer += dt
119
120 if keyboard.SPACE:
121 if bullet_timer >= bullet_timer_limit:
122 bullet_timer = 0
123 x, y = point_on_circle(ship_x, ship_y, PLAYER_R, ship_angle)
124 bullets.append({
125 'x': x, 'y': y,
126 'a': ship_angle, 't': 4,
127 })
128
129
130 # Because bullets are removed from the list while it is being looped
131 # through, a copy of the list is created to loop through.
132 for bullet in bullets.copy():
133 bullet['t'] -= dt
134 if bullet['t'] <= 0:
135 bullets.remove(bullet)
136 continue
137 bullet['x'] += math.cos(bullet['a']) * BULLET_SPEED * dt
138 bullet['y'] += math.sin(bullet['a']) * BULLET_SPEED * dt
139 # bullet['x'] %= WIDTH
140 # bullet['y'] %= HEIGHT
141
142 for asteroid in asteroids.copy():
143 if are_circles_intersecting(
144 bullet['x'], bullet['y'], BULLET_RADIUS,
145 asteroid['x'], asteroid['y'], asteroid_stages[asteroid['stage']]['r']
146 ):
147 if asteroid['stage'] > 0:
148 a1 = random.random() * 2 * math.pi
149 a2 = (a1 - math.pi) % (2*math.pi)
150 asteroids.append({
151 'x': asteroid['x'],
152 'y': asteroid['y'],
153 'angle': a1,
154 'c': C_ASTEROID_STROKE,
155 'stage': asteroid['stage']-1,
156 })
157
158 asteroids.append({
159 'x': asteroid['x'],
160 'y': asteroid['y'],
161 'angle': a2,
162 'c': C_ASTEROID_STROKE,
163 'stage': asteroid['stage']-1,
164 })
165
166 bullets.remove(bullet)
167 asteroids.remove(asteroid)
168 break
169
170 # }}}
171def draw(): # {{{
172 global ship_angle
173 screen.fill(C_BACKGROUND)
174
175
176
177
178
179 for y in (-1, 0, 1):
180 for x in (-1, 0, 1):
181 offset_x = x * WIDTH
182 offset_y = y * HEIGHT
183
184 # ASTEROIDS
185 for asteroid in asteroids:
186 ax = asteroid['x'] + offset_x
187 ay = asteroid['y'] + offset_y
188 screen.draw.filled_circle((ax, ay), asteroid_stages[asteroid['stage']]['r'], color=C_ASTEROID_FILL)
189 screen.draw.circle((ax, ay), asteroid_stages[asteroid['stage']]['r'], color=asteroid['c'])
190
191 # SHIP
192 point_f = point_on_circle(ship_x+offset_x, ship_y+offset_y, PLAYER_R, ship_angle)
193 point_1 = point_on_circle(ship_x+offset_x, ship_y+offset_y, PLAYER_R, ship_angle + 10)
194 point_2 = point_on_circle(ship_x+offset_x, ship_y+offset_y, PLAYER_R, ship_angle - 10)
195 screen.draw.filled_circle((ship_x+offset_x, ship_y+offset_y), PLAYER_R, color=C_PLAYER_FILL)
196 screen.draw.line(point_f, point_1, color=C_PLAYER_STROKE)
197 screen.draw.line(point_1, point_2, color=C_PLAYER_STROKE)
198 screen.draw.line(point_2, point_f, color=C_PLAYER_STROKE)
199
200 # # BULLETS
201 # for bullet in bullets:
202 # screen.draw.filled_circle((
203 # bullet['x'] + offset_x,
204 # bullet['y'] + offset_y
205 # ), 3, color=C_BULLET)
206
207
208 # BULLETS
209 for bullet in bullets:
210 screen.draw.filled_circle(( bullet['x'], bullet['y']), BULLET_RADIUS, color=C_BULLET)
211 # screen.draw.filled_circle(( bullet['x'], bullet['y']), 3, color='red')
212
213 # screen.draw.text(
214 # 'ship_angle: ' + str((ship_angle/math.pi)*180) + '\n' +
215 # 'ship_x: ' + str(ship_x) + '\n' +
216 # 'ship_y: ' + str(ship_y) + '\n' +
217 # 'ship_speed_x: ' + str(ship_speed_x) + '\n' +
218 # 'ship_speed_y: ' + str(ship_speed_y),
219 # (0, 0))
220
221 # }}}
222
223reset()
224pgzrun.go()