pygame游戏

坚强是说给别人听的谎言 提交于 2020-04-05 21:00:07

本次项目为pygame游戏开发,使用pycharm来进行开发。本项目命名:迷航。

游戏设定:设定一架简略图标飞机。只可前进,和进攻,前进的方向可以由鼠标或者键盘的左右方向键控制,攻击命令可由空格或者单击鼠标左键完成,一次一发子弹。边缘会不停的刷新陨石,偶尔会刷新外星飞船。注:大陨石被子弹击中时会分散成多个小的陨石。

以下为所需的土图片素材

1:开始场景

2:游戏所需场景

3.音效素材省略

项目代码如下

1.alien.py(生成外星目标)

import os
import math
import random

import pygame
from pygame import mixer

import util
import sprite
import bullet
import ship

class Alien(sprite.Sprite):
    def __init__(self, world):
        super(Alien, self).__init__(world)

        self.points = [[1, 0], [-1, 0], [-0.7, 0],
                       [-0.5, 0.2], [0.5, 0.2],
                       [0.7, 0],
                       [0.5, -0.4], [-0.5, -0.4],
                       [-0.7, 0]]
        self.direction = random.randint(1, 2) * 2 - 3
        self.position = [world.width / 2 - self.direction * world.width / 2, 
                         random.randint(0, world.height)]
        self.angle = 0
        self.scale = 10
        self.direction_timer = random.randint(10, 50)
        self.random_velocity()

        self.alien_sound = mixer.Sound(os.path.join("sounds", "alien_engine.ogg"))
        self.alien_channel = pygame.mixer.Channel(3)
        self.alien_channel.play(self.alien_sound, loops = -1)

    def random_velocity(self):
        self.velocity = [self.direction * (random.random() * 2 + 1), 
                         random.random() * 6 - 3]

    def update(self):
        self.direction_timer -= 1
        if self.direction_timer < 0:
            self.direction_timer = random.randint(10, 50)
            self.random_velocity()

        if self.angle > 0:
            self.angle -= 1
        elif self.angle < 0:
            self.angle += 1

        if self.direction == 1 and self.position[0] > self.world.width - 10:
            self.kill = True
        elif self.direction == -1 and self.position[0] < 10:
            self.kill = True

        if self.kill:
            self.alien_channel.fadeout(500)

        super(Alien, self).update()

    def impact(self, other):
        self.angle = random.randint(-90, 90)
        super(Alien, self).impact(other)

2:asteroid.py(生成陨石)

import pygame
import math
import random

import util
import sprite
import bullet
import ship
import alien

class Asteroid(sprite.Sprite):
    def __init__(self, world, scale, max_speed):
        super(Asteroid, self).__init__(world)
        world.n_asteroids += 1

        # spawn on a screen edge
        if random.randint(0, 1) == 0:
            x = random.randint(0, world.width)
            y = random.randint(0, 1) * world.height
        else:
            x = random.randint(0, 1) * world.width
            y = random.randint(0, world.height)
        self.position = [x, y] 

        n_points = random.randint(5, 10)
        self.points = []
        for i in range(n_points):
            angle = i * 360 / n_points + random.randint(-20, 20)
            distance = random.random() / 4.0 + 0.75
            self.points.append([distance * util.cos(angle), 
                                distance * util.sin(angle)])
        self.velocity = [random.random() * max_speed * 2 - max_speed, 
                         random.random() * max_speed * 2 - max_speed]
        self.angle = 0
        self.scale = scale
        self.angular_velocity = random.random() * 4 - 2

    def update(self):
        self.angle += self.angular_velocity
        super(Asteroid, self).update()

    def collide(self, other):
        if isinstance(other, Asteroid):
            # exchange spins
            x = other.angular_velocity
            other.angular_velocity = self.angular_velocity
            self.angular_velocity = x

            # calculate point of impact for sparks
            dx = self.position[0] - other.position[0]
            dy = self.position[1] - other.position[1]
            d2 = dx * dx + dy * dy 
            d = math.sqrt(d2)
            if d == 0:
                d = 0.0001
            u = dx / d
            v = dy / d
            impact = [other.position[0] + u * other.scale,
                      other.position[1] + v * other.scale]
            self.world.particle.sparks(impact, other.velocity)

        super(Asteroid, self).collide(other)

3:bullet.py(发射的子弹)


import pygame
import math
import random

import util
import sprite
import asteroid
import alien

class Bullet(sprite.Sprite):
    def __init__(self, world):
        super(Bullet, self).__init__(world)

        self.points = [[1, 0], 
                       [util.cos(120), util.sin(120)],
                       [util.cos(240), util.sin(240)]]
        self.scale = 2
        self.life = 100
        self.angle = 0

    def update(self):
        super(Bullet, self).update()

        self.life -= 1
        if self.life == 0:
            self.kill = True

    def collision(self, other):
        # don't chain up, we don't want to exchange velocity or anything like
        # that
        pass

    def impact(self, other):
        if isinstance(other, alien.Alien):
            other.kill = True
            self.kill = True
            self.world.score += 1000
            self.world.particle.explosion(20, 
                                          other.position, other.velocity)
        elif isinstance(other, asteroid.Asteroid):
            other.kill = True
            self.kill = True
            self.world.score += other.scale
            self.world.n_asteroids -= 1
            self.world.particle.explosion(other.scale / 3, 
                                          other.position, other.velocity)

            if other.scale > 15:
                n = random.randint(2, max(2, min(5, int(other.scale / 5))))
                for i in range(n):
                    new_asteroid = asteroid.Asteroid(self.world, 
                                                     other.scale / n, 1)
                    new_asteroid.position[0] = other.position[0]
                    new_asteroid.position[1] = other.position[1]
                    new_asteroid.velocity[0] += other.velocity[0]
                    new_asteroid.velocity[1] += other.velocity[1]

4:particle.py(微粒特效)


import os
import random

import pygame
from pygame import mixer

import util

