带薪玩游戏,是多么开心的事情,我就找到了。

前段时间,公司接到一个模拟业务场景的项目,需要在图形界面上模拟业务场景,比如人跑动,拖拽物体等,从而获取不太业务场景的模拟数据。

由于商务限制,无法展示模拟程序,所以今天制作一个打猴子游戏,来介绍 Pygame 的一些用法,这个游戏也是我完成模拟程序的主要学习对象。

重识 Pygame

之前对 Pygame 的认识很肤浅,停留在画图工具的层面上。

通过学习和探索之后,才发现 Pygame 的强度功能,而且有很多框架和组件,帮助开发者提高效率,比如对象类Sprite等。

Pygame 中 Surface 是个很重要的概念,相当于PS(Photo Shop)的图层,图层之间可以叠加,可以相对所在图层定位,比如将背景图层相对屏幕定位后,背景图层上的其他图层可以相对于背景定位,这样就不用每次都计算一个图层想对于屏幕的具体位置了。

打猴子游戏

Chimp是 Pygame 文档中的一个示例,帮助开发者学习和理解,我们就以这个游戏为,并且在原版基础上,做了些改动,比如加入了游戏统计信息的显示等。

最终效果是这样的:

思路

打猴子游戏,就是一只猴子在不断地跑,然后用鼠标控制一个拳头去击打它,玩的过程中会记录击中次数和击中率。

根据游戏思路,游戏中有猴子和拳头两个对象,对了提高可玩性,需要添加一些音效和动作。

实现

实现过程将分为 游戏加载、对象设置、游戏主循环三个方面做说明。

游戏资源

游戏有两种资源,对象图像和声效。

图像资源可以是图片,格式可以是比如 bmp,jpg,png 等。

我们编写一个图像加载方法:

def load_image(name, colorkey=None):fullname = os.path.join('chimp_data', name)try: image = pygame.image.load(fullname)except pygame.error as message:print('Cannot load image:', name)raise SystemExit(message)image = image.convert()if colorkey is not None:if colorkey is -1:colorkey = image.get_at((0, 0))image.set_colorkey(colorkey, RLEACCEL)return image, image.get_rect()
  • load_image 方法用来加载一个图像,参数 name 为图像文件名,colorkey 为需要去除的关键颜色
  • 利用 Pygame.image.load 用图片文件创建为 image 对象
  • image.convert() 的作用是对图像做适应环境的优化,以便绘制更高效
  • 如果 colorkey 参数没有提供的话,会将图像上第一个像素颜色作为 colorkey
  • image.set_colorkey(colorkey, RLEACCEL) 用于设置图像的 colorkey,其中 RLEACCEL 作用是对 colorkey 做除去操作
  • 方法返回图像对象和图像的矩形区域,矩形区域在对象绘制时很重要

声效资源的加载也类似:

def load_sound(name):class NoneSound:def play(self): passif not pygame.mixer:return NoneSound()fullname = os.path.join('chimp_data', name)try:sound = pygame.mixer.Sound(fullname)except pygame.error as message:print('Cannot load sound:', fullname)raise SystemExit(message)return sound
  • pygame.mixer 是 Pygame 的声音合成器,如果电脑设备上没有声卡(声音处理组件),将无法播放声音
  • 定义了一个 NoneSound 类,实现了空的 play 方法,以便在没有声卡的设备上正常运行
  • 最好返回声音资源

通过 load_image 和 load_sound 两个方法,就完成了游戏中资源的加载。

对象设置

现在可以定义游戏对象了,需要处理样式,形态,状态等,为了对象定义动作行为等。

如果光靠手工绘制,是很麻烦的,Pygame 提供了对象类 Sprite,只需要初始化数据,实现状态更新就可以了。

游戏需要两种对象:拳头和猴子。

拳头,需要在屏幕上显示一个拳头,并且需要跟着鼠标移动,当做打击动作时,需要变化形态,具体的代码如下:

