Python实现飞机大战游戏

最近开始用Python制作游戏,真心觉得开发游戏比玩游戏有趣多了,虽然Python的主业不是可视化和游戏制作,但通过游戏开发的经历来检验学习的效果是很棒的体验。

一、游戏效果

在这里插入图片描述
在这里插入图片描述
游戏是有音效的,在这里没法给大家展示了

二、游戏代码
#导入模块
import pygame
import random
from pygame.locals import *
from os import path

#######################################基本参数配置#######################################

#获取图片库和声音库路径
img_dir = path.join(path.dirname(__file__),'pic')
sound_folder = path.join(path.dirname(__file__),'sounds')

#定义游戏窗口、玩家血量条尺寸,游戏运行速度、炮火持续时间等参数
WIDTH = 480
HEIGHT = 600
FPS = 60
POWERUP_TIME = 5000
BAR_LENGTH = 100
BAR_HEIGHT = 10

#定义白、黑、红、绿、蓝、黄的RGB参数 
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)

#初始化pygame模块,创建游戏窗口、游戏窗口命名、创建跟踪时间对象
pygame.init()
pygame.mixer.init()  #初始化音效
screen = pygame.display.set_mode((WIDTH,HEIGHT))
pygame.display.set_caption("Aircraft Battle")
clock = pygame.time.Clock()

#定义文本字体
font_name = pygame.font.match_font('arial')

#######################################加载图片#######################################

#加载游戏进行中背景图片
background = pygame.image.load(path.join(img_dir,'starfield.png')).convert()
background = pygame.transform.scale(background,(WIDTH,1536))
height = -936

#加载玩家图片
player_img = pygame.image.load(path.join(img_dir,'player.png')).convert()
player_mini_img = pygame.transform.scale(player_img,(25, 19))
player_mini_img.set_colorkey(BLACK)

#加载玩家炮弹、导弹图片
bullet_img = pygame.image.load(path.join(img_dir,'bullet.png')).convert()
missile_img = pygame.image.load(path.join(img_dir,'missile.png')).convert_alpha()

#加载敌机炮弹图片
enemies_bullet_img = pygame.image.load(path.join(img_dir,'enemies_bullet.png')).convert()

#加载盾牌、闪电图片
powerup_images = {}
powerup_images['shield'] = pygame.image.load(path.join(img_dir, 'shield.png')).convert()
powerup_images['gun'] = pygame.image.load(path.join(img_dir, 'bolt.png')).convert()

#加载敌机和火山石图片
enemies_images = []
lava_images = []
#敌机
enemies_list = [
    'enemies1.png',
    'enemies2.png',
    'enemies3.png'
]
#火山石
lava_list = [
    'lava_med.png',
    'lava_small1.png',
    'lava_small2.png',
    'lava_tiny.png'
]
for image in enemies_list:
    enemies_img = pygame.image.load(path.join(img_dir,image)).convert()
    enemies_img = pygame.transform.scale(enemies_img,(80, 60))
    enemies_images.append(enemies_img)
for image in lava_list:
    lava_images.append(pygame.image.load(path.join(img_dir,image)).convert())

#加载爆炸图片
explosion_anim = {}
explosion_anim['lg'] = []
explosion_anim['sm'] = []
explosion_anim['player'] = []
for i in range(9):
    #敌机、火山石爆炸
    filename = 'regularExplosion0{}.png'.format(i)
    img = pygame.image.load(path.join(img_dir,filename)).convert()
    img.set_colorkey(BLACK)
    #大爆炸    
    img_lg = pygame.transform.scale(img,(75,75))
    explosion_anim['lg'].append(img_lg)
    #小爆炸
    img_sm = pygame.transform.scale(img,(32,32))
    explosion_anim['sm'].append(img_sm)
    #玩家爆炸
    filename = 'sonicExplosion0{}.png'.format(i)
    img = pygame.image.load(path.join(img_dir,filename)).convert()
    img.set_colorkey(BLACK)
    explosion_anim['player'].append(img)

#######################################加载声音#######################################

#加载炮弹、导弹发射声音
shooting_sound = pygame.mixer.Sound(path.join(sound_folder,'pew.wav'))
missile_sound = pygame.mixer.Sound(path.join(sound_folder,'rocket.ogg'))

