python打飞机小游戏

前言

1 学习pygame 检测矩形碰撞过程中,制作了一个打飞机的小游戏,如果感觉代码不错,请不吝给个赞,如果有BUG的地方请留言或私聊,如果有相同游戏制作爱好者,可以加好友交流心得,共同进步。
2 如果借用这段代码请注明出处。
3 游戏设计的比较简单,有些变量取得也比较随意,可以自行优化和进阶。

素材

1 程序所用的图片素材、背景音乐均来自爱给网
2.爆炸音效来自小白博主分享的素材,小白博主的代码更高级,有兴趣的可以看看

1 爆炸素材

在py文件同目录下,建一个explosion文件夹,里面存放爆炸图片,命名从explosion_0.png到sxplosion_8.png
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2. 图片素材–飞机 背景

建一个pngs文件夹里面的三个文件命名分别为bg_image.png、bullet.png、enemy.png、plane.png、player.png
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3. 音乐

背景音乐和音效,直接放在py文件同目录下,因为博客没法上传音频,所以需要自己准备音频。
背景音乐命名为 1.mp3,音效命名为expl0.wav。
如果实在没有音频,就把所有的音频代码注释掉,不会找的话,运行的时候自然会有报错提示,到时候再一个一个注释掉。

完整代码

import pygame
import random
import os
import time
"""
一、图片
    1.正在如背景图片 bg = pygame.image.load() screen.blit(bg, (x, y))
    2.更改载入图片大小 im = pygame.transform.scale(image, (width, height))
    3.更改图片方向 im = pygame.transform.rotate(image, num)
    4.解决图片报错  libpng warning: iCCP: known incorrect sRGB profile
二、群组与矩形碰撞
    1.增加敌机群组 并循环显示  group.draw(screen)  group.update()
    2.战机与敌机碰撞 spritecollite()
    3.添加子弹 同敌机
    4.子弹与敌机碰撞 groupcollite()
三、爆炸
    1.载入爆炸图片
    2.建立爆炸群组
    3.添加群组
四、分数 血条 生命 结束 重启
    1.player.score
    2.player.blood
    3.player.lives
    4.游戏结束后文字显示
    5.重新开始
五、背景音乐
    1.载入音乐 pygame.mixer.music.load('bg_music.mp3')
    2.设置音量 pygame.mixer.music.set_volume(0-1之间)
    3.播放音乐 pygame.mixer.music.play()
    4.停止播放 pygame.mixer.music.stop()
六、音效
    1.载入音效 
        winner_sound = pygame.mixer.Sound("winner.wav")
        loser_sound = pygame.mixer.Sound("loser.wav")
    2.播放音效
        winner_sound.play()
        loser_sound.play()
七、修改
    1.敌机运动轨迹
    2.增加发射子弹的敌机
"""

BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
GRAY = (194, 194, 194)


WIDTH = 473
HEIGHT = 710

pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('model')
clock = pygame.time.Clock()
FPS = 60

# 背景图片
bg_image = pygame.image.load(os.path.join('pngs', 'bg_image.png')).convert_alpha()
bg_y = 0
speedy = 3
height = 0

# 爆炸图片
explosion_lst = []
for i in range(9):
    exp = pygame.image.load(f'explosion/explosion_{i}.png').convert_alpha()
    explosion_lst.append(exp)

