一晃自己用python写小游戏也有段时间了,自娱自乐之余,也对这些模块如数家珍下,仅做一家之言供后来者参考吧。

首先是范畴问题,python适合写什么游戏呢?

简言之,python适合写一些2D的小游戏。比如贪吃蛇啊,超级玛丽,FC或者90年代街机之类的游戏,写这些游戏的难度,对Python爱好者来说都是no problem的。当然大神级别的尝尝3D也是可以滴,比如惊艳的fogleman/Minecraft。其实大神就是一层窗户纸加上多年的修行,如果对Ctypes,OpenGL了然于胸,那任督二脉已然打通了,随便摆个架势就能被人当成老司机。不过我实在不建议这样炫技,毕竟python玩3D还是 toooooooooooooo slow了点。

然后,用什么模块来写游戏呢?

好吧,这可能只有我这种,天秤座且带着选择困难症的人,才会有这种疑问,用嘛玩意来写呢?单机游戏,pygame or pyglet,手机游戏,kivy(虽然不完美,但也没有别的选择了)。

开始进入正题,首先是pygame。

在我眼里,pygame是Python写游戏的第一选择,为什么这么说涅,LMGTFY?在pygame官网里也有自嘲自夸的关于pygame的废话。

我先来段代码吧,一起来看看pygame怎么样。简单点,就在屏幕显示个‘hello pygame’。

import pygame as pg
from label import Labelclass Game(object):def __init__(self,width,height):self.screen_width = widthself.screen_height = heightself.screen = pg.display.set_mode((self.screen_width,self.screen_height))self.done = Falseself.clock = pg.time.Clock()self.fps = 60.0self.labels = pg.sprite.Group()self.label = Label('hello pygame',{'center':(self.screen_width/2,self.screen_height/2)},self.labels,font_size = 100)def event_loop(self):for event in pg.event.get():if event.type == pg.QUIT:self.done = Trueif event.type == pg.KEYDOWN:if event.key == pg.K_ESCAPE:self.done = Truedef draw(self):self.labels.draw(self.screen)def update(self,dt):passdef run(self):dt = self.clock.tick(self.fps)while not self.done:self.event_loop()self.update(dt)self.draw()pg.display.update()if __name__ == '__main__':pg.init()game = Game(800,600)game.run()pg.quit()

if no time to check the code:

就跳过以下段落

else:

我简单啰嗦一下。看def run这里。在游戏运行时,循环里包括三块,event_loop,update和draw,这也是游戏组成的几个部分。

首先event_loop是获取玩家输入的,比如通过WSAD控制角色移动,代码里实现的是玩家点叉退出和按Esc键退出。

其次update处理游戏逻辑,比如角色和boss距离在100px时boss发起攻击。代码里pass,因为只是一个label显示,如果让label变成blinker,一闪一闪的。就可以在update里面调用label.update方法,然后就ok了。

最后是draw和display.update。就是显示在屏幕上咯,经过逻辑计算后,角色和boss的位置在屏幕上显示。代码里就把label在屏幕上显示出来了。

经过这个过程后,玩家再次输入,控制角色开始新的循环。如果没看懂再回过头再看一遍。

# 其实我感觉代码已经很清楚了,直接看代码应该都能理解每句话什么意思,如果不行,问问身边Python老司机,如果对里面fps,clock之类不懂的话,可以看看相关游戏编程的书:)

怎么样,写游戏这个事整体有了个宏观把握了吧,即便是一个连面向对象都不懂的python新手,是不是也可以架构自己的游戏了?下图是我在某游戏编程书里扒拉出来的。

不难看出,用pygame写游戏第一个特点,结构清晰,如果你是新手,有助于你了解游戏的组成结构。

那么第二个特点,自由度高,如果你是老手,可以上下其手,为所欲为。举一个平常的例子,简单的鼠标操作,单击选中,双击运行,但硬件层面上是不存在双击事件的,如果需要,在pygame里当鼠标单击的时候,记录下时间,再次单击的时候,再一次记录时间,如果间隔小于某一阈值,返回True。还有屏幕上鼠标箭头的这种显示,也是很底层硬件的东西,但是pygame就可以修改它,而且还不难,强大吧。不要以为这些游戏里都碰不上,以游戏怒首领蜂为例,Button A, tap是机枪,hold on是激光,同样是按键,短按是机枪,长按是激光,这种控制在pygame里只需记录下Button A 的keydown时间就可以实现,所以还是很有用滴。