class Fist(pygame.sprite.Sprite):def __init__(self):super().__init__(self)self.image, self.rect = load_image('fist.bmp', -1)self.punching = 0def update(self):"""拳头随鼠标移动"""pos = pygame.mouse.get_pos()self.rect.midtop = posif self.punching:self.rect.move_ip(5, 10)def punch(self, target):"""返回是否打击到目标"""if not self.punching:self.punching = 1hitbox = self.rect.inflate(-5, -5)return hitbox.colliderect(target.rect)def unpunch(self):"""结束打击"""self.punching = 0
  • 在初始化方法 __init__ 里,用 load_image 加载了拳头图像,获得了 image 和 rect,这两个属性是 Sprite 对象必须的
  • update 是必须实现的 Sprite 方法,用来更新对象的状态:首先获得鼠标的位置坐标,并将位置赋予对象区域,即将对象区域的中上位置移动到鼠标位置,从而实现对象位置的变化
  • 然后判读对象是否处于击打状态,如果是则将对象的相对位置,向右移动 5 个像素,向下移动 10 个像素,表示在向下挥舞拳头
  • punch 是自定义方法,作为外边调用的接口。调用时会设置对象状态,并返回是否击中。具体是:如果击打的话,且当前不是在击打状态时,设置状态为击打中,并将对象的区域缩小 5 个像素,即打击下去的话拳头远去,区域会缩小。
  • colliderect 方法用于做碰撞检测,即与目标的区域做判断,是否碰撞到一起
  • unpunch 也是自定方法,结束击打之后,将击打状态设置为否

仔细阅读代码就会发现,Sprite 让一个业务复杂的对象很简单地实现了,而且不用关注如何绘制。

同样的方式定义猴子对象,猴子对象需要自动移动,如果被打击到,会做旋转动作,具体代码如下:

class Chimp(pygame.sprite.Sprite):def __init__(self):super().__init__(self)self.image, self.rect = load_image('chimp.bmp', -1)screen = pygame.display.get_surface()self.area = screen.get_rect()self.rect.topleft = 60, 10self.move = 9self.dizzy = 0def update(self):"""根据状态调整猴子行为"""if self.dizzy:self._spin()else:self._walk()passdef _walk(self):"""猴子在屏幕之间移动,当碰到屏幕边缘时返回"""newpos = self.rect.move((self.move, 0))if not self.area.contains(newpos):self.move = -self.movenewpos = self.rect.move((self.move, 0))self.image = pygame.transform.flip(self.image, 1, 0)self.rect = newposdef _spin(self):"""旋转猴子图片"""center = self.rect.centerself.dizzy += 12if self.dizzy >= 360:self.dizzy = 0self.image = self.originalelse:rotate = pygame.transform.rotateself.image = rotate(self.original, self.dizzy)self.rect = self.image.get_rect(center=center)def punched(self):"""被击中时调用"""if not self.dizzy:self.dizzy = 1self.original = self.image
  • __init__ 中,area 获取了屏幕的区域,以便判断猴子移动范围;move 为移动速度,即每帧移动多数像素,值越大速度越快
  • update 方法中,根据对象状态调用对于状态的行为
  • _walk 方法为走动行为,首先将对象区域移动到新位置,获得新位置范围 newpos,然后判断新位置是否在屏幕区域 area中,没有的话,将移动距离设置为相反数,向相反的方向移动;pygame.transform.flip 的作用时让图片水平翻转,好像猴子掉了个头一样
  • _spin 方法为转圈行为,当被打中之后,做360度旋转,dizzy 为旋转角度,每帧旋转 12 度,rotate 方法用于图像旋转,当旋转角度超出 360 度后,回复图像样式。
  • punched 方法在被击中时调用,只做状态设置,其中 original 是将旋转前的图像暂存起来,用于旋转结束后的图像恢复

请注意 图像旋转方法 rotate,虽然能产生旋转效果,但是却不能指定旋转中心点,其旋转中心点为将图像刚好放在一个正方形的左侧时,正方形的中心点作为旋转中心点。
如果要实现围绕特定中心点旋转,就需要在旋转之后,将图像移动到这个点。
这就是在 _spin 方法中,self.rect = self.image.get_rect(center=center) 这句代码的作用——让图像围绕图像中心点旋转。

到这里,我们的游戏对象就设置完成了。

理解主循环

Pygame 中有个重要的概念就是主循环。

一般来说,会认为对象会自动发生移动和操作。

其实各种动作的游戏场景是由每帧图像合并而成的,就好比拍一个 pose,拍一张照,如此反复,最后将图片快速的切换,可以看到动画效果一样。

理解了这个,就能理解为什么电脑游戏的性能常常用更多的帧数来衡量的,更多的帧,意味着需要每秒绘制更多的图像。

Pygame 就是这么做的,通过一个主循环,不断地绘制对象的行为,从而产生动画效果。

主循环实际上就是个死循环,通过 pygame.time.Clock 控制游戏帧数。

来看看具体代码:

