随笔 - 97, 文章 - 22, 评论 - 81, 引用 - 0
数据加载中……

Pygame游戏开发 之四

Pygame游戏开发之四

初学乍练

Pygame中除了Group这个Sprite的容器类,还有一些继承自Group的容器类,它们分别是RenderUpdatesOrderedUpdatesLayeredUpdatesLayeredDirty

pygame.sprite.RenderUpdates继承自pygame.sprite.Group,它相对于Group的不同点就是重写了Groupdraw函数,原型是:RenderUpdates.draw(surface) : return Rect_list它将所有它包含的Sprites绘制到surface上,和Group.draw一样。但是这个函数返回了一系列的屏幕上发生改变的矩形列表,这个矩形列表应该被传递到pygame.display.update中去。

pygame.sprite.OrderedUpdates继承自pygame.sprite.RenderUpdates,它绘制Sprite的时候是以Sprite被添加时的顺序来绘制的。

pygame.sprite. LayeredUpdates绘制的方式和pygame.sprite.OrderedUpdates类似,只是它引入了图层的概念。你可以通过'default_layer'设置默认图层,或者一个整数来表示图层。如果添加的Sprite自己有一个layer的图层属性那么就是用这个,否则在添加Sprite的时候,在pygame.sprite. LayeredUpdates(*sprites, **kwarges)中的**kwarges参数中对layer属性进行设置,如果两者都没有设置,那么系统将采用默认图层。

pygame.sprite. LayeredDirty继承自pygame.sprite.LayeredUpdates,它是DirtySprites的专用容器类,继承了Group的所有操作。

因为我们需要用到DirtySprite,所以之前我们用到的所有Group类都替换成LayeredDirty,而且为了便于扩展,我们将LayeredDirty再封装一层,以便添加新的成员函数。

class gameManager(pygame.sprite.LayeredDirty) :

    def __init__(self, selfdata) :

        pygame.sprite.LayeredDirty.__init__(self)

    def keyevent(self, keypressed) :

        for son in self.sprites() :

            son.keyevent(keypressed)

       定义一个gameManager类,它继承了pygame.sprite.LayeredDirty,并且添加一个keyevent的成员函数,用于对键盘事件进行处理,它的操作很简单,调用它容器里的元素的keyevent函数,它容器里的元素有可能是另一个gameManager、或者是一个单纯的RenderObject。如果是gameManager的话就会进行递归调用,直到是RenderObject,所以我们还要给RenderObject定义一个keyevent函数,像这样:

class RenderObject(pygame.sprite.DirtySprite) :

       … …

    def keyevent(self, keypressed) :

        pass

我们把keyevent定义在基类RenderObject中,并且用pass表示它什么都不做,然后等着子类去实现它。

class Player(RenderObject) :

       … …

    def keyevent(self, keypressed) :

        left_or_right = keypressed[K_RIGHT] - keypressed[K_LEFT]

        up_or_down    = keypressed[K_DOWN] - keypressed[K_UP]

        self.move(left_or_right, up_or_down)

PlayerRenderObject的一个子类,我们可以用以上的语句实现Player的行走,keypressed其实是pygame.key.get_pressed(),用于获取当前键盘的某个键是否按下的映射表。

       接下来我们用之前的模块来写一个游戏的背景,利用图4-1的资源拼接出图4-2的图像,并且让它在屏幕Y轴方向进行滚屏操作。

4-1

4-2

       首先要明确的一点就是图片的四个方向必须是可拼接的,也就是说用9张相同的图片拼成一个九宫格,用肉眼是分辨不出它们是九张图片的,看到的是一个完整的图像。

       我们定义一个RenderBack类:

class RenderBack(RenderObject) :

    def __init__(self, selfdata) :

        RenderObject.__init__(self, selfdata)

              do_init()

def update(self) :

       RenderObject.update(self)

              do_update()

首先确定做这么一个背景需要用到的数据,背景的宽高是肯定要的,而且要求它在Y方向做滚屏操作,所以这个背景的实际的高肯定要比屏幕上显示高还要长(我们假设他是图4-1图片高的整数倍),那么我们用一个四元组(x, y, z, w)来表示需要知道的数据:

x : 背景图资源在images[]的索引号

y : 生成图的宽

z : 生成图的高

w: 生成图在竖直方向的原图图块的数量

这个四元组是作为selfdata被传到__init__函数中进行初始化的,并且可以在配置文件中修改它的值。

       因为最后的图像要进行Y方向的滚屏操作,所以我们还需要定义一个Y方向的偏移量,以便每次绘制的时候进行偏移操作。这样初始化就可以这么写:

self.image       = pygame.Surface( (int(selfdata[1]), int(selfdata[2])) )

self.rect         = self.image.get_rect()

self.source_rect   = self.image.get_rect()

       

self.backlen      = int(selfdata[3])

self.backimage    = RenderObject( [ selfdata[0] ] )

self.top_offset    = self.backimage.image.get_height() * self.backlen - self.rect.height

这里需要注意的是,LayeredDirty在对DirtySprite进行绘制的时候总是对sprite.image的内容进行绘制的,所以在RenderBack里我们需要额外定义一个backimage来对原图进行缓存,然后通过循环将它blitimage上。这样RenderBack的拥有者才能找到image将它绘制出来。

       对于update函数,每一帧我们需要更新self.top_offset这个Y方向的偏移量,并且根据它更新image图像。具体实现如下:

def update(self) :

RenderObject.update(self)

xstep = self.backimage.image.get_width()

ystep = self.backimage.image.get_height()

self.top_offset -= 3

 

y_offset = self.top_offset % ystep

for x in range(0, self.rect.width + xstep, xstep) :

self.image.blit( self.backimage.image, (x, 0), ((0, y_offset), (xstep, ystep - y_offset) ) )

 

for y in range(ystep - y_offset, self.rect.height + ystep, ystep) :

for x in range(0, self.rect.width + xstep, xstep) :

self.image.blit( self.backimage.image, (x, y), ((0,0), (xstep, ystep) ) )

 

(xstep, ystep)是原图的尺寸,每一帧我们对self.top_offset进行自减操作(效果就是让最后的图像有一种向上延伸的感觉,也就是滚屏的效果)。

然后我们分x方向和y方向进行讨论,因为x方向没有滚屏操作,所以只要用现有的图片填充整个宽度即可,比如原图是W=100个像素,需要填充的背景是D=250个像素,那么水平方向至少需要用到[ (D + W – 1) / W ] = 3张原图([x]表示比x小的最大整数,即取下整)。对于竖直方向,因为有滚屏操作,所以有两部分组成:第一排(从原图的y方向某个位置粘贴过来的)以及非第一排(总是粘贴原图)。将self.top_offset ystep 取模,得到的是需要绘制图像的最上方在原图的偏移量,通过它可以绘制第一排,然后再调用两层for循环绘制后面几排。这样随着时间的推移,一个Y方向的滚屏效果就出来了。(未完待续)

 

posted on 2011-04-28 02:19 英雄哪里出来 阅读(2674) 评论(0)  编辑 收藏 引用 所属分类: Pygame


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理