但是与此同时,带来了一个问题,自由度大了,代码量就上来了,如上面的代码,需要自己去写一个Label类,这里我也把代码贴上来吧。

import copy
import pygame as pgLOADED_FONTS = {}
LABEL_DEFAULTS = {"font_path": None,"font_size": 12,"text_color": "white","fill_color": None,"alpha": 255}def _parse_color(color):if color is not None:try:return pg.Color(str(color))except ValueError as e:return pg.Color(*color)return colorclass _KwargMixin(object):def process_kwargs(self, name, defaults, kwargs):settings = copy.deepcopy(defaults)for kwarg in kwargs:if kwarg in settings:if isinstance(kwargs[kwarg], dict):settings[kwarg].update(kwargs[kwarg])else:settings[kwarg] = kwargs[kwarg]else:message = "{} has no keyword: {}"raise AttributeError(message.format(name, kwarg))for setting in settings:setattr(self, setting, settings[setting])class Label(pg.sprite.Sprite,_KwargMixin):def __init__(self, text, rect_attr, *groups, **kwargs):super(Label, self).__init__(*groups)self.process_kwargs("Label", LABEL_DEFAULTS, kwargs)path, size = self.font_path, self.font_sizeif (path, size) not in LOADED_FONTS:LOADED_FONTS[(path, size)] = pg.font.Font(path, size)self.font = LOADED_FONTS[(path, size)]self.fill_color = _parse_color(self.fill_color)self.text_color = _parse_color(self.text_color)self.rect_attr = rect_attrself.set_text(text)def set_text(self, text):self.text = textself.update_text()def update_text(self):if self.alpha != 255:self.fill_color = pg.Color(*[x + 1 if x < 255 else x - 1 for x in self.text_color[:3]])if self.fill_color:render_args = (self.text, True, self.text_color, self.fill_color)else:render_args = (self.text, True, self.text_color)self.image = self.font.render(*render_args)if self.alpha != 255:self.image.set_colorkey(self.fill_color)self.image.set_alpha(self.alpha)self.rect = self.image.get_rect(**self.rect_attr)def draw(self, surface):surface.blit(self.image, self.rect)

感受一下,何如?不仔细看就看不明白了吧,如果对pygame不了解,现在已经彻底懵圈了。没关系,这不是重点,我只是举这个例子来说明,好多人诟病pygame不是那么pythonic,这可能就是其中一个原因吧。

其实很多python爱好者对写游戏并不感冒,更多的时候只是想找个工具写写UI,如果抛开什么像素碰撞检测之类纯游戏里的东东,也没太多精力和兴趣自己造轱辘玩,大可以使用pyglet

说个题外话,因为带娃的缘故,pyglet实在太像piglet(小猪皮杰_百度百科)了,看看pyglet的logo,是不是就是一个猪屁股上安了一个猪尾巴 ……(好吧,原谅我太有想象力了)

同样,还是先上代码再分析吧,同样让屏幕显示个‘hello pyglet’吧。