# stolen from a PET scanner
colour_table = [[ 15, 0, 30 ],
                [ 19, 0, 40 ],
                [ 23, 0, 48 ],
                [ 28, 0, 57 ],
                [ 36, 0, 74 ],
                [ 42, 0, 84 ],
                [ 46, 0, 93 ],
                [ 51, 0, 102 ],
                [ 59, 0, 118 ],
                [ 65, 0, 130 ],
                [ 69, 0, 138 ],
                [ 72, 0, 146 ],
                [ 81, 0, 163 ],
                [ 47, 0, 95 ],
                [ 12, 0, 28 ],
                [ 64, 0, 144 ],
                [ 61, 0, 146 ],
                [ 55, 0, 140 ],
                [ 52, 0, 137 ],
                [ 47, 0, 132 ],
                [ 43, 0, 128 ],
                [ 38, 0, 123 ],
                [ 30, 0, 115 ],
                [ 26, 0, 111 ],
                [ 23, 0, 108 ],
                [ 17, 0, 102 ],
                [ 9, 0, 94 ],
                [ 6, 0, 91 ],
                [ 2, 0, 87 ],
                [ 0, 0, 88 ],
                [ 0, 0, 100 ],
                [ 0, 0, 104 ],
                [ 0, 0, 108 ],
                [ 0, 0, 113 ],
                [ 0, 0, 121 ],
                [ 0, 0, 125 ],
                [ 0, 0, 129 ],
                [ 0, 0, 133 ],
                [ 0, 0, 141 ],
                [ 0, 0, 146 ],
                [ 0, 0, 150 ],
                [ 0, 0, 155 ],
                [ 0, 0, 162 ],
                [ 0, 0, 167 ],
                [ 0, 0, 173 ],
                [ 0, 0, 180 ],
                [ 0, 0, 188 ],
                [ 0, 0, 193 ],
                [ 0, 0, 197 ],
                [ 0, 0, 201 ],
                [ 0, 0, 209 ],
                [ 0, 0, 214 ],
                [ 0, 0, 218 ],
                [ 0, 0, 222 ],
                [ 0, 0, 230 ],
                [ 0, 0, 235 ],
                [ 0, 0, 239 ],
                [ 0, 0, 243 ],
                [ 0, 0, 247 ],
                [ 0, 4, 251 ],
                [ 0, 10, 255 ],
                [ 0, 14, 255 ],
                [ 0, 18, 255 ],
                [ 0, 24, 255 ],
                [ 0, 31, 255 ],
                [ 0, 36, 255 ],
                [ 0, 39, 255 ],
                [ 0, 45, 255 ],
                [ 0, 53, 255 ],
                [ 0, 56, 255 ],
                [ 0, 60, 255 ],
                [ 0, 66, 255 ],
                [ 0, 74, 255 ],
                [ 0, 77, 255 ],
                [ 0, 81, 255 ],
                [ 0, 88, 251 ],
                [ 0, 99, 239 ],
                [ 0, 104, 234 ],
                [ 0, 108, 230 ],
                [ 0, 113, 225 ],
                [ 0, 120, 218 ],
                [ 0, 125, 213 ],
                [ 0, 128, 210 ],
                [ 0, 133, 205 ],
                [ 0, 141, 197 ],
                [ 0, 145, 193 ],
                [ 0, 150, 188 ],
                [ 0, 154, 184 ],
                [ 0, 162, 176 ],
                [ 0, 167, 172 ],
                [ 0, 172, 170 ],
                [ 0, 180, 170 ],
                [ 0, 188, 170 ],
                [ 0, 193, 170 ],
                [ 0, 197, 170 ],
                [ 0, 201, 170 ],
                [ 0, 205, 170 ],
                [ 0, 211, 170 ],
                [ 0, 218, 170 ],
                [ 0, 222, 170 ],
                [ 0, 226, 170 ],
                [ 0, 232, 170 ],
                [ 0, 239, 170 ],
                [ 0, 243, 170 ],
                [ 0, 247, 170 ],
                [ 0, 251, 161 ],
                [ 0, 255, 147 ],
                [ 0, 255, 139 ],
                [ 0, 255, 131 ],
                [ 0, 255, 120 ],
                [ 0, 255, 105 ],
                [ 0, 255, 97 ],
                [ 0, 255, 89 ],
                [ 0, 255, 78 ],
                [ 0, 255, 63 ],
                [ 0, 255, 55 ],
                [ 0, 255, 47 ],
                [ 0, 255, 37 ],
                [ 0, 255, 21 ],
                [ 0, 255, 13 ],
                [ 0, 255, 5 ],
                [ 2, 255, 2 ],
                [ 13, 255, 13 ],
                [ 18, 255, 18 ],
                [ 23, 255, 23 ],
                [ 27, 255, 27 ],
                [ 35, 255, 35 ],
                [ 40, 255, 40 ],
                [ 43, 255, 43 ],
                [ 48, 255, 48 ],
                [ 55, 255, 55 ],
                [ 60, 255, 60 ],
                [ 64, 255, 64 ],
                [ 69, 255, 69 ],
                [ 72, 255, 72 ],
                [ 79, 255, 79 ],
                [ 90, 255, 82 ],
                [ 106, 255, 74 ],
                [ 113, 255, 70 ],
                [ 126, 255, 63 ],
                [ 140, 255, 56 ],
                [ 147, 255, 53 ],
                [ 155, 255, 48 ],
                [ 168, 255, 42 ],
                [ 181, 255, 36 ],
                [ 189, 255, 31 ],
                [ 197, 255, 27 ],
                [ 209, 255, 21 ],
                [ 224, 255, 14 ],
                [ 231, 255, 10 ],
                [ 239, 255, 7 ],
                [ 247, 251, 3 ],
                [ 255, 243, 0 ],
                [ 255, 239, 0 ],
                [ 255, 235, 0 ],
                [ 255, 230, 0 ],
                [ 255, 222, 0 ],
                [ 255, 218, 0 ],
                [ 255, 214, 0 ],
                [ 255, 209, 0 ],
                [ 255, 201, 0 ],
                [ 255, 197, 0 ],
                [ 255, 193, 0 ],
                [ 255, 188, 0 ],
                [ 255, 180, 0 ],
                [ 255, 176, 0 ],
                [ 255, 172, 0 ],
                [ 255, 167, 0 ],
                [ 255, 156, 0 ],
                [ 255, 150, 0 ],
                [ 255, 146, 0 ],
                [ 255, 142, 0 ],
                [ 255, 138, 0 ],
                [ 255, 131, 0 ],
                [ 255, 125, 0 ],
                [ 255, 121, 0 ],
                [ 255, 117, 0 ],
                [ 255, 110, 0 ],
                [ 255, 104, 0 ],
                [ 255, 100, 0 ],
                [ 255, 96, 0 ],
                [ 255, 90, 0 ],
                [ 255, 83, 0 ],
                [ 255, 78, 0 ],
                [ 255, 75, 0 ],
                [ 255, 71, 0 ],
                [ 255, 67, 0 ],
                [ 255, 65, 0 ],
                [ 255, 63, 0 ],
                [ 255, 59, 0 ],
                [ 255, 54, 0 ],
                [ 255, 52, 0 ],
                [ 255, 50, 0 ],
                [ 255, 46, 0 ],
                [ 255, 41, 0 ],
                [ 255, 39, 0 ],
                [ 255, 36, 0 ],
                [ 255, 32, 0 ],
                [ 255, 25, 0 ],
                [ 255, 22, 0 ],
                [ 255, 20, 0 ],
                [ 255, 17, 0 ],
                [ 255, 13, 0 ],
                [ 255, 10, 0 ],
                [ 255, 7, 0 ],
                [ 255, 4, 0 ],
                [ 255, 0, 0 ],
                [ 252, 0, 0 ],
                [ 251, 0, 0 ],
                [ 249, 0, 0 ],
                [ 248, 0, 0 ],
                [ 244, 0, 0 ],
                [ 242, 0, 0 ],
                [ 240, 0, 0 ],
                [ 237, 0, 0 ],
                [ 234, 0, 0 ],
                [ 231, 0, 0 ],
                [ 229, 0, 0 ],
                [ 228, 0, 0 ],
                [ 225, 0, 0 ],
                [ 222, 0, 0 ],
                [ 221, 0, 0 ],
                [ 219, 0, 0 ],
                [ 216, 0, 0 ],
                [ 213, 0, 0 ],
                [ 212, 0, 0 ],
                [ 210, 0, 0 ],
                [ 207, 0, 0 ],
                [ 204, 0, 0 ],
                [ 201, 0, 0 ],
                [ 199, 0, 0 ],
                [ 196, 0, 0 ],
                [ 193, 0, 0 ],
                [ 192, 0, 0 ],
                [ 190, 0, 0 ],
                [ 188, 0, 0 ],
                [ 184, 0, 0 ],
                [ 183, 0, 0 ],
                [ 181, 0, 0 ],
                [ 179, 0, 0 ],
                [ 175, 0, 0 ]]
