modelAnimation.ts 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. import { Vector3 } from "babylonjs/Maths/math";
  2. import { AnimationGroup, Animatable } from "babylonjs/Animations/index";
  3. /**
  4. * Animation play mode enum - is the animation looping or playing once
  5. */
  6. export const enum AnimationPlayMode {
  7. ONCE,
  8. LOOP
  9. }
  10. /**
  11. * An enum representing the current state of an animation object
  12. */
  13. export const enum AnimationState {
  14. INIT,
  15. PLAYING,
  16. PAUSED,
  17. STOPPED,
  18. ENDED
  19. }
  20. /**
  21. * The different type of easing functions available
  22. */
  23. export const enum EasingFunction {
  24. Linear = 0,
  25. CircleEase = 1,
  26. BackEase = 2,
  27. BounceEase = 3,
  28. CubicEase = 4,
  29. ElasticEase = 5,
  30. ExponentialEase = 6,
  31. PowerEase = 7,
  32. QuadraticEase = 8,
  33. QuarticEase = 9,
  34. QuinticEase = 10,
  35. SineEase = 11
  36. }
  37. /**
  38. * Defines a simple animation to be applied to a model (scale).
  39. */
  40. export interface ModelAnimationConfiguration {
  41. /**
  42. * Time of animation, in seconds
  43. */
  44. time: number;
  45. /**
  46. * Scale to apply
  47. */
  48. scaling?: Vector3;
  49. /**
  50. * Easing function to apply
  51. * See SPECTRE.EasingFunction
  52. */
  53. easingFunction?: number;
  54. /**
  55. * An Easing mode to apply to the easing function
  56. * See BABYLON.EasingFunction
  57. */
  58. easingMode?: number;
  59. }
  60. /**
  61. * This interface can be implemented to define new types of ModelAnimation objects.
  62. */
  63. export interface IModelAnimation {
  64. /**
  65. * Current animation state (playing, stopped etc')
  66. */
  67. readonly state: AnimationState;
  68. /**
  69. * the name of the animation
  70. */
  71. readonly name: string;
  72. /**
  73. * Get the max numbers of frame available in the animation group
  74. *
  75. * In correlation to an arry, this would be ".length"
  76. */
  77. readonly frames: number;
  78. /**
  79. * Get the current frame playing right now.
  80. * This can be used to poll the frame currently playing (and, for exmaple, display a progress bar with the data)
  81. *
  82. * In correlation to an array, this would be the current index
  83. */
  84. readonly currentFrame: number;
  85. /**
  86. * Animation's FPS value
  87. */
  88. readonly fps: number;
  89. /**
  90. * Get or set the animation's speed ration (Frame-to-fps)
  91. */
  92. speedRatio: number;
  93. /**
  94. * Gets or sets the aimation's play mode.
  95. */
  96. playMode: AnimationPlayMode;
  97. /**
  98. * Start the animation
  99. */
  100. start();
  101. /**
  102. * Stop the animation.
  103. * This will fail silently if the animation group is already stopped.
  104. */
  105. stop();
  106. /**
  107. * Pause the animation
  108. * This will fail silently if the animation is not currently playing
  109. */
  110. pause();
  111. /**
  112. * Reset this animation
  113. */
  114. reset();
  115. /**
  116. * Restart the animation
  117. */
  118. restart();
  119. /**
  120. * Go to a specific
  121. * @param frameNumber the frame number to go to
  122. */
  123. goToFrame(frameNumber: number);
  124. /**
  125. * Dispose this animation
  126. */
  127. dispose();
  128. }
  129. /**
  130. * The GroupModelAnimation is an implementation of the IModelAnimation interface using BABYLON's
  131. * native GroupAnimation class.
  132. */
  133. export class GroupModelAnimation implements IModelAnimation {
  134. private _playMode: AnimationPlayMode;
  135. private _state: AnimationState;
  136. /**
  137. * Create a new GroupModelAnimation object using an AnimationGroup object
  138. * @param _animationGroup The aniamtion group to base the class on
  139. */
  140. constructor(private _animationGroup: AnimationGroup) {
  141. this._state = AnimationState.INIT;
  142. this._playMode = AnimationPlayMode.LOOP;
  143. this._animationGroup.onAnimationEndObservable.add(() => {
  144. this.stop();
  145. this._state = AnimationState.ENDED;
  146. });
  147. }
  148. /**
  149. * Get the animation's name
  150. */
  151. public get name() {
  152. return this._animationGroup.name;
  153. }
  154. /**
  155. * Get the current animation's state
  156. */
  157. public get state() {
  158. return this._state;
  159. }
  160. /**
  161. * Gets the speed ratio to use for all animations
  162. */
  163. public get speedRatio(): number {
  164. return this._animationGroup.speedRatio;
  165. }
  166. /**
  167. * Sets the speed ratio to use for all animations
  168. */
  169. public set speedRatio(value: number) {
  170. this._animationGroup.speedRatio = value;
  171. }
  172. /**
  173. * Get the max numbers of frame available in the animation group
  174. *
  175. * In correlation to an arry, this would be ".length"
  176. */
  177. public get frames(): number {
  178. return this._animationGroup.to - this._animationGroup.from;
  179. }
  180. /**
  181. * Get the current frame playing right now.
  182. * This can be used to poll the frame currently playing (and, for exmaple, display a progress bar with the data)
  183. *
  184. * In correlation to an array, this would be the current index
  185. */
  186. public get currentFrame(): number {
  187. if (this._animationGroup.targetedAnimations[0] && this._animationGroup.targetedAnimations[0].animation.runtimeAnimations[0]) {
  188. return this._animationGroup.targetedAnimations[0].animation.runtimeAnimations[0].currentFrame - this._animationGroup.from;
  189. } else {
  190. return 0;
  191. }
  192. }
  193. /**
  194. * Get the FPS value of this animation
  195. */
  196. public get fps(): number {
  197. // get the first currentFrame found
  198. for (let i = 0; i < this._animationGroup.animatables.length; ++i) {
  199. let animatable: Animatable = this._animationGroup.animatables[i];
  200. let animations = animatable.getAnimations();
  201. if (!animations || !animations.length) {
  202. continue;
  203. }
  204. for (let idx = 0; idx < animations.length; ++idx) {
  205. if (animations[idx].animation && animations[idx].animation.framePerSecond) {
  206. return animations[idx].animation.framePerSecond;
  207. }
  208. }
  209. }
  210. return 0;
  211. }
  212. /**
  213. * What is the animation'S play mode (looping or played once)
  214. */
  215. public get playMode(): AnimationPlayMode {
  216. return this._playMode;
  217. }
  218. /**
  219. * Set the play mode.
  220. * If the animation is played, it will continue playing at least once more, depending on the new play mode set.
  221. * If the animation is not set, the will be initialized and will wait for the user to start playing it.
  222. */
  223. public set playMode(value: AnimationPlayMode) {
  224. if (value === this._playMode) {
  225. return;
  226. }
  227. this._playMode = value;
  228. if (this.state === AnimationState.PLAYING) {
  229. this._animationGroup.play(this._playMode === AnimationPlayMode.LOOP);
  230. } else {
  231. this._animationGroup.reset();
  232. this._state = AnimationState.INIT;
  233. }
  234. }
  235. /**
  236. * Reset the animation group
  237. */
  238. reset() {
  239. this._animationGroup.reset();
  240. }
  241. /**
  242. * Restart the animation group
  243. */
  244. restart() {
  245. if (this.state === AnimationState.PAUSED) {
  246. this._animationGroup.restart();
  247. }
  248. else {
  249. this.start();
  250. }
  251. }
  252. /**
  253. *
  254. * @param frameNumber Go to a specific frame in the animation
  255. */
  256. goToFrame(frameNumber: number) {
  257. this._animationGroup.goToFrame(frameNumber + this._animationGroup.from);
  258. }
  259. /**
  260. * Start playing the animation.
  261. */
  262. public start() {
  263. this._animationGroup.start(this.playMode === AnimationPlayMode.LOOP, this.speedRatio);
  264. if (this._animationGroup.isStarted) {
  265. this._state = AnimationState.PLAYING;
  266. }
  267. }
  268. /**
  269. * Pause the animation
  270. */
  271. pause() {
  272. this._animationGroup.pause();
  273. this._state = AnimationState.PAUSED;
  274. }
  275. /**
  276. * Stop the animation.
  277. * This will fail silently if the animation group is already stopped.
  278. */
  279. public stop() {
  280. this._animationGroup.stop();
  281. if (!this._animationGroup.isStarted) {
  282. this._state = AnimationState.STOPPED;
  283. }
  284. }
  285. /**
  286. * Dispose this animation object.
  287. */
  288. public dispose() {
  289. this._animationGroup.dispose();
  290. }
  291. }