05_OPhone平台2D游戏引擎实现——时间动画

上传人:陈** 文档编号:98293071 上传时间:2022-05-29 格式:DOCX 页数:26 大小:66.39KB
返回 下载 相关 举报
05_OPhone平台2D游戏引擎实现——时间动画_第1页
第1页 / 共26页
05_OPhone平台2D游戏引擎实现——时间动画_第2页
第2页 / 共26页
05_OPhone平台2D游戏引擎实现——时间动画_第3页
第3页 / 共26页
点击查看更多>>
资源描述
编号:时间:2021年x月x日书山有路勤为径,学海无涯苦作舟页码:第26页 共26页经过几篇文章的介绍,我们的引擎基本上已经开始慢慢成形了,上一节我们虽然我们实现了各种组件,但是这些组件和节点(Node)都处于静止状态,很显然既然是游戏,就不可能没有动画,那么这一片文章我们就将给大家介绍引擎的动画系统,这里我们将动画系统分为两个大类,其一是一些基本的动画,包括位置的移动,缩放、旋转,透明度变化等,其二是帧动画,即由许多帧构成的动画,在实现这些动画之前,我们都需要对一些基础类进行封装,以方便我们对各种动画的实现。动作(Action)这里我们说的动作类便是所有动画的基类,该类封装一个特定行为,在运行时赋予动作一个目标,于是这个目标将会执行该动作。同时需要注意只有节点(Node)的子类才能执行一个动作。有些动作只有特定的节点类型才能运行,但是大部分动作都不限制节点具体类型。由于是所有动画的基类,所以我们只需要实现动画的路框架,包括动画结束的回调函数等,具体的动画效果实现将在其子类来实现,如代码清单5-1所示。代码清单5-1:Action实现view plaincopy to clipboardprint?1. publicabstractclassActionimplementsYFSCopyable 2. /非法的标记,为-1 3. publicstaticfinalintINVALID_TAG=-1; 4. /源目标 5. privateNodemOriginalTarget; 6. /目标节点 7. publicNodemTarget; 8. /动画标记 9. privateintmTag; 10. /回调 11. privateCallbackmCallback; 12. /得到源节点 13. publicNodegetOriginalTarget() 14. returnthis.mOriginalTarget; 15. 16. /设置源节点 17. publicvoidsetOriginalTarget(Nodevalue) 18. this.mOriginalTarget=value; 19. 20. /得到目标 21. publicNodegetTarget() 22. returnthis.mTarget; 23. 24. /设置目标 25. publicvoidsetTarget(Nodevalue) 26. this.mTarget=value; 27. 28. /设置回调 29. publicvoidsetCallback(Callbackcallback) 30. this.mCallback=callback; 31. 32. /得到回调 33. publicCallbackgetCallback() 34. returnthis.mCallback; 35. 36. /得到,设置tag 37. publicintgetTag() 38. returnthis.mTag; 39. 40. publicvoidsetTag(intvalue) 41. this.mTag=value; 42. 43. /构建动作 44. protectedAction() 45. this.mTarget=(this.mOriginalTarget=null); 46. this.mTag=INVALID_TAG; 47. 48. /拷贝动作 49. publicabstractActioncopy(); 50. /生成反响动作 51. publicabstractActionreverse(); 52. /开始在指定节点上执行动作 53. publicvoidstart(Nodetarger) 54. this.mOriginalTarget=(this.mTarget=targer); 55. 56. /停止 57. publicvoidstop() 58. this.mTarget=null; 59. 60. /是否完成 61. publicbooleanisDone() 62. returntrue; 63. 64. /单步执行 65. publicabstractvoidstep(floatparamFloat); 66. /更新 67. publicabstractvoidupdate(floatparamFloat); 68. /回调接口,动作完成之后进入 69. publicstaticabstractinterfaceCallback 70. publicabstractvoidonDone(ActionparamAction); 71. 72. public abstract class Action implements YFSCopyable /非法的标记,为-1 public static final int INVALID_TAG = -1; /源目标 private Node mOriginalTarget; /目标节点 public Node mTarget; /动画标记 private int mTag; /回调 private Callback mCallback; /得到源节点 public Node getOriginalTarget() return this.mOriginalTarget; /设置源节点 public void setOriginalTarget(Node value) this.mOriginalTarget = value; /得到目标 public Node getTarget() return this.mTarget; /设置目标 public void setTarget(Node value) this.mTarget = value; /设置回调 public void setCallback(Callback callback) this.mCallback = callback; /得到回调 public Callback getCallback() return this.mCallback; /得到,设置tag public int getTag() return this.mTag; public void setTag(int value) this.mTag = value; /构建动作 protected Action() this.mTarget = (this.mOriginalTarget = null); this.mTag = INVALID_TAG; /拷贝动作 public abstract Action copy(); /生成反响动作 public abstract Action reverse(); /开始在指定节点上执行动作 public void start(Node targer) this.mOriginalTarget = (this.mTarget = targer); /停止 public void stop() this.mTarget = null; /是否完成 public boolean isDone() return true; /单步执行 public abstract void step(float paramFloat); /更新 public abstract void update(float paramFloat); /回调接口,动作完成之后进入 public static abstract interface Callback public abstract void onDone(Action paramAction); 从代码中我们可以看到,我们构建了两个Node对象,mOriginalTarget和mTarget分别是源目标和当前的目标,源目标主要用于处理特定的动画,比如:屏幕的翻转效果等,当前目标表示当前动画在其目标上执行,同时我们还为每个动画都分配了一个标记(mTag),这样方便管理,这里特别需要说明的是我们的回调接口Callback,用于处理动画执行完毕之后触发其接口中的onDone函数,同时还提供了生成反向动画的函数reverse,当然这并不是每个动画都能生成反向动画,需要在子类进行实现,后面我们会有实例介绍。动作管理器(ActionManager)动作管理器则是用来管理整个引擎中的动画,我们知道由于一个节点可以包含很多个动画,因此我们就构建了一个HashElement来表示一个节点的动画情况,HashElement中包括了一个目标节点和该节点的动画序列以及是否暂停,线面我们看ActionManager的具体实现,如代码清单5-2所示。代码清单5-2:ActionManager实现view plaincopy to clipboardprint?1. publicclassActionManager 2. /所有的动作列表,包括每个节点的动画 3. privateConcurrentHashMaptargets; 4. privatestaticActionManagersInstance; 5. static 6. sInstance=null; 7. 8. /取得本类实例对象 9. publicstaticActionManagergetInstance() 10. synchronized(ActionManager.class) 11. if(sInstance=null) 12. sInstance=newActionManager(); 13. 14. returnsInstance; 15. 16. 17. /构建动作管理器对象 18. privateActionManager() 19. synchronized(ActionManager.class) 20. /构建一个计时器 21. /指定更新函数为tick 22. Scheduler.getInstance().schedule(newScheduler.Timer(this,tick); 23. this.targets=newConcurrentHashMap(131); 24. 25. 26. /清楚动作 27. privatevoiddeleteHashElement(HashElementelement) 28. element.actions.clear(); 29. this.targets.remove(element.target); 30. 31. /动作列表 32. privatevoidactionAlloc(HashElementelement) 33. if(element.actions=null) 34. element.actions=newCopyOnWriteArrayList(); 35. 36. /移除指定动作 37. privatevoidremoveAction(intindex,HashElementelement) 38. element.actions.remove(index); 39. 40. if(element.actions.size()=0) 41. deleteHashElement(element); 42. 43. /暂停所有动作 44. publicvoidpauseAllActions(Nodetarget) 45. HashElementelement=(HashElement)this.targets.get(target); 46. if(element!=null) 47. element.paused=true; 48. 49. /重新开始所有动作 50. publicvoidresumeAllActions(Nodetarget) 51. HashElementelement=(HashElement)this.targets.get(target); 52. if(element!=null) 53. element.paused=false; 54. 55. /添加动作 56. publicvoidaddAction(Actionaction,Nodetarget,booleanpaused) 57. assert(action!=null):Argumentactionmustbenon-null; 58. assert(target!=null):Argumenttargetmustbenon-null; 59. 60. HashElementelement=(HashElement)this.targets.get(target); 61. if(element=null) 62. element=newHashElement(target,paused); 63. this.targets.put(target,element); 64. 65. 66. actionAlloc(element); 67. 68. assert(!element.actions.contains(action):runAction:Actionalreadyrunning; 69. 70. element.actions.add(action); 71. /开始动作 72. action.start(target); 73. 74. /移除所有动作 75. publicvoidremoveAllActions() 76. for(HashElementelement:this.targets.values() 77. removeAllActions(element.target); 78. 79. /移除指定节点的所有动作 80. publicvoidremoveAllActions(Nodetarget) 81. if(target=null) 82. return; 83. 84. /先找到指定节点 85. HashElementelement=(HashElement)this.targets.get(target); 86. if(element!=null) 87. element.actions.clear(); 88. deleteHashElement(element); 89. 90. 91. /移除指定动作 92. publicvoidremoveAction(Actionaction) 93. /先找到动作的源目标 94. HashElementelement=(HashElement)this.targets.get(action 95. .getOriginalTarget(); 96. if(element!=null) 97. inti=element.actions.indexOf(action); 98. if(i!=Action.INVALID_TAG) 99. removeAction(i,element); 100. 101. 102. /移除指定 103. publicvoidremoveAction(inttag,Nodetarget) 104. assert(tag!=Action.INVALID_TAG):Invalidtag; 105. HashElementelement=(HashElement)this.targets.get(target); 106. if(element=null)|(element.actions=null) 107. return; 108. intlimit=element.actions.size(); 109. for(inti=0;ilimit;+i) 110. Actiona=(Action)element.actions.get(i); 111. if(a.getTag()=tag)&(a.getOriginalTarget()=target) 112. removeAction(i,element); 113. 114. 115. /得到指定目标的指定动作 116. publicActiongetAction(inttag,Nodetarget) 117. assert(tag!=Action.INVALID_TAG):Invalidtag; 118. HashElementelement=(HashElement)this.targets.get(target); 119. if(element!=null)&(element.actions!=null) 120. intlimit=element.actions.size(); 121. for(inti=0;ilimit;+i) 122. Actiona=(Action)element.actions.get(i); 123. if(a.getTag()=tag) 124. returna; 125. 126. 127. 128. returnnull; 129. 130. /得到运行中的动作的数量 131. publicintgetRunningActionCount(Nodetarget) 132. HashElementelement=(HashElement)this.targets.get(target); 133. if(element!=null) 134. return(element.actions!=null)?element.actions.size():0; 135. 136. return0; 137. 138. /计时 139. publicvoidtick(floatdt) 140. for(HashElementcurrentTarget:this.targets.values() 141. if(!currentTarget.paused) 142. for(intactionIndex=0;actionIndexcurrentTarget.actions.size();+actionIndex) 143. /取得动作 144. ActioncurrentAction=(Action)currentTarget.actions 145. .get(actionIndex); 146. /设置单步执行 147. currentAction.step(dt); 148. /如果动作完成则调用所指定的回调函数 149. if(currentAction.isDone() 150. currentAction.stop(); 151. if(currentAction.getCallback()!=null) 152. currentAction.getCallback().onDone(currentAction); 153. 154. removeAction(currentAction); 155. 156. 157. 158. /没有动作就清楚 159. if(currentTarget.actions.size()=0) 160. deleteHashElement(currentTarget); 161. 162. 163. 164. staticclassHashElement 165. /动作列表 166. CopyOnWriteArrayListactions; 167. /目标节点 168. Nodetarget; 169. /是否暂停 170. booleanpaused; 171. HashElement(Nodet,booleanp) 172. this.target=t; 173. this.paused=p; 174. 175. publicStringtoString() 176. Strings=target=+this.target+,paused=+this.paused 177. +,actions=+this.actions+n; 178. for(Actiona:this.actions) 179. s=s+a.toString()+n; 180. 181. returns; 182. 183. 184. public class ActionManager /所有的动作列表,包括每个节点的动画 private ConcurrentHashMap targets; private static ActionManager sInstance; static sInstance = null; /取得本类实例对象 public static ActionManager getInstance() synchronized (ActionManager.class) if (sInstance = null) sInstance = new ActionManager(); return sInstance; /构建动作管理器对象 private ActionManager() synchronized (ActionManager.class) /构建一个计时器 /指定更新函数为tick Scheduler.getInstance().schedule(new Scheduler.Timer(this, tick); this.targets = new ConcurrentHashMap(131); /清楚动作 private void deleteHashElement(HashElement element) element.actions.clear(); this.targets.remove(element.target); /动作列表 private void actionAlloc(HashElement element) if (element.actions = null) element.actions = new CopyOnWriteArrayList(); /移除指定动作 private void removeAction(int index, HashElement element) element.actions.remove(index); if (element.actions.size() = 0) deleteHashElement(element); /暂停所有动作 public void pauseAllActions(Node target) HashElement element = (HashElement) this.targets.get(target); if (element != null) element.paused = true; /重新开始所有动作 public void resumeAllActions(Node target) HashElement element = (HashElement) this.targets.get(target); if (element != null) element.paused = false; /添加动作 public void addAction(Action action, Node target, boolean paused) assert (action != null) : Argument action must be non-null; assert (target != null) : Argument target must be non-null; HashElement element = (HashElement) this.targets.get(target); if (element = null) element = new HashElement(target, paused); this.targets.put(target, element); actionAlloc(element); assert (!element.actions.contains(action) : runAction: Action already running; element.actions.add(action); /开始动作 action.start(target); /移除所有动作 public void removeAllActions() for (HashElement element : this.targets.values() removeAllActions(element.target); /移除指定节点的所有动作 public void removeAllActions(Node target) if (target = null) return; /先找到指定节点 HashElement element = (HashElement) this.targets.get(target); if (element != null) element.actions.clear(); deleteHashElement(element); /移除指定动作 public void removeAction(Action action) /先找到动作的源目标 HashElement element = (HashElement) this.targets.get(action .getOriginalTarget(); if (element != null) int i = element.actions.indexOf(action); if (i != Action.INVALID_TAG) removeAction(i, element); /移除指定 public void removeAction(int tag, Node target) assert (tag != Action.INVALID_TAG) : Invalid tag; HashElement element = (HashElement) this.targets.get(target); if (element = null) | (element.actions = null) return; int limit = element.actions.size(); for (int i = 0; i limit; +i) Action a = (Action) element.actions.get(i); if (a.getTag() = tag) & (a.getOriginalTarget() = target) removeAction(i, element); /得到指定目标的指定动作 public Action getAction(int tag, Node target) assert (tag != Action.INVALID_TAG) : Invalid tag; HashElement element = (HashElement) this.targets.get(target); if (element != null) & (element.actions != null) int limit = element.actions.size(); for (int i = 0; i limit; +i) Action a = (Action) element.actions.get(i); if (a.getTag() = tag) return a; return null; /得到运行中的动作的数量 public int getRunningActionCount(Node target) HashElement element = (HashElement) this.targets.get(target); if (element != null) return (element.actions != null) ? element.actions.size() : 0; return 0; /计时 public void tick(float dt) for (HashElement currentTarget : this.targets.values() if (!currentTarget.paused) for (int actionIndex = 0; actionIndex currentTarget.actions.size(); +actionIndex) /取得动作 Action currentAction = (Action) currentTarget.actions .get(actionIndex); /设置单步执行 currentAction.step(dt); /如果动作完成则调用所指定的回调函数 if (currentAction.isDone() currentAction.stop(); if (currentAction.getCallback() != null) currentAction.getCallback().onDone(currentAction); removeAction(currentAction); /没有动作就清楚 if (currentTarget.actions.size() = 0) deleteHashElement(currentTarget); static class HashElement /动作列表 CopyOnWriteArrayList actions; /目标节点 Node target; /是否暂停 boolean paused; HashElement(Node t, boolean p) this.target = t; this.paused = p; public String toString() String s = target= + this.target + , paused= + this.paused + , actions= + this.actions + n; for (Action a : this.actions) s = s + a.toString() + n; return s; 大家可以看到HashElement的定义正如我们所说,包含一个节点的所有动画序列,然后整个ActionManager就应该包含每一个节点,因此使用了ConcurrentHashMap来表示这所有节点的所有动画。大家可以看到我们在构建动作管理器对象时创建了一个计时器,该计时器会不停的调用tick函数,因此我们在tick函数中就需要先去的当前执行动画的节点,但后在找到该节点正在执行的动画(一个节点可以同时执行多个动画,或者后面即将介绍的组合动画),最后通过step函数来设置动画的单步执行,同时我们在tick函数中就可以时刻检查当前动画是否结束,如果结束就调用动作类(Action)中的回调接口中的函数onDone。另外的一些操作就比较简单了,就是从动画管理器中添加、删除动画,当添加一个动画时,我们就将对该动画调用start函数来触发开始动画操作。时间动画(FiniteTimeAction)“时间动画”这个标题或许概括得并不完善,实际上该类用于表示在有限时间内可以完成的动作,即有限时间动画,当然也就对应会有无限时间动画了,比如后面我们要给大家介绍的永久不停的动画就属于无限时间动画。首先我们分析该类属于动作范围,所以它将继承自Action类,在因为他有一段有限的时间限制,所以我们需要一个表示动画时间的变量,另外:同样还有很多动画都需要在制定时间内完成,所以它还是我们封装的一个基类,有了这些条件下面来看我们的具体实现,如代码清单5-3所示。代码清单5-3:FiniteTimeAction实现view plaincopy to clipboardprint?1. /用于表示在有限时间内可以完成的动作。 2. publicabstractclassFiniteTimeActionextendsAction 3. /执行动画的时间限制 4. protectedfloatmDuration; 5. protectedFiniteTimeAction(floatduration) 6. this.mDuration=duration; 7. 8. publicfloatgetDuration() 9. returnthis.mDuration; 10. 11. publicvoidsetDuration(floatduration) 12. this.mDuration=duration; 13. 14. /用于表示在有限时间内可以完成的动作。 public abstract class FiniteTimeAction extends Action /执行动画的时间限制 protected float mDuration; protected FiniteTimeAction(float duration) this.mDuration = duration; public float getDuration() return this.mDuration; public void setDuration(float duration) this.mDuration = duration; 其中mDuration用来表示动画的时间,实现很简单,就包括了一个设置和一个得到时间的函数。下面我们将来基于这个类实现两种有限时间的动画,他们分别是瞬时动画和定时动画。瞬时动画(InstantAction)这里我们先来看一个较为简单的瞬时动画,瞬时动画就是将在一瞬间内疚完成的,不需要持续一段较长的时间,给大家举个例子就很好理解了,比如我们要隐藏和显示某个节点对象,那么这个显示和隐藏就是在一瞬间类完成,不需要持续很长一段时间才完成,更就不需要持续更新,或者我们要立刻调用某个函数,这类动画都是在一瞬间类完成。下面我们来看如何实现这样的动画,他们的共同点式什么呢?这杨一个基类如何来封装,如代码清单5-4所示。代码清单5-4:InstantAction实现view plaincopy to clipboardprint?1. /瞬发动作 2. publicabstractclassInstantActionextendsFiniteTimeAction 3. protectedInstantAction() 4. super(0.0F); 5. 6. /拷贝动画 7. publicabstractInstantActioncopy(); 8. /是否完成 9. publicbooleanisDone() 10. returntrue; 11. 12. /单步执行 13. publicvoidstep(floatdelta) 14. 15. /更新 16. publicvoidupdate(floatinput) 17. 18. /生成反向动画 19. publicabstractInstantActionreverse(); 20. /瞬发动作 public abstract class InstantAction extends FiniteTimeAction protected InstantAction() super(0.0F); /拷贝动画 public abstract InstantAction copy(); /是否完成 public boolean isDone() return true; /单步执行 public void step(float delta) /更新 public void update(float input) /生成反向动画 public abstract InstantAction reverse(); 大家是否觉得我们的方法并没有进行什么实质的处理,正确,我们的确没有处理什么,因为我们在具体的瞬时动画实现中才会来具体的实现,这里就是一个瞬时动画的框架,因为它是一瞬间完成的,所以我们处理也并不是很多,下面我们通过几个具体的例子来实现,大家就会明白了。隐藏动画(Hide)这里就拿上面我们的距离来给大家实现并说明吧,隐藏动画实际上就是隐藏一个节点,他需要在动画一开始start时就执行,并且马上就会完成该动画,我们就能见到隐藏的效果,废话不多说,直接看实现,如代码清单5-5所示。代码清单5-5:Hide实现view plaincopy to clipboardprint?1. publicclassHideextendsInstantAction 2. publicstaticHidemake() 3. returnnewHide(); 4.
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 管理文书 > 工作总结


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!