添加play按钮
- 首先修改game_stats.py中的游戏状态属性,一开始为非活动状态
self.game_active=False
- 创建一个button.py的类
用于创建带标签的实心矩形,可以自定义创建任何按钮,下面是代码
#导入模块pygame.ftfont,它能让pygame将文本渲染到屏幕
import pygame.ftfont
class Button():
#msg是要在按钮中显示的文本
def __init__(self, ai, screen, msg):
"""初始化按钮的属性"""
self.screen=screen
self.screen_rect=screen.get_rect()
#设置按钮的尺寸和颜色以及文本的颜色和字体
self.width,self.height=200,50
self.button_color=(0,255,0)
self.text_color=(255,255,255)
#传入实参None为默认字体,字体大小48号
self.font=pygame.ftfont.SysFont(None,48)
#创建按钮,并且将rect对象并居中
self.rect=pygame.Rect(0,0,self.width,self.height)
self.rect.center=self.screen_rect.center
#接受实参self,以及要渲染为图像的文本
self.prep_msg(msg)
def prep_msg(self,msg):
"""将msg渲染为图形,并使按钮居中"""
#调用font.render(文本,反锯齿开关(使文本的边缘更加平滑),文本颜色渲染,按钮颜色渲染)将储存在msg的文本装换为图像
self.msg_image=self.font.render(msg,True,self.text_color,self.button_color)
#使图像居中
self.msg_image_rect=self.msg_image.get_rect()
self.msg_image_rect.center=self.rect.center
def draw_button(self):
#绘制一个用颜色填充的按钮,在绘制文本
self.screen.fill(self.button_color,self.rect)
self.screen.blit(self.msg_image,self.msg_image_rect)
首先导入模块pygame.ftfont,它能让pygame将文本渲染到屏幕上,
- 在屏幕上绘制按钮
为方便,就直接粘贴源码了
alien.invasion.py
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
from pygame.sprite import Group
from game_stats import GameState
from button import Button
def run_game():
#初始化游戏并创建一个屏幕对象
pygame.init()
#实例化settings对象
ai=Settings()
#创建游戏窗口大小
screen=pygame.display.set_mode((ai.screen_width,ai.screen_height))
#创建游戏标题
pygame.display.set_caption("外星人大战")
#创建按钮
play_button=Button(ai,screen,"Play")
bg_color=(230,230,230)
#实例化飞船对象ship,传入屏幕实参
ship=Ship(ai,screen)
#创建一个用于存储游戏统计信息的实例
stats=GameState(ai)
#创造一个用于存储子弹和外星人的编组
bullets=Group()
aliens=Group()
gf.create_fleet(ai,screen,ship,aliens)
#开始游戏的主循环
while True:
gf.check_events(ai, screen, stats, play_button, ship, bullets)
if stats.game_active:
ship.update()
gf.update_bullets(ai,screen,ship,aliens,bullets)
gf.update_aliens(ai,stats,screen,ship,aliens,bullets)
gf.update_screen(ai,screen,stats,ship,aliens,bullets,play_button)
if __name__ == '__main__':
run_game()
主要是在主程序中实例化了按钮,以及按键事件监控和屏幕更新函数中修改了传入的实参,之后需要在game_functions.py中添加函数,实现开始按钮的作用
- 开始游戏
game_functions,py中实现相应的函数的创建与修改
import sys
from time import sleep
import pygame
from bullet import Bullet
from alien import Alien
def check_keydown_events(event, ai, screen, ship, bullets):
if event.key == pygame.K_RIGHT:
ship.moving_right = True
elif event.key == pygame.K_LEFT:
ship.moving_left = True
elif event.key == pygame.K_SPACE:
fire_bullet(ai, screen, ship, bullets)
elif event.key == pygame.K_q:
sys.exit()
def check_keyup_events(event, ship):
if event.key == pygame.K_RIGHT:
ship.moving_right = False
elif event.key == pygame.K_LEFT:
ship.moving_left = False
def check_events(ai, screen, stats,play_button,ship, bullets):
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
check_keydown_events(event, ai, screen, ship, bullets)
elif event.type == pygame.KEYUP:
check_keyup_events(event, ship)
elif event.type==pygame.MOUSEBUTTONDOWN:
mouse_x,mouse_y=pygame.mouse.get_pos()
check_play_button(stats,play_button,mouse_x,mouse_y)
def check_play_button(stats,play_button,mouse_x,mouse_y):
"""在玩家单击play按钮是开始游戏"""
if play_button.rect.collidepoint(mouse_x,mouse_y):
stats.game_active=True
def fire_bullet(ai, screen, ship, bullets):
if len(bullets) < ai.bullet_nums:
new_bullet = Bullet(ai, screen, ship)
bullets.add(new_bullet)
def update_screen(ai_settings, screen,stats, ship, aliens, bullets,play_button):
screen.fill(ai_settings.bg_color)
for bullet in bullets.sprites():
bullet.draw_bullet()
ship.blitme()
aliens.draw(screen)
#如果游戏处于非活动状态,就绘制按钮play
if not stats.game_active:
play_button.draw_button()
pygame.display.flip()
def update_bullets(ai, screen, ship, aliens, bullets):
bullets.update()
for bullet in bullets.copy():
if bullet.rect.bottom <= 0:
bullets.remove(bullet)
check_bullet_alien_collisions(ai, screen, ship, aliens, bullets)
def check_bullet_alien_collisions(a, screen, ship, aliens, bullets):
collisions = pygame.sprite.groupcollide(bullets, aliens, True, True)
if len(aliens) == 0:
bullets.empty()
create_fleet(ai, screen, ship, aliens)
def check_fleet_edges(ai, aliens):
for alien in aliens.sprites():
if alien.check_edges():
change_fleet_direction(ai, aliens)
break
def change_fleet_direction(ai, aliens):
for alien in aliens.sprites():
alien.rect.y += ai.fleet_drop_speed
ai.fleet_direction *= -1
def ship_hit(ai, stats, screen, ship, aliens, bullets):
if stats.ships_left > 0:
# Decrement ships_left.
stats.ships_left -= 1
else:
stats.game_active = False
aliens.empty()
bullets.empty()
create_fleet(ai, screen, ship, aliens)
ship.center_ship()
# Pause.
sleep(0.5)
def check_aliens_bottom(ai, stats, screen, ship, aliens, bullets):
screen_rect = screen.get_rect()
for alien in aliens.sprites():
if alien.rect.bottom >= screen_rect.bottom:
ship_hit(ai, stats, screen, ship, aliens, bullets)
break
def update_aliens(ai, stats, screen, ship, aliens, bullets):
check_fleet_edges(ai, aliens)
aliens.update()
if pygame.sprite.spritecollideany(ship, aliens):
ship_hit(ai, stats, screen, ship, aliens, bullets)
check_aliens_bottom(ai, stats, screen, ship, aliens, bullets)
def get_number_aliens_x(ai, alien_width):
available_space_x = ai.screen_width - 2 * alien_width
number_aliens_x = int(available_space_x / (2 * alien_width))
return number_aliens_x
def get_number_rows(ai, ship_height, alien_height):
available_space_y = (ai.screen_height -
(3 * alien_height) - ship_height)
number_rows = int(available_space_y / (2 * alien_height))
return number_rows
def create_alien(ai, screen, aliens, alien_number, row_number):
alien = Alien(ai, screen)
alien_width = alien.rect.width
alien.x = alien_width + 2 * alien_width * alien_number
alien.rect.x = alien.x
alien.rect.y = alien.rect.height + 2 * alien.rect.height * row_number
aliens.add(alien)
def create_fleet(ai, screen, ship, aliens):
alien = Alien(ai, screen)
number_aliens_x = get_number_aliens_x(ai, alien.rect.width)
number_rows = get_number_rows(ai, ship.rect.height,
alien.rect.height)
for row_number in range(number_rows):
for alien_number in range(number_aliens_x):
create_alien(ai, screen, aliens, alien_number,
row_number)
在监听事件中,监听鼠标是否点击play按钮,绘制开始按钮,并激活游戏状态
话不多说,上效果图
重置游戏
- 重置游戏与隐藏光标
game_functions.py,
为了便于显示,加注释的为新更新的部分代码
import sys
from time import sleep
import pygame
from bullet import Bullet
from alien import Alien
def check_keydown_events(event, ai, screen, ship, bullets):
if event.key == pygame.K_RIGHT:
ship.moving_right = True
elif event.key == pygame.K_LEFT:
ship.moving_left = True
elif event.key == pygame.K_UP:
ship.moving_up = True
elif event.key == pygame.K_DOWN:
ship.moving_down = True
elif event.key == pygame.K_SPACE:
fire_bullet(ai, screen, ship, bullets)
elif event.key == pygame.K_q:
sys.exit()
def check_keyup_events(event, ship):
if event.key == pygame.K_RIGHT:
ship.moving_right = False
elif event.key == pygame.K_LEFT:
ship.moving_left = False
elif event.key == pygame.K_UP:
ship.moving_up = False
elif event.key == pygame.K_DOWN:
ship.moving_down = False
def check_events(ai, screen, stats, play_button, ship, aliens, bullets):
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
check_keydown_events(event, ai, screen, ship, bullets)
elif event.type == pygame.KEYUP:
check_keyup_events(event, ship)
elif event.type==pygame.MOUSEBUTTONDOWN:
mouse_x,mouse_y=pygame.mouse.get_pos()
check_play_button(ai, screen, stats, play_button, ship, aliens, bullets, mouse_x, mouse_y)
def check_play_button(ai,screen,stats,play_button,ship,aliens,bullets,mouse_x,mouse_y):
"""在玩家单击play按钮是开始游戏"""
if not stats.game_active and play_button.rect.collidepoint(mouse_x,mouse_y):
#隐藏光标
pygame.mouse.set_visible(False)
#重置游戏统计信息
stats.reset_stats()
stats.game_active=True
#清空外星人列表和子弹列表
aliens.empty()
bullets.empty()
#创建一群新的外星人,并让飞船居中
create_fleet(ai,screen,ship,aliens)
ship.center_ship()
def fire_bullet(ai, screen, ship, bullets):
if len(bullets) < ai.bullet_nums:
new_bullet = Bullet(ai, screen, ship)
bullets.add(new_bullet)
def update_screen(ai_settings, screen,stats, ship, aliens, bullets,play_button):
screen.fill(ai_settings.bg_color)
for bullet in bullets.sprites():
bullet.draw_bullet()
ship.blitme()
aliens.draw(screen)
#如果游戏处于非活动状态,就绘制按钮play
if not stats.game_active:
play_button.draw_button()
pygame.display.flip()
def update_bullets(ai, screen, ship, aliens, bullets):
bullets.update()
for bullet in bullets.copy():
if bullet.rect.bottom <= 0:
bullets.remove(bullet)
check_bullet_alien_collisions(ai, screen, ship, aliens, bullets)
def check_bullet_alien_collisions(a, screen, ship, aliens, bullets):
collisions = pygame.sprite.groupcollide(bullets, aliens, True, True)
if len(aliens) == 0:
bullets.empty()
create_fleet(ai, screen, ship, aliens)
def check_fleet_edges(ai, aliens):
for alien in aliens.sprites():
if alien.check_edges():
change_fleet_direction(ai, aliens)
break
def change_fleet_direction(ai, aliens):
for alien in aliens.sprites():
alien.rect.y += ai.fleet_drop_speed
ai.fleet_direction *= -1
def ship_hit(ai, stats, screen, ship, aliens, bullets):
if stats.ships_left > 0:
# Decrement ships_left.
stats.ships_left -= 1
else:
stats.game_active = False
#光标显示
pygame.mouse.set_visible(True)
aliens.empty()
bullets.empty()
create_fleet(ai, screen, ship, aliens)
ship.center_ship()
# Pause.
sleep(0.5)
def check_aliens_bottom(ai, stats, screen, ship, aliens, bullets):
screen_rect = screen.get_rect()
for alien in aliens.sprites():
if alien.rect.bottom >= screen_rect.bottom:
ship_hit(ai, stats, screen, ship, aliens, bullets)
break
def update_aliens(ai, stats, screen, ship, aliens, bullets):
check_fleet_edges(ai, aliens)
aliens.update()
if pygame.sprite.spritecollideany(ship, aliens):
ship_hit(ai, stats, screen, ship, aliens, bullets)
check_aliens_bottom(ai, stats, screen, ship, aliens, bullets)
def get_number_aliens_x(ai, alien_width):
available_space_x = ai.screen_width - 2 * alien_width
number_aliens_x = int(available_space_x / (2 * alien_width))
return number_aliens_x
def get_number_rows(ai, ship_height, alien_height):
available_space_y = (ai.screen_height -
(3 * alien_height) - ship_height)
number_rows = int(available_space_y / (2 * alien_height))
return number_rows
def create_alien(ai, screen, aliens, alien_number, row_number):
alien = Alien(ai, screen)
alien_width = alien.rect.width
alien.x = alien_width + 2 * alien_width * alien_number
alien.rect.x = alien.x
alien.rect.y = alien.rect.height + 2 * alien.rect.height * row_number
aliens.add(alien)
def create_fleet(ai, screen, ship, aliens):
alien = Alien(ai, screen)
number_aliens_x = get_number_aliens_x(ai, alien.rect.width)
number_rows = get_number_rows(ai, ship.rect.height,
alien.rect.height)
for row_number in range(number_rows):
for alien_number in range(number_aliens_x+1):
create_alien(ai, screen, aliens, alien_number,
row_number)
- 主程序随之相应调整
alien_invasion.py
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
from pygame.sprite import Group
from game_stats import GameState
from button import Button
def run_game():
#初始化游戏并创建一个屏幕对象
pygame.init()
#实例化settings对象
ai=Settings()
#创建游戏窗口大小
screen=pygame.display.set_mode((ai.screen_width,ai.screen_height))
#创建游戏标题
pygame.display.set_caption("外星人大战")
#创建按钮
play_button=Button(ai,screen,"Play")
bg_color=(230,230,230)
#实例化飞船对象ship,传入屏幕实参
ship=Ship(ai,screen)
#创建一个用于存储游戏统计信息的实例
stats=GameState(ai)
#创造一个用于存储子弹和外星人的编组
bullets=Group()
aliens=Group()
gf.create_fleet(ai,screen,ship,aliens)
#开始游戏的主循环
while True:
gf.check_events(ai, screen, stats, play_button, ship, aliens, bullets)
if stats.game_active:
ship.update()
gf.update_bullets(ai,screen,ship,aliens,bullets)
gf.update_aliens(ai,stats,screen,ship,aliens,bullets)
gf.update_screen(ai,screen,stats,ship,aliens,bullets,play_button)
if __name__ == '__main__':
run_game()
拓展
- 这里还有一个bug没有解决,不过也是考验大家的一点小问题了,后面会解决的,有能力的可以先解决,那就是飞船上去碰撞后,死亡原地复活,没有重置到屏幕底端,导致与重新刷新的外星人碰撞,碰撞检测下再次死亡,结果,游戏崩溃卡死,这里先留下一个小问题,后面笔者会解决的,不过不影响游戏的运行,bug图如下