n_colour = len(colour_table)

class Particle(object):
    def __init__(self, surface):
        self.surface = surface
        self.width = surface.get_width()
        self.height = surface.get_height()

        self.show_particles = True

        # a row of this hash stores:
        #
        # 0 - life .. down counter until death
        # 1 - x
        # 2 - y
        # 3 - u  horizontal component of velocity
        # 4 - v  vertical component of velocity
        # 5 - colour index ... int index into colour array above
        # 6 - colour delta ... add this to index each update
        self.particles = {}
        self.index = 0

        self.explosion1_sound = mixer.Sound(os.path.join("sounds", "planet_crush.ogg"))
        self.explosion2_sound = mixer.Sound(os.path.join("sounds", "ship_crush.ogg"))

    def show(self, show_particles):
        self.show_particles = show_particles

    def add(self, position, velocity, colour, colour_delta, life):
        if not self.show_particles:
            return

        particle = [life,
                    position[0], position[1], 
                    velocity[0], velocity[1],
                    colour, colour_delta]
        self.particles[self.index] = particle
        self.index += 1

    def n_particles(self):
        return len(self.particles)

    def remove_all(self):
        self.particles = {}

    def explosion(self, n_points, position, velocity):
        self.explosion1_sound.play()
        for i in range(int(n_points)):
            delta = 360 / n_points
            angle = i * delta + random.randint(int(-delta / 2), int(delta / 2))
            speed = random.random() * 2.0 
            self.add(position, 
                     [velocity[0] + speed * util.cos(angle),
                      velocity[1] + speed * util.sin(angle)],
                     n_colour - random.randint(1, 50), 
                     -1, 
                     random.randint(50, 100))

    def explosion2(self, n_points, position, velocity):
        self.explosion2_sound.play()
        for i in range(int(n_points)):
            delta = 360.0 / n_points
            angle = i * delta + random.randint(int(-delta), int(delta))
            speed = random.random() * 4.0 
            self.add(position, 
                     [velocity[0] + speed * util.cos(angle),
                      velocity[1] + speed * util.sin(angle)],
                     n_colour - random.randint(1, 50), 
                     -1, 
                     random.randint(50, 300))

    def sparks(self, position, velocity):
        n_points = 3
        delta = 360 / n_points
        for i in range(int(n_points)):
            angle = i * delta + random.randint(-delta / 2, delta / 2)
            speed = random.random() * 2.0 
            self.add(position, 
                     [velocity[0] + speed * util.cos(angle),
                      velocity[1] + speed * util.sin(angle)],
                     n_colour - random.randint(1, 200), 
                     -113, 
                     random.randint(50, 100))

    def jet(self, position, velocity, angle):
        angle = angle + random.randint(-10, 10) + 180
        u = 2 * util.cos(angle)
        v = 2 * util.sin(angle)
        self.add([position[0] + 3 * u, position[1] + 3 * v],
                 [velocity[0] + u, velocity[1] + v],
                 random.randint(50, 200),
                 random.randint(20, 200),
                 random.randint(20, 30))

    def starfield(self):
        for i in range(30):
            self.add([random.randint(0, self.width),
                      random.randint(0, self.height)],
                     [0, 0],
                     random.randint(50, 200),
                     random.randint(1, 3),
                     100000000)

    def update(self):
        if not self.show_particles:
            return

        keys = list(self.particles.keys())
        for i in keys:
            part = self.particles[i]
            if part[0] > 0:
                part[0] -= 1
                if part[0] == 0:
                    del self.particles[i]
                    continue

                part[1] += part[3]
                part[2] += part[4]
                part[1] %= self.width
                part[2] %= self.height

                part[5] += part[6]
                part[5] %= n_colour

    def draw(self):
        if not self.show_particles:
            return

        for i in self.particles:
            part = self.particles[i]
            rect = [part[1], part[2], 3, 3]
            pygame.draw.rect(self.surface, colour_table[part[5]], rect)

5:ship.py(飞船)

import os
import math
import random

import pygame
from pygame import mixer

import util
import sprite
import bullet
import alien
import asteroid

# default shield behavior 
# 0 is old regenerating shield behavior, 1 is manual shields
SHIELDMODE = 0

