文章目录

  • 前言
  • 思维导图
  • 思路分析
    • 三大对象
      • 飞船
      • 子弹
      • 小行星
    • 主函数
      • 开始界面
      • 游戏界面
      • 结束界面
  • End

本篇是一文帮你理清"游戏思路+实现逻辑"专栏的第篇文章,我个人开此专栏的目的主要是:

  • 理清代码的思路
  • 增长知识覆盖面
  • 记录以便于以后查看参考

前言

在最近的学习中,突然觉得有必要去学习一些综合的小项目来增强自己的能力,而对于项目我想到了利用小游戏来学习的方法(毕竟玩游戏有意思哈哈),当然,我现在处于学习前期阶段,以我的能力来写一些游戏显得很不现实,毕竟我也没看过多少游戏代码什么的,但是我觉得可以去搜集一些小游戏的开源代码,然后阅读、理解,之后在理解的基础上结合自己的思想去做些更改,如果自己能称心如意的更改源代码并正常运行,那么我觉得能力也算是一种提高了,甚至一段时间以后自己可以根据自己的想法来做一些小游戏。


本文我要给大家带来的是一款经典的游戏-飞机大战,使用Python编写而成。
本代码是github上的开源代码,项目地址:https://github.com/CharlesPikachu/Games/tree/master/Game10

思维导图

首先附上一张我对该代码总结的思维导图:

此思维导图是我根据对项目源代码的理解作出的,大家可以先浏览一下游戏的思维导图,然后再看下文思路分析,或者先看完下文再回来查看思维导图亦可,不过毕竟鄙人能力尚且不好,难免会有一些理解错误或是其它错误,还请大家包容并指出。

思路分析

首先,既然是一个小游戏,一般来讲当然要用到面向对象的思想,在这个游戏中,主要分为三大对象:

  • 玩家操控的飞船
  • 随机出现的小行星
  • 飞船可以发射的子弹

当然,万物皆对象嘛,实际上代码中的界面什么的都可以被看作对象,不过在这里我们主要需要封装是以上三大对象。

三大对象

飞船

首先,看一下封装飞船的代码:

class Ship(pygame.sprite.Sprite):def __init__(self, idx):pygame.sprite.Sprite.__init__(self)self.imgs = ['./resources/imgs/ship.png', './resources/imgs/ship_exploded.png']self.image = pygame.image.load(self.imgs[0]).convert_alpha()self.explode_img = pygame.image.load(self.imgs[1]).convert_alpha()# 位置self.position = {'x': random.randrange(-10, 918), 'y': random.randrange(-10, 520)}self.rect = self.image.get_rect()self.rect.left, self.rect.top = self.position['x'], self.position['y']# 速度self.speed = {'x': 10, 'y': 5}# 玩家编号self.playerIdx = idx# 子弹冷却时间self.cooling_time = 0# 爆炸用self.explode_step = 0'''飞船爆炸'''def explode(self, screen):img = self.explode_img.subsurface((48*(self.explode_step-1), 0), (48, 48))screen.blit(img, (self.position['x'], self.position['y']))self.explode_step += 1'''移动飞船'''def move(self, direction):if direction == 'left':self.position['x'] = max(-self.speed['x']+self.position['x'], -10)elif direction == 'right':self.position['x'] = min(self.speed['x']+self.position['x'], 918)elif direction == 'up':self.position['y'] = max(-self.speed['y']+self.position['y'], -10)elif direction == 'down':self.position['y'] = min(self.speed['y']+self.position['y'], 520)self.rect.left, self.rect.top = self.position['x'], self.position['y']'''画飞船'''def draw(self, screen):screen.blit(self.image, self.rect)'''射击'''def shot(self):return Bullet(self.playerIdx, (self.rect.center[0] - 5, self.position['y'] - 5))

首先,飞船作为游戏中的一大对象,其继承了pygame中的精灵对象pygame.sprite.Sprite,先对飞船初始化,

  • 设置飞船游戏中的图片及爆炸时的图片
  • 然后给出游戏开始后初始化飞船的位置,此位置利用random模块实现在屏幕中随机初始化位置。
  • 定义飞船移动时的速度常量
  • 玩家编号属性是为区分飞船而定,便于后续双人模式中各飞船对方法的调用实现。你也可以利用此参数并增加相应代码实现n人模式
  • 子弹冷却时间可以理解为保证游戏平衡的一个参数吧,可有可无,可大可小,自己修改下看看效果就知道了。
  • 最后一个参数是截取爆炸图片用的参数,因为初始化的爆炸图片是size为(144,48)的图片,里面有三张图,此参数配合选择爆炸的唯一图。