#加载敌机、火山石爆炸声音
expl_sounds = []
for sound in ['expl3.wav', 'expl6.wav']:
    expl_sounds.append(pygame.mixer.Sound(path.join(sound_folder,sound)))
#调低音量
pygame.mixer.music.set_volume(0.2)

#加载玩家爆炸声音
player_die_sound = pygame.mixer.Sound(path.join(sound_folder,'rumble1.ogg'))

#######################################函数区#######################################

#游戏初始界面和准备开始界面函数
def main_menu():
    global screen
    #加载游戏初始界面背景音乐
    menu_song = pygame.mixer.music.load(path.join(sound_folder,"menu.ogg"))
    #循环播放
    pygame.mixer.music.play(-1)
    #加载游戏初始界面背景图片
    title = pygame.image.load(path.join(img_dir,"main.png")).convert()
    title = pygame.transform.scale(title,(WIDTH, HEIGHT),screen)
    screen.blit(title,(0,0))
    pygame.display.update()
    #检测玩家操作事件
    while True:
        ev = pygame.event.poll()
        if ev.type == pygame.KEYDOWN:
            if ev.key == pygame.K_RETURN:
                break
        elif ev.type == pygame.QUIT:
                pygame.quit()
                quit()
        else:
            draw_text(screen, "Press [ENTER] To Begin", 30, WIDTH/2, HEIGHT/2)
            draw_text(screen, "[A] ←  [S] ↓  [D] →  [W] ↑", 30, WIDTH/2, 2*HEIGHT/3) 
            draw_text(screen, "[Space] fire", 30, WIDTH/2, 3*HEIGHT/4)           
            pygame.display.update()
    #加载准备声音
    ready = pygame.mixer.Sound(path.join(sound_folder,'getready.ogg'))
    ready.play()
    #加载准备开始界面背景颜色和文本
    screen.fill(BLACK)
    draw_text(screen, "GET READY!", 40, WIDTH/2, HEIGHT/3)
    pygame.display.update()

#设置文本属性函数
def draw_text(surf,text,size,x,y):
    #定义文本参数
    font = pygame.font.Font(font_name,size)
    text_surface = font.render(text,True,WHITE)
    text_rect = text_surface.get_rect()
    text_rect.midtop = (x,y)
    surf.blit(text_surface,text_rect)

#设置玩家血量条属性函数
def draw_shield_bar(surf,x,y,pct):
    pct = max(pct,0)
    fill = (pct/100)*BAR_LENGTH
    outline_rect = pygame.Rect(x,y,BAR_LENGTH,BAR_HEIGHT)
    fill_rect = pygame.Rect(x,y,fill,BAR_HEIGHT)
    pygame.draw.rect(surf,GREEN,fill_rect)
    pygame.draw.rect(surf,WHITE,outline_rect,2)

#设置玩家生命数量属性函数
def draw_lives(surf,x,y,lives,img):
    for i in range(lives):
        img_rect = img.get_rect()
        img_rect.x = x+30*i
        img_rect.y = y
        surf.blit(img,img_rect)

#添加敌机函数
def newmob():
    mob_element = Mob()
    all_sprites.add(mob_element)
    mobs.add(mob_element)

#添加火山石函数
def newlava():
    lava_element = Lava()
    all_sprites.add(lava_element)
    lavas.add(lava_element)

#######################################类区#######################################

class Explosion(pygame.sprite.Sprite):
    '''创建爆炸类'''
    def __init__(self,center,size):
        pygame.sprite.Sprite.__init__(self)
        self.size = size
        self.image = explosion_anim[self.size][0]
        self.rect = self.image.get_rect()
        self.rect.center = center
        self.frame = 0 
        self.last_update = pygame.time.get_ticks()
        self.frame_rate = 75

    def update(self):        
        now = pygame.time.get_ticks()
        if now - self.last_update > self.frame_rate:
            self.last_update = now
            self.frame += 1
            if self.frame == len(explosion_anim[self.size]):
                self.kill()
            else:
                center = self.rect.center
                self.image = explosion_anim[self.size][self.frame]
                self.rect = self.image.get_rect()
                self.rect.center = center

