在学过《python从入门到实践》后,我觉得项目一的小游戏-外星人入侵的主题与玩法有些单调,想为其增点色彩,在之后的一段时间里,我断断续续地产生新想法,每当觉得想法不错的时候,就会想方试法的将其实现。整个游戏的主题为夏目友人帐,因为能力有限,事实上我更想做一个剧情类游戏。
外星人入侵原有的框架包含的class有ship,bullet,alien,记分板等等,我在此基础上,添加了一些增益效果和金币,并且通过消耗金币可以释放一些技能,创建了一些不同的敌人和boss,在ship碰到某些敌人会触发一定的限制效果,增加了ship阵亡的显示效果,背景音乐,封面等。所用图片都是网上搜索和自己截取经过ps处理的,图片的资源放在文末的链接。
先给大家看一下实际效果吧!
视频链接:
Python-pygame 《外星人入侵》升级_哔哩哔哩_bilibili-https://www.bilibili.com/video/BV1Yv411G7v4
Python-pygame小游戏《外星人入侵》主题玩法升级版_哔哩哔哩_bilibili-https://www.bilibili.com/video/BV1m3411y7gm图片,音乐资源(方便复现):链接:https://pan.baidu.com/s/1LA6hxg00qRZujnblPKCFJg
提取码:bb33
一开始用的纯色背景,看起来颜色比较鲜明,这个做成GIF内存小点,能放的时间长点,
封面:
下面是整个程序所涉及的python文件:
要想程序简洁高效,一定要学会面向对象的编程思想,根据不同对象的需求和特点,为之编写属性与方法,比如ship,它需要位置属性,图像属性等,还要为之制定绘制ship、更新位置等方法。
主模块: 对应alien_invasion.py文件,即程序要在该文件下运行,其他模块均为导入模块,我将主模块程序进行了简单分类,方便大家寻找使用。(代码略多,还可以重构优化)
下面是主模块init、游戏主循环、键盘鼠标事件响应,屏幕更新,还有背景音乐(这个是最后加上去的)
import sys
from time import sleep,time
import pygame.image
from bullet import *
from alien import *
from settings import Settings
from game_stats import Gamestats
from button import *
from scoreboard import *
from miaobi_r import Miaobir
from random import choice,randint
class AlienInvasion:
"""管理游戏资源和行为的类"""
def __init__(self):
"""初始化游戏并创建游戏资源"""
pygame.init()
self.settings= Settings()
self.screen=pygame.display.set_mode((self.settings.screen_width,self.settings.screen_height))
pygame.display.set_caption("夏目友人帐")
# 创建一个用于存储游戏统计信息的实例
self.stats = Gamestats(self)
self.ship=Ship(self,'images/ship.png')
self.bullets=pygame.sprite.Group()
self.jineng1=pygame.sprite.Group()
self.aliens=pygame.sprite.Group()
self.boss1=pygame.sprite.Group()
self.miaobi=pygame.sprite.Group()
self.jineng2_1duan=pygame.sprite.Group()
self.jineng2_2duan=pygame.sprite.Group()
self.heimao_bulletgroup=pygame.sprite.Group()
self._create_fleet()
self._create_miaobiqun()
self.play_button=Button(self,'click to play~',255,255,255)
self.replay_button=Button(self,'replay',255,255,255)
self.music_button=Music_flag(self,'playing',255,255,255)
self.youxishuoming=Youxishuoming(self,'Game Description',255,255,255)
self.score_board=Scoreboard(self)
self.history=History(self)
self.miaobi_note=Miaobir(self)
#self.clock=pygame.time.Clock()
#self.current_time=pygame.time.get_ticks()
def run_game(self):
"""开始游戏的主循环"""
while True:
self._check_events()
self.music_update()
if self.stats.game_active==True:
if self.settings.jiluboss_time_flag:
self.settings.create_boss_time = time()
self.settings.jiluboss_time_flag=False
self.ship.update()
self.update_bullets()
self.update_jineng1()
self.update_jineng2_1duan()
self.update_jineng2_2duan()
self.update_aliens()
self.update_boss1()
self.update_heimaobullet()
self.update_miaobi()
self._update_screen()
#self.clock.tick(100)
def _check_events(self):
"""响应按键和鼠标事件"""
for event in pygame.event.get():
if event.type==pygame.QUIT:
sys.exit()
elif event.type==pygame.MOUSEBUTTONDOWN:
mouse_pos = pygame.mouse.get_pos()
if self.stats.ships_left==self.settings.ship_limit:
self._check_play_button(mouse_pos)
self._check_youxishuoming_button(mouse_pos)
elif self.stats.ships_left==0:
self._check_replay_button(mouse_pos)
elif event.type==pygame.KEYDOWN:
self._check_keydown_events(event)
elif event.type==pygame.KEYUP:
self._check_keyup_events(event)
def music1_start(self):
pygame.mixer.init() # 初始化
pygame.mixer.music.load('musics/bgmusic1.mp3') # 加载音乐文件
pygame.mixer.music.play(-1)
def music_update(self):
if self.stats.game_active==False:
if self.settings.music2_active == False:
self.music2_start()
self.settings.music2_active=True
else:
if self.settings.music1_active == False:
self.music1_start()
self.settings.music1_active = True
def music2_start(self):
pygame.mixer.init() # 初始化
pygame.mixer.music.load('musics/bgmusic2.mp3') # 加载音乐文件
pygame.mixer.music.play(-1)
def _update_screen(self):
"""更新屏幕上的图像,并切换到新屏幕"""
if self.stats.play_click==False:
self.screen.blit(self.settings.background1,(0,0))
if self.settings.show_youxishuoming_flag:
self.screen.blit(self.settings.youxiguize_image,(0,0))
if self.stats.play_click==True:
#self.screen.fill(self.settings.bg_color)
self.screen.blit(self.settings.background2, (0, 0))
self.ship_show()
for bullet in self.bullets.sprites():
bullet.draw_bullet()
#for heimaobullet in self.new_bulletgroup.copy():
for bullet in self.heimao_bulletgroup.sprites():
bullet.draw_bullet()
self.jineng1.draw(self.screen)
self.jineng2_1duan.draw(self.screen)
self.jineng2_2duan.draw(self.screen)
self.aliens.draw(self.screen)
self.boss1.draw(self.screen)
self.miaobi.draw(self.screen)
self.score_board.show_score()
self.shuaxin_history()
self.history.show_history()
self.miaobi_note.show_miaobi_note()
self.miaobi_note.show_amount()
self.music_button.draw_button()
self.music_button.draw_note_image()
if not self.stats.game_active:
if self.stats.ships_left==self.settings.ship_limit and self.stats.play_click==False:
if self.settings.show_youxishuoming_flag==False:
self.play_button.draw_button()
self.play_button.draw_note_image()
self.youxishuoming.draw_button()
self.youxishuoming.draw_youxishuoming_image()
self.banquanshuoming.draw_button()
elif self.stats.ships_left<=self.settings.ship_limit and self.stats.ships_left>0:
self.play_button.draw_button()
self.play_button.draw_note_pause_image()
elif self.stats.ships_left==0:
self.replay_button.draw_button()
self.replay_button.draw_note_image()
self.ship.center_ship()
pygame.display.flip()
def _check_keydown_events(self,event):
if event.key==pygame.K_j:
self._fire_bullet(self.settings.bullet_allowed)
if self.stats.zifa_limit_flag==False:
if event.key==pygame.K_u:
if self.stats.amount>=5:
if len(self.jineng1) < self.settings.jineng1_bullet_allowed:
self._fire_jineng1()
self.stats.amount -= 5
self.miaobi_note.prep_miaobi_amount()
if event.key==pygame.K_i:
if self.stats.amount>=10:
self._fire_jineng2_1duan()
self.stats.amount-=10
self.miaobi_note.prep_miaobi_amount()
if event.key==pygame.K_o:
if self.stats.amount>=20:
self.jineng3_xiangyin()
if event.key==pygame.K_TAB:
if self.stats.ships_left<=3 and self.stats.ships_left>0:
self.stats.game_active=False
pygame.mouse.set_visible(True)
if event.key==pygame.K_CAPSLOCK:
if self.stats.ships_left <= 3 and self.stats.ships_left > 0:
self.stats.game_active=True
if event.key==pygame.K_RIGHT:
self.ship.moving_right=True
if event.key==pygame.K_LEFT:
self.ship.moving_left=True
if event.key==pygame.K_UP:
self.ship.moving_up=True
if event.key==pygame.K_DOWN:
self.ship.moving_down=True
if event.key==pygame.K_d:
self.ship.moving_right=True
if event.key==pygame.K_a:
self.ship.moving_left=True
if event.key==pygame.K_w:
self.ship.moving_up=True
if event.key==pygame.K_s:
self.ship.moving_down=True
if event.key==pygame.K_p:
self.settings.music_switch*=-1
if self.settings.music_switch == -1:
self.music_button.msg='pause'
pygame.mixer.music.pause()
else:
self.music_button.msg='playing'
pygame.mixer.music.unpause()
self.music_button._prep_msg()
if event.key==pygame.K_ESCAPE:
sys.exit()
def _check_keyup_events(self,event):
if event.key==pygame.K_RIGHT:
self.ship.moving_right=False
if event.key==pygame.K_LEFT:
self.ship.moving_left=False
if event.key==pygame.K_UP:
self.ship.moving_up=False
if event.key==pygame.K_DOWN:
self.ship.moving_down=False
if event.key==pygame.K_d:
self.ship.moving_right=False
if event.key==pygame.K_a:
self.ship.moving_left=False
if event.key==pygame.K_w:
self.ship.moving_up=False
if event.key==pygame.K_s:
self.ship.moving_down=False
下面是bullet的不同种类,创建,更新,检查碰撞等方法,bullet当然是技能的主要表现方式,普攻是单发(最多同时存在6发),技能1(散射),技能2(爆炸),我自认为技能2是游戏的亮点之一了,发射一个巨大的娘口三三,碰到目标后可以往16个方向释放猫爪。释放多个猫爪的情况,这里我通过创建列表存储update方法中要用到的位移参数,再通过循环遍历达到效果,但实际运行中,猫爪不会往指定的方向径直移动(其实这样的效果也蛮有意思的,所以就没再处理)。
"""bullet..."""
def _fire_bullet(self,bullet_allowed):
if len(self.bullets)<bullet_allowed:
if self.ship.image_prep=='images/ship.png':
new_bullet=Bullet(self,'images/maozhua.png')
self.bullets.add(new_bullet)
elif self.ship.image_prep=='images/ban22.png':
new_bullet=Bullet(self,'images/sansan1.png')
self.bullets.add(new_bullet)
def _fire_jineng1(self):
i=0
while i<9:
new_bullet = Jineng1(self,'images/maozhua.png')
self.jineng1.add(new_bullet)
i+=1
def _fire_jineng2_1duan(self):
if len(self.jineng2_1duan.sprites())<1:
new_bullet=Jineng2_1duan(self,'images/feipu.png')
self.jineng2_1duan.add(new_bullet)
def update_jineng1(self):
pianyi_x=[-4,-3,-2,-1,0,1,2,3,4]
i=0
for bullet in self.jineng1.sprites():
bullet.update(pianyi_x[i])
i+=1
if i==8:
i=0
for bullet in self.jineng1.copy():
if bullet.rect.bottom <= 0 or bullet.rect.right<=0 or bullet.rect.left >= self.screen.get_rect().right:
self.jineng1.remove(bullet)
self._check_jineng1_alien_collisions()
def update_jineng2_1duan(self):
self.jineng2_1duan.update()
for bullet in self.jineng2_1duan.copy():
if bullet.rect.bottom <= 0:
self.jineng2_1duan.remove(bullet)
self._check_jineng1_1duan_alien_collisions()
def _check_jineng1_1duan_alien_collisions(self):
#collisions = pygame.sprite.groupcollide(self.jineng2_1duan, self.aliens, True, True)
for alien in self.aliens.sprites():
for bullet in self.jineng2_1duan.sprites():
if bullet.rect.colliderect(alien):
"""if collisions:
for alien,aliens in collisions.values():
self.stats.score += self.settings.alien_point * len(aliens)"""
self.stats.score+=self.settings.alien_point
self.score_board.prep_score()
self.aliens.remove(alien)
self.jineng2_1duan.remove(bullet)
self._fire_jineng2_2duan(alien)
break
def _fire_jineng2_2duan(self,alien):
i=0
while i<16:
new_bullet=Jineng2_2duan(self,'images/maozhua1.jpg',alien)
self.jineng2_2duan.add(new_bullet)
i+=1
def update_jineng2_2duan(self):
pianyi_x=[0,0.5,1,2,1,2,1,0.5,0,-0.5,-1,-2,-1,-2,-1,-0.5]
pianyi_y=[1,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,0,1,1,1]
i=0
for bullet in self.jineng2_2duan.sprites():
bullet.update(pianyi_x[i],pianyi_y[i])
i+=1
if i==15:
i=0
for bullet in self.jineng2_2duan.copy():
if bullet.rect.bottom <= 0 or bullet.rect.right<=0 or bullet.rect.left >= self.screen.get_rect().right \
or bullet.rect.top>=self.screen.get_rect().bottom:
self.jineng2_2duan.remove(bullet)
self._check_jineng1_2duan__alien_collisions()
def _check_jineng1_2duan__alien_collisions(self):
collisions = pygame.sprite.groupcollide(self.jineng2_2duan, self.aliens, True, True)
if collisions:
for aliens in collisions.values():
self.stats.score += self.settings.alien_point * len(aliens)
self.score_board.prep_score()
def update_bullets(self):
self.bullets.update()
for bullet in self.bullets.copy():
if bullet.rect.bottom <= 0:
self.bullets.remove(bullet)
self._check_bullet_alien_collisions()
下面是关于alien的一些方法,有些检查碰撞的方法也在里面了,关于alien我创建了两种,一是黑猫(可以发射黑猫爪),二是紫发(忘了这妖怪叫啥了,ship碰到她会触发魅惑效果,期间不能使用技能),我是通过对image的判别来区分出两种不同的妖怪效果,这其中魅惑效果的时间计算要用到time()方法,后面的boss计时、miaobi计时出现也要用到。
"""alien..."""
def _create_fleet(self):
images = ['images/heimao.png', 'images/zifa.png']
choose_image = choice(images)
alien=Alien(self,choose_image)
number_alien_x=4
number_rows=2
#创建群体
i=1
j=randint(0,5)
while(i<=j):
row_number=randint(0,number_rows)
alien_number=randint(0,number_alien_x-1)
self._create_alien(alien_number,row_number)
i+=1
def _create_alien(self,alien_number,row_number):
images=['images/heimao.png','images/zifa.png']
choose_image=choice(images)
alien = Alien(self,choose_image)
alien_width,alien_height=alien.rect.size
alien.x = alien_width + 2 * alien_width * alien_number
alien.rect.x = float(alien.x)
alien.rect.y=float(alien.rect.height+1.5*alien.rect.height*row_number)
self.aliens.add(alien)
def update_aliens(self):
h_time2=time()
#print(f"h_time2:{h_time2}")
h_time1=self.settings.create_bullet
#print(f"h_time2-h_time1:{h_time2-h_time1}")
if h_time2-h_time1>=1:
self.create_heimao_bullets()
self._check_fleet_edges()
self.aliens.update()
#检测飞船与目标的碰撞
for alien in self.aliens.copy():
if alien.rect.colliderect(self.ship):
if self.settings.wudi_flag==True:
self.aliens.remove(alien)
else:
if alien.image_prep=='images/zifa.png':
self.zifa_xiangyin()
self.aliens.remove(alien)
if alien.image_prep=='images/heimao.png':
self._ship_hit()
#检测目标到达屏幕底端
self._check_alien_bottom()
def create_heimao_bullets(self):
self.settings.create_bullet=time()
for alien in self.aliens.sprites():
if alien.image_prep=='images/heimao.png':
new_bullet=Heimao_bullet(self,'images/heimaozhua.png',alien)
self.heimao_bulletgroup.add(new_bullet)
def update_heimaobullet(self):
#for heimao_bullet in self.new_bulletgroup.copy():
self.heimao_bulletgroup.update()
self._check_heimaobullet_bottom()
self._check_heimaobullet_ship_collision()
def _check_heimaobullet_bottom(self):
for bullet in self.heimao_bulletgroup.copy():
if bullet.rect.top>self.screen.get_rect().bottom:
self.heimao_bulletgroup.remove(bullet)
def _check_heimaobullet_ship_collision(self):
for heimaobullet in self.heimao_bulletgroup.sprites():
if heimaobullet.rect.colliderect(self.ship):
if self.settings.wudi_flag==True:
self.heimao_bulletgroup.remove(heimaobullet)
else:
self._ship_hit()
def _check_fleet_edges(self):
for alien in self.aliens.sprites():
if alien.a_check_edges():
self.change_fleet_direction()
break
def change_fleet_direction(self):
for alien in self.aliens.sprites():
alien.rect.y+=self.settings.fleet_drop_speed
self.settings.fleet_direction*=-1
def change_miaobiqun_direction(self):
for miaobi in self.miaobi.sprites():
miaobi.rect.y+=self.settings.miaobiqun_drop_speed
self.settings.miaobiqun_direction*=-1
def _check_bullet_alien_collisions(self):
#检查是否击中
collisions = pygame.sprite.groupcollide(self.bullets,self.aliens,True,True)
if collisions:
for aliens in collisions.values():
self.stats.score+=self.settings.alien_point*len(aliens)
self.score_board.prep_score()
#全部击中后清空子弹并再次生成目标
if not self.aliens:
self.bullets.empty()
self._create_fleet()
self.settings.increase_speed() # 加速
def _check_jineng1_alien_collisions(self):
collision =pygame.sprite.groupcollide(self.jineng1,self.aliens,True,True)
if collision:
for aliens in collision.values():
self.stats.score += self.settings.alien_point * len(aliens)
self.score_board.prep_score()
def _ship_hit(self):
self.stats.ships_left-=1
if self.stats.ships_left>0:
self.score_board.prep_ships_sign()
print(f"剩余:{self.stats.ships_left}")
#zhuangji
self.ship.image=pygame.image.load('images/zhuangji.png')
self._update_screen()
#暂停
sleep(1.0)
self.ship.image=pygame.image.load('images/ship.png')
self._empty_all()
self.heimao_bulletgroup.empty()
#重绘
self._create_fleet()
self.ship.center_ship()
else:
self.stats.game_active=False
self.score_board.prep_ships_sign()
pygame.mouse.set_visible(True)
print(f"剩余:{self.stats.ships_left}\nGame over!")
def _check_alien_bottom(self):
for alien in self.aliens.sprites():
if alien.rect.bottom>=self.screen.get_rect().bottom:
self._ship_hit() #像ship被撞到一样处理
break
下面是关于boss的一系列方法,关于boss我还没有设置攻击之类的(没什么想法),想做个动图效果(主要是因为图片制作麻烦)。boss设置了hp生命值,其实后来我想也可以给ship也添加hp属性,忙着上网课啥,就没改(主要是因为懒),想做的小伙伴可以参考boss的方法处理。
"""boss1"""
def _create_boss1(self):
self.settings.create_boss_time=time()
boss1=Boss1(self,'images/boss1.png')
self.boss1.add(boss1)
def update_boss1(self):
boss1_time2 = time()
boss1_time1 = self.settings.create_boss_time
#print(boss1_time2-boss1_time1)
if (boss1_time2-boss1_time1) >= 30:
self._create_boss1()
self.boss1.update()
self._check_boss1_bottom()
self._check_boss1_gezhong_bullets_collision()
def _check_boss1_bottom(self):
for boss1 in self.boss1.copy():
if boss1.rect.top>self.screen.get_rect().bottom:
self._ship_hit()
self.boss1.remove(boss1)
def _check_boss1_ship_collision(self):
if self.settings.wudi_flag==False:
for boss1 in self.boss1.sprites():
if boss1.rect.colliderect(self.ship):
self._ship_hit()
boss1.hp-=15
def _check_boss1_gezhong_bullets_collision(self):
for boss1 in self.boss1.sprites():
for bullet in self.bullets.sprites():
if boss1.rect.colliderect(bullet):
if bullet.image_prep=='images/maozhua.png':
boss1.hp-=1
print(boss1)
elif bullet.image_prep=='images/lanhei.png':
boss1.hp-=4
self.bullets.remove(bullet)
if boss1.hp==0:
self.hp_0(boss1,5)
for bullet1 in self.jineng1.sprites():
if boss1.rect.colliderect(bullet1):
self.jineng1.remove(bullet1)
boss1.hp-=1
print(boss1)
if boss1.hp==0:
self.hp_0(boss1,5)
for bullet2 in self.jineng2_1duan.sprites():
if boss1.rect.colliderect(bullet2):
self.jineng2_1duan.remove(bullet2)
self._fire_jineng2_2duan(boss1)
boss1.hp -= 1
print(boss1)
if boss1.hp==0:
self.hp_0(boss1, 5)
for bullet3 in self.jineng2_2duan.sprites():
if boss1.rect.colliderect(bullet3):
self.jineng2_2duan.remove(bullet3)
boss1.hp -= 1
print(boss1)
if boss1.hp==0:
self.hp_0(boss1,5)
def hp_0(self,boss,beishu):
self.boss1.remove(boss)
self.stats.score += self.settings.alien_point * beishu
self.score_board.prep_score()
下面是关于miaobi的一些方法,miaobi也有两中,一种是真的喵币,拾取后可以通过消耗喵币释放技能,另一种是夏目,碰到后变身斑形态 ,变身过程我只弄了两张图,效果还行,变身期间无敌并且普攻换成另一种形态,并对boss伤害增加(变身的攻击其实我也是想弄个动画效果)
"""miaobi..."""
def _create_miaobiqun(self):
self.miaobi.create_time=time()
images=['images/1.png','images/xiamu1.png']
choose_image=choice(images)
miaobi=Miaobis(self,choose_image)
miaobi_width,miaobi_height=miaobi.rect.size
available_space_x= self.settings.screen_width-(2*miaobi_width)
number_miaobi_x=available_space_x//(2*miaobi_width)
#print(number_alien_x)
available_space_y=(self.settings.screen_height-3*miaobi_height)
number_rows=available_space_y//(2*miaobi_height)
#print(number_rows)
#创建群体
i=1
while(i<=2):
row_number=randint(0,number_rows)
miaobi_number=randint(0,number_miaobi_x-1)
self._create_miaobi(miaobi_number,row_number)
i+=1
def _create_miaobi(self,miaobi_number,row_number):
images = ['images/1.png', 'images/xiamu1.png']
choose_image = choice(images)
miaobi = Miaobis(self, choose_image)
miaobi_width,miaobi_height=miaobi.rect.size
miaobi.x = miaobi_width + 2 * miaobi_width * miaobi_number
miaobi.rect.x = miaobi.x
miaobi.rect.y=miaobi.rect.height+1.5*miaobi.rect.height*row_number
self.miaobi.add(miaobi)
def update_miaobi(self):
#self._check_miaobiqun_edges()
self.miaobi.update()
#检测飞船与喵币的碰撞
for miaobi in self.miaobi.copy():
if miaobi.rect.colliderect(self.ship):
if miaobi.image_prep=='images/1.png':
self.stats.amount += 100
self.miaobi_note.prep_miaobi_amount()
self.miaobi.remove(miaobi)
self.stats.score += 10*self.settings.miaobi_point
self.score_board.prep_score()
elif miaobi.image_prep=='images/xiamu1.png':
self.ship.image_prep='images/ban11.png'
self.ship.image=pygame.image.load(self.ship.image_prep)
self.settings.xiamu_time=time()
self.miaobi.remove(miaobi)
if not self.miaobi:
m_time1 = self.miaobi.create_time
m_time2 = time()
#print(m_time2 - m_time1)
if m_time2 - m_time1 > 15:
self._create_miaobiqun()
# 检测喵币到达底部
self._check_miaobi_bottom()
def _check_miaobi_bottom(self):
for miaobi in self.miaobi.copy():
if miaobi.rect.top>=self.screen.get_rect().bottom:
self.miaobi.remove(miaobi)
if not self.miaobi:
m_time1=self.miaobi.create_time
m_time2=time()
#print(m_time2-m_time1)
if m_time2-m_time1>15:
self._create_miaobiqun()
下面的代码包含了检查鼠标事件、技能3响应(使自身变小持续三秒)、紫发响应、刷新历史、ship显示等方法,其中ship显示是个需要仔细处理的方法,因为技能变身,触碰变身的ship.image都不同,其中我设置了image_prep属性,能更好地处理传递参数和条件判断,在其他的对象中我也用到了这个方法。
"""..."""
def _check_youxishuoming_button(self,mouse_pos):
button_clicked=self.youxishuoming.youxishuoming_image_rect.collidepoint(mouse_pos)
if button_clicked:
if self.settings.show_youxishuoming_flag==False:
self.settings.show_youxishuoming_flag=True
else:
self.settings.show_youxishuoming_flag=False
def _check_play_button(self,mouse_pos):
button_clicked = self.replay_button.rect.collidepoint(mouse_pos)
if button_clicked and not self.stats.game_active:
self.prep()
self.stats.play_click=True
def _check_replay_button(self,mouse_pos):
button_clicked = self.replay_button.rect.collidepoint(mouse_pos)
if button_clicked and not self.stats.game_active:
self.settings.initialize_dynamic_settings()
self._empty_all()
self.stats.reset_stats()
self.stats.amount=0
self.prep()
self._update_screen()
def prep(self):
print("Game start!")
self.stats.game_active = True
self.score_board.prep_score()
self.shuaxin_history()
self.score_board.prep_ships_sign()
self.miaobi_note.prep_miaobi_amount()
pygame.mouse.set_visible(False)
def shuaxin_history(self):
if self.stats.score>=self.stats.history:
self.stats.history=self.stats.score
self.history.prep_history()
def zifa_xiangyin(self):
self.ship.image_prep='images/zifaxiangyin.png'
self.ship.image=pygame.image.load(self.ship.image_prep)
self.ship.bianshen_time=time()
self.stats.zifa_limit_flag=True
def jineng3_xiangyin(self):
self.ship.image_prep='images/jineng3xiangyin.png'
self.ship.image = pygame.image.load(self.ship.image_prep)
self.ship.suoxiao_time = time()
def ship_show(self):
if self.ship.image_prep=='images/ship.png':
self.ship.blitme()
"""下述代码有待改进"""
elif self.ship.image_prep=='images/ban11.png' or self.ship.image_prep=='images/ban22.png':
xiamu_last_time2=time()
xiamu_last_time1=self.settings.xiamu_time
self.settings.wudi_flag = True
if (xiamu_last_time2-xiamu_last_time1)<3:
xiamu_time1=self.settings.xiamu_time
xiamu_time2=time()
if (xiamu_time2-xiamu_time1)<0.2:
self.ship.blitme()
else:
self.ship.image_prep='images/ban22.png'
self.ship.image=pygame.image.load(self.ship.image_prep)
self.ship.blitme()
else:
self.settings.wudi_flag = False
self.ship.image_prep = 'images/ship.png'
self.ship.image=pygame.image.load(self.ship.image_prep)
self.ship.blitme()
elif self.ship.image_prep=='images/zifaxiangyin.png':
end=time()
start=self.ship.bianshen_time
#print(end-start)
if end-start<2:
self.ship.blitme()
else:
self.ship.image_prep = 'images/ship.png'
self.ship.image=pygame.image.load(self.ship.image_prep)
self.ship.blitme()
self.stats.zifa_limit_flag=False
elif self.ship.image_prep=='images/jineng3xiangyin.png':
end=time()
start=self.ship.suoxiao_time
#print(end-start)
if end-start<2:
self.ship.blitme()
else:
self.ship.image_prep = 'images/ship.png'
self.ship.image=pygame.image.load(self.ship.image_prep)
self.ship.blitme()
def _empty_all(self):
self.heimao_bulletgroup.empty()
self.aliens.empty()
self.bullets.empty()
self.jineng1.empty()
self.jineng2_1duan.empty()
self.jineng2_2duan.empty()
self.miaobi.empty()
if __name__ == '__main__':
#创建游戏实例并运行游戏
ai=AlienInvasion()
ai.run_game()
OK,到此主模块的程序就介绍完了,接下来就是导入模块的程序,如下:
ship.py:
import pygame
from pygame.sprite import Sprite
class Ship(Sprite):
"""管理飞船的类"""
def __init__(self,ai_game,image):
"""初始化飞船并设置其初始位置"""
super().__init__()
self.screen=ai_game.screen
self.settings=ai_game.settings
self.screen_rect=ai_game.screen.get_rect()
self.bianshen_time=0
self.suoxiao_time=0
#加载飞船图像并获取其外接矩形
self.image_prep=image
self.image=pygame.image.load(self.image_prep)
self.rect=self.image.get_rect()
#对于每艘飞船,都将其放在屏幕的底部中央
self.rect.midbottom=self.screen_rect.midbottom
#飞船属性x,y存储小数值
self.x=float(self.rect.x)
self.y=float(self.rect.y)
#移动标志
self.moving_right=False
self.moving_left=False
self.moving_up=False
self.moving_down=False
def update(self):
if self.moving_right and self.rect.x< self.screen_rect.right-100:
self.x+= self.settings.ship_speed
if self.moving_left and self.rect.x>0:
self.x-= self.settings.ship_speed
if self.moving_up and self.rect.y>0:
self.y-= self.settings.ship_speed
if self.moving_down and self.rect.bottom<= self.screen_rect.bottom:
self.y+= self.settings.ship_speed
self.rect.x=self.x
self.rect.y=self.y
def blitme(self):
"""在指定位置绘制飞船"""
self.screen.blit(self.image,self.rect)
def center_ship(self):
"""ship底部居中"""
self.rect.midbottom=self.screen_rect.midbottom
self.x=float(self.rect.x)
self.y=float(self.rect.y)
alien.py: boss的类也放在这个文件中了,主要是为了使用继承
import pygame
from pygame.sprite import Sprite
class Alien(Sprite):
def __init__(self,ai_game,image):
super().__init__()
self.screen = ai_game.screen
self.settings = ai_game.settings
self.image_prep = image
self.image = pygame.image.load(self.image_prep)
self.rect = self.image.get_rect()
#每个外星人最初在屏幕左上角附近
self.rect.x=self.rect.width-100
self.rect.y=self.rect.height-100
#存储外星人的精确水平位置
self.x=float(self.rect.x)
self.y=float(self.rect.y)
def update(self):
"""移动"""
self.x+=(self.settings.alien_speed*self.settings.fleet_direction)
self.rect.x=self.x
def a_check_edges(self):
screen_rect=self.screen.get_rect()
if self.rect.right>=screen_rect.right or self.rect.left<=0:
return True
class Miaobis(Alien):
def __init__(self,ai_game,image):
super().__init__(ai_game,image)
self.create_time=0
# 每个喵币最初在屏幕左上角附近
self.rect.x = self.rect.width - 150
self.rect.y = self.rect.height - 150
# 存储喵币的精确水平位置
self.x = float(self.rect.x)
self.y = float(self.rect.y)
def update(self):
"""移动"""
self.y += self.settings.miaobi_speed
self.rect.y = self.y
class Boss1(Alien):
def __init__(self,ai_game,image):
super().__init__(ai_game,image)
self.hp=50
self.rect.midtop = self.screen.get_rect().midtop
self.rect.y = -100
self.x = float(self.rect.x)
self.y = float(self.rect.y)
def update(self):
self.y+=self.settings.boss1_speed
self.rect.y=self.y
def __repr__(self):
return 'hp:%r' % (self.hp)
bullet.py: 存放各种bullet的类
import pygame
from pygame.sprite import Sprite
class Bullet(Sprite):
"""管理飞船所发射子弹的类"""
def __init__(self,ai_game,image):
"""在飞船当前位置创建一个子弹对象"""
super().__init__()
self.screen=ai_game.screen
self.settings=ai_game.settings
self.image_prep=image
self.image=pygame.image.load(self.image_prep)
self.rect=self.image.get_rect()
self.rect.midtop=ai_game.ship.rect.midtop
self.x=float(self.rect.x)
self.y=float(self.rect.y)
def update(self):
"""向上移动子弹"""
self.y-=self.settings.bullet_speed
self.rect.y=self.y
def draw_bullet(self):
self.screen.blit(self.image, self.rect)
class Jineng1(Bullet):
def __init__(self,ai_game,image):
super().__init__(ai_game,image)
def update(self,x):
"""各方位移动子弹"""
self.x+=x
self.y-=self.settings.bullet_speed
self.rect.x=self.x
self.rect.y=self.y
class Jineng2_1duan(Bullet):
pass
class Jineng2_2duan(Bullet):
def __init__(self,ai_game,image,mubiao):
super().__init__(ai_game,image)
self.rect.midtop = mubiao.rect.midbottom
self.x = float(self.rect.x)
self.y = float(self.rect.y)
def update(self,x,y):
self.x+=x
self.y+=y
self.rect.x=self.x
self.rect.y=self.y
class Heimao_bullet(Bullet):
def __init__(self,ai_game,image,alien):
super().__init__(ai_game,image)
self.rect.midbottom=alien.rect.midbottom
self.x = float(self.rect.x)
self.y = float(self.rect.y)
def update(self):
self.y+=self.settings.heimao_bullet_speed
self.rect.y=self.y
button.py:里面有play、replay、游戏说明按钮,还有music_flag这个其实一开始想通过鼠标点击来开关音乐,但是前面设置了游戏中隐藏鼠标,所以就设置了按键p来开关,这个button就只是为了显示image,这里可以进行一些优化。
import pygame.font
class Button():
def __init__(self,ai_game,msg,t_R,t_G,t_B):
"""chushihua button 的属性"""
self.screen=ai_game.screen
self.screen_rect=ai_game.screen.get_rect()
"""设置按钮的属性"""
self.width,self.height=200,50
self.text_color=(t_R,t_G,t_B)
self.font=pygame.font.SysFont('Times New Roman',40)
#创建按钮的rect对象
self.rect=pygame.Rect(0,0,self.width,self.height)
self.rect.center=self.screen_rect.center
# button标签只创建一次
self.msg=msg
self._prep_msg()
# note_image图片
self.note_image = pygame.image.load('images/heibai.png')
self.note_pause_image = pygame.image.load('images/zanting.png')
def _prep_msg(self):
"""将msg渲染成图像,并使其在按钮上居中"""
self.msg_image=self.font.render(self.msg,True,self.text_color)
self.msg_image_rect=self.msg_image.get_rect()
self.msg_image_rect.midtop=self.rect.midbottom
self.msg_image_rect.top=self.rect.bottom+20
def draw_button(self):
#self.screen.fill(self.button_color,self.rect)
self.screen.blit(self.msg_image,self.msg_image_rect)
def draw_note_image(self):
self.note_image_rect=self.note_image.get_rect()
self.note_image_rect.center=self.rect.center
self.screen.blit(self.note_image,self.note_image_rect)
def draw_note_pause_image(self):
self.note_pause_image_rect=self.note_pause_image.get_rect()
self.note_pause_image_rect.center=self.rect.center
self.screen.blit(self.note_pause_image,self.note_pause_image_rect)
class Music_flag(Button):
def __init__(self,ai_game,msg,t_R,t_G,t_B):
super().__init__(ai_game,msg,t_R,t_G,t_B)
self.music_flag_image=pygame.image.load('images/music_flag.png')
self.font = pygame.font.SysFont('Times New Roman', 30)
self.rect = pygame.Rect(0, 0, self.width, self.height)
self.rect.left=self.screen_rect.left
self.rect.y=0
# button标签只创建一次
self.msg=msg
self._prep_msg()
# note_image图片
self.note_image = pygame.image.load('images/heibai.png')
self.note_pause_image = pygame.image.load('images/zanting.png')
self.youxishuoming_image=pygame.image.load('images/xiaohuli.png')
def _prep_msg(self):
"""将msg渲染成图像,并使其在按钮上居中"""
self.msg_image = self.font.render(self.msg, True, self.text_color)
self.msg_image_rect=self.msg_image.get_rect()
self.msg_image_rect.y=65
self.msg_image_rect.left=self.rect.left+50
def draw_note_image(self):
self.music_flag_image_rect=self.music_flag_image.get_rect()
self.music_flag_image_rect.left=self.rect.left+10
self.music_flag_image_rect.y=65
self.screen.blit(self.music_flag_image,self.music_flag_image_rect)
class Youxishuoming(Button):
def __init__(self,ai_game,msg,t_R,t_G,t_B):
super().__init__(ai_game,msg,t_R,t_G,t_B)
self.font = pygame.font.SysFont('Times New Roman', 30)
self.rect = pygame.Rect(0, 0, self.width, self.height)
# button标签只创建一次
self.msg=msg
self._prep_msg()
# note_image图片
self.note_image = pygame.image.load('images/heibai.png')
self.note_pause_image = pygame.image.load('images/zanting.png')
self.youxishuoming_image=pygame.image.load('images/mao11.png')
def _prep_msg(self):
"""将msg渲染成图像,并使其在按钮上居中"""
self.msg_image = self.font.render(self.msg, True, self.text_color)
self.msg_image_rect=self.msg_image.get_rect()
self.msg_image_rect.y=20
self.msg_image_rect.left=self.rect.left+30
def draw_youxishuoming_image(self):
self.youxishuoming_image_rect=self.youxishuoming_image.get_rect()
self.youxishuoming_image_rect.top=self.msg_image_rect.bottom
self.youxishuoming_image_rect.x=30
self.screen.blit(self.youxishuoming_image,self.youxishuoming_image_rect)
game_stats.py: 这里面主要是游戏数据信息和标志属性
class Gamestats():
def __init__(self,ai_game):
"""初始化统计信息"""
self.game_active=False
self.settings=ai_game.settings
self.reset_stats()
self.score=0
self.amount=0
self.history=0
self.zifa_limit_flag=False
self.create_m_limit=False
self.play_click=False
def reset_stats(self):
"""初始化在游戏运行期间可能变化的统计信息"""
self.ships_left=self.settings.ship_limit
self.score=0
miaobi_r.py:这个文件的类可以在button.py里面通过继承来实现,会简洁许多,作用是显示喵币标识和数量。
import pygame
class Miaobir():
def __init__(self,ai_game):
self.screen=ai_game.screen
self.screen_rect = ai_game.screen.get_rect()
self.sb=ai_game.score_board
self.stats=ai_game.stats
self.settings=ai_game.settings
self.image=pygame.image.load('images/miaobi_note.png')
self.rect=self.image.get_rect()
# 显示喵币信息的字体设置
self.text_color = (169, 89, 30)
self.font = pygame.font.SysFont(None, 48)
# 准备喵币数图像
self.prep_miaobi_amount()
#位置
self.rect.top=self.sb.score_rect.bottom+14
self.rect.x=self.screen_rect.right-40
def show_miaobi_note(self):
self.screen.blit(self.image, self.rect)
def prep_miaobi_amount(self):
amount_str = f"{str(self.stats.amount)} x "
self.miaobi_amount_image = self.font.render(amount_str, True, self.text_color)
self.miaobi_amount_rect = self.miaobi_amount_image.get_rect()
self.miaobi_amount_rect.right = self.rect.right - 40
self.miaobi_amount_rect.top = self.rect.bottom-30
def show_amount(self):
self.screen.blit(self.miaobi_amount_image, self.miaobi_amount_rect)
scoreboard.py:显示分数和历史记录,这里也可以使用继承
import pygame.font
from ship import Ship
class Scoreboard():
def __init__(self,ai_game):
self.ai_game=ai_game
self.screen=ai_game.screen
self.screen_rect=ai_game.screen.get_rect()
self.settings=ai_game.settings
self.stats=ai_game.stats
#显示得分信息的字体设置
self.text_color=(169,89,30)
self.font=pygame.font.SysFont(None,48)
#准备得分图像
self.prep_score()
self.ships_sign = pygame.sprite.Group()
def prep_score(self):
"""将得分转换为一幅渲染的图像"""
score_str=f"score: {str(self.stats.score)}"
self.score_image=self.font.render(score_str,True,self.text_color)
#右上角显示得分
self.score_rect=self.score_image.get_rect()
self.score_rect.right=self.screen_rect.right-20
self.score_rect.top=20
def prep_ships_sign(self):
self.ships_sign = pygame.sprite.Group()
for ship_number in range(self.stats.ships_left):
ship_sign=Ship(self.ai_game,'images/niangkou.png')
ship_sign.rect.x=10+ship_number * (ship_sign.rect.width+3)
ship_sign.rect.y=10
self.ships_sign.add(ship_sign)
def show_score(self):
self.screen.blit(self.score_image,self.score_rect)
self.ships_sign.draw(self.screen)
class History():
def __init__(self,ai_game):
self.ai_game = ai_game
self.screen = ai_game.screen
self.screen_rect = ai_game.screen.get_rect()
self.settings = ai_game.settings
self.stats = ai_game.stats
self.text_color = (169, 89, 30)
self.font = pygame.font.SysFont(None, 48)
def prep_history(self):
history_str = f"History: {str(self.stats.history)}"
self.history_image = self.font.render(history_str, True, self.text_color)
self.history_rect = self.history_image.get_rect()
self.history_rect.midtop=self.screen_rect.midtop
def show_history(self):
self.screen.blit(self.history_image, self.history_rect)
settings.py:Settings类存储各个对象的设置,还有初始化设置等方法
import pygame
class Settings:
"""存储游戏中所有的设置的类"""
def __init__(self):
"""初试化游戏的设置"""
#屏幕设置
self.screen_width=1200
self.screen_height=780
self.bg_color=(106,90,205)
self.background1 = pygame.image.load('images/bg4 1200 780.png')
self.background2=pygame.image.load('images/bg1 1200 780.jpg')
#三三设置
self.ship_limit=3
self.ship_speed=1.2
self.xiamu_time=0
self.wudi_flag=False
#子弹设置
self.bullet_width=30
self.bullet_height=15
self.bullet_speed=1.5
self.bullet_allowed=6
self.jineng1_bullet_allowed=10
#heimao目标设置
self.alien_speed=0.8
self.fleet_drop_speed=15
self.fleet_direction=1 #right
self.alien_point=10
self.heimao_bullet_speed=1
self.create_bullet = 0
#boss1设置
self.boss1_speed=0.1
self.create_boss_time = 0.1
self.c_b_limit=False
self.jiluboss_time_flag=True
#maobi目标设置
self.miaobi_speed=0.4
self.miaobiqun_drop_speed=10
self.miaobiqun_direction=-1#left
self.miaobi_point=1
#加快节奏
self.speedup_scale=1.1
self.score_scale=1.3
self.initialize_dynamic_settings()
#背景音乐
self.music1=pygame.mixer.music.load('musics/bgmusic1.mp3')
self.music2 = pygame.mixer.music.load('musics/bgmusic2.mp3')
self.music1_active= False
self.music2_active = False
self.music_switch=1
#游戏说明
self.youxiguize_image=pygame.image.load('images/youxiguize22.png')
self.youxiguize_image_rect=self.youxiguize_image.get_rect()
self.youxiguize_image_rect.x=300
self.youxiguize_image_rect.y=200
self.show_youxishuoming_flag=False
def initialize_dynamic_settings(self):
"""初始化设置"""
self.ship_speed = 1.0
self.bullet_speed = 1
self.alien_speed = 0.5
self.alien_point=10
self.fleet_direction = 1 # right
def increase_speed(self):
if self.ship_speed<=1.7:
self.ship_speed*=self.speedup_scale
if self.alien_speed<=1.5:
self.alien_speed*=self.speedup_scale
self.alien_point = int(self.alien_point * self.score_scale)
if self.bullet_speed<=2.5:
self.bullet_speed*=self.speedup_scale
if self.alien_speed>1.5 and self.fleet_drop_speed<30:
self.fleet_drop_speed*=self.speedup_scale
#print(f"s:{float(self.ship_speed)} a:{float(self.alien_speed)}\nb:{float(self.bullet_speed)} p:{self.alien_point}")
结语:这就是游戏程序的全部内容啦,希望这篇文章能够帮助你,感兴趣的小伙伴欢迎交流!