给定飞船的方法:

  • move()用来移动飞船,移动是判断位置,保证存在边界
  • draw()用来更新飞船
  • shot()用来发射子弹

子弹

class Bullet(pygame.sprite.Sprite):def __init__(self, idx, position):pygame.sprite.Sprite.__init__(self)self.imgs = ['./resources/imgs/bullet.png']self.image = pygame.image.load(self.imgs[0]).convert_alpha()self.image = pygame.transform.scale(self.image, (10, 10))# 位置self.rect = self.image.get_rect()self.rect.left, self.rect.top = positionself.position = position# 速度self.speed = 8# 玩家编号self.playerIdx = idx'''移动子弹'''def move(self):self.position = self.position[0], self.position[1] - self.speedself.rect.left, self.rect.top = self.position'''画子弹'''def draw(self, screen):screen.blit(self.image, self.rect)

子弹同样继承pygame中的精灵对象pygame.sprite.Sprite

  • 先初始化构造方法
  • 设置子弹图片,同时利用transform.scale给图片做了放缩处理
  • 初始化位置
  • 初始化速度
  • 设置玩家编号属性

子弹具有的行为方法:

  • move()用来给出子弹的位置
  • draw()用来更新子弹

小行星

class Asteroid(pygame.sprite.Sprite):def __init__(self):pygame.sprite.Sprite.__init__(self)self.imgs = ['./resources/imgs/asteroid.png']self.image = pygame.image.load(self.imgs[0]).convert_alpha()# 位置self.rect = self.image.get_rect()self.position = (random.randrange(20, WIDTH-20), -64)self.rect.left, self.rect.top = self.position# 速度self.speed = random.randrange(3, 9)self.angle = 0self.angular_velocity = random.randrange(1, 5)self.rotate_ticks = 3'''移动小行星'''def move(self):self.position = self.position[0], self.position[1] + self.speedself.rect.left, self.rect.top = self.position'''转动小行星'''def rotate(self):self.rotate_ticks -= 1if self.rotate_ticks == 0:self.angle = (self.angle + self.angular_velocity) % 360orig_rect = self.image.get_rect()rot_image = pygame.transform.rotate(self.image, self.angle)rot_rect = orig_rect.copy()rot_rect.center = rot_image.get_rect().centerrot_image = rot_image.subsurface(rot_rect).copy()self.image = rot_imageself.rotate_ticks = 3'''画小行星'''def draw(self, screen):screen.blit(self.image, self.rect)

小行星当然也是继承pygame中的精灵对象pygame.sprite.Sprite

  • 初始化构造方法
  • 设置行星图片
  • 设置行星出现的随机位置
  • 初始化速度,速度也是在一个范围内随机给出,初始化角度等用于自转参数。

行为方法:

  • move()用来确定小行星的位置
  • rotate()用来让小行星转起来
  • draw()用来更新

主函数

好了,三大对象有了,游戏的核心就有了,接下来就是设置界面、刷新、让对象"活起来"的操作了。
源代码:

def main():pygame.init()pygame.font.init()pygame.mixer.init()screen = pygame.display.set_mode((WIDTH, HEIGHT))pygame.display.set_caption('飞机大战-goldsun')#转到开始界面num_player = start_interface(screen)#对开始界面的操作会返回数字,即选择单双人模式if num_player == 1:while True:GameDemo(num_player=1, screen=screen)end_interface(screen)else:while True:GameDemo(num_player=2, screen=screen)end_interface(screen)

主函数非常简短,因为其它的操作都在别的模块中完成了,主函数这里只负责调用即可。
实现过程:
首先初始化游戏环境,设置游戏界面屏幕,转入开始界面,待用户操作之后程序正常运行并根据用户选择的模式进入循环过程中,此循环为大循环,即游戏界面与结束界面的循环,以实现重新开始功能。

开始界面

源代码:

def start_interface(screen):#创建一个时钟clock = pygame.time.Clock()while True:button_1 = BUTTON(screen, (330, 190), '单人模式')button_2 = BUTTON(screen, (330, 305), '双人模式')for event in pygame.event.get():if event.type == pygame.QUIT:pygame.quit()sys.exit()if event.type == pygame.MOUSEBUTTONDOWN:if button_1.collidepoint(pygame.mouse.get_pos()):return 1elif button_2.collidepoint(pygame.mouse.get_pos()):return 2clock.tick(60)pygame.display.update()