class Player(pygame.sprite.Sprite):
    '''创建玩家类'''
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.transform.scale(player_img,(50, 38))
        self.image.set_colorkey(BLACK)
        self.rect = self.image.get_rect()
        self.radius = 20
        self.rect.centerx = WIDTH/2
        self.rect.bottom = HEIGHT-10
        self.speedx = 0
        self.speedy = 0
        self.shield = 100
        self.shoot_delay = 250
        self.last_shot = pygame.time.get_ticks()
        self.lives = 3
        self.hidden = False
        self.hide_timer = pygame.time.get_ticks()
        self.power = 1
        self.power_timer = pygame.time.get_ticks()

    def update(self):
        if self.power >= 2 and pygame.time.get_ticks() - self.power_time > POWERUP_TIME: 
            self.power -= 1
            self.power_time = pygame.time.get_ticks()
        if self.hidden and pygame.time.get_ticks() - self.hide_timer > 1000:
            self.hidden = False
            self.rect.centerx = WIDTH/2
            self.rect.bottom = HEIGHT-30
        self.speedx = 0
        self.speedy = 0
        #方向控制:A控制左、D控制右、W控制上、S控制下、A+W控制左上、A+S控制左下、D+W控制右上、D+S控制右下
        keystate = pygame.key.get_pressed()
        if keystate[K_a]:
            self.speedx = -5
        if keystate[K_d]:
            self.speedx = 5
        if keystate[K_w]:
            self.speedy = -5
        if keystate[K_s]:
            self.speedy = 5
        #发射控制:空格
        if keystate[pygame.K_SPACE]:
            self.shoot()
        #设置玩家移动边界
        if self.rect.right > WIDTH:
            self.rect.right = WIDTH
        if self.rect.left < 0:
            self.rect.left = 0
        if self.rect.top < 10:
            self.rect.top = 10
        if self.rect.bottom > HEIGHT-10:
            self.rect.bottom = HEIGHT-10
        self.rect.x += self.speedx
        self.rect.y += self.speedy

    def shoot(self):
        now = pygame.time.get_ticks()
        if now-self.last_shot > self.shoot_delay:
            self.last_shot = now
            #单火力
            if self.power == 1:
                bullet = Bullet(self.rect.centerx, self.rect.top)
                all_sprites.add(bullet)
                bullets.add(bullet)
                shooting_sound.play()
            #双火力
            if self.power == 2:
                bullet1 = Bullet(self.rect.left, self.rect.centery)
                bullet2 = Bullet(self.rect.right, self.rect.centery)
                all_sprites.add(bullet1)
                all_sprites.add(bullet2)
                bullets.add(bullet1)
                bullets.add(bullet2)
                shooting_sound.play()
            #三火力
            if self.power >= 3:
                bullet1 = Bullet(self.rect.left, self.rect.centery)
                bullet2 = Bullet(self.rect.right, self.rect.centery)
                missile1 = Missile(self.rect.centerx, self.rect.top) # 导弹
                all_sprites.add(bullet1)
                all_sprites.add(bullet2)
                all_sprites.add(missile1)
                bullets.add(bullet1)
                bullets.add(bullet2)
                bullets.add(missile1)
                shooting_sound.play()
                missile_sound.play()

    def powerup(self):
        self.power += 1
        self.power_time = pygame.time.get_ticks()

    def hide(self):
        self.hidden = True
        self.hide_timer = pygame.time.get_ticks()
        self.rect.center = (WIDTH/2, HEIGHT+200)

class Mob(pygame.sprite.Sprite):
    '''创建敌机类'''
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image_orig = random.choice(enemies_images)
        self.image_orig.set_colorkey(BLACK)
        self.image = self.image_orig.copy()
        self.rect = self.image.get_rect()
        self.radius = int(self.rect.width*.90/2)
        self.rect.x = random.randrange(0, WIDTH-self.rect.width)
        self.rect.y = random.randrange(-150,-100)       
        self.speedy = random.randrange(5,10)
        self.speedx = random.randrange(-3,3)
        self.shoot_delay = 1000
        self.last_shot = pygame.time.get_ticks()        

    def update(self):
        self.rect.x += self.speedx
        self.rect.y += self.speedy
        if random.randrange(10) >= 6:
            self.enemies_shoot()        
        if (self.rect.top > HEIGHT+10) or (self.rect.left < -25) or (self.rect.right > WIDTH+20):
            self.rect.x = random.randrange(0,WIDTH-self.rect.width)
            self.rect.y = random.randrange(-100,-40)
            self.speedy = random.randrange(1,8)
    
    def enemies_shoot(self):
        now = pygame.time.get_ticks()
        if now-self.last_shot > self.shoot_delay:
            self.last_shot = now
            enemies_bullet = EnemiesBullet(self.rect.centerx, self.rect.bottom)
            all_sprites.add(enemies_bullet)
            enemies_bullets.add(enemies_bullet)
            shooting_sound.play()

