今天是2月21日,我开始去跟着书本去写一个python小游戏,没想到一个小游戏,我每天大概看两个小时左右,没想到我写到了今天。
没想到一个小游戏,对我来说信息量竟然这么多
飞机大战外星人
前言
我写的这个游戏主要是想对于我学习面向对象编程的一种复习和知识再现,里面主要是,类(类方法,类属性,多态)的使用,如果对面向编程比较模糊不如试着去分析一下代码。飞机大战外星人的历程过于长,大部分都是我个人的总结和感悟,可以不看,直接点击上方蓝色字体(代码)即可传送到最终代码处进行分析代码!
这是我第二篇文章,非常非常感谢我博客第一篇文章《大一的第一篇文章》中各位前辈的支持
也许没有他们的支持,我可能没有坚持去写博客的动力!我真的很谢谢你们。
还有这些前辈的建议,正是因为有你们的建议,我才能成长。CSDN里的氛围真的很好,是一个很好的学习分享平台!
3月2日补充
截止今天
谢谢大家的支持,有你们的支持,坚定了我要坚持下去的理由,真的很谢谢大家!
飞机大战外星人的历程
首先学完面向对象编程后,我和大部分刚学完面向对象编程的一样,对于面向对象编程有点懵,这玩意儿是在是有点抽象,在程序中就行上帝一样去创造一类东西,就比如说女娲造人,我们写程序就像女娲在造人一样,去创造 人这一类东西,人就是一类东西的总称,人有眼睛和鼻子,这就是人的属性,人会生火,人会制造工具,那么生火和制造工具不就是类的方法,我目前来说是这么浅显的理解,如果哪里有错误或者不足欢迎大佬前辈斧正,非常感谢。
正是因为我学习的时候理解的比较浅显,再加上我正好看到了这个项目,所以我就跟着书本的思路去写这个游戏代码,带着疑问去项目当中,去进行一个知识的复现。
刚一开始就遇到了困难 ,我因为pip没有更新一直在转圈
,所以一直导入不了pygame这个库,又没有发现问题的所在,因为pycharm是一个比较成熟的软件,所以问题出在我本身
如果你的pycharm没有出现红框这个版本号,可能的原因是pip需要更新了,更新了就可以加入库了。
解决好问题后我开始跟着代码去编写程序,因为pycharm自动补写功能过于强大,有一些缩进总是过了或忘了,这里建议刚学语法的时候先别用一写集成编译软件,黑窗口命令行python就好。
——————————————————分割线——————————————————
2.28日
因为最近是开学季,明天要去送朋友去车站,因为我是河北学生,开学延期了,3月1号要开始网课生活,所以从今天以后可能写不了太多
已经从飞机的实例的创建到飞机的武装了,我已经把我的飞机装上了子弹,但是为了外星人的公平和建议玩家有效攻击,限制了子弹为3发子弹。
先把第一步代码分享一下,这是游戏的运行代码
import pygame
import sys
from settings import Settings
from ship import Ship
from bullet import Bullet
class AlienInvasion(object):
'''管理游戏资源和行为的类'''
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('Alin Invasion')
self.ship = Ship(self)
self.bullets = pygame.sprite.Group()
def run_game(self):
'''开始游戏的主循环'''
while True:
# 监视键盘和鼠标事件
self._check_events()
self._update_bullets()
self.bullets.update()
self._updata_screen()
# 每次循环时都重绘屏幕
self.screen.fill(self.settings.bg_color)
self.ship.blitme()
# 让最近绘制的屏幕可见
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)
def _updata_screen(self):
'''更新屏幕上的图像,并切换到新屏幕'''
self.screen.fill(self.settings.bg_color)
self.ship.blitme()
for bullet in self.bullets.sprites():
bullet.draw_bullet()
pygame.display.flip()
def _fire_bullet(self):
'''创建一颗子弹,并将其加入编组bullets中'''
if len(self.bullets) < self.settings.bullet_allowed:
new_bullet = Bullet(self)
self.bullets.add(new_bullet)
def _check_keydown_events(self,event):
'''响应按键'''
if event.key == pygame.K_RIGHT:
self.ship.moving_right = True
elif event.key == pygame.K_LEFT:
self.ship.moving_left = True
# 按q关闭界面
elif event.key == pygame.K_q:
sys.exit()
elif event.key == pygame.K_SPACE:
self._fire_bullet()
def _check_keyup_events(self,event):
'''响应松开'''
if event.key == pygame.K_RIGHT:
self.ship.moving_right = False
elif event.key == pygame.K_LEFT:
self.ship.moving_left = False
def _update_bullets(self):
'''更新的子弹位置并删除消失的子弹'''
# 更新子弹位置
self.ship.update()
# 删除消失的子弹
for bullet in self.bullets.copy():
if bullet.rect.bottom <= 0:
self.bullets.remove(bullet)
if __name__ == '__main__':
# 创建实例并运行游戏
ai = AlienInvasion()
ai.run_game()
下面这个是游戏的设置代码,其中的方法名字定义顾名思义,英语有点硬伤的可以有道翻译一下
class Settings():
'''存储《外星人入侵》所有设置的类'''
def __init__(self):
'''初始化游戏的设置'''
# 屏幕设置
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (230,230,230)
# 飞船设置
self.ship_speed = 1.5
# 子弹设置
self.bullet_speed = 1.0
self.bullet_width = 3
self.bullet_height = 15
self.bullet_color = (60,60,60)
#allowed 允许 允许子弹发射的数目
self.bullet_allowed = 3
这个下面的代码是飞船的设置,可以根据自己喜好改变飞船的绘制
import pygame
class Ship():
'''管理飞船的类'''
def __init__(self,ai_game):
'''初始化飞船并设置其初始位置'''
self.screen = ai_game.screen
self.settings = ai_game.settings
self.screen_rect = ai_game.screen.get_rect()
# 加载飞船图像并获取其外接矩形
self.image = pygame.image.load('images/ship.bmp')
self.rect = self.image.get_rect()
# 对于每艘新飞船,都将其放在屏幕底部*
self.rect.midbottom = self.screen_rect.midbottom
# 在飞船的属性x中存小数值
self.x = float(self.rect.x)
# 移动标志
self.moving_right = False
self.moving_left = False
def update(self):
'''根据移动标志调整飞船的位置'''
# 更新飞船而不是rect对象的x值
if self.moving_right and self.rect.right <self.screen_rect.right:
self.x += self.settings.ship_speed
if self.moving_left and self.rect.left > 0:
self.x -= self.settings.ship_speed
# 根据self.x更新rect对象
self.rect.x = self.x
def blitme(self):
'''在指定位置绘制飞船'''
self.screen.blit(self.image,self.rect)
这段代码是飞船图像的文件,可以根据自己喜好改变飞船的样子
接下来就是子弹的绘制代码
import pygame
from pygame.sprite import Sprite
class Bullet(Sprite):
'''管理所有发射的子弹'''
def __init__(self,ai_game):
# 在飞船当前位置创建一个子弹对象
super().__init__()
self.screen = ai_game.screen
self.settings = ai_game.settings
self.color = self.settings.bullet_color
# 在(0,0)处创建一个表示字典的矩形,再设置正确的位置
self.rect = pygame.Rect(0,0,self.settings.bullet_width,
self.settings.bullet_height)
self.rect.midtop = ai_game.ship.rect.midtop
# 存储用小数表示的子弹位置
self.y = float(self.rect.y)
def update(self):
'''向上移动子弹'''
# 更新表示子弹位置的小数值
self.y -= self.settings.bullet_speed
# 更新表示子弹的rect的位置
self.rect.y = self.y
def draw_bullet(self):
'''在屏幕上绘制子弹'''
pygame.draw.rect(self.screen,self.color,self.rect)
截止到这段代码,你写完之后就可以把飞船和发射子弹的行为做出来。
3.1
成功吧外星人创建出来了
下一步就是把外星人写出来
截止2021年3月3日23:30分
我终于吧基本配置完毕,合张影留个纪念吧!!!
最终代码(五个模块)
飞机大战主程序模块[alien_invasion]
import pygame
import sys
from time import sleep
import alien
from settings import Settings
from game_stats import GameStats
from ship import Ship
from bullet import Bullet
from alien import Alien
class AlienInvasion(object):
'''管理游戏资源和行为的类'''
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('Alin Invasion')
# 创建一个用于存储游戏统计信息的实例
self.stats = GameStats(self)
self.ship = Ship(self)
self.bullets = pygame.sprite.Group()
self.aliens = pygame.sprite.Group()
self._create_fleet()
def run_game(self):
'''开始游戏的主循环'''
while True:
# 监视键盘和鼠标事件
self._check_events()
if self.stats.game_active:
self.ship.update()
self._update_bullets()
self._update_aliens()
self.bullets.update()
# 每次循环时都重绘屏幕
# self.screen.fill(self.settings.bg_color)
self.ship.blitme()
# 让最近绘制的屏幕可见
pygame.display.flip()
self._update_screen()
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)
def _update_screen(self):
'''更新屏幕上的图像,并切换到新屏幕'''
self.screen.fill(self.settings.bg_color)
self.ship.blitme()
for bullet in self.bullets.sprites():
bullet.draw_bullet()
self.aliens.draw(self.screen)
pygame.display.flip()
def _fire_bullet(self):
'''创建一颗子弹,并将其加入编组bullets中'''
if len(self.bullets) < self.settings.bullet_allowed:
new_bullet = Bullet(self)
self.bullets.add(new_bullet)
def _check_keydown_events(self, event):
'''响应按键'''
if event.key == pygame.K_RIGHT:
self.ship.moving_right = True
elif event.key == pygame.K_LEFT:
self.ship.moving_left = True
# 按q关闭界面
elif event.key == pygame.K_q:
sys.exit()
elif event.key == pygame.K_SPACE:
self._fire_bullet()
def _check_keyup_events(self, event):
'''响应松开'''
if event.key == pygame.K_RIGHT:
self.ship.moving_right = False
elif event.key == pygame.K_LEFT:
self.ship.moving_left = False
def _update_bullets(self):
'''更新的子弹位置并删除消失的子弹'''
# 更新子弹位置
self.ship.update()
# 删除消失的子弹
for bullet in self.bullets.copy():
if bullet.rect.bottom <= 0:
self.bullets.remove(bullet)
self._check_bullet_allien_collisions()
def _check_bullet_allien_collisions(self):
'''响应子弹和外星人碰撞'''
# 删除发生碰撞的子弹和外星人
collisions = pygame.sprite.groupcollide(
self.bullets, self.aliens, True, True)
if not self.aliens:
# 删除现有的子弹并新建一群外星人
self.bullets.empty()
self._create_fleet()
def _create_fleet(self):
'''创建外星人群'''
# 创建一个外星人
# 创建一个外星人并计算一行可容纳多少外星人
# 外星人间距为外星人宽度
alien = Alien(self)
alien_width, alien_height = alien.rect.size
alien_width = alien.rect.width
available_space_x = self.settings.screen_width - (2 * alien_width)
number_aliens_x = available_space_x // (2 * alien_width)
# 计算屏幕可容纳多少外星人
ship_height = self.ship.rect.height
available_space_y = (self.settings.screen_height -
(3 * alien_height) - ship_height)
number_rows = available_space_y // (2 * alien_height)
# 创建外星人群
for row_number in range(number_rows):
# 创建第一行外星人
for alien_number in range(number_aliens_x):
# 创建一个外星人并将其加入当前行
self._create_alien(alien_number, row_number)
def _create_alien(self, alien_number, row_number):
'''创建一个外星人并将其放在当前行'''
alien = Alien(self)
alien_width, alien_heidth = alien.rect.size
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
self.aliens.add(alien)
def _update_aliens(self):
'''更新外星人群中所有外星人的位置'''
self.aliens.update()
'''检查是否有外星人位于屏幕边缘并更新整群外星人的位置'''
self._check_fleet_edges()
# 检测外星人和飞船之间的碰撞
if pygame.sprite.spritecollideany(self.ship, self.aliens):
self._ship_hit()
# 检查是否有外星人到达了屏幕底端
self._check_aliens_bottom()
def _check_fleet_edges(self):
'''有外星人到达边缘时采取响应措施'''
for alien in self.aliens.sprites():
if alien.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 _ship_hit(self):
'''响应飞船被外星人撞到'''
# 将ship_left减1
if self.stats.ship_left > 0:
self.stats.ship_left -= 1
# 清空余下的外星人和子弹
self.aliens.empty()
self.bullets.empty()
# 创建一群新的外星人,并将飞船放到屏幕底端或*
self._create_fleet()
self.ship.center_ship()
# 暂停
sleep(0.5)
else:
self.stats.game_active = False
def _check_aliens_bottom(self):
'''检查是否有外星人到达了屏幕底端'''
screen_rect = self.screen.get_rect()
for alien in self.aliens.sprites():
if alien.rect.bottom >= screen_rect.bottom:
# 像飞船被撞到一样处理
self._ship_hit()
break
if __name__ == '__main__':
# 创建实例并运行游戏
ai = AlienInvasion()
ai.run_game()
飞机大战子弹模块[bullet]
import pygame
from pygame.sprite import Sprite
class Bullet(Sprite):
'''管理所有发射的子弹'''
def __init__(self, ai_game):
# 在飞船当前位置创建一个子弹对象
super().__init__()
self.screen = ai_game.screen
self.settings = ai_game.settings
self.color = self.settings.bullet_color
# 在(0,0)处创建一个表示字典的矩形,再设置正确的位置
self.rect = pygame.Rect(0, 0, self.settings.bullet_width,
self.settings.bullet_height)
self.rect.midtop = ai_game.ship.rect.midtop
# 存储用小数表示的子弹位置
self.y = float(self.rect.y)
def update(self):
'''向上移动子弹'''
# 更新表示子弹位置的小数值
self.y -= self.settings.bullet_speed
# 更新表示子弹的rect的位置
self.rect.y = self.y
def draw_bullet(self):
'''在屏幕上绘制子弹'''
pygame.draw.rect(self.screen, self.color, self.rect)
飞船模块[ship]
import pygame
class Ship():
'''管理飞船的类'''
def __init__(self,ai_game):
'''初始化飞船并设置其初始位置'''
self.screen = ai_game.screen
self.settings = ai_game.settings
self.screen_rect = ai_game.screen.get_rect()
# 加载飞船图像并获取其外接矩形
self.image = pygame.image.load('images/ship.bmp')
self.rect = self.image.get_rect()
# 对于每艘新飞船,都将其放在屏幕底部*
self.rect.midbottom = self.screen_rect.midbottom
# 在飞船的属性x中存小数值
self.x = float(self.rect.x)
# 移动标志
self.moving_right = False
self.moving_left = False
def update(self):
'''根据移动标志调整飞船的位置'''
# 更新飞船而不是rect对象的x值
if self.moving_right and self.rect.right <self.screen_rect.right:
self.x += self.settings.ship_speed
if self.moving_left and self.rect.left > 0:
self.x -= self.settings.ship_speed
# 根据self.x更新rect对象
self.rect.x = self.x
def blitme(self):
'''在指定位置绘制飞船'''
self.screen.blit(self.image,self.rect)
def center_ship(self):
'''让飞船在屏幕底端居中'''
self.rect.midbottom = self.screen_rect.midbottom
self.x = float(self.rect.x)
游戏状态模块[game_stats]
class GameStats:
'''跟踪游戏的统计信息'''
def __init__(self, ai_game):
'''初始化统计信息'''
self.settings = ai_game.settings
self.reset_stats()
# 游戏刚启动处于活动状态
self.game_active = True
def reset_stats(self):
'''初始化在游戏运行期间可能变化的统计信息'''
self.ship_left = self.settings.ship_limit
外星人模块[alien]
import pygame
from pygame.sprite import Sprite
class Alien(Sprite):
'''表示外星人的类'''
def __init__(self, ai_game):
'''初始化外星人并设置起始位置'''
super().__init__()
self.settings = ai_game.settings
self.screen = ai_game.screen
# 加载外星人图像并设置其screen属性
self.image = pygame.image.load('images/alien.bmp')
self.rect = self.image.get_rect()
# 每个外星人最初都在屏幕的左上角附近
self.rect.x = self.rect.width
self.rect.y = self.rect.height
# 存储外星人的精准水平位置
self.x = float(self.rect.x)
def update(self):
'''向左或右移动外星人'''
self.x += (self.settings.alien_speed*
self.settings.fleet_direction)
self.rect.x = self.x
def check_edges(self):
'''如果外星人位于屏幕边缘,就返回Ture'''
screen_rect = self.screen.get_rect()
if self.rect.right >= screen_rect.right or self.rect.left < 0:
return True
游戏整体设置模块[settings]
class Settings():
'''存储《外星人入侵》所有设置的类'''
def __init__(self):
'''初始化游戏的设置'''
# 屏幕设置
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (230, 230, 230)
# 飞船设置
self.ship_speed = 1.5
self.ship_limit = 3
# 子弹设置
self.bullet_speed = 1.5
self.bullet_width = 3
self.bullet_height = 15
self.bullet_color = (60, 60, 60)
# allowed 允许 允许子弹发射的数目
self.bullet_allowed = 3
# 外星人设置
self.alien_speed = 0.5
self.fleet_drop_speed = 10
# fleet_direction 为1表示向右移,为-1表示向左移
self.fleet_direction = 1
项目源代码
文章过长,需要项目源代码的,我已经打包好了,直接下载即可
百度云:
链接:https://pan.baidu.com/s/1iRRaUhWOj1321XRrTbp4VQ
提取码:0oo8
复制这段内容后打开百度网盘手机App,操作更方便哦
最后一点点想说的
写了这么多,最后真的是写不动了,我刚开始写这篇文章还想着最后说点什么总结一下,但是真的到这天了,我却一点也写不动了,我做这个项目对我来说真的很辛苦,但是提升也很大,我发表出来记录一下自己的成长过程!
如果您觉得我写的不错(就算写的不好,也挺辛苦的),麻烦您动动小手,点赞评论关注,您的支持就我坚持写下去,坚持记录自己成长的最大动力,谢谢您的支持。