[pygame]有趣的游戏循环

不知道大家是怎么写pygame的绘制、时间循环的?像下面这样?

while True:
     for event in pygame.event.get():
         if event.type == QUIT: return
     #game loop...

很多教程,都很简单地使用了这样的循环……可惜的是这样跳出循环很容易导致很多问题,一是程序结构不好看(《DOM scripting with Javascript》的作者说的);二是,如果你的绘制代码是放在其他线程的话或者绘制代码时间滞后了,那个线程、那段代码可能会先抛出一个不明不白的“错误”才让你退出(至少对用户来说是这样)。

我以前也这样做,于是我的朋友问我,为什么你说你的程序做好了,但退出时却有一个令人费解的对话框出现啊?

我以前不太注重这些细节,因为对于我们来说,这些东西对使用时没有影响的。但对于用户来说,他们不知道我在程序里确切干了些什么,总会有一点害怕,害怕我把他的电脑搞坏了,或者怀疑自己的硬件有问题到维修店白跑一遍……呵呵,说得有点夸张了。

于是,我去pygame.org看看有没有人写出更好的循环结构呢?找到了一个……

while True:
     clock.tick(15)
     #game loop...
     for event in pygame.event.get():
         if event.type == pygame.locals.QUIT:
             raise SystemExit

这次把return改为raise SystemExit了,这样整个系统都会退出,这样基本上不会出现Windows那个什么提示错误的对话框了……然而,终端运行还是有问题,抛出了一个虚拟机退出而线程未完全退出的异常,不过对于Windows用户来说关系不大——他们大概不会在cmd下运行这个程序吧?但对于追求一个完美的结局,这样的结构显然还不够好……

while pygame.display.get_init():
     clock.tick(60)
     pygame.display.update()
     for event in pygame.event.get():
         if event.type == QUIT:
             t.running = False #退出线程
             pygame.quit() #退出pygame模块

这样就好了,循环根据pygame的display模块是否退出来判断是否继续执行,退出之前通知所有线程停止执行。(但对于线程执行时间滞后问题还是没有很好地解决)

其实都是具体问题具体分析,暂时还没有发现一个更好的方案了……

不知道大家有没有更好的循环写法呢?

 

 

 

[pygame]对象碰撞检测(二)

上一篇文章写了一个不完整的介绍,现在继续写它,当然,也是不完整的。

其实都是pygame 1.8.1更新的函数,由于没有中文资料,写写吧……虽然现在英文文档已经更新了。

以下所说的Sprite指的是继承了pygame.sprite.Sprite类的对象。

PyGame 1.8.1提供的新函数/类: 

pygame.sprite.collide_rect_ratio(ratio): return collided_callable
pygame.sprite.collide_circle(left, right): return bool
pygame.sprite.collide_circle_ratio( object ): return collided_callable

就写这三个吧。


pygame.sprite.collide_rect_ratio(ratio): return collided_callable

用于把Sprite的面积(rect属性,继承自pygame.Rect类)扩大ratio倍再进行比较,返回的是一个函数。它不会对Sprite的rect进行真实的扩大/缩小。

返回的函数可以作为

pygame.sprite.spritecollide(sprite, group, dokill, collided = None): return Sprite_list

中collided参数使用的(见上一篇文章)。但注意的是,这个不是一个函数,而是一个类,collided参数用的是这个类的实例,和上篇文章不同。
简化了自己编写自定义碰撞检测的麻烦,不过该函数仅仅对两个Sprite的rect扩大ratio倍再比较面积是否相交。

与之相似的是

pygame.sprite.collide_circle_ratio( ratio ): return collided_callable

不过,这个函数要求Sprite必须有radius属性(半径),根据半径扩大ratio倍。

这也是个类,定义与用法与pygame.sprite.collide_rect_ratio(ratio): return collided_callable相似。


pygame.sprite.collide_circle(left, right): return bool

left和right分别代表一个Sprite,事实上与Sprite所处的位置并没有要求(并不是规定left和right)。但这两个Sprite需要有额外的radius属性(表明半径)。

返回一个boolean(是否相交的布尔值)。这个函数也可以作为

pygame.sprite.spritecollide(sprite, group, dokill, collided = None): return Sprite_list

的collided参数使用。但和上两个类不同,这是一个函数,需要把这个函数的引用作为参数(例如:collided = pygame.sprite.collide_circle不需要括号)。


其实这些类或许在实际使用pygame模块没有什么用处,不过提供给我们一个对游戏中对象碰撞检测的参考~~~

 

 

[PyGame]碰撞检测

PyGame 1.7在pygame.sprite里为碰撞检测提供了三个函数:

 

spritecollide(sprite, group, dokill)

sprite - pygame.sprite.Sprite对象

group - pygame.sprite.Group对象(或其子类对象)

dokill - 是否杀死group中与sprite碰撞的sprite对象

返回包含所有group中与sprite相撞的sprite的列表(list)

 

groupcollide(groupa, groupb, dokilla, dokillb)

groupa - pygame.sprite.Group对象(或其子类对象)

groupb - pygame.sprite.Group对象(或其子类对象)

dokilla - 是否杀死groupa中与groupb中碰撞的sprite对象

dokillb - 是否杀死groupb中与groupa中碰撞的sprite对象

返回包含所有groupa中与groupb相撞的sprite的字典(dict)

 

spritecollideany(sprite, group)

和spritecollide(sprite, group, dokill)相似,但只是返回group中最第一个与sprite相碰撞的sprite。

PyGame模块学习:Sprite

发现PyGame文档中的中文资料甚少,学习PyGame真的有点困难,但是Python又是如此容易学习的语言,不肯放弃。

我想许多人会对pygame.sprite.Sprite类不理解,至少我是这样,我看过一些程序后也还是觉得有点抽象──它到底如何绘制的呢?(绘制pygame.sprite.Sprite类里的哪个东西?)