def main():# 初始化pygame.init() screen = pygame.display.set_mode((468, 90))  # 设置窗口大小,获得窗口屏幕pygame.display.set_caption('Monkey Fever')  # 窗口标题pygame.mouse.set_visible(0)  # 隐藏鼠标background = pygame.Surface(screen.get_size()) # 设置背景background = background.convert()background.fill((250, 250, 250))if pygame.font:font = pygame.font.SysFont('SimHei',24)  # 设置字体whiff_sound = load_sound('whiff.wav')  # 加载声音资源punch_sound = load_sound('punch.wav')# 创建对象chimp = Chimp()fist = Fist()# 将对象添加到对象控制组allsprites = pygame.sprite.Group((fist, chimp))# 获取游戏时钟clock = pygame.time.Clock()# 游戏统计punchcount = 0hitcount = 0while 1:clock.tick(60)  # 设置游戏帧数# 事件循环for event in pygame.event.get():if event.type == QUIT:returnelif event.type == KEYDOWN and event.key == K_ESCAPE:returnelif event.type == MOUSEBUTTONDOWN:punchcount += 1if fist.punch(chimp):punch_sound.play()  # 击中chimp.punched()hitcount += 1else:whiff_sound.play()  # 错过passelif event.type == MOUSEBUTTONUP:fist.unpunch()bg = background.copy()# 合成游戏统计信息        if punchcount > 0:msg = "打中次数: %d 击中率: %d%s" % (hitcount, round((hitcount/punchcount)*100), "%")else:msg = "挥舞拳头吧!"# 绘制统计信息text = font.render(msg, 1, (10, 10, 10))textpos = text.get_rect(centerx=background.get_width()/2)bg.blit(text, textpos)allsprites.update() # 更新对象状态screen.blit(bg, (0, 0)) # 绘制背景allsprites.draw(screen) # 绘制对象pygame.display.flip() # 刷新屏幕
  • main 方法为游戏的主方法,会在游戏启动时调用
  • 在 while 之前的代码主要做的是初始化和定义,需要注意字体的设置,如果需要显示汉字的话,需要加载中文字体
  • while 里面是个游戏的主循环,首先设置游戏帧数为 60 帧;然后进入事件循环,游戏过程中的事件都会存储在 Pygame 的 event 中,通过 get 方获取,对我们关心的事件进行处理,比如游戏退出事件,鼠标点击事件等
  • 在鼠标点击中,判断是否打中猴子,如果打中,播放打中音效,并且调用猴子被击中的方法 punched;如果没有打中,播放挥舞空拳的音效。如果捕获到鼠标键抬起事件,则调用停止打击方法。
  • 事件循环之后,进行画面绘制,首先是拷贝一个起始背景,因为在每次绘制都会污染背景。然后绘制游戏信息,将信息绘制在背景上。
  • allsprites.update() 会调用对象组里的每个对象的 update 方法,完成对象的状态更新
  • allsprites.draw(screen) 将对象图像绘制到窗口中
  • pygame.display.flip() 刷新屏幕,我们就会看到新的游戏画面了

至此游戏的主要编码工作就完成了,不到 200 行代码,做了一个可以玩的小游戏,赶紧运行起来试试吧。

总结

这个简单的游戏制作过程,让我更深入地理解了 Pygame 的特点和使用方法,建立起来游戏开发的基本认知。

总体来看,要学会一个新东西,需要正确的理解它的核心概念,与自己原来的知识体系相融合,就能很快习得,而能灵活应用的前提是多玩多练。

通过一个星期的探索实践,为客户解决了模拟业务场景的问题,坐等加薪。

期望通过这个练习也能帮助你扩展一项技能,开拓一条道路。

最后祝大家天天进步!!学习Python最重要的就是心态。我们在学习过程中必然会遇到很多难题,可能自己想破脑袋都无法解决。这都是正常的,千万别急着否定自己,怀疑自己。如果大家在刚开始学习中遇到困难,想找一个python学习交流环境,可以加入我们的【python裙】,领取学习资料,一起讨论,会节约很多时间,减少很多遇到的难题。

