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