import pygletclass Game(pyglet.window.Window):def __init__(self,*args,**kwargs):super(Game,self).__init__(*args,**kwargs)self.label = pyglet.text.Label('hello pyglet',font_size=100,x=self.width//2,y=self.height//2,anchor_x='center',anchor_y='center')def on_draw(self):self.clear()self.label.draw()if __name__=='__main__':game = Game(width = 800,height = 600)pyglet.app.run()

ok,回过头来看,也就不到20行吧。感觉何如,比pygame简洁很多,自带label模块,自带app运行模式。这也是许多人用pyglet的原因之一吧,高效啊,国人有个很牛逼的feisuzhu/thbattle project的前端就是用的pyglet。

# 我自己也是个弹幕类游戏爱好者,但东方系列实在太变态了,说实话我并不怎么爱玩东方系列,但Zun神绝对是独立游戏者的楷模了,全才啊,而且同人文化这种擦边版权的问题,对Zun神来说似乎起到了帮助宣传的作用 :)。

和pygame部分模块用C语言编写相比,pyglet是纯Python。一大特点就是免安装,拷贝到文件夹下到处运行,如果搭配embed版本的Python,那简直就是插上优盘到处开车啊。据说pygame在Window下其实也可以拷走免安装运行,但需要相同的环境。不要小看这个免安装运行,它可以让你打包的时候不出错或者少出错。记得一年前steam上有款游戏Switchcars,就是pygame写的(严格的说是 pygame_sdl2,可以理解为pygame 2.0版本,小白鼠可以自行搜索体验,支持Android哦),作者透露说开始是用sdl1,后来打包steam api的时候遇到了麻烦,改成了sdl2,不过这些都是C语言大神们干的事,咱们也就听听怎么回事就好。作者从写这个游戏到最终上线花了3年多,好吧,国外就是闲人多~~~(其实我是想说人家执着,我也想窝家里写三年游戏,但是我老婆孩子咋弄?)

言归正传,pyglet支持多个显示器,也支持多个窗口,pygame只能有一个显示器一个窗口,貌似多线程多进程也不行。如果你有多台显示器,而且要实现多个窗口,那就必须pyglet了。此外pyglet直接关联OpenGL,虽然这玩意有点out of date赶脚,但现在也号召延迟退休了好吧。pyglet的作者也并非拿来主义,还是对opengl的画图操作进行了重组,更容易被新手掌握,但怎么说呢,一方面opengl是可以调用gpu的,理论上比单纯cpu更快,这是pygame达不到的。另一方面python本身实在不适合做3D,如果只用2D,其实还是pygame的Surface操作起来直观。当然一些渲染之类,还是上opengl更带劲,比如在pyglet基础上还有个cocos2d,里面有很多酷炫效果。接着说opengl的事,如果用这玩意,要用ctypes,这个就挺不伦不类的,比如说创建一个array,代码里就是‘a = (GLfloat * 2)()’,这种一点毛病没有的写法,估计让处女座强迫症们死的心都有了。因为pyglet速度慢,主要是写3D游戏而言,有大神要重新造轮子,名字都起好了Cyglet,但我觉得还真是一条路子,但从C往python转很easy,从python回到C估计如果不是图速度,没有人愿意读那些鼠标谷轮半天也不见底的代码。

再说说kivy吧,跨平台,实际上就是针对Android和ios的。如果你写的好,可以上线卖钱哦,比如Google商店里的mancala就是kivy写的哦。其实我本人也是新手,没有太多的经验,还是直接上代码来个‘hello kivy’吧

from kivy.base import runTouchApp
from kivy.lang import BuilderrunTouchApp(Builder.load_string('''
Label:text:'hello kivy'font_size:100
''')) 

∑q|゚Д゚|p,是的,你没看错,就是这么短小精悍,kivy本身也是个自造词,而不是py啥啥啥,这也有点老子就是要来个新语言kvlang的野心。为了了解kivy的来源,我还专门在kivy-dev里发了封邮件问了下,得到的回复是

和我猜的答案也差不多,就是来源于几维鸟,也可以看看那个动画,就当是干了这碗鸡汤吧。

其实用kivy和用pygame,pyglet写游戏在逻辑上没有太多的颠覆性的东西,相反有些东西变得更加容易,比如说自带Animation类,就是不同的easing functions,当然自己去写一点问题也没有,但现成的轮子干嘛不用呢。还有Screenmanager,这就是游戏里活生生的statemachine啊,而且还自带切换效果:)

当然有好也有坏,目前我发现用kivy写游戏一个很大的问题,木有一个合适的Layout去显示分辨率固定的图片。大部分游戏还是基于像素的,如果所有的图片像素是基于800x600的,那么在1024x960里就乐呵了,要么拉伸扭曲,要么有黑边(好多war3运行的时候就是有黑边)。目前我的解决方法是按大比例方向拉伸,如果长度方向拉伸1.5倍,高度方法拉伸2倍,那就都拉伸2倍,只是部分图片跑到屏幕外边而已。其实kivy的wiki上有个方法,带黑边的viewport,不是很完美啊,还有前面提到的mancala,那哥哥用的是在Floatlayout上改的,一方面别人卖钱的东西我不愿意拿来用,因为License也不是MIT。另一方面我发现它也并不是很完美啊。

总之,用kivy开发游戏还有很多路要走,当然,对Python玩家来说,这不正是我们的菜么?

一晃写了这么多了,比起写文章,我还是愿意写代码啊:)

ps,再压轴介绍两个模块吧。

pymunk Pymunk - pymunk 5.2.0 documentation

如果游戏里有物理因素必用,比如愤怒的小鸟之类,具体就不解释了,谁用谁知道。

pytmx https://github.com/bitcraft/PyTMX

如果游戏里有tiled map必用,比如开源的Tuxemon,同样不解释了,谁用谁知道。

顺便说下,tuxemon的代码还是很棒的,如果是新手,模仿里面的style不失为一种很好的提高途径。