首先实例化一个Clock对象,用于跟踪时间,然后进入屏幕的刷新循环中,屏幕中有两个按钮,循环中对按钮进行监听,两个按钮若有被触发时则跳出循环并返回相应的值以供主函数的大循环判断并实现相应模式。
这里的clock.tick(60)其实也可以写作clock.tick(),当括号中的参数被激活时会使得程序延迟,如给定60,则游戏将会以低于60帧的速率进行,给定的参数是一个程序刷新上限,如果不给定参数,程序将以本身的运行速率进行刷新。

游戏界面

源代码:

def GameDemo(num_player, screen):pygame.mixer.music.load(("./resources/sounds/Cool Space Music.mp3"))pygame.mixer.music.set_volume(0.4)pygame.mixer.music.play(-1)explosion_sound = pygame.mixer.Sound('./resources/sounds/boom.wav')fire_sound = pygame.mixer.Sound('./resources/sounds/shot.ogg')font = pygame.font.Font('./resources/font/simkai.ttf', 20)# 游戏背景图bg_imgs = ['./resources/imgs/bg_big.png','./resources/imgs/seamless_space.png','./resources/imgs/space3.jpg']bg_move_dis = 0bg_1 = pygame.image.load(bg_imgs[0]).convert()bg_2 = pygame.image.load(bg_imgs[1]).convert()bg_3 = pygame.image.load(bg_imgs[2]).convert()# 玩家, 子弹和小行星精灵组playerGroup = pygame.sprite.Group()bulletGroup = pygame.sprite.Group()asteroidGroup = pygame.sprite.Group()# 产生小行星的时间间隔asteroid_ticks = 90for i in range(num_player):playerGroup.add(Ship(i+1))clock = pygame.time.Clock()# 分数Score_1 = 0Score_2 = 0while True:for event in pygame.event.get():if event.type == pygame.QUIT:pygame.quit()sys.exit()# 玩家一: ↑↓←→控制, 键盘九宫格的1射击# 玩家二: wsad控制, j射击pressed_keys = pygame.key.get_pressed()i = -1for player in playerGroup:i += 1direction = Noneif i == 0:if pressed_keys[pygame.K_UP]:direction = 'up'elif pressed_keys[pygame.K_DOWN]:direction = 'down'elif pressed_keys[pygame.K_LEFT]:direction = 'left'elif pressed_keys[pygame.K_RIGHT]:direction = 'right'if direction:player.move(direction)if pressed_keys[pygame.K_KP1]:if player.cooling_time == 0:fire_sound.play()bulletGroup.add(player.shot())player.cooling_time = 20elif i == 1:if pressed_keys[pygame.K_w]:direction = 'up'elif pressed_keys[pygame.K_s]:direction = 'down'elif pressed_keys[pygame.K_a]:direction = 'left'elif pressed_keys[pygame.K_d]:direction = 'right'if direction:player.move(direction)if pressed_keys[pygame.K_j]:if player.cooling_time == 0:fire_sound.play()bulletGroup.add(player.shot())player.cooling_time = 20if player.cooling_time > 0:player.cooling_time -= 1if (Score_1 + Score_2) < 50:background = bg_1elif (Score_1 + Score_2) < 150:background = bg_2else:background = bg_3# 向下移动背景图实现飞船向上移动的效果screen.blit(background, (0, -background.get_rect().height + bg_move_dis))screen.blit(background, (0, bg_move_dis))bg_move_dis = (bg_move_dis + 2) % background.get_rect().height# 生成小行星if asteroid_ticks == 0:asteroid_ticks = 90asteroidGroup.add(Asteroid())else:asteroid_ticks -= 1# 画飞船for player in playerGroup:if pygame.sprite.spritecollide(player, asteroidGroup, True, None):player.explode_step = 1explosion_sound.play()elif player.explode_step > 0:if player.explode_step > 3:playerGroup.remove(player)if len(playerGroup) == 0:returnelse:player.explode(screen)else:player.draw(screen)# 画子弹for bullet in bulletGroup:bullet.move()if pygame.sprite.spritecollide(bullet, asteroidGroup, True, None):bulletGroup.remove(bullet)if bullet.playerIdx == 1:Score_1 += 1else:Score_2 += 1else:bullet.draw(screen)# 画小行星for asteroid in asteroidGroup:asteroid.move()asteroid.rotate()asteroid.draw(screen)# 显示分数Score_1_text = '玩家一得分: %s' % Score_1Score_2_text = '玩家二得分: %s' % Score_2text_1 = font.render(Score_1_text, True, (0, 0, 255))text_2 = font.render(Score_2_text, True, (255, 0, 0))screen.blit(text_1, (2, 5))screen.blit(text_2, (2, 35))pygame.display.update()clock.tick(60)