class Ship(sprite.Sprite):
    def __init__(self, world):
        super(Ship, self).__init__(world)

        self.position = [world.width / 2, 
                         world.height / 2]
        self.points = [[1, 0], 
                       [util.cos(140), util.sin(140)],
                       [-0.3, 0],
                       [util.cos(220), util.sin(220)]]
        self.shield_points = []
        for i in range(5):
            self.shield_points.append([util.cos(i * 360 / 5 - 15), 
                                       util.sin(i * 360 / 5 - 15)])
            self.shield_points.append([util.cos(i * 360 / 5 + 15), 
                                       util.sin(i * 360 / 5 + 15)])
        self.velocity = [0, 0]
        self.angle = 0
        self.scale = 5
        self.reload_timer = 0
        self.regenerate_timer = 0
        self.max_shields = 3
        self.shields = self.max_shields
        self.shield_tick = 0
        self.jet_tick = 0
        self.shield_timer = 0
        self.shield_mode = SHIELDMODE
        self.engines = False

        self.fire_sound = mixer.Sound(os.path.join("sounds", "shot.ogg"))
        self.engine_sound = mixer.Sound(os.path.join("sounds", "engine.ogg"))
        self.fire_channel = pygame.mixer.Channel(2)
        self.engine_channel = pygame.mixer.Channel(1)

    def rotate_by(self, angle):
        self.angle += angle
        self.angle %= 360

    # power is a bool for thrust on or off
    def thrust(self, power):
        # engine state changed?
        if power != self.engines:
            if power:
                self.engine_channel.play(self.engine_sound, loops = -1)
            else:
                self.engine_channel.fadeout(500)
            self.engines = power

        if power:
            u = 0.1 * util.cos(self.angle)
            v = 0.1 * util.sin(self.angle)
            self.velocity = [self.velocity[0] + u, self.velocity[1] + v]
            
            self.jet_tick -= 1
            if self.jet_tick < 0:
                self.jet_tick = 3
                self.world.particle.jet(self.position, self.velocity, self.angle)

    def fire(self):
        if self.reload_timer == 0:
            self.fire_channel.stop()
            self.fire_channel.play(self.fire_sound)
            
            a = util.cos(self.angle)
            b = util.sin(self.angle)
            
            projectile = bullet.Bullet(self.world)
            projectile.position = [self.position[0] + self.scale * a,
                                   self.position[1] + self.scale * b]
            projectile.velocity = [a * 7.0 + self.velocity[0],
                                   b * 7.0 + self.velocity[1]]
            projectile.angle = self.angle
            
            self.reload_timer = 10

    def update(self):
        self.reload_timer = max(0, self.reload_timer - 1)
        self.shield_tick += 1

        if self.shield_mode == 0:
            self.regenerate_timer = max(0, self.regenerate_timer - 1)
            if self.regenerate_timer == 0 and self.shields < self.max_shields:
                self.regenerate_timer = 500 
                self.shields += 1
        elif self.shield_mode == 1:
            self.shield_timer = max(0,self.shield_timer - 1)
            if self.shield_timer < 1 and self.shields > 0:
                self.shields -= 3

        if self.kill:
            self.engine_channel.fadeout(500)

        super(Ship, self).update()

    # used for manual shields 
    def shield_on(self):
        if self.shield_mode == 1:
            if self.regenerate_timer == 0 and self.shields < self.max_shields:
                # change shield regeneration time below
                # actually regenerate time is  the difference
                # between "regenerate_timer" and "shield_timer"
                self.regenerate_timer = 1000 
                self.shields += 3
                if self.shields > 0:
                    self.shield_timer = 500 #change time shield is on here

    def impact(self, other):
        if isinstance(other, alien.Alien) or isinstance(other, asteroid.Asteroid):
            self.world.particle.sparks(self.position, self.velocity)
            self.shields -= 1
            self.regenerate_timer = 1000 
            if self.shields < 0:
                self.kill = True
                self.world.particle.explosion2(300, 
                                               self.position, self.velocity)

        super(Ship, self).impact(other)
    
    def draw(self):
        super(Ship, self).draw()

        for i in range(max(0, self.shields)):
            radius = int(self.scale + 5 + 4 * i)
            angle = ((i & 1) * 2 - 1) * self.shield_tick
            a = radius * util.cos(angle)
            b = radius * -util.sin(angle)
            c = -b
            d = a

            screen_points = [[int(a * x + b * y + self.position[0]), 
                              int(c * x + d * y + self.position[1])] 
                              for x, y in self.shield_points]

            for i in range(0, len(screen_points), 2):
                pygame.draw.line(self.world.surface, util.WHITE,
                                 screen_points[i], 
                                 screen_points[i + 1])

6:sprite.py


import pygame
import math

import util

class Sprite(object):
    def __init__(self, world):
        self.world = world
        self.position = [0, 0]
        self.velocity = [0, 0]
        self.points = []
        self.kill = False
        self.tested_collision = False
        self.continuous = True
        self.scale = 10
        self.angle = 0
        world.add(self)

    def test_collisions(self, possible_sprites):
        width = self.world.width
        height = self.world.height

        for other in possible_sprites:
            if other == self:
                continue
            if other.tested_collision:
                continue

            dx = self.position[0] - other.position[0]
            dy = self.position[1] - other.position[1]

            # we need to do wrap-around testing
            #
            # we know that possible_sprites is only other sprites in the
            # immediate neighbourhood, therefore if dx > half screen width,
            # then this and other must be on opposite sides of the screen and
            # must be possibly colliding via warp-around
            #
            # in this case, notionally move down by a screen width 

            if dx > width / 2:
                dx -= width
            elif dx < -width / 2:
                dx += width

            if dy > height / 2:
                dy -= height
            elif dy < -height / 2:
                dy += height

            d2 = dx * dx + dy * dy 
            t = self.scale + other.scale
            t2 = t * t
            if d2 > t2:
                continue

            # unit vector
            d = math.sqrt(d2)
            if d == 0:
                d = 0.0001
            u = dx / d
            v = dy / d

            # amount of overlap
            overlap = d - t

            # displace by overlap in that direction
            other.position[0] += u * overlap 
            other.position[0] %= width
            other.position[1] += v * overlap
            other.position[1] %= height

            # tell the objects they have collided ... both objects need to be
            # told
            self.impact(other)
            other.impact(self)

            # don't do the physics if either object is now dead
            if not self.kill and not other.kill:
                self.collide(other)

            break

    # this method is triggered for both objects involved in the collision ... do
    # asymmetric things like bullets blowing up aliens
    def impact(self, other):
        pass

    # this is triggered just once, so symmetric things happen in this, like
    # physics
    def collide(self, other):
        x = other.velocity[0]
        other.velocity[0] = self.velocity[0]
        self.velocity[0] = x

        x = other.velocity[1]
        other.velocity[1] = self.velocity[1]
        self.velocity[1] = x

    def update(self):
        self.position = [self.position[0] + self.velocity[0], 
                         self.position[1] + self.velocity[1]]
        self.position[0] %= self.world.width
        self.position[1] %= self.world.height

    def draw(self):
        a = self.scale * util.cos(self.angle)
        b = self.scale * -util.sin(self.angle)
        c = -b
        d = a

        screen_points = [[int(a * x + b * y + self.position[0]), 
                          int(c * x + d * y + self.position[1])] 
                         for x, y in self.points]

        if self.continuous:
            pygame.draw.lines(self.world.surface, util.WHITE, True, 
                              screen_points)
        else:
            for i in range(0, len(screen_points), 2):
                pygame.draw.line(self.world.surface, util.WHITE, 
                                 screen_points[i], 
                                 screen_points[i + 1])

