飞天鸽
如果学会了python,我可以做游戏吗(格斗篇2)

接上一贴

所谓精灵动画,就是要让每一帧都动起来,这里我采用的是单帧的方式,利用pivotanimator来制作火柴人动画

做法请自行百度,导出单帧图片在一个目录然后利用photoshop结合成一张大图

这里我只做了部分,从上向下是向右走,向左走和待机状态(其实待机状态也分为面向左还是右)

最后,我们希望通过

if event.type == userevent.PERSONCHECKCHANGE:

p1.update(screen,p1state) #screen是屏幕对象,p1state是palyer1的状态

然后,每50ms触发一次userevent.PERSONCHECKCHANGE,来画下一帧

接下来,就需要仔细的思考一下这个person类要如何来做,才能满足只传入状态就能获得当前帧

要求:对于update函数传入‘left’,函数会在第一行循环圈定矩形,9帧

对于update函数传入‘right’,函数会在第二行循环圈定矩形,9帧

对于update函数传入‘right’,函数会在第二行循环圈定矩形,9帧

于是,我在class Person1类中做了如下定义,每个动作占一整行

item_dict=[

("left",personutils.child(w=256,h=256,itemlen=9)), #w和h是每帧的宽高

("right",personutils.child(w=256,h=256,itemlen=9)),

("normal",personutils.child(w=256,h=256,itemlen=9))

#可能会添加新的动作,比如'出拳',‘出脚’

]

child只是一个nametuple:child = collections.namedtuple('child','w h itemlen')

在init函数里加入一个init_child来加载我们的设定

def init_child(self):

dic = self.item_dict

nextindex = 0

for item in dic:

value = childRects(w=item[1].w,\

h=item[1].h,\

itemlen=item[1].itemlen,\

index=nextindex)

setattr(self,item[0],value)

nextindex = value.nextindex

分析一下:这段代码在运行时动态的向Person1类注入名称是left,right,normal的childRects类

childRects类如下:

class childRects(object):

def __init__(self,index,itemlen,h=256,w=256):

self.__h = h

self.__w = w

self.__itemlen = itemlen

self.init_rects(index,itemlen)

self.nextindex = index + h

def init_rects(self,index,itemlen):

change_mapper = lambda x,y: (x,y,x+self.__w,y+self.__h)

split_pos = range(0,\

self.__w*itemlen,\

self.__w)

self.rects = map(change_mapper,split_pos,\

[index]*itemlen)

def get_next_rect(self):

itor = [0]

def next_itor():

now = itor[0]

itor[0] = (itor[0] + 1) % self.__itemlen

return self.rects[now]

return next_itor

这一段对于C或者C++的同学可能有些难以理解,init_rects的作用就是在一行按照w和h画itemlen个方框,返回这些的列表

不得不说,python的lambda实在太过方便了

get_next_rect是一个闭包计数器,至于为什么是闭包,之所以选择闭包,额,等一下讲哈

类里面的nextindex是为了指向下一个动作的起始高度,比如left帧在0,0像素开始,那么right帧就会在0,256开始,也就是nametuple与构造函数差掉的那个index

至此,我们可以通过某个person1的实例p1,调用p1.right.get_next_rect来创建right帧的迭代器,这里的好处就体现出来了

def update_state(self,state):

bfstate = self.now_state

if cmp(state,self.now_state) != 0:

self.now_state = state

attr = getattr(self,self.now_state,"not found")

if type(attr)!=type(""):

self.next = attr.get_next_rect()

else:

self.now_state = bfstate

通过调用update_state并传入状态值,就会在实例中更新next方法,此时的next适配了各种状态

最后的最后,完成了update

def update(self,screen,state):

point = self.point

self.update_state(state)

n = self.next()

tmp = pygame.Surface((n[2]-n[0],n[3]-n[1]))

tmp.blit(self.image,(0,0),n)

attr = getattr(self,"action_"+self.now_state,"not found") #在处理动画的同时,我们还可以编写这个精灵的逻辑函数

if type(attr)!=type(""): #例如action_right

attr()

screen.blit(tmp,tuple(point))

逻辑函数在我的例子中比较简单,只有左移右移,因为normal态是不进行任何逻辑处理的233

def action_left(self):

point = self.point

point[0] -= self.speed

point[0] = max(0,point[0])

def action_right(self):

point = self.point

point[0] += self.speed

归根结底,程序完全是依赖注入的方式,这种设计下添加一个新的动作只需要设定 item_dict就可以动起来,添加action_名称就可以完成逻辑

这么一看代码复用度起始还是蛮高的呀

既然获得了各种状态,那么,状态之间的转换似乎就有必要讲一讲了

下节课,我们来讲讲FSM,传说中的状态机,嗯(深思状)

讲述比较乱,还是附上代码吧,运行game.py 就可以测试运行效果了,233

http://pan.baidu.com/s/1o6JtBse

Q版宝宝
楼主这么无私的教程我觉得我应该有必要顶上天
展开Biu

楼主这么无私的教程我觉得我应该有必要顶上天=3=

[查看全文]
ID:L1
坐等大神教程全了
展开Biu

坐等大神教程全了

[查看全文]
命数
又见一枚技术宅
展开Biu

又见一枚技术宅

[查看全文]
命数
又见一枚技术宅
展开Biu

又见一枚技术宅

[查看全文]
秋栗子
好教程贴居然没人顶
展开Biu

好教程贴居然没人顶

[查看全文]