游戏界面是这个程序最重要的部分之一(但其实并不是最难的),因为我们既然做的是游戏,那么玩的过程肯定非常重要啊哈哈,而此过程当然就持续运行在游戏界面中。

  • 首先,载入游戏背景音乐,设置音量,开始播放等初始化,包括字体(展示分数等会用到)背景图处理等一系列初始化,还设置了三大对象的精灵组,如果你想开个必杀技的外挂可以从此入手哈哈。
  • 根据玩家选择的模式实例化飞船并标记。
    进入游戏循环
  • 事件判断,如当玩家关闭游戏时结束程序运行,给玩家设置操作键以进行相关操作。
  • 如果判断分数来进入关卡,这个游戏的关卡设置比较简陋哈哈,其余都没变只是换张背景图。不过你可以自行更改哦。
  • 生成小行星(判断画面帧的间隔),游戏中的间隔帧设置的为90,也就是刷新90帧生成一个小行星。如我们设置的clock.tick(60),如果电脑运行速度很快的话基本就是以60帧的速率在刷新,也就是说每1.5s生成一个小行星,你可以更改asteroid_ticks的大小来加快/慢小行星的生成。
  • 对飞船和行星组进行碰撞检测,只要该飞船碰到任一小行星则爆炸,同时调用相关方法如播放爆炸音频。没有碰撞则程序继续向后运行。
  • 对子弹和行星组进行碰撞检测,只要子弹碰到任一行星,则子弹和行星都被移除同时该玩家加分。
    (此程序中的碰撞检测均使用的pygame内置的碰撞检测函数,我们也可以自己写碰撞检测函数)
  • 在界面显示玩家得分
  • 更新屏幕
    再次进入循环

结束界面

源代码:

def end_interface(screen):clock = pygame.time.Clock()while True:button_1 = BUTTON(screen, (330, 190), '重新开始')button_2 = BUTTON(screen, (330, 305), '退出游戏')for event in pygame.event.get():if event.type == pygame.QUIT:pygame.quit()sys.exit()if event.type == pygame.MOUSEBUTTONDOWN:if button_1.collidepoint(pygame.mouse.get_pos()):returnelif button_2.collidepoint(pygame.mouse.get_pos()):pygame.quit()sys.exit()clock.tick(60)pygame.display.update()

结束界面和开始界面非常类似,也是两个按钮连接两个功能,对事件监听并处理罢了,在此不多赘述,而结束界面的入口是在主函数的大循环中,也就是当游戏界面跳出时便顺序进入结束界面。

End

到这里正篇文章的内容就结束了,本文章的目的并不是展示如何写这个游戏,而是用于理清游戏中的逻辑思路,这个时候你再去看前文的思维导图会不会感觉焕然一新呢,即使我们虽然看懂了这游戏的逻辑,我们可能还是写不出来什么游戏,原因就是我们看的还是太少了,因此我们还是多读游戏源代码多思考提升自己,总有一天,我们也能写出来很好的游戏!
最后,既然都看到这里了,如果感觉文章对您有帮助,不妨点个赞吧,谢谢~~