7:text.py

import pygame
import math
import random

import util
import sprite
import alien

# character designs from https://github.com/rickwight/meteors, thank you rick

# oh god why
char_points = {
   '0':  [[-0.5, 0.25], [-0.25, 0.5], [-0.25, 0.5], [0.25, 0.5], [0.25, 0.5], [0.5, 0.25], [0.5, 0.25], [0.5, -0.25], [0.5, -0.25], [0.25, -0.5], [0.25, -0.5], [-0.25, -0.5], [-0.25, -0.5], [-0.5, -0.25], [-0.5, -0.25], [-0.5, 0.25], [-0.25, 0.5], [0.25, -0.5]], 
   '1':  [[0.5, 0.25], [-0.0, 0.5], [-0.0, 0.5], [-0.0, -0.5], [0.5, -0.5], [-0.5, -0.5]], 
   '2':  [[-0.5, -0.5], [0.5, -0.5], [0.5, -0.5], [-0.25, 0.0], [-0.25, 0.0], [-0.5, 0.25], [-0.5, 0.25], [-0.25, 0.5], [-0.25, 0.5], [0.25, 0.5], [0.25, 0.5], [0.5, 0.25]], 
   '3':  [[0.5, 0.25], [0.25, 0.5], [0.25, 0.5], [-0.25, 0.5], [-0.25, 0.5], [-0.5, 0.25], [-0.5, 0.25], [-0.25, 0.0], [-0.25, 0.0], [-0.5, -0.25], [-0.5, -0.25], [-0.25, -0.5], [-0.25, -0.5], [0.25, -0.5], [0.25, -0.5], [0.5, -0.25], [0.25, 0.0], [-0.25, 0.0]], 
   '4':  [[-0.25, -0.5], [-0.25, 0.5], [-0.25, 0.5], [0.5, -0.25], [0.5, -0.25], [-0.5, -0.25]], 
   '5':  [[-0.5, 0.5], [0.5, 0.5], [0.5, 0.5], [0.5, 0.0], [0.5, 0.0], [-0.25, 0.0], [-0.25, 0.0], [-0.5, -0.25], [-0.5, -0.25], [-0.25, -0.5], [-0.25, -0.5], [0.5, -0.5]], 
   '6':  [[-0.5, 0.25], [-0.25, 0.5], [-0.25, 0.5], [0.25, 0.5], [0.25, 0.5], [0.5, 0.25], [0.5, 0.25], [0.5, -0.25], [0.5, -0.25], [0.25, -0.5], [0.25, -0.5], [-0.25, -0.5], [-0.25, -0.5], [-0.5, -0.25], [-0.5, -0.25], [-0.25, 0.0], [-0.25, 0.0], [0.5, 0.0]], 
   '7':  [[0.5, 0.5], [-0.5, 0.5], [-0.5, 0.5], [0.25, -0.5]], 
   '8':  [[0.5, 0.25], [0.25, 0.5], [0.25, 0.5], [-0.25, 0.5], [-0.25, 0.5], [-0.5, 0.25], [-0.5, 0.25], [-0.25, 0.0], [-0.25, 0.0], [-0.5, -0.25], [-0.5, -0.25], [-0.25, -0.5], [-0.25, -0.5], [0.25, -0.5], [0.25, -0.5], [0.5, -0.25], [0.5, -0.25], [0.25, 0.0], [0.25, 0.0], [0.5, 0.25], [0.25, 0.0], [-0.25, 0.0]], 
   '9':  [[0.5, -0.25], [0.25, -0.5], [0.25, -0.5], [-0.25, -0.5], [-0.25, -0.5], [-0.5, -0.25], [-0.5, -0.25], [-0.5, 0.25], [-0.5, 0.25], [-0.25, 0.5], [-0.25, 0.5], [0.25, 0.5], [0.25, 0.5], [0.5, 0.25], [0.5, 0.25], [0.25, 0.0], [0.25, 0.0], [-0.5, 0.0]], 
   'A':  [[0.5, -0.5], [-0.0, 0.5], [-0.0, 0.5], [-0.5, -0.5], [0.25, 0.0], [-0.25, 0.0]], 
   'B':  [[0.5, -0.5], [0.5, 0.5], [0.5, 0.5], [-0.25, 0.5], [-0.25, 0.5], [-0.5, 0.25], [-0.5, 0.25], [-0.25, 0.0], [-0.25, 0.0], [-0.5, -0.25], [-0.5, -0.25], [-0.25, -0.5], [-0.25, -0.5], [0.5, -0.5], [0.5, 0.0], [-0.25, 0.0]], 
   'C':  [[-0.5, -0.25], [-0.25, -0.5], [-0.25, -0.5], [0.25, -0.5], [0.25, -0.5], [0.5, -0.25], [0.5, -0.25], [0.5, 0.25], [0.5, 0.25], [0.25, 0.5], [0.25, 0.5], [-0.25, 0.5], [-0.25, 0.5], [-0.5, 0.25]], 
   'D':  [[0.5, -0.5], [0.5, 0.5], [0.5, 0.5], [-0.25, 0.5], [-0.25, 0.5], [-0.5, 0.25], [-0.5, 0.25], [-0.5, -0.25], [-0.5, -0.25], [-0.25, -0.5], [-0.25, -0.5], [0.5, -0.5]], 
   'E':  [[0.5, 0.5], [-0.5, 0.5], [0.5, 0.0], [-0.25, 0.0], [0.5, -0.5], [-0.5, -0.5], [0.5, -0.5], [0.5, 0.5]], 
   'F':  [[0.5, -0.5], [0.5, 0.5], [0.5, 0.5], [-0.5, 0.5], [0.5, 0.0], [-0.25, 0.0]], 
   'G':  [[-0.5, 0.25], [-0.25, 0.5], [-0.25, 0.5], [0.25, 0.5], [0.25, 0.5], [0.5, 0.25], [0.5, 0.25], [0.5, -0.25], [0.5, -0.25], [0.25, -0.5], [0.25, -0.5], [-0.25, -0.5], [-0.25, -0.5], [-0.5, -0.25], [-0.5, -0.25], [-0.5, 0.0], [-0.5, 0.0], [-0.0, 0.0]], 
   'H':  [[0.5, -0.5], [0.5, 0.5], [-0.5, -0.5], [-0.5, 0.5], [0.5, 0.0], [-0.5, 0.0]], 
   'I':  [[0.25, 0.5], [-0.25, 0.5], [0.25, -0.5], [-0.25, -0.5], [-0.0, -0.5], [-0.0, 0.5]], 
   'J':  [[0.5, -0.5], [-0.0, -0.5], [-0.0, -0.5], [-0.0, 0.5], [0.5, 0.5], [-0.5, 0.5]], 
   'K':  [[0.5, -0.5], [0.5, 0.5], [0.5, 0.0], [-0.5, 0.5], [0.5, 0.0], [-0.5, -0.5]], 
   'L':  [[0.5, -0.5], [0.5, 0.5], [0.5, -0.5], [-0.5, -0.5]], 
   'M':  [[0.5, -0.5], [0.5, 0.5], [0.5, 0.5], [-0.0, 0.0], [-0.0, 0.0], [-0.5, 0.5], [-0.5, 0.5], [-0.5, -0.5]], 
   'N':  [[0.5, -0.5], [0.5, 0.5], [0.5, 0.5], [-0.5, -0.5], [-0.5, -0.5], [-0.5, 0.5]], 
   'O':  [[-0.5, 0.25], [-0.25, 0.5], [-0.25, 0.5], [0.25, 0.5], [0.25, 0.5], [0.5, 0.25], [0.5, 0.25], [0.5, -0.25], [0.5, -0.25], [0.25, -0.5], [0.25, -0.5], [-0.25, -0.5], [-0.25, -0.5], [-0.5, -0.25], [-0.5, -0.25], [-0.5, 0.25]], 
   'P':  [[0.5, -0.5], [0.5, 0.5], [0.5, 0.5], [-0.25, 0.5], [-0.25, 0.5], [-0.5, 0.25], [-0.5, 0.25], [-0.25, 0.0], [-0.25, 0.0], [0.5, 0.0]], 
   'Q':  [[-0.5, 0.25], [-0.25, 0.5], [-0.25, 0.5], [0.25, 0.5], [0.25, 0.5], [0.5, 0.25], [0.5, 0.25], [0.5, -0.25], [0.5, -0.25], [0.25, -0.5], [0.25, -0.5], [-0.25, -0.5], [-0.25, -0.5], [-0.5, -0.25], [-0.5, -0.25], [-0.5, 0.25], [-0.25, -0.25], [-0.5, -0.5]], 
   'R':  [[0.5, -0.5], [0.5, 0.5], [0.5, 0.5], [-0.25, 0.5], [-0.25, 0.5], [-0.5, 0.25], [-0.5, 0.25], [-0.25, 0.0], [-0.25, 0.0], [0.5, 0.0], [-0.25, 0.0], [-0.5, -0.5]], 
   'S':  [[0.5, -0.25], [0.25, -0.5], [0.25, -0.5], [-0.25, -0.5], [-0.25, -0.5], [-0.5, -0.25], [-0.5, -0.25], [-0.25, 0.0], [-0.25, 0.0], [0.25, 0.0], [0.25, 0.0], [0.5, 0.25], [0.5, 0.25], [0.25, 0.5], [0.25, 0.5], [-0.25, 0.5], [-0.25, 0.5], [-0.5, 0.25]], 
   'T':  [[0.5, 0.5], [-0.5, 0.5], [-0.0, 0.5], [-0.0, -0.5]], 
   'U':  [[0.5, 0.5], [0.5, -0.25], [0.5, -0.25], [0.25, -0.5], [0.25, -0.5], [-0.25, -0.5], [-0.25, -0.5], [-0.5, -0.25], [-0.5, -0.25], [-0.5, 0.5]], 
   'V':  [[0.5, 0.5], [-0.0, -0.5], [-0.0, -0.5], [-0.5, 0.5]], 
   'W':  [[0.5, 0.5], [0.5, -0.5], [0.5, -0.5], [-0.0, 0.0], [-0.0, 0.0], [-0.5, -0.5], [-0.5, -0.5], [-0.5, 0.5]], 
   'X':  [[0.5, -0.5], [-0.5, 0.5], [-0.5, -0.5], [0.5, 0.5]], 
   'Y':  [[0.5, 0.5], [-0.0, 0.0], [-0.0, 0.0], [-0.5, 0.5], [-0.0, 0.0], [-0.0, -0.5]], 
   'Z':  [[0.5, 0.5], [-0.5, 0.5], [-0.5, 0.5], [0.5, -0.5], [0.3, -0.5], [-0.5, -0.5]],
   '-':  [[0.3, 0.0], [-0.3, 0.0]],
   'm':  [[0.5, -0.8],  [0.1, -0.4], [0.1, -0.4],  [0.5, -0.4],
                [0.5, -0.8],  [0.5, 0.4], [0.5, 0.4],   [-0.5, 0.6],
                [0.5, 0.3],   [-0.5, 0.5], [-0.5, 0.6],  [-0.5, -0.6],
                [-0.5, -0.6], [-0.9, -0.2], [-0.9, -0.2], [-0.5, -0.2]]
}