# 生命图片
player_lives = pygame.image.load('pngs/player.png').convert_alpha()
player_rect = player_lives.get_rect()
player_lives = pygame.transform.scale(player_lives, (player_rect.width // 4, player_rect.height // 4))

# 载入音乐
# 加载音乐
pygame.mixer.music.load('1.mp3')
# 设置音量
pygame.mixer.music.set_volume(0.5)
# 播放音乐
pygame.mixer.music.play(-1)

# 载入音效
explosion_music = pygame.mixer.Sound('expl0.wav')

# 解决图片报错
# from PIL import Image
# def fix_image_srgb_profile(file_path):
#     img = Image.open(file_path)
#     img.save(file_path, icc_profile=None)
#
# fix_image_srgb_profile(os.path.join('pngs', 'plane.png'))


class Player(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(os.path.join('pngs', 'player.png')).convert_alpha()
        self.rect = self.image.get_rect()
        # 更改图片大小
        self.image = pygame.transform.scale(self.image, (self.rect.width // 2, self.rect.height // 2))
        self.rect = self.image.get_rect()
        self.rect.center = (WIDTH // 2, HEIGHT - 50)
        self.speed = 5
        self.direction = 0
        self.up = 0
        self.bullet_speed = 8
        self.bullet = 0
        self.score = 0
        self.blood = 100
        self.state = 'running'
        self.lives = 3

    def move(self):
        old_x = self.rect.centerx
        old_y = self.rect.centery
        self.rect.centerx += self.speed * self.direction
        if self.rect.centerx < self.rect.width // 2 or self.rect.centerx > WIDTH - self.rect.width // 2:
            self.rect.centerx = old_x
        self.rect.centery += self.speed * self.up
        if self.rect.centery > HEIGHT - self.rect.height // 2 or self.rect.centery < self.rect.height // 2:
            self.rect.centery = old_y

    def bullets(self):
        self.bullet = Bullet((self.rect.centerx, self.rect.centery - self.rect.height // 2 + 2))


enemy_lst = []
enemy_image0 = pygame.image.load('pngs/plane.png').convert_alpha()
enemy_rect0 = enemy_image0.get_rect()
enemy_image0 = pygame.transform.scale(enemy_image0, (enemy_rect0.width // 2, enemy_rect0.height // 2))
enemy_image0 = pygame.transform.rotate(enemy_image0, 180)
enemy_image1 = pygame.image.load('pngs/enemy.png').convert_alpha()
enemy_rect1 = enemy_image1.get_rect()
enemy_image1 = pygame.transform.scale(enemy_image1, (enemy_rect1.width // 2, enemy_rect1.height // 2))
enemy_lst.append(enemy_image0)
enemy_lst.append(enemy_image1)

enemy_bullet_group = pygame.sprite.Group()


class Enemy(pygame.sprite.Sprite):
    def __init__(self, locate):
        pygame.sprite.Sprite.__init__(self)
        # self.image = pygame.image.load('pngs/plane.png').convert_alpha()
        # self.rect = self.image.get_rect()
        # # 更改飞机尺寸、方向
        # self.image = pygame.transform.scale(self.image, (self.rect.width //2, self.rect.height // 2))
        # self.image = pygame.transform.rotate(self.image, 180)
        self.random_num = random.randint(0, 1)
        self.image = enemy_lst[self.random_num]
        self.rect = self.image.get_rect()
        self.rect.center = locate
        self.speedy = random.randint(3, 8)
        self.speedx = random.randint(-3, 3)
        self.b = 0

    def update(self):
        self.b += 1
        self.rect.centery += self.speedy
        self.rect.centerx += self.speedx
        if 0 < self.rect.centery < HEIGHT and self.random_num == 1 and self.b % 30 == 0:
            bullet = EnemyBullet((self.rect.centerx, self.rect.centery + self.rect.height // 2 + 5))
            enemy_bullet_group.add(bullet)
        if self.rect.centerx < self.rect.width // 2 or self.rect.centerx > WIDTH - self.rect.width // 2:
            self.speedx = -self.speedx
        if self.rect.centery > HEIGHT:  # or self.rect.centerx < self.rect.width // 2 or self.rect.centerx > WIDTH - self.rect.width // 2:
            self.kill()


class Bullet(pygame.sprite.Sprite):
    def __init__(self, locate):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load('pngs/bullet.png').convert_alpha()
        self.rect = self.image.get_rect()
        # 更改尺寸
        self.image = pygame.transform.scale(self.image, (self.rect.width // 2, self.rect.height // 2))
        self.rect = self.image.get_rect()
        self.rect.center = locate
        self.speed = 8

    def update(self):
        self.rect.centery -= self.speed
        if self.rect.centery < 0:
            self.kill()


class EnemyBullet(pygame.sprite.Sprite):
    def __init__(self, locate):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load('pngs/bullet.png').convert_alpha()
        self.rect = self.image.get_rect()
        # 更改尺寸
        self.image = pygame.transform.scale(self.image, (self.rect.width // 2, self.rect.height // 2))
        self.image = pygame.transform.rotate(self.image, 180)
        self.rect = self.image.get_rect()
        self.rect.center = locate
        self.speed = 8

    def update(self):
        self.rect.centery += self.speed
        if self.rect.centery > HEIGHT:
            self.kill()


# 初始化敌机群组
def enemy_location():
    locations = []
    for i in range(4):
        row = random.randint(0, 8)
        column = random.randint(0, 6)
        location = (32 + column * 64, -320 + row * 64)
        if not (location in locations):
            locations.append(location)
            enemy = Enemy(location)
            enemies.add(enemy)


class Explosion(pygame.sprite.Sprite):
    def __init__(self, enemy_position, n):
        pygame.sprite.Sprite.__init__(self)
        self.num = 0
        self.size = n
        self.image = explosion_lst[self.num]
        self.rect = self.image.get_rect()
        self.image = pygame.transform.scale(self.image, (self.rect.width // self.size, self.rect.height // self.size))
        self.rect = self.image.get_rect()
        self.rect.center = enemy_position
        self.old_time = time.time() * 1000
        self.new_time = 0

    def update(self):
        self.new_time = time.time() * 1000
        if self.new_time - self.old_time > 100:
            self.num += 1
            if self.num <= 8:
                self.image = explosion_lst[self.num]
                self.image = pygame.transform.scale(self.image,
                                                    (self.rect.width // self.size, self.rect.height // self.size))
                self.old_time = self.new_time
            else:
                self.kill()


enemies = pygame.sprite.Group()
enemy_location()
player = Player()
Flag = False
bullets_group = pygame.sprite.Group()

explosion_animation = False
explosions = pygame.sprite.Group()

font_score = pygame.font.SysFont('times', 20)
font_end = pygame.font.SysFont('times', 40)
font_restart = pygame.font.SysFont('times', 30)
background_speed = 1

counter = 0
while not Flag:
    clock.tick(FPS)
    counter += 1
    if counter == 10000:
        counter = 0
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            Flag = True
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                player.direction = -1
            if event.key == pygame.K_RIGHT:
                player.direction = 1
            if event.key == pygame.K_UP:
                player.up = -1
            if event.key == pygame.K_DOWN:
                player.up = 1
            if event.key == pygame.K_SPACE:
                if player.state == 'running':
                    player.bullets()
                    bullets_group.add(player.bullet)
            if event.key == pygame.K_ESCAPE:
                player = Player()
                pygame.mixer.music.load('1.mp3')
                # 设置音量
                pygame.mixer.music.set_volume(0.5)
                # 播放音乐
                pygame.mixer.music.play(-1)
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT:
                player.direction = 0
            if event.key == pygame.K_RIGHT:
                player.direction = 0
            if event.key == pygame.K_UP:
                player.up = 0
            if event.key == pygame.K_DOWN:
                player.up = 0

    # 载入背景图片
    screen.blit(bg_image, (0, bg_y))
    screen.blit(bg_image, (0, -bg_image.get_rect().height + bg_y))
    bg_y += background_speed
    if bg_y >= bg_image.get_rect().height:
        bg_y = 0

    player.move()

    # 生命数为0时 游戏结束
    if player.blood > 0:
        screen.blit(player.image, player.rect)
    else:
        if player.lives > 0:
            player.blood = 100
            player.rect.center = (WIDTH // 2, HEIGHT - 50)
        else:
            pygame.mixer.music.stop()  # 背景音乐播放停止
            player.state = 'game_over'
            end_text = font_end.render('Game-Over', 1, RED)
            screen.blit(end_text, (WIDTH // 2 - 100, HEIGHT // 2))
            score_end = font_end.render(f'SCORE: {player.score}', 1, RED)
            screen.blit(score_end, (WIDTH // 2 - 100, HEIGHT // 4))
            restart = font_restart.render('PRESS ESC T0 RESTART GAME', 1, RED)
            screen.blit(restart, (25, HEIGHT * 3 // 4))

    # game_over时不再显示飞机
    if player.state == 'running':
        enemies.draw(screen)
        enemies.update()
        # 如果敌机数量少于4,那么再添加4个敌机
        if len(enemies) < 4:
            enemy_location()
        bullets_group.draw(screen)
        bullets_group.update()

        enemy_bullet_group.draw(screen)
        enemy_bullet_group.update()
    else:
        background_speed = 0

    # 碰撞 飞机与敌机碰撞  hit1是个列表,元素是敌机
    hit1 = pygame.sprite.spritecollide(player, enemies, True)
    if hit1:
        explosion_music.play()
        explosion_image = Explosion(hit1[0].rect.center, 2)
        explosions.add(explosion_image)
        player.blood -= 10
        hit1[0].kill()
        if player.blood < 10:
            player.lives -= 1
            explosion_image = Explosion(player.rect.center, 1)
            explosions.add(explosion_image)
    # 子弹与敌机碰撞 hit2 是个字典,key是子弹,value是个敌机列表
    hit2 = pygame.sprite.groupcollide(bullets_group, enemies, True, True)
    if hit2:
        explosion_music.play()
        player.score += 1
        explosion_animation = True
        for k, v in hit2.items():
            explosion_image = Explosion(v[0].rect.center, 1)
            explosions.add(explosion_image)
            k.kill()
            v[0].kill()
    explosions.draw(screen)
    explosions.update()
    # 敌机子弹与战机碰撞
    hit3 = pygame.sprite.spritecollide(player, enemy_bullet_group, True)
    if hit3:
        explosion_music.play()
        player.blood -= 10
        explosion_image = Explosion(hit3[0].rect.center, 2)
        explosions.add(explosion_image)
        hit3[0].kill()
        if player.blood < 10:
            player.lives -= 1
            explosion_image = Explosion(player.rect.center, 1)
            explosions.add(explosion_image)

    # 血条
    pygame.draw.rect(screen, RED, (10, 10, 104, 20), 2)
    pygame.draw.rect(screen, GREEN, (12, 12, player.blood, 16))
    # 分数
    score_text = font_score.render(f'score: {player.score}', 1, WHITE)
    screen.blit(score_text, (WIDTH // 2 - 20, 10))
    # 生命数量
    for i in range(player.lives):
        screen.blit(player_lives, (WIDTH - 120 + i * 40, 10))

    pygame.display.flip()

pygame.quit()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值