/src/de/nulldesign/nd2d/materials/texture/ASpriteSheetBase.as
ActionScript | 250 lines | 143 code | 54 blank | 53 comment | 19 complexity | 163c1c4a5ec2469017a16c1bb298446a MD5 | raw file
1/*
2 * ND2D - A Flash Molehill GPU accelerated 2D engine
3 *
4 * Author: Lars Gerckens
5 * Copyright (c) nulldesign 2011
6 * Repository URL: http://github.com/nulldesign/nd2d
7 * Getting started: https://github.com/nulldesign/nd2d/wiki
8 *
9 *
10 * Licence Agreement
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a copy
13 * of this software and associated documentation files (the "Software"), to deal
14 * in the Software without restriction, including without limitation the rights
15 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 * copies of the Software, and to permit persons to whom the Software is
17 * furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included in
20 * all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28 * THE SOFTWARE.
29 */
30
31package de.nulldesign.nd2d.materials.texture {
32
33 import de.nulldesign.nd2d.events.SpriteSheetAnimationEvent;
34 import de.nulldesign.nd2d.materials.texture.SpriteSheetAnimation;
35
36 import flash.events.EventDispatcher;
37
38 import flash.geom.Point;
39 import flash.geom.Rectangle;
40 import flash.utils.Dictionary;
41
42 public class ASpriteSheetBase extends EventDispatcher {
43
44 protected var frames:Vector.<Rectangle> = new Vector.<Rectangle>();
45 protected var offsets:Vector.<Point> = new Vector.<Point>();
46 protected var frameNameToIndex:Dictionary = new Dictionary();
47 protected var uvRects:Vector.<Rectangle>;
48 protected var animationMap:Dictionary = new Dictionary();
49 protected var activeAnimation:SpriteSheetAnimation;
50
51 protected var spritesPackedWithoutSpace:Boolean;
52
53 protected var ctime:Number = 0.0;
54 protected var otime:Number = 0.0;
55 protected var interp:Number = 0.0;
56
57 protected var triggerEventOnLastFrame:Boolean = false;
58
59 protected var frameIdx:uint = 0;
60
61 public var frameUpdated:Boolean = true;
62
63 protected var fps:uint;
64
65 protected var _spriteWidth:Number;
66 protected var _spriteHeight:Number;
67 protected var _sheetWidth:Number;
68 protected var _sheetHeight:Number;
69
70 public function get spriteWidth():Number {
71 return _spriteWidth;
72 }
73
74 public function get spriteHeight():Number {
75 return _spriteHeight;
76 }
77
78 protected var _frame:uint = int.MAX_VALUE;
79
80 public function get frame():uint {
81 return _frame;
82 }
83
84 public function set frame(value:uint):void {
85 if(frame != value) {
86 _frame = value;
87 frameUpdated = true;
88
89 if(frames.length - 1 >= _frame) {
90 _spriteWidth = frames[_frame].width;
91 _spriteHeight = frames[_frame].height;
92 }
93 }
94 }
95
96 /**
97 * returns the total number of frames (sprites) in a spritesheet
98 */
99 public function get totalFrames():uint {
100 return frames.length;
101 }
102
103 public function ASpriteSheetBase() {
104
105 }
106
107 public function update(t:Number):void {
108
109 if(!activeAnimation) return;
110
111 var prevFrameIdx:int = frameIdx;
112
113 ctime = t;
114
115 // Update the timer part, to get time based animation
116 interp += fps * (ctime - otime);
117 if(interp >= 1.0) {
118 frameIdx++;
119 interp = 0;
120 }
121
122 if(activeAnimation.loop) {
123 frameIdx = frameIdx % activeAnimation.numFrames;
124 } else {
125 frameIdx = Math.min(frameIdx, activeAnimation.numFrames - 1);
126 }
127
128 frame = activeAnimation.frames[frameIdx];
129
130 otime = ctime;
131
132 // skipped frames
133 if(triggerEventOnLastFrame && (frameIdx == activeAnimation.numFrames - 1 || frameIdx < prevFrameIdx)) {
134 if(!activeAnimation.loop) {
135 triggerEventOnLastFrame = false;
136 }
137 dispatchEvent(new SpriteSheetAnimationEvent(SpriteSheetAnimationEvent.ANIMATION_FINISHED));
138 }
139 }
140
141 public function stopCurrentAnimation():void {
142 activeAnimation = null;
143 }
144
145 public function playAnimation(name:String, startIdx:uint = 0, restart:Boolean = false, triggerEventOnLastFrame:Boolean = false):void {
146
147 this.triggerEventOnLastFrame = triggerEventOnLastFrame;
148
149 if(restart || activeAnimation != animationMap[name]) {
150 frameIdx = startIdx;
151 activeAnimation = animationMap[name];
152 frame = activeAnimation.frames[0];
153 }
154 }
155
156 public function addAnimation(name:String, keyFrames:Array, loop:Boolean):void {
157
158 }
159
160 public function clone():ASpriteSheetBase {
161 return null;
162 }
163
164 public function getOffsetForFrame():Point {
165 return offsets[frame];
166 }
167
168 /**
169 * Returns the current selected frame rectangle if no frameIdx is specified, otherwise the rect of the given frameIdx
170 * @param frameIdx
171 * @return
172 */
173 public function getDimensionForFrame(frameIdx:int = -1):Rectangle {
174 return frames[frameIdx > -1 ? frameIdx : frame];
175 }
176
177 /**
178 * converts a frame name to a index
179 * @param name
180 * @return
181 */
182 public function getIndexForFrame(name:String):uint {
183 return frameNameToIndex[name];
184 }
185
186 /**
187 * sets an a frame by a given name
188 * @param value
189 */
190 public function setFrameByName(value:String):void {
191 frame = getIndexForFrame(value);
192 }
193
194 /**
195 * Convenience method to directly set an animation frame by name
196 * @param name of the animation to set
197 * @param index frame in the animation to set
198 */
199 public function setFrameByAnimationName(name:String, index:uint = 0):void {
200 if(animationMap[name]) {
201 frame = animationMap[name].frames[index];
202 }
203 }
204
205 public function getUVRectForFrame(textureWidth:Number, textureHeight:Number):Rectangle {
206
207 if(uvRects[frame]) {
208 return uvRects[frame];
209 }
210
211 var rect:Rectangle = frames[frame].clone();
212 var texturePixelOffset:Point = new Point((textureWidth - _sheetWidth) / 2.0, (textureHeight - _sheetHeight) / 2.0);
213
214 rect.x += texturePixelOffset.x;
215 rect.y += texturePixelOffset.y;
216
217 if(spritesPackedWithoutSpace) {
218 rect.x += 0.5;
219 rect.y += 0.5;
220
221 rect.width -= 1.0;
222 rect.height -= 1.0;
223 }
224
225 rect.x /= textureWidth;
226 rect.y /= textureHeight;
227 rect.width /= textureWidth;
228 rect.height /= textureHeight;
229
230 uvRects[frame] = rect;
231
232 return rect;
233 }
234
235 public function dispose():void
236 {
237 frames = null;
238 offsets = null;
239 frameNameToIndex = null;
240 uvRects = null;
241 animationMap = null;
242
243 if(activeAnimation)
244 {
245 activeAnimation.dispose();
246 activeAnimation = null;
247 }
248 }
249 }
250}