class Character(sprite.Sprite):
    # drawable text object
    def __init__(self, world, character, position, scale = 20):
        super(Character, self).__init__(world)
        self.scale = scale
        self.angle = 180
        self.position = position
        self.character = character
        self.points = char_points[character]
        self.angular_velocity = 0
        self.continuous = False

    def impact(self, other):
        self.angular_velocity = random.random() * 2 - 1
        super(Character, self).impact(other)

    def update(self):
        if abs(self.angular_velocity) > 0.01:
            self.angle += self.angular_velocity
        super(Character, self).update()

    @classmethod
    def string(cls, world, string, position, scale = 20):
        kern = 2.5
        x = position[0] - len(string) * scale * kern / 2.0
        y = position[1]
        for ch in string:
            if ch in char_points:
                pos = [x, y]
                Character(world, ch, pos, scale)
            x += scale * kern

def draw_string(surface, string, colour, scale, position, 
                centre = False, angle = 0):
    kern = 2.5
    x = position[0]
    y = position[1]
    a = scale * util.cos(angle)
    b = scale * -util.sin(angle)
    c = -b
    d = a
    if centre:
        x -= a * kern * len(string) / 2.0
        y -= c * kern * len(string) / 2.0
    for ch in string:
        if ch in char_points:
            screen = [[int(-a * u - b * v + x), 
                       int(-c * u - d * v + y)] 
                      for u, v in char_points[ch]]
            for i in range(0, len(screen), 2):
                pygame.draw.line(surface, util.WHITE, screen[i], screen[i + 1])
        x += a * kern
        y += c * kern