来源:https://zhuanlan.zhihu.com/p/26661987

Python里那些可爱的游戏模块们相关推荐

  1. python可爱代码_Python里那些可爱的游戏模块们

    一晃自己用python写小游戏也有段时间了,自娱自乐之余,也对这些模块如数家珍下,仅做一家之言供后来者参考吧. 首先是范畴问题,python适合写什么游戏呢? 简言之,python适合写一些2D的小游 ...

  2. python守护线程错误 退出子线程_请问用python里threading和queue模块来写多线程程序,子线程是如何结束的?...

    import queue import threading class Consumer(threading.Thread): def __init__(self, queue): threading ...

  3. python里的collections模块

    python里的collections模块 collections模块里提供了一些特殊功能的容器: namedtuple deque ChainMap Counter OrderedDict defa ...

  4. 小福利,运用python里面的talib模块和cufflinks模块实现stock可视化分析

    小福利,运用python里面的talib模块和cufflinks模块实现stock可视化分析 import pandas as pd from sqlalchemy import create_eng ...

  5. 下列哪个不是目前python里的内置模块-python引入模块的五种方式与内置模块

    模块导入的五种方式 1.import 模块名 2.from 模块名 import 方法名 3.from 模块名 import * 4.import 模块名 as 别名 5.from 模块名 impor ...

  6. Python炫技操作:模块重载的五种方法

    作者 | 写代码的明哥 来源 | Python编程时光 环境准备 新建一个 foo 文件夹,其下包含一个 bar.py 文件 $ tree foofoo└── bar.py 0 directories ...

  7. 一篇长文带你在python里玩转Json数据

    Json简介 Json(JavaScript Object Notation) 很多网站都会用到Json格式来进行数据的传输和交换. 这因为Json是一种轻量级的数据交换格式,具有数据格式简单,读写方 ...

  8. 下列哪个不是目前python里的内置模块-不吹不擂,你想要的Python面试都在这里了【315+道题】...

    有缘人如果看到这些题,不妨留言一下答案,来证明下你到底有多水,哈哈哈哈哈哈哈哈哈哈哈 第一部分 Python基础篇(80题) 1.为什么学习Python? 2.通过什么途径学习的Python? 3.P ...

  9. 下列哪个不是目前python里的内置模块-python中那些小众但有用的内置模块

    今天带来的是python里一些小众但是却比较实用的python库,一起来看看吧! pprint:更清晰的打印 pprint 是 pretty printer 的缩写,用来打印 Python 数据结构, ...

最新文章

  1. 面试官问你MyBatis SQL是如何执行的?把这篇文章甩给他
  2. hdu1018--Big Number
  3. [APIO/CTSC 2007]数据备份(贪心+堆)
  4. Unity中使用gRPC
  5. 计算机电竞方向,关于电竞专业的就业方向
  6. 《CCNP ROUTE 300-101认证考试指南》——2.10节 复习所有考试要点
  7. Ubuntu安装Tensorflow及anaconda环境下使用TensorFlow
  8. spring boot 配置启动后执行sql, 中文乱码
  9. Atitit WebDriver技术规范原理与概念
  10. C语言关键字浅析-case
  11. 适合草根站长的认证产品介绍
  12. 【信号与系统|吴大正】5:离散信号的傅里叶变换
  13. Eucalyptus云平台搭建
  14. scoop bucket add 后仍然报错 Couldn‘t find manifest for
  15. BZOJ5294 BJOI2018二进制(线段树)
  16. python尼姆游戏_python实现聪明的尼姆游戏(人机对战)
  17. 操作系统实验报告_ucore_lab1
  18. 2022 - 软件构造复习
  19. 字符集本地化(locale)与输入法系列讲座-----(3) truetype造字程序详解
  20. 微信惊现超级大Bug:试过的人都哭了...

热门文章

  1. QT的QAxBase类的使用
  2. python 将图片转换成像素画_Canvas 实现位图转像素画
  3. 怎么用matlab处理数据,如何用Matlab处理.wfm格式的数据
  4. hive按照某个字段分组,然后获取每个分组中最新的n条数据
  5. 阿里redis规范(转自别人的公众号)
  6. 13寸笔记本电脑尺寸_2020笔记本电脑推荐(华为篇)
  7. Linux怎么查看设置系统语言包
  8. 图像处理之中值滤波介绍及C实现
  9. MFC中简单绘图几种方式
  10. Windows下用VS2013加载caffemodel做图像分类