作为机器人工程专业的废柴,学完学校教的简单python后,安排的大作业,利用pygame编写一个完整的游戏。是指自己动手参照《python从入门到实践》中的外星人入侵的游戏改写而来。
Tips:利用pygame调用图片编写游戏程序是记得要抠图!!!
完成程序文件及相关图片已存入gitee仓库中:
https://gitee.com/wang-wenyu-312/python.git
以下分别是游戏的开始界面、游戏运行界面、游戏结束界面的截图。
主程序代码:
元宝多多.py
import sys
import pygame
import random
from button import Button
from scoreboard import Scoreboard
from cornucopia import Cornucopia
from settings import Settings, GameStats
from money import Baoxiang, Bomb, Yuanbao_L, Yuanbao_S, Zuanshi
class Game():
def __init__(self):
pygame.init()
self.settings = Settings()
self.screen = pygame.display.set_mode((self.settings.screen_width,self.settings.screen_height))
self.screen_rect = self.screen.get_rect()
pygame.display.set_caption("元宝多多")
self.colock = pygame.time.Clock()
self.cornucopia = Cornucopia(self)
#小元宝的精灵容器
self.yuanbao_S = pygame.sprite.Group()
#大元宝的精灵容器
self.yuanbao_L = pygame.sprite.Group()
#钻石的精灵容器
self.zuanshi = pygame.sprite.Group()
#宝箱的精灵容器
self.baoxiang = pygame.sprite.Group()
#炸弹的精灵容器
self.bomb = pygame.sprite.Group()
self.stats = GameStats(self)
self.play_button = Button(self,'play')
self.exit_button = Button(self,'exit')
self.restart_button = Button(self,'restart')
self.score = Scoreboard(self)
def run_game(self):
'''开始游戏的主循环'''
while True:
self._check_events()
self.colock.tick(90)
if self.stats.game_active == 1:
self._check_events()
self._money_score_grade_ctrl()
self._update_screen()
def _update_screen(self):
'''更新屏幕显示,显示函数的位置顺序不能随意更改'''
self.screen.blit(self.settings.background_image,self.settings.background_image.get_rect())
self.cornucopia.blitme()
self.yuanbao_S.draw(self.screen)
self.yuanbao_L.draw(self.screen)
self.zuanshi.draw(self.screen)
self.baoxiang.draw(self.screen)
self.bomb.draw(self.screen)
self.cornucopia.update()
self.score.show_score()
#如果游戏处于非活动状态,就显示Play按钮
if self.stats.game_active == 0:
self.play_button.draw_button()
if self.stats.game_active == 2:
self.score.prep_over()
self.exit_button.draw_button()
self.restart_button.draw_button()
pygame.display.flip()
'''鼠标或按键响应'''
def _check_events(self):
'''响应按键和鼠标事件'''
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type==pygame.KEYDOWN:
self._check_keydown_events(event)
elif event.type==pygame.KEYUP:
self._check_keyup_events(event)
elif event.type==pygame.MOUSEBUTTONDOWN:
mouse_pos=pygame.mouse.get_pos()
if self.stats.game_active == 0:
self._check_play_button(mouse_pos)
elif self.stats.game_active == 2:
self._check_restart_button(mouse_pos)
self._check_exit_button(mouse_pos)
def _check_keydown_events(self,event):
'''响应按下按键'''
if event.key == pygame.K_RIGHT:
self.cornucopia.moving_right=True
elif event.key == pygame.K_LEFT:
self.cornucopia.moving_left=True
elif event.key == pygame.K_ESCAPE:
sys.exit()
def _check_keyup_events(self,event):
'''响应松开按键'''
if event.key==pygame.K_RIGHT:
self.cornucopia.moving_right=False
elif event.key==pygame.K_LEFT:
self.cornucopia.moving_left=False
def _money_score_grade_ctrl(self):
'''money的生成和管理控制'''
self._check_corn_capture()
self._money_move()
self._check_get_score()
self._up_grade()
self._check_crash_bomb()
self.score.check_highest_score()
def _creat_money(self):
'''创建money的群'''
#向小元宝精灵容器中添加小元宝精灵
for i in range(0,5*self.stats.level+1):
yuanbao_s = Yuanbao_S(self)
yuanbao_s.x = random.randint(0,self.settings.screen_width-30)
yuanbao_s.y = random.randint(-self.settings.screen_height,-10)
yuanbao_s.rect.x = yuanbao_s.x
yuanbao_s.rect.y = yuanbao_s.y
self.yuanbao_S.add(yuanbao_s)
if self.stats.level > 1:
#向大元宝精灵容器中添加大元宝精灵
for i in range(0,2*self.stats.level+1):
yuanbao_l =Yuanbao_L(self)
yuanbao_l.x = random.randint(0,self.settings.screen_width-60)
yuanbao_l.y = random.randint(-self.settings.screen_height,-10)
yuanbao_l.rect.x = yuanbao_l.x
yuanbao_l.rect.y = yuanbao_l.y
self.yuanbao_L.add(yuanbao_l)
if self.stats.level > 3:
#向钻石精灵容器、炸弹精灵容器中分别添加添加钻石精灵和炸弹精灵
for i in range(0,int((self.stats.level+1)/3)):
zuanshi = Zuanshi(self)
zuanshi.x = random.randint(0,self.settings.screen_width-60)
zuanshi.y = random.randint(-self.settings.screen_height,-10)
zuanshi.rect.x = zuanshi.x
zuanshi.rect.y = zuanshi.y
self.zuanshi.add(zuanshi)
bomb = Bomb(self)
bomb.x = random.randint(0,self.settings.screen_width-60)
bomb.y = random.randint(-self.settings.screen_height,-10)
bomb.rect.x = bomb.x
bomb.rect.y = bomb.y
self.bomb.add(bomb)
if self.stats.level > 5:
#向宝箱精灵容器中添加宝箱精灵
for i in range(0,int((self.stats.level-4)/4)):
baoxiang = Baoxiang(self)
baoxiang.x = random.randint(0,self.settings.screen_width-90)
baoxiang.y = random.randint(-self.settings.screen_height,-10)
baoxiang.rect.x = baoxiang.x
baoxiang.rect.y = baoxiang.y
self.baoxiang.add(baoxiang)
def _money_move(self):
'''更新money中各部分的位置'''
#
'''该程序实现对精灵容器中的精灵统一控制,若需要对每个精灵需要单独控制需增加代码的复
杂程度,且本游戏不需要那么高的复杂度'''
for yuanbao_S in self.yuanbao_S.sprites():
yuanbao_S_y = float(yuanbao_S.rect.y)
yuanbao_S_y += self.settings.yb_S_speed
yuanbao_S.rect.y = yuanbao_S_y
for yuanbao_L in self.yuanbao_L.sprites():
yuanbao_L_y = float(yuanbao_L.rect.y)
yuanbao_L_y += self.settings.yb_L_speed
yuanbao_L.rect.y = yuanbao_L_y
for zuanshi in self.zuanshi.sprites():
zuanshi_y = float(zuanshi.rect.y)
zuanshi_y += self.settings.zs_speed
zuanshi.rect.y = zuanshi_y
for baoxiang in self.baoxiang.sprites():
baoxiang_y = float(baoxiang.rect.y)
baoxiang_y += self.settings.bx_speed
baoxiang.rect.y = baoxiang_y
for bomb in self.bomb.sprites():
bomb_y = float(bomb.rect.y)
bomb_y += self.settings.zd_speed
bomb.rect.y = bomb_y
self._check_money_bottom()
def _check_money_bottom(self):
'''元宝、钻石等到达屏幕底部处理办法'''
for yuanbao_s in self.yuanbao_S.copy():
if yuanbao_s.rect.top >= self.screen_rect.bottom:
self.yuanbao_S.remove(yuanbao_s)
for yuanbao_l in self.yuanbao_L.copy():
if yuanbao_l.rect.top >= self.screen_rect.bottom:
self.yuanbao_L.remove(yuanbao_l)
for zuanshi in self.zuanshi.copy():
if zuanshi.rect.top >= self.screen_rect.bottom:
self.zuanshi.remove(zuanshi)
for baoxiang in self.baoxiang.copy():
if baoxiang.rect.top >= self.screen_rect.bottom:
self.baoxiang.remove(baoxiang)
for bomb in self.bomb.copy():
if bomb.rect.top >= self.screen_rect.bottom:
self.bomb.remove(bomb)
def _check_corn_capture(self):
'''判断是否生成新的money群'''
if len(self.yuanbao_S) ==0 and len (self.yuanbao_L) == 0 :
if len(self.zuanshi) == 0 and len(self.bomb) == 0 :
if len(self.baoxiang) == 0 :
self._creat_money()
def _check_get_score(self):
'''响应得分'''
collisions_1 = pygame.sprite.spritecollideany(self.cornucopia,self.yuanbao_S)
if collisions_1 :
self.stats.score += self.settings.yuanbao_s_point
self.score.prep_score()
self.score.prep_highest_score()
self.yuanbao_S.remove(collisions_1)
collisions_2 = pygame.sprite.spritecollideany(self.cornucopia,self.yuanbao_L)
if collisions_2 :
self.stats.score += self.settings.yuanbao_l_point
self.score.prep_score()
self.score.prep_highest_score()
self.yuanbao_L.remove(collisions_2)
collisions_3 = pygame.sprite.spritecollideany(self.cornucopia,self.zuanshi)
if collisions_3 :
self.stats.score += self.settings.zuanshi_point
self.score.prep_score()
self.score.prep_highest_score()
self.zuanshi.remove(collisions_3)
collisions_4 = pygame.sprite.spritecollideany(self.cornucopia,self.baoxiang)
if collisions_4 :
self.stats.score += self.settings.baoxiang_point
self.score.prep_score()
self.score.prep_highest_score()
self.baoxiang.remove(collisions_4)
def _check_crash_bomb(self):
'''响应聚宝盆碰到炸弹的处理办法'''
collisions = pygame.sprite.spritecollideany(self.cornucopia,self.bomb)
if collisions :
self.stats.game_active = 2
self._check_gameover()
def _check_gameover(self):
'''响应游戏结束的控制'''
self.yuanbao_S.empty()
self.yuanbao_L.empty()
self.zuanshi.empty()
self.baoxiang .empty()
self.bomb.empty()
def _check_exit_button(self,mouse_pos):
'''在玩家单击"重新开始"按钮时开始新游戏'''
button_clicked=self.exit_button.rect.collidepoint(mouse_pos)
if button_clicked and self.stats.game_active == 2:
sys.exit()
def _check_restart_button(self,mouse_pos):
'''在玩家单击"重新开始"按钮时开始新游戏'''
button_clicked=self.restart_button.rect.collidepoint(mouse_pos)
if button_clicked and self.stats.game_active == 2:
# 重置游戏统计信息
self.stats.reset_stats()
self.stats.game_active=1
self.score.prep_score()
self.score.prep_level()
# 创建一群新的money精灵并让聚宝盆居中
self._creat_money()
self.cornucopia._center_corn()
def _check_play_button(self,mouse_pos):
'''响应玩家点击"play"按钮是开始游戏'''
button_clicked=self.play_button.rect.collidepoint(mouse_pos)
if button_clicked and self.stats.game_active == 0:
self.stats.reset_stats()
self.stats.game_active=1
self.score.prep_score()
self.score.prep_level()
def _up_grade(self):
'''升级控制方法'''
if self.stats.score//(20*self.stats.level):
self.stats.level += 1
self.score.prep_level()
if __name__ == '__main__':
game = Game()
game.run_game()
button.py
import pygame.font
class Button:
def __init__(self,game,msg):
'''初始化按钮的属性'''
self.screen=game.screen
self.screen_rect=self.screen.get_rect()
# 设置按钮的尺寸和其他属性
self.width,self.height=200,50
self.button_color=(0,255,0)
self.text_color=(255,255,255)
# 指定字体和文本字号
self.font=pygame.font.SysFont("fangsong",48)
# 创建按钮的rect对象,并使其居中
if msg == 'play':
self.rect=pygame.Rect(0,0,self.width,self.height)
self.rect.center=self.screen_rect.center # 使按钮中心和屏幕中心重合
elif msg == 'exit':
self.rect=pygame.Rect(0,0,self.width,self.height)
self.rect.centerx = self.screen_rect.centerx - 120
self.rect.centery = self.screen_rect.centery + 40
elif msg == 'restart':
self.rect=pygame.Rect(0,0,self.width,self.height)
self.rect.centerx = self.screen_rect.centerx + 120
self.rect.centery = self.screen_rect.centery + 40
# 按钮的标签只需创建一次
self._prep_msg(msg)
def _prep_msg(self,msg):
'''将msg渲染为图像,并使其在按钮上居中'''
# render(message,抗锯齿标签,字体颜色,背景颜色)
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)
# blit(图像对象,图像的矩形位置信息)
self.screen.blit(self.msg_image,self.msg_image_rect)
cornucopia.py
import pygame
class Cornucopia:
'''聚宝盆的类'''
def __init__(self,game):
self.screen = game.screen
self.settings = game.settings
self.screen_rect = game.screen.get_rect()
#加载聚宝盆的图像
self.image = pygame.image.load('image/聚宝盆.bmp')
self.image = pygame.transform.scale(self.image,(60,60))
self.rect = self.image.get_rect()
#将聚宝盆放在屏幕的底部
self.rect.midbottom = self.screen_rect.midbottom
self.x = float(self.rect.x)
self.y = float(self.rect.y)
#移动标识
self.moving_right = False
self.moving_left = False
def update(self):
'''根据移动标识调整聚宝盆位置'''
if self.moving_right and self.rect.right<self.screen_rect.right:
self.x += self.settings.corn_speed
if self.moving_left and self.rect.left>0:
self.x -= self.settings.corn_speed
self.rect.x = self.x
self.rect.y = self.y
def blitme(self):
'''在指定位置绘制聚宝盆'''
self.screen.blit(self.image,self.rect)
def _center_corn(self):
'''让聚宝盆居中'''
self.rect.midbottom = self.screen_rect.midbottom
money.py
import pygame
from pygame.sprite import Sprite
class Yuanbao_S(Sprite):
'''表示单个小元宝的类'''
def __init__(self,game):
super().__init__()
self.screen = game.screen
self.setting = game.settings
#加载小元宝的图像
self.image = pygame.image.load("image/yuanbao.bmp")
self.image = pygame.transform.scale(self.image,(30,30))
self.rect = self.image.get_rect()
self.x=float(self.rect.x)
self.y=float(self.rect.y)
class Yuanbao_L(Sprite):
'''表示单个大元宝的类'''
def __init__(self,game):
super().__init__()
self.screen = game.screen
self.setting = game.settings
#加载大元宝的图像
self.image = pygame.image.load("image/yuanbao.bmp")
self.image = pygame.transform.scale(self.image,(60,60))
self.rect = self.image.get_rect()
self.x=float(self.rect.x)
self.y=float(self.rect.y)
class Zuanshi(Sprite):
'''表示单个钻石的类'''
def __init__(self,game):
super().__init__()
self.screen = game.screen
self.setting = game.settings
#加载钻石的图像
self.image = pygame.image.load("image/zuanshi.bmp")
self.image = pygame.transform.scale(self.image,(60,60))
self.rect = self.image.get_rect()
self.x=float(self.rect.x)
self.y=float(self.rect.y)
class Baoxiang(Sprite):
'''表示单个宝箱的类'''
def __init__(self,game):
super().__init__()
self.screen = game.screen
self.setting = game.settings
#加载宝箱的图像
self.image = pygame.image.load("image/baoxiang.bmp")
self.image = pygame.transform.scale(self.image,(90,90))
self.rect = self.image.get_rect()
self.x=float(self.rect.x)
self.y=float(self.rect.y)
class Bomb(Sprite):
def __init__(self,game):
super().__init__()
self.screen = game.screen
self.setting = game.settings
#加载炸弹的图像
self.image = pygame.image.load("image/zhadan.bmp")
self.image = pygame.transform.scale(self.image,(60,60))
self.rect = self.image.get_rect()
self.x = float(self.rect.x)
self.y=float(self.rect.y)
scoreboard.py文章来源:https://www.toymoban.com/news/detail-523578.html
import pygame.font
class Scoreboard:
'''显示得分信息的类'''
def __init__(self,game):
'''初始化显示得分设计的属性'''
self.screen = game.screen
self.screen_rect = self.screen.get_rect()
self.settings = game.settings
self.stats = game.stats
#显示得分信息时使用的字体设置
self.text_color = (30,30,30)
self.font = pygame.font.SysFont("arial",30)
#准备出事得分图像
self.prep_score()
self.prep_highest_score()
self.prep_level()
def prep_score(self):
'''将得分转换为一幅渲染的图像'''
score_str = str(self.stats.score)
self.score_image = self.font.render(f"score:{score_str}",True,self.text_color,self.settings.button_bg_color)
#在屏幕右上角显示得分
self.score_rect = self.score_image.get_rect()
#得分显示距离屏幕右侧边缘20像素,距离屏幕顶部边缘20像素
self.score_rect.right = self.screen_rect.right-20
self.score_rect.top = 20
def prep_level(self):
'''将等级渲染为图像'''
level_str = str(self.stats.level)
self.level_image = self.font.render(f"Level: {level_str}",True,self.text_color,self.settings.button_bg_color)
#将等级放在得分的下方
self.level_rect=self.level_image.get_rect()
self.level_rect.right=self.score_rect.right
self.level_rect.top=self.score_rect.bottom+10
def prep_highest_score(self):
'''将最高分渲染为图像'''
highest_score_str = str(self.stats.highest_score)
self.highest_score_image=self.font.render(f"Highest Score:{highest_score_str}",True,self.text_color,
self.settings.button_bg_color)
# 将最高分放到屏幕顶部中央
self.highest_score_rect = self.highest_score_image.get_rect()
self.highest_score_rect.centerx=self.screen_rect.centerx
self.highest_score_rect.top = 20
def prep_over(self):
gameover_str = 'GameOver!'
self.over_font = pygame.font.SysFont("arial",90)
gameover_image = self.over_font.render(f'{gameover_str}',True,self.text_color,self.settings.button_bg_color)
gameover_rect = gameover_image.get_rect()
gameover_rect.centerx = self.screen_rect.centerx
gameover_rect.centery = self.screen_rect.centery - 60
self.screen.blit(gameover_image,gameover_rect)
def check_highest_score(self):
'''检查是否产生了最高分'''
if self.stats.score > int(self.stats.highest_score):
filename = 'Data/data.txt'
with open(filename,'w') as f:
f.write(str(self.stats.score))
self.stats.highest_score = self.stats.score
self.prep_highest_score()
def show_score(self):
'''在屏幕上显示得分'''
self.screen.blit(self.score_image,self.score_rect)
self.screen.blit(self.highest_score_image,self.highest_score_rect)
self.screen.blit(self.level_image,self.level_rect)
settings.py文章来源地址https://www.toymoban.com/news/detail-523578.html
from fileinput import filename
import pygame
class Settings():
def __init__(self):
self.screen_width = 630
self.screen_height = 810
self.button_bg_color=(255,255,255) #由RGB值指定颜色
self.background_image = pygame.image.load("image/bg_image.bmp")
self.background_image = pygame.transform.scale(self.background_image,(630,810))
self.corn_speed = 5
self.yb_S_speed = 2.5
self.yb_L_speed = 2.5
self.zs_speed = 2.5
self.bx_speed = 2.5
self.zd_speed = 2.5
self.yuanbao_s_point = 2
self.yuanbao_l_point = 4
self.zuanshi_point = 8
self.baoxiang_point = 10
class GameStats:
def __init__(self,game):
'''初始化统计信息'''
self.reset_stats()
# 游戏刚启动时处于活动状态
self.game_active=0
# 在任何情况下都不应置最高分
filename = 'Data/data.txt'
with open(filename) as f:
self.highest_score = f.read()
def reset_stats(self):
'''初始化在游戏运行期间可能变化的统计信息'''
self.score = 0
self.level = 1
到了这里,关于pygame实现“元宝多多”完整代码的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!