8:util.py

import math

# Colors
BLACK    = (   0,   0,   0) 
WHITE    = ( 255, 255, 255) 
BLUE     = (   0,   0, 128)
GREEN    = (   0, 128, 0)
RED      = ( 128,   0, 0)

DEG2RAD = 2.0 * math.pi / 360.0

def rad(angle):
    return angle * DEG2RAD

# maybe faster on some systems with weak FP hardware?
cos_table = [0] * 360
for i in range(360):
    cos_table[i] = math.cos(rad(i))

def cos(angle):
    try:
        return cos_table[int(angle % 360)]
    except:
        print("util.cos() of", angle)
def sin(angle):
    try:
        return cos_table[int((angle - 90) % 360)]
    except:
        print("util.sin() of", angle)

8:world.py

import os
import math
import random
import sys

import pygame
from pygame import mixer

import util
import sprite
import particle
import text
import alien
import ship
import asteroid

class World(object):
    def __init__(self, surface):
        self.surface = surface
        self.width = surface.get_width()
        self.height = surface.get_height()
        self.sprites = []
        self.particle = particle.Particle(surface)
        self.score = 0
        self.n_asteroids = 0
        self.text_y = 100

        # input state
        self.quit = False
        self.rotate_left = False
        self.rotate_right = False
        self.rotate_by = 0
        self.thrust = False
        self.info = False
        self.fire = False
        self.spawn = False
        self.show_particles = True
        self.enter = False
        self.next_level = False

        # the ship ... or none for no ship on screen
        self.player = None

        # countdown timer until next alien
        self.alien_time = random.randint(1000, 2000)

        self.music_playing = True
        self.background_music = mixer.Sound(os.path.join("sounds", "hoarse_space_cadet.ogg"))
        self.background_channel = pygame.mixer.Channel(0)
        self.background_channel.play(self.background_music, loops = -1)

    def n_objects(self):
        return len(self.sprites)

    def play_music(self, play):
        if play:
            self.background_channel.unpause()
        else:
            self.background_channel.pause()

    def reset(self):
        self.sprites = []
        self.n_asteroids = 0
        self.particle.remove_all()
        self.text_y = 100
        self.score = 0
        self.player = None

    def remove_asteroids(self):
        self.sprites = [x for x in self.sprites 
                        if not isinstance(x, asteroid.Asteroid)]

    def add(self, sprite):
        self.sprites.append(sprite)

    def add_player(self):
        if not self.player:
            self.player = ship.Ship(self)

    def add_text(self, string, scale = 10):
        text.Character.string(self, string, 
                              [self.width / 2, self.text_y], scale)
        self.text_y += scale * 5

    def update(self):
        for event in pygame.event.get(): 
            if event.type == pygame.QUIT: 
                self.quit = True 

            if event.type == pygame.KEYDOWN or event.type == pygame.KEYUP:
                if event.key == pygame.K_ESCAPE:
                    self.quit = event.type == pygame.KEYDOWN
                elif event.key == pygame.K_LEFT:
                    self.rotate_left = event.type == pygame.KEYDOWN
                elif event.key == pygame.K_RIGHT:
                    self.rotate_right = event.type == pygame.KEYDOWN
                elif event.key == pygame.K_UP:
                    self.thrust = event.type == pygame.KEYDOWN
                elif event.key == pygame.K_SPACE:
                    self.fire = event.type == pygame.KEYDOWN
                elif event.key == pygame.K_s:
                    self.spawn = event.type == pygame.KEYDOWN
                elif event.key == pygame.K_n:
                    self.next_level = event.type == pygame.KEYDOWN
                elif event.key == pygame.K_m and event.type == pygame.KEYDOWN:
                    self.music_playing = not self.music_playing
                    self.play_music(self.music_playing)
                elif event.key == pygame.K_p:
                    if event.type == pygame.KEYDOWN:
                        self.show_particles = not self.show_particles
                elif event.key == pygame.K_i:
                    self.info = event.type == pygame.KEYDOWN
                elif event.key == pygame.K_RETURN:
                    self.enter = event.type == pygame.KEYDOWN
                elif event.key == pygame.K_f:
                    if self.player:
                        self.player.shield_on()
            elif event.type == pygame.MOUSEBUTTONDOWN or event.type == pygame.MOUSEBUTTONUP:
                if event.button == 3:
                    self.thrust = event.type == pygame.MOUSEBUTTONDOWN
                elif event.button == 1:
                    self.fire = event.type == pygame.MOUSEBUTTONDOWN

        self.particle.show(self.show_particles)

        x, y = pygame.mouse.get_rel()
        self.rotate_by = x / 5.0

        if self.rotate_left:
            self.rotate_by = -3
        elif self.rotate_right:
            self.rotate_by = 3

        if self.player:
            self.player.thrust(self.thrust)

            if self.fire:
                self.player.fire();

            self.player.rotate_by(self.rotate_by)

        for i in self.sprites:
            i.update()
        self.particle.update()

        self.alien_time -= 1
        if self.alien_time < 0:
            self.alien_time = random.randint(1000, 2000)
            alien.Alien(self)

        if self.player and self.player.kill:
            self.player = None

        self.sprites = [x for x in self.sprites if not x.kill]

        # split the world into a map of 100x100 squares, put a note in each
        # square of each sprite which intersects with that square ... then when
        # we test for collisions, we only need to test against the sprites in
        # that map square

        # 100 is the max radius of the asteroids we make
        map_spacing = 100
        map_width = int(math.ceil(float(self.width) / map_spacing))
        map_height = int(math.ceil(float(self.height) / map_spacing))
        world_map = []
        for x in range(map_width):
            map_row = [[] for y in range(map_height)]
            world_map.append(map_row)

        for i in self.sprites:
            i.tested_collision = False
            x = int(i.position[0] / map_spacing) % map_width
            y = int(i.position[1] / map_spacing) % map_height
            for a in range(x - 1, x + 2):
                for b in range(y - 1, y + 2):
                    world_map[a % map_width][b % map_height].append(i)

        for i in self.sprites:
            x = int(i.position[0] / map_spacing) % map_width
            y = int(i.position[1] / map_spacing) % map_height
            i.test_collisions(world_map[x][y])

            # now we've tested i against everything it could possibly touch, 
            # we no longer need to test anything against i
            i.tested_collision = True

    def draw(self):
        self.particle.draw()
        for i in self.sprites:
            i.draw()