带薪玩一周游戏,还要涨工资相关推荐

  1. 三年级计算机怎么进入到游戏,三年级开始,带孩子玩7个游戏训练成“最强大脑”...

    原标题:三年级开始,带孩子玩7个游戏训练成"最强大脑" 亲子游戏大全 childrengames 亲子游戏大全联合多位早教达人,结合早教知识,提供最丰富最齐全的亲子游戏大集合,包括 ...

  2. Python带你玩澳门赌场游戏

    Python带你玩澳门赌场游戏 1.开发环境:pycharm 2.完整代码: import random print('*'*40) print('欢迎进入澳门赌场') print('*'*40) u ...

  3. 美国洛杉矶市拟立法 规定新父母可带薪休假18周

    中新网1月31日电 据美国侨报网报道,美国洛杉矶市议会两名议员日前提出一项提议,要求制定一项产假政策,允许新父母在不降薪的前提下,享受长达18周的带薪产假. 据报道,洛杉矶市议员柳大卫(David R ...

  4. Android 带你玩转实现游戏2048 其实2048只是个普通的控件

    转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/40020137,本文出自: [张鸿洋的博客] 1.概述 博主本想踏入游戏开放行业 ...

  5. Android 带你玩转实现游戏2048 其实2048只是个普通的控件(转)

    1.概述 博主本想踏入游戏开放行业,无奈水太深,不会游泳:于是乎,只能继续开发应用,但是原生Android也能开发游戏么,2048.像素鸟.别踩什么来着:今天给大家带来一篇2048的开发篇,别怕不分上 ...

  6. Android 带你玩转实现游戏2048 其实2048只是个普通的控件

    转自: http://blog.csdn.net/lmj623565791/article/details/40020137 ,本文出自: [张鸿洋的博客] 1.概述 博主本想踏入游戏开放行业,无奈水 ...

  7. 《Red Hat Linux命令速查》—— 带你玩转字符游戏

    命令行管理,一个玩转字符的战场! 忽隐忽现的光标  神秘莫测的符号  闪转腾挪的玄机  直捣黄龙的快意 能领略这一切的人,只有你--深谙命令行管理之道的系统管理员和软件开发人员! 命令行之于优秀的系统 ...

  8. 专家称我国带薪休假制度偏重单位利益-长假-黄金周-带薪休假

    专家称我国带薪休假制度偏重单位利益|长假|黄金周|带薪休假 带薪休假难实施原因 超七成人不休年假 秋高气爽,正是旅游.出行的好时候,忙碌了大半年,也该给自己的身心放个假了.利好来了,今年中秋" ...

  9. 7月31日云栖精选夜读 | 在浏览器上也能训练神经网络?TensorFlow.js带你玩游戏~...

    无论你是刚开始深度学习,亦或是个老练的老手,建立一个神经网络的训练环境有时都会很痛苦.让神经网络的训练像加载一个网页,然后点击几下,然后你就准备好马上进行推理,会不会是件很棒的事呢?(那必须棒) 在本 ...

最新文章

  1. Linux ps aux指令詳解--转
  2. boost::python::pointee相关的测试程序
  3. JavaScript 自执行函数和 jQuery扩展方法
  4. 【leetcode】Maximum Subarray
  5. 使用eclipse遇到的unable to install breakpoint的问题
  6. 交公粮了,我经常逛的技术网站,你最爱哪个?
  7. 头部互金科技负责人领路知识图谱
  8. SpringBoot高级篇JdbcTemplate之数据查询上篇
  9. 关于树形插件展示中数据结构转换的算法
  10. Android 系统广播
  11. 深入学习javascript:cookie
  12. oracle 11g表空间之最大最小
  13. c语言中根号绝对值,根号的绝对值怎么算?
  14. glob库:文件名的匹配
  15. ubuntu mysql 默认安装路径_ubuntu安装mysql并修改默认目录
  16. 为什么最大的品牌信任Beaver Builder - 我应该选择哪个WordPress页面构建器
  17. 面对服务器层出不穷的攻击,我们该如何迎刃而解
  18. 滤波器_理想低通滤波器python案例
  19. 一年前转行RPA,如今聊聊RPA
  20. 招商银行为什么选用MySQL

热门文章

  1. Flink SQL - OVER windows‘ ordering in stream mode must be defined on a time attribute.
  2. linux目录、文件操作命令
  3. 计算机知识office答案,计算机二级office题库及答案
  4. iOS适配iPhoneX/iphone11/iphone12 导航栏高度 (刘海屏幕)
  5. 齐志科技双层跳板机登陆机制v3.3.6 --shell脚本自动登陆实现
  6. canvas文字绘制(大小、粗体、倾斜、对齐、基线)
  7. 个人电脑进行AI数据训练需要的硬件配置
  8. ios 图片裁剪框架_iOS图片裁剪器 – RSKImageCropper
  9. 高新技术企业审计报告包含哪些内容?
  10. 【翻译】在极度不确定的时期追求组织的复原力