喵宅苑 MewoGarden × 技术宅社区II | Z站 Z Station 棒棒哒纯文字二次元技术社区

正文

如果学会了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

回复

0%
站点地图友情链接:
喵宅苑
喵空间社区程序
喵宅苑 静态版
宅喵RPG地图编辑器
络合兔
Lanzainc
技术宅
小五四博客
莉可POI
Mithril.js
枫の主题社
Project1
午后少年
机智库
七濑胡桃
xiuno
幻想の日常
魂研社
Nothentai
0xffff
欲望之花
泽泽社长
淀粉月刊
HAYOU