9:mian.py

import os
import random
import math

import pygame
from pygame import mixer

import util
import asteroid
import text
import world
import ship

class Game(object):
    def __init__(self, surface):
        self.surface = surface
        self.world = world.World(surface)
        self.width = self.world.width
        self.height = self.world.height
        self.clock = pygame.time.Clock()
        self.level = 1

    def draw_hud(self):
        text.draw_string(self.surface, "SCORE %d" % self.world.score, 
                         util.WHITE, 10, [10, 20])
        text.draw_string(self.surface, "LEVEL %d" % self.level, 
                         util.WHITE, 10, [10, 40])

    def start_screen(self):
        self.world.add_text('ARGH ITS THE ASTEROIDS', scale = 20)
        self.world.add_text('PRESS ESC TO QUIT') 
        self.world.add_text('PRESS LEFT AND RIGHT TO ROTATE') 
        self.world.add_text('PRESS UP FOR THRUST')
        self.world.add_text('PRESS SPACE FOR FIRE')
        self.world.add_text('PRESS M TO TURN MUSIC ON OR OFF')
        self.world.add_text('OR USE MOUSE CONTROLS') 
        self.world.add_text('WATCH OUT FOR ALLEN THE ALIEN')
        self.world.add_text('PRESS ENTER TO START', scale = 20)

        for i in range(4):
            asteroid.Asteroid(self.world, random.randint(50, 100), 1)
        self.world.particle.starfield()

        while not self.world.quit and not self.world.enter:
            self.world.update()
            self.surface.fill(util.BLACK)
            self.draw_info()
            self.world.draw()
            # set the limit very high, we can use the start screen as a 
            # benchmark
            self.clock.tick(200)
            pygame.display.flip()

    def draw_info(self):
        if self.world.info:
            text.draw_string(self.surface, 
                             "FPS %d" % self.clock.get_fps(),
                             util.WHITE, 10, [10, self.height - 20])
            text.draw_string(self.surface, 
                             "OBJECTS %d" % self.world.n_objects(), 
                             util.WHITE, 10, [10, self.height - 40])
            text.draw_string(self.surface, 
                             "PARTICLES %d" % self.world.particle.n_particles(),
                             util.WHITE, 10, [10, self.height - 60])

    def level_start(self):
        start_animation_frames = 100
        start_animation_time = start_animation_frames

        while not self.world.quit:
            if start_animation_time == 0:
                break

            self.world.update()
            if self.world.spawn:
                asteroid.Asteroid(self.world, 
                                  random.randint(75, 100), 
                                  self.level)

            self.surface.fill(util.BLACK)
            self.draw_hud()

            self.draw_info()
            start_animation_time -= 1
            t = float(start_animation_time) / start_animation_frames
            text.draw_string(self.surface, "LEVEL START", util.WHITE,
                             t * 150,
                             [self.width / 2, self.height / 2],
                             centre = True, 
                             angle = t * 200.0)
            self.world.draw()
            self.clock.tick(60)
            pygame.display.flip()

    def play_level(self):
        while not self.world.quit:
            if self.world.n_asteroids == 0:
                break
            if not self.world.player:
                break
            if self.world.next_level:
                self.world.remove_asteroids()
                break

            self.world.update()
            self.surface.fill(util.BLACK)
            self.draw_hud()
            self.draw_info()
            self.world.draw()
            self.clock.tick(60)
            pygame.display.flip()

    def game_over(self):
        end_animation_frames = 100
        end_animation_time = end_animation_frames

        while not self.world.quit:
            if end_animation_time == 0:
                break

            self.world.update()

            self.surface.fill(util.BLACK)
            self.draw_hud()
            self.draw_info()
            end_animation_time -= 1
            t = float(end_animation_time) / end_animation_frames
            text.draw_string(self.surface, "GAME OVER", util.WHITE,
                             math.log(t + 0.001) * 150,
                             [self.width / 2, self.height / 2],
                             centre = True,
                             angle = 180)
            self.world.draw()
            self.clock.tick(60)
            pygame.display.flip()

    def epilogue(self):
        while not self.world.quit:
            if self.world.enter:
                break

            self.world.update()

            self.surface.fill(util.BLACK)
            text.draw_string(self.surface, "PRESS ENTER TO PLAY AGAIN", 
                             util.WHITE,
                             20,
                             [self.width / 2, self.height / 2],
                             centre = True,
                             angle = 0)
            self.draw_hud()
            self.draw_info()
            self.world.draw()
            self.clock.tick(60)
            pygame.display.flip()

    def play_game(self):
        self.start_screen()

        while not self.world.quit:
            self.level = 1
            self.world.reset()
            self.world.particle.starfield()

            while not self.world.quit:
                self.level_start()

                self.world.add_player()
                for i in range(self.level * 2):
                    asteroid.Asteroid(self.world, 
                                      random.randint(75, 100), 
                                      0.5 + self.level / 4.0)

                self.play_level()

                if not self.world.player:
                    break

                self.level += 1

            self.game_over()
            self.epilogue()

def main():
    pygame.init()
    mixer.init()

    # audio channel allocation:
    # 
    #   0 - background music
    #   1 - ship engines
    #   2 - ship guns
    #   3 - alien
    #   4 to 7 - explosions
    # 
    # we reserve the first four channels for us to allocate and let mixer pick
    # channels for explosions automatically
    mixer.set_reserved(4)

    surface = pygame.display.set_mode([0, 0], pygame.FULLSCREEN)
    #surface = pygame.display.set_mode([800, 600])
    pygame.mouse.set_visible(False)
    pygame.display.set_caption("Argh, it's the Asteroids!!")

    game = Game(surface)

    game.play_game()

    pygame.quit()

if __name__ == "__main__":
    main()

运行效果:

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!