class Lava(pygame.sprite.Sprite):
    '''创建火山石类'''
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image_orig = random.choice(lava_images)
        self.image_orig.set_colorkey(BLACK)
        self.image = self.image_orig.copy()
        self.rect = self.image.get_rect()
        self.radius = int(self.rect.width*.90/2)
        self.rect.x = random.randrange(0, WIDTH-self.rect.width)
        self.rect.y = random.randrange(-150,-100)       
        self.speedy = random.randrange(5,10)
        self.speedx = random.randrange(-3,3)
        self.rotation = 0
        self.rotation_speed = random.randrange(-8, 8)
        self.last_update = pygame.time.get_ticks()

    #添加火山石旋转效果
    def rotate(self):
        time_now = pygame.time.get_ticks()
        if time_now-self.last_update > 50:
            self.last_update = time_now
            self.rotation = (self.rotation+self.rotation_speed)%360 
            new_image = pygame.transform.rotate(self.image_orig,self.rotation)
            old_center = self.rect.center
            self.image = new_image
            self.rect = self.image.get_rect()
            self.rect.center = old_center                

    def update(self):
        self.rotate()
        self.rect.x += self.speedx
        self.rect.y += self.speedy               
        if (self.rect.top > HEIGHT+10) or (self.rect.left < -25) or (self.rect.right > WIDTH+20):
            self.rect.x = random.randrange(0,WIDTH-self.rect.width)
            self.rect.y = random.randrange(-100,-40)
            self.speedy = random.randrange(1,8)       

class Bullet(pygame.sprite.Sprite):
    '''创建玩家炮弹类'''
    def __init__(self, x, y):
        pygame.sprite.Sprite.__init__(self)
        self.image = bullet_img
        self.image.set_colorkey(BLACK)
        self.rect = self.image.get_rect()
        self.rect.bottom = y 
        self.rect.centerx = x
        self.speedy = -10

    def update(self):
        self.rect.y += self.speedy
        if self.rect.bottom < 0:
            self.kill()

class EnemiesBullet(pygame.sprite.Sprite):
    '''创建敌机炮弹类'''
    def __init__(self, x, y):
        pygame.sprite.Sprite.__init__(self)
        self.image = enemies_bullet_img
        self.image.set_colorkey(BLACK)
        self.rect = self.image.get_rect()
        self.rect.top = y 
        self.rect.centerx = x
        self.speedy = 10

    def update(self):
        self.rect.y += self.speedy
        if self.rect.top > 600:
            self.kill()

class Missile(pygame.sprite.Sprite):
    '''创建导弹类'''
    def __init__(self, x, y):
        pygame.sprite.Sprite.__init__(self)
        self.image = missile_img
        self.image.set_colorkey(BLACK)
        self.rect = self.image.get_rect()
        self.rect.bottom = y
        self.rect.centerx = x
        self.speedy = -10

    def update(self):
        self.rect.y += self.speedy
        if self.rect.bottom < 0:
            self.kill()

class Pow(pygame.sprite.Sprite):
    '''创建补给类'''
    def __init__(self, center):
        pygame.sprite.Sprite.__init__(self)
        self.type = random.choice(['shield', 'gun'])
        self.image = powerup_images[self.type]
        self.image.set_colorkey(BLACK)
        self.rect = self.image.get_rect()
        self.rect.center = center
        self.speedy = 4

    def update(self):
        self.rect.y += self.speedy
        if self.rect.top > HEIGHT:
            self.kill()

#######################################主循环#######################################

#定义游戏开始界面标识
running = True
menu_display = True

