Asteroids

Tags: pgzero, game

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()