summary refs log tree commit diff stats
path: root/libs/cocos2d/CCActionManager.m
diff options
context:
space:
mode:
Diffstat (limited to 'libs/cocos2d/CCActionManager.m')
-rwxr-xr-xlibs/cocos2d/CCActionManager.m345
1 files changed, 345 insertions, 0 deletions
diff --git a/libs/cocos2d/CCActionManager.m b/libs/cocos2d/CCActionManager.m new file mode 100755 index 0000000..8bdfbb7 --- /dev/null +++ b/libs/cocos2d/CCActionManager.m
@@ -0,0 +1,345 @@
1/*
2 * cocos2d for iPhone: http://www.cocos2d-iphone.org
3 *
4 * Copyright (c) 2009 Valentin Milea
5 *
6 * Copyright (c) 2008-2010 Ricardo Quesada
7 * Copyright (c) 2011 Zynga Inc.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 *
27 */
28
29
30#import "CCActionManager.h"
31#import "CCScheduler.h"
32#import "ccMacros.h"
33
34
35//
36// singleton stuff
37//
38static CCActionManager *sharedManager_ = nil;
39
40@interface CCActionManager (Private)
41-(void) removeActionAtIndex:(NSUInteger)index hashElement:(tHashElement*)element;
42-(void) deleteHashElement:(tHashElement*)element;
43-(void) actionAllocWithHashElement:(tHashElement*)element;
44@end
45
46
47@implementation CCActionManager
48
49#pragma mark ActionManager - init
50+ (CCActionManager *)sharedManager
51{
52 if (!sharedManager_)
53 sharedManager_ = [[self alloc] init];
54
55 return sharedManager_;
56}
57
58+(id)alloc
59{
60 NSAssert(sharedManager_ == nil, @"Attempted to allocate a second instance of a singleton.");
61 return [super alloc];
62}
63
64+(void)purgeSharedManager
65{
66 [[CCScheduler sharedScheduler] unscheduleUpdateForTarget:self];
67 [sharedManager_ release];
68 sharedManager_ = nil;
69}
70
71-(id) init
72{
73 if ((self=[super init]) ) {
74 [[CCScheduler sharedScheduler] scheduleUpdateForTarget:self priority:0 paused:NO];
75 targets = NULL;
76 }
77
78 return self;
79}
80
81- (void) dealloc
82{
83 CCLOGINFO( @"cocos2d: deallocing %@", self);
84
85 [self removeAllActions];
86
87 sharedManager_ = nil;
88
89 [super dealloc];
90}
91
92#pragma mark ActionManager - Private
93
94-(void) deleteHashElement:(tHashElement*)element
95{
96 ccArrayFree(element->actions);
97 HASH_DEL(targets, element);
98// CCLOG(@"cocos2d: ---- buckets: %d/%d - %@", targets->entries, targets->size, element->target);
99 [element->target release];
100 free(element);
101}
102
103-(void) actionAllocWithHashElement:(tHashElement*)element
104{
105 // 4 actions per Node by default
106 if( element->actions == nil )
107 element->actions = ccArrayNew(4);
108 else if( element->actions->num == element->actions->max )
109 ccArrayDoubleCapacity(element->actions);
110}
111
112-(void) removeActionAtIndex:(NSUInteger)index hashElement:(tHashElement*)element
113{
114 id action = element->actions->arr[index];
115
116 if( action == element->currentAction && !element->currentActionSalvaged ) {
117 [element->currentAction retain];
118 element->currentActionSalvaged = YES;
119 }
120
121 ccArrayRemoveObjectAtIndex(element->actions, index);
122
123 // update actionIndex in case we are in tick:, looping over the actions
124 if( element->actionIndex >= index )
125 element->actionIndex--;
126
127 if( element->actions->num == 0 ) {
128 if( currentTarget == element )
129 currentTargetSalvaged = YES;
130 else
131 [self deleteHashElement: element];
132 }
133}
134
135#pragma mark ActionManager - Pause / Resume
136
137-(void) pauseTarget:(id)target
138{
139 tHashElement *element = NULL;
140 HASH_FIND_INT(targets, &target, element);
141 if( element )
142 element->paused = YES;
143// else
144// CCLOG(@"cocos2d: pauseAllActions: Target not found");
145}
146
147-(void) resumeTarget:(id)target
148{
149 tHashElement *element = NULL;
150 HASH_FIND_INT(targets, &target, element);
151 if( element )
152 element->paused = NO;
153// else
154// CCLOG(@"cocos2d: resumeAllActions: Target not found");
155}
156
157#pragma mark ActionManager - run
158
159-(void) addAction:(CCAction*)action target:(id)target paused:(BOOL)paused
160{
161 NSAssert( action != nil, @"Argument action must be non-nil");
162 NSAssert( target != nil, @"Argument target must be non-nil");
163
164 tHashElement *element = NULL;
165 HASH_FIND_INT(targets, &target, element);
166 if( ! element ) {
167 element = calloc( sizeof( *element ), 1 );
168 element->paused = paused;
169 element->target = [target retain];
170 HASH_ADD_INT(targets, target, element);
171// CCLOG(@"cocos2d: ---- buckets: %d/%d - %@", targets->entries, targets->size, element->target);
172
173 }
174
175 [self actionAllocWithHashElement:element];
176
177 NSAssert( !ccArrayContainsObject(element->actions, action), @"runAction: Action already running");
178 ccArrayAppendObject(element->actions, action);
179
180 [action startWithTarget:target];
181}
182
183#pragma mark ActionManager - remove
184
185-(void) removeAllActions
186{
187 for(tHashElement *element=targets; element != NULL; ) {
188 id target = element->target;
189 element = element->hh.next;
190 [self removeAllActionsFromTarget:target];
191 }
192}
193-(void) removeAllActionsFromTarget:(id)target
194{
195 // explicit nil handling
196 if( target == nil )
197 return;
198
199 tHashElement *element = NULL;
200 HASH_FIND_INT(targets, &target, element);
201 if( element ) {
202 if( ccArrayContainsObject(element->actions, element->currentAction) && !element->currentActionSalvaged ) {
203 [element->currentAction retain];
204 element->currentActionSalvaged = YES;
205 }
206 ccArrayRemoveAllObjects(element->actions);
207 if( currentTarget == element )
208 currentTargetSalvaged = YES;
209 else
210 [self deleteHashElement:element];
211 }
212// else {
213// CCLOG(@"cocos2d: removeAllActionsFromTarget: Target not found");
214// }
215}
216
217-(void) removeAction: (CCAction*) action
218{
219 // explicit nil handling
220 if (action == nil)
221 return;
222
223 tHashElement *element = NULL;
224 id target = [action originalTarget];
225 HASH_FIND_INT(targets, &target, element );
226 if( element ) {
227 NSUInteger i = ccArrayGetIndexOfObject(element->actions, action);
228 if( i != NSNotFound )
229 [self removeActionAtIndex:i hashElement:element];
230 }
231// else {
232// CCLOG(@"cocos2d: removeAction: Target not found");
233// }
234}
235
236-(void) removeActionByTag:(NSInteger)aTag target:(id)target
237{
238 NSAssert( aTag != kCCActionTagInvalid, @"Invalid tag");
239 NSAssert( target != nil, @"Target should be ! nil");
240
241 tHashElement *element = NULL;
242 HASH_FIND_INT(targets, &target, element);
243
244 if( element ) {
245 NSUInteger limit = element->actions->num;
246 for( NSUInteger i = 0; i < limit; i++) {
247 CCAction *a = element->actions->arr[i];
248
249 if( a.tag == aTag && [a originalTarget]==target) {
250 [self removeActionAtIndex:i hashElement:element];
251 break;
252 }
253 }
254
255 }
256}
257
258#pragma mark ActionManager - get
259
260-(CCAction*) getActionByTag:(NSInteger)aTag target:(id)target
261{
262 NSAssert( aTag != kCCActionTagInvalid, @"Invalid tag");
263
264 tHashElement *element = NULL;
265 HASH_FIND_INT(targets, &target, element);
266
267 if( element ) {
268 if( element->actions != nil ) {
269 NSUInteger limit = element->actions->num;
270 for( NSUInteger i = 0; i < limit; i++) {
271 CCAction *a = element->actions->arr[i];
272
273 if( a.tag == aTag )
274 return a;
275 }
276 }
277// CCLOG(@"cocos2d: getActionByTag: Action not found");
278 }
279// else {
280// CCLOG(@"cocos2d: getActionByTag: Target not found");
281// }
282 return nil;
283}
284
285-(NSUInteger) numberOfRunningActionsInTarget:(id) target
286{
287 tHashElement *element = NULL;
288 HASH_FIND_INT(targets, &target, element);
289 if( element )
290 return element->actions ? element->actions->num : 0;
291
292// CCLOG(@"cocos2d: numberOfRunningActionsInTarget: Target not found");
293 return 0;
294}
295
296#pragma mark ActionManager - main loop
297
298-(void) update: (ccTime) dt
299{
300 for(tHashElement *elt = targets; elt != NULL; ) {
301
302 currentTarget = elt;
303 currentTargetSalvaged = NO;
304
305 if( ! currentTarget->paused ) {
306
307 // The 'actions' ccArray may change while inside this loop.
308 for( currentTarget->actionIndex = 0; currentTarget->actionIndex < currentTarget->actions->num; currentTarget->actionIndex++) {
309 currentTarget->currentAction = currentTarget->actions->arr[currentTarget->actionIndex];
310 currentTarget->currentActionSalvaged = NO;
311
312 [currentTarget->currentAction step: dt];
313
314 if( currentTarget->currentActionSalvaged ) {
315 // The currentAction told the node to remove it. To prevent the action from
316 // accidentally deallocating itself before finishing its step, we retained
317 // it. Now that step is done, it's safe to release it.
318 [currentTarget->currentAction release];
319
320 } else if( [currentTarget->currentAction isDone] ) {
321 [currentTarget->currentAction stop];
322
323 CCAction *a = currentTarget->currentAction;
324 // Make currentAction nil to prevent removeAction from salvaging it.
325 currentTarget->currentAction = nil;
326 [self removeAction:a];
327 }
328
329 currentTarget->currentAction = nil;
330 }
331 }
332
333 // elt, at this moment, is still valid
334 // so it is safe to ask this here (issue #490)
335 elt = elt->hh.next;
336
337 // only delete currentTarget if no actions were scheduled during the cycle (issue #481)
338 if( currentTargetSalvaged && currentTarget->actions->num == 0 )
339 [self deleteHashElement:currentTarget];
340 }
341
342 // issue #635
343 currentTarget = nil;
344}
345@end