while running:
    if menu_display:
        main_menu()
        pygame.time.wait(3000)
        pygame.mixer.music.stop()
        pygame.mixer.music.load(path.join(sound_folder,'tgfcoder-FrozenJam-SeamlessLoop.ogg'))
        pygame.mixer.music.play(-1)
        menu_display = False

        all_sprites = pygame.sprite.Group()
        player = Player()
        all_sprites.add(player)        
        mobs = pygame.sprite.Group()
        for i in range(4):
            newmob()
        lavas = pygame.sprite.Group()
        for i in range(4): 
            newlava()
        bullets = pygame.sprite.Group()
        enemies_bullets = pygame.sprite.Group()
        powerups = pygame.sprite.Group()

        score = 0   

    clock.tick(FPS)
    
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                running = False

    all_sprites.update()
    
    #敌机与玩家炮弹碰撞检测
    hits = pygame.sprite.groupcollide(mobs,bullets,True,True)    
    for hit in hits:
        score += 50-hit.radius
        random.choice(expl_sounds).play()       
        expl = Explosion(hit.rect.center,'lg')
        all_sprites.add(expl)
        if random.random() > 0.9:
            pow = Pow(hit.rect.center)
            all_sprites.add(pow)
            powerups.add(pow)
        newmob()
    
    #火山石与玩家炮弹碰撞检测
    hits = pygame.sprite.groupcollide(lavas,bullets,True,True)    
    for hit in hits:
        score += 50-hit.radius
        random.choice(expl_sounds).play()      
        expl = Explosion(hit.rect.center,'lg')
        all_sprites.add(expl)
        if random.random() > 0.9:
            pow = Pow(hit.rect.center)
            all_sprites.add(pow)
            powerups.add(pow)
        newlava()

    #玩家与敌机碰撞检测
    hits = pygame.sprite.spritecollide(player,mobs,True,pygame.sprite.collide_circle)
    for hit in hits:
        player.shield -= hit.radius*2
        expl = Explosion(hit.rect.center,'sm')
        all_sprites.add(expl)
        newmob()
        if player.shield <= 0: 
            player_die_sound.play()
            death_explosion = Explosion(player.rect.center,'player')
            all_sprites.add(death_explosion)
            player.hide()
            player.lives -= 1
            player.shield = 100

    #玩家与火山石碰撞检测
    hits = pygame.sprite.spritecollide(player,lavas,True,pygame.sprite.collide_circle)
    for hit in hits:
        player.shield -= hit.radius*2
        expl = Explosion(hit.rect.center,'sm')
        all_sprites.add(expl)
        newlava()
        if player.shield <= 0: 
            player_die_sound.play()
            death_explosion = Explosion(player.rect.center,'player')
            all_sprites.add(death_explosion)
            player.hide()
            player.lives -= 1
            player.shield = 100
    
    #玩家与敌机炮弹碰撞检测
    hits = pygame.sprite.spritecollide(player,enemies_bullets,True,pygame.sprite.collide_circle)
    for hit in hits:
        player.shield -= hit.radius*2
        expl = Explosion(hit.rect.center,'sm')
        all_sprites.add(expl)        
        if player.shield <= 0: 
            player_die_sound.play()
            death_explosion = Explosion(player.rect.center,'player')
            all_sprites.add(death_explosion)
            player.hide()
            player.lives -= 1
            player.shield = 100
    
    #玩家与补给碰撞检测
    hits = pygame.sprite.spritecollide(player,powerups,True)
    for hit in hits:
        if hit.type == 'shield':
            player.shield += random.randrange(10,30)
            if player.shield >= 100:
                player.shield = 100
        if hit.type == 'gun':
            player.powerup()

    if player.lives == 0 and not death_explosion.alive():
        pygame.time.wait(1000)
        screen.fill(BLACK)
        draw_text(screen, "Game Over", 40, WIDTH/2, HEIGHT/3)
        pygame.display.update()
        pygame.time.wait(3000)
        menu_display = True

    #背景画卷向下滚动
    screen.fill(BLACK)    
    screen.blit(background,(0,height))
    height += 2
    if height >= -168:
        height = -936

    all_sprites.draw(screen)
    draw_text(screen,str(score),18,WIDTH/2,10)
    draw_shield_bar(screen,5,5,player.shield)    
    draw_lives(screen,WIDTH-100,5,player.lives,player_mini_img)

    pygame.display.flip()    

pygame.quit()

感兴趣的朋友可以到我的Gitee码云下载源代码、图片库和声音库,链接如下:
添加链接描述

  • 20
    点赞
  • 82
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值