一文帮你理清游戏思路+实现逻辑- Python飞机大战相关推荐

  1. linux系统解锁用户百度,详细到没朋友,一文帮你理清Linux 用户与用户组关系~

    原标题:详细到没朋友,一文帮你理清Linux 用户与用户组关系~ 1.用户和用户组文件 在 linux 中,用户帐号,用户密码,用户组信息和用户组密码均是存放在不同的配置文件中的. 在 linux 系 ...

  2. python飞机大战设计思路_python飞机大战pygame游戏背景设计详解

    本文实例讲述了python飞机大战pygame游戏背景设计.分享给大家供大家参考,具体如下: 目标 背景交替滚动的思路确定 显示游戏背景 01. 背景交替滚动的思路确定 运行 备课代码,观察 背景图像 ...

  3. python飞机大战功能模块图_基于Python的飞机大战游戏设计

    第 2 3 卷 第 1 期 2019年 3 月 扬 州 职 业 大 学 学 报 Journal of Yangzhou Polytechnic College Vol .23 No . 1 Mar . ...

  4. Python 飞机大战游戏中 获取被击中飞机的坐标位置信息

    Python 飞机大战游戏中 获取被击中飞机的坐标位置信息 在参考现有的飞机大战游戏代码,写第一个python游戏,子弹击中飞机后,飞机消失,想着如果能有爆照效果就好了. 于是新建了一个爆炸效果的sp ...

  5. python飞机大战加背景音乐_python实现飞机大战小游戏 python飞机大战中的音频文件怎么改成MP3...

    怎么样用Python写飞机大战游戏 python开发飞机大战外星人游戏怎么弄双人模式新的一年,哪怕仍是一个人,也要活得像一支队伍,为自己的头脑和心灵招兵买马,不气馁,有召唤,爱自由. 主函数 impo ...

  6. python 飞机大战等游戏类编程思路

    一.  类与对象的概念 一个游戏里面的组成元素其实都是一个个的对象,而对象又是在类中的一个实例. 比如你是一个人,而你所属的类别叫做人类,你是人类中的一个实例.类中可以定义属性和方法,而对象是具有这些 ...

  7. python飞机大战游戏高级_05.python实现飞机大战游戏

    python的核心编程跟着学习完了,终于到了第一个实战项目的演练,很是激动. 按着黑马老师指导的思路,代码主要分成两个模块主模块plane_main.py和工具模块plane_sprites.py. ...

  8. python飞机大战概要设计说明书_飞机大战概要设计文档 4改

    飞机大战概要设计 文档规格说明书 1. 引言部分 1.1目的 该文档描述的是飞机大战的概要设计,主要内容包括飞机大战功能简介等. 本文档预期的读者包括全体小组成员及指导教师. 1.2 范围 1.2.1 ...

  9. python飞机大战概要设计_飞机大战游戏开发文档(Android版)

    飞机大战游戏 开发文档 (Android版) 课程名称:飞机大战游戏 课程类型:Android游戏编程精彩内容,尽在百度攻略:https://gl.baidu.com 姓名:苏均灿 学号:131342 ...

最新文章

  1. git误删文件找回方法/git版本回退方法
  2. CSS(1)——如何使用css选择器
  3. 在Django将已有数据库生成models文件
  4. hadoop设置用户权限_No.9 MySQL之用户管理与权限设置
  5. AndroidStudio_Android Studio项目中报Call requires API level 18 (current min is 16)---Android原生开发工作笔记232
  6. Soul网关源码阅读(八)路由匹配初探
  7. DisplayX显示器测试、显示器屏幕检测
  8. 六大排序算法:插入排序、希尔排序、选择排序、冒泡排序、堆排序、快速排序
  9. 防火墙 蓝精灵DoS P127
  10. 阿啊-有意思的表情包
  11. C/C++开发,无可避免的多线程(篇二).thread与其支持库
  12. 利用群发短信进行精准高效的会员营销
  13. 怎么压缩图片 ? 掌握这几种免费压缩图片的方法就够了
  14. OPEN(SAP) UI5 学习入门系列之二: 最佳实践练习(上)
  15. 执行HiveSql时报错“FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.mr.MapRedTa”
  16. js 苹果手机点击事件 兼容
  17. Dev-C++常用快捷键
  18. 二叉查找树与红黑树原理和程序全面介绍
  19. 【UE4源代码观察】尝试调试UBT
  20. 平板电脑如何蓝牙和手机配对_如何将蓝牙设备与计算机,平板电脑或手机配对...

热门文章

  1. Pyecharts中Map和Geo的使用笔记
  2. VS2019:创建模板文件,自定义代码片段
  3. zeek(bro) 脚本学习 三
  4. python笔记(摘抄廖雪峰python课堂)
  5. 保时捷遇最强对手?玛莎拉蒂发布全新SUV;比亚迪壳牌计划合资在深圳运营一万个电动汽车充电终端 | 美通社头条...
  6. 移动魔百盒CM201-1_CW_S905L2_MT7668_线刷固件包
  7. 【MySQL系列】使用C语言来连接数据库
  8. 软件著作权一次下证快速下载教程
  9. JS new操作符的具体干了什么?
  10. 黑马程序员——基础学习感悟总结...