Minor reorg of unit crap.
authordsc <david.schoonover@gmail.com>
Mon, 6 Jun 2011 13:23:56 +0000 (06:23 -0700)
committerdsc <david.schoonover@gmail.com>
Mon, 6 Jun 2011 13:23:56 +0000 (06:23 -0700)
34 files changed:
src/Tanks.h
src/TanksMacros.h
src/game/QQActive.h
src/game/QQDisplayable.h
src/game/QQGame.h
src/game/QQGame.mm
src/game/QQPhysical.h
src/game/QQThing.h
src/game/ability/QQCooldown.h
src/game/ability/QQCooldown.mm
src/game/unit/QQActor.h
src/game/unit/QQActor.mm
src/game/unit/QQBullet.h
src/game/unit/QQBullet.mm
src/game/unit/QQTank.h
src/game/unit/QQTank.mm
src/game/unit/QQUnit.h
src/game/unit/QQUnit.mm
src/qq/Collections+FP.h [new file with mode: 0644]
src/qq/Collections+FP.mm [new file with mode: 0644]
src/qq/NSArray+QQExtensions.h [new file with mode: 0644]
src/qq/NSArray+QQExtensions.mm [new file with mode: 0644]
src/qq/NSDictionary+QQExtensions.h [new file with mode: 0644]
src/qq/NSDictionary+QQExtensions.mm [new file with mode: 0644]
src/qq/NSSet+QQExtensions.h
src/qq/NSSet+QQExtensions.mm
src/qq/event/QQNotificationCenter.h
src/qq/event/QQNotificationCenter.mm
src/qq/event/QQNotificationProxy.h
src/qq/event/QQNotificationProxy.mm
src/qq/event/QQNotifier.h
src/qq/event/QQNotifiers.h
src/qq/event/QQObservable.h
tanks.xcodeproj/project.pbxproj

index a2a448b..6246017 100644 (file)
@@ -1,14 +1,20 @@
 #ifndef TANKS_H
 #define TANKS_H
 
+
 #ifdef DEBUG
 #define TANKS_DEBUG_LOG 1
-#else
+
+#else // DEBUG
 #define TANKS_DEBUG_LOG 0
+
 #endif // DEBUG
 
+
 #endif // TANKS_H
 
 #import "TanksMacros.h"
+#import "qq/NSArray+QQExtensions.h"
+#import "qq/NSDictionary+QQExtensions.h"
 #import "qq/NSSet+QQExtensions.h"
 #import "render/QQSparrowExtensions.h"
index b36a57c..b2c9fd0 100644 (file)
@@ -4,4 +4,7 @@
 #define b2s(__val) ((__val)?("YES"):("NO"))
 
 
+#define ATTACK_COOLDOWN_NAME @"attack"
+
+
 #endif
\ No newline at end of file
index 4bc669b..eba0aed 100644 (file)
@@ -1,16 +1,22 @@
 #import "game/QQGameTime.h"
 #import "game/QQThing.h"
+#import "game/ability/QQCooldown.h"
+
 
 /**
  * Anything that takes a turn is QQActive.
  */
 @protocol QQActive <QQThing>
 
-@property (nonatomic, readwrite, getter=isActive) BOOL active;
-// @property (nonatomic, readwrite, getter=isSleeping) BOOL sleeping;
-@property (nonatomic, readwrite, retain) NSArray* cooldowns;
+@property (nonatomic, readwrite, getter=isActive)   BOOL active;
+@property (nonatomic, readwrite, getter=isSleeping) BOOL sleeping;
+
+@property (nonatomic, readonly, retain) NSMutableDictionary* cooldowns;
+- (void) addCooldown:(QQCooldown*)cool;
+- (void) tickCooldowns;
 
 - (void) tick;
 - (void) act;
 
+
 @end
\ No newline at end of file
index ab60dbf..b7031cf 100644 (file)
@@ -12,7 +12,7 @@
 /**
  * Called to setup the Sparrow shape.
  */
-- (SPDisplayObject*) setupShape;
+- (void) setupShape;
 
 /**
  * Called to update appearance after game actions have occurred
index f69644d..aaef0b2 100644 (file)
@@ -1,5 +1,6 @@
 #import "Sparrow.h"
 
+#import "Tanks.h"
 #import "qq/event/QQNotificationCenter.h"
 
 #import "physics/QQWorld.h"
@@ -38,7 +39,7 @@
 @property (nonatomic, readonly) float elapsed;
 @property (nonatomic, readonly) long  ticks;
 
-@property (nonatomic, readonly, getter=isPaused) BOOL paused;
+@property (nonatomic, readonly, getter=isRunning) BOOL running;
 @property (nonatomic, readwrite, assign) BOOL debugDrawingEnabled;
 
 @property (nonatomic, readonly) SPStage* stage;
 @property (nonatomic, readonly) QQLevel* level;
 
 @property (nonatomic, readonly) QQWorld* world;
-
 @property (nonatomic, readonly, retain) NSSet* actors;
 
 
-- (void) tick:(float)elapsed;
-
 /** Alerts the game to a new actor.  */
 - (QQGame*) addActor:(QQActor*)actor;
 - (QQGame*) removeActor:(QQActor*)actor;
@@ -62,6 +60,9 @@
 /** Pauses the game. */
 - (void) stop;
 
+/** Advances the game clock one step and elapsed ms. */
+- (void) tick:(float)elapsed;
+
 
 + (QQGame*) current;
 
index ad60683..6ec2b28 100644 (file)
@@ -1,6 +1,5 @@
 #import <Box2D/Box2D.h>
 
-#import "Tanks.h"
 #import "game/QQGame.h"
 #import "game/unit/QQActors.h"
 #import "physics/event/QQContactNotification.h"
@@ -11,6 +10,7 @@
 
 - (void) onEnterFrame:(SPEnterFrameEvent*)event;
 - (void) onCollide:(QQContactNotification*)msg;
+- (void) logEvent:(SPEvent*)evt;
 @end
 
 
@@ -25,6 +25,7 @@ static QQGame* _CurrentGame = NULL;
     return _CurrentGame;
 }
 
+
 - (id) init {
     if (_CurrentGame) {
         [self release];
@@ -70,9 +71,10 @@ static QQGame* _CurrentGame = NULL;
         [[[QQTank alloc] initAtX:wMax/6 y:hMax/6 width:50 height:50 color:0xFF0071] autorelease];
         [[[QQUnit alloc] initAtX:wMax/3 y:hMax/2 width:50 height:50 color:0x4596FF] autorelease];
         
-#if TANKS_DEBUG_LOG
-        [_stage addEventListener:@selector(logEvent:) atObject:self forType:SP_EVENT_TYPE_ANY];
-#endif
+        #if TANKS_DEBUG_LOG
+            [_stage addEventListener:@selector(logEvent:) atObject:self forType:SP_EVENT_TYPE_ANY];
+        #endif
+        
     }
     return self;
 }
@@ -106,7 +108,7 @@ static QQGame* _CurrentGame = NULL;
 
 - (id<QQGameTime>) time { return self; }
 
-@synthesize paused = _running;
+@synthesize running = _running;
 
 @synthesize stage  = _stage;
 @synthesize root   = _root;
@@ -126,10 +128,11 @@ static QQGame* _CurrentGame = NULL;
 /// methods
 
 - (void) tick:(float)elapsed {
-    if (!self.isPaused) return;
+    if (!self.isRunning) return;
+    
     _ticks++;
-    _elapsed  = elapsed;
-    _now     += elapsed;
+    _elapsed = elapsed;
+    _now += elapsed;
     
     for (QQActor* actor in self.actors)
         [actor tick];
@@ -185,20 +188,22 @@ static QQGame* _CurrentGame = NULL;
 }
 
 - (void) onCollide:(QQContactNotification*)msg {
-    NSLog(@"%@", msg);
+//    NSLog(@"\v\t%@", msg);
 }
 
 - (void) logEvent:(SPEvent*)evt {
     // ignore enter-frame events, as they happen constantly
     if ([evt.type isEqualToString:SP_EVENT_TYPE_ENTER_FRAME]) return;
-    NSLog(@"%@", evt);
+    NSLog(@"\v\t%@", evt);
 }
 
 
 - (NSString*) description {
-    return [NSString stringWithFormat:@"<%@: %p> {running=%s, #actors=%i, time={now=%f, elapsed=%f, ticks=%l}}",
-            [self class], (long)self, b2s(self.isPaused), [self.actors count],
-            self.now, self.elapsed, self.ticks];
+    return [NSString stringWithFormat:@"<%@: %p> {running=%s, #actors=%i, time={now=%f, ticks=%l, elapsed=%f}}",
+            [self class], (long)self,
+            b2s(self.isRunning), [self.actors count],
+            self.now, self.ticks, self.elapsed
+        ];
 }
 
 
index 951567e..5714c23 100644 (file)
@@ -14,6 +14,7 @@
 /// The y coordinate in the simulation.
 @property (nonatomic, readwrite, assign) float y;
 
+/// Simulation coordinates
 @property (nonatomic, readwrite) CGPoint position;
 - (void) setPositionX:(float)x y:(float)y;
 
 /// The height of the object in simulation units.
 //@property (nonatomic, assign) float height;
 
-
-
-
 // FIXME: don't expose these, instead aggregate properties from body & fixtures/shapes
 @property (nonatomic, readonly) b2Body* body;
 @property (nonatomic, readonly) b2Fixture* fixture;
 
+
+/// methods
+
 /**
- * Called after initialization to create the various bodies, fixtures, and shapes
- * that represent the Unit in Box2D.
+ * Called to create the various bodies, fixtures, and shapes that represent
+ * the Unit in Box2D. Normally called after initialization completes, but may
+ * be deferred if in a callback.
  */
-- (void) setupPhysics;
+- (void) setupPhysics:(b2BodyDef*)bd;
 
+- (void) applyLinearImpulse:(CGPoint)vec;
 - (void) applyLinearImpulseX:(float)xNs y:(float)yNs;
 
 
index 8ee089f..231988a 100644 (file)
@@ -1,4 +1,4 @@
-#import "qq/event/QQObservable.h"
+#import "qq/event/QQNotifier.h"
 
 @class QQGame;
 @class QQWorld;
index 63fd4cd..b706bf9 100644 (file)
@@ -1,3 +1,4 @@
+#import "Tanks.h"
 #import "game/QQGameTime.h"
 
 
@@ -6,10 +7,14 @@
  */
 @interface QQCooldown : NSObject {
 @private
+    NSString* _name;
     float _duration;
     float _elapsed;
 }
 
+/** Name of this cooldown timer. */
+@property (nonatomic, readwrite, retain) NSString* name;
+
 /** Duration of this cooldown timer (ms). */
 @property (nonatomic, readwrite, assign) float duration;
 
@@ -17,7 +22,7 @@
 @property (nonatomic, readwrite, assign) float elapsed;
 
 /** Whether Cooldown timer is ready to be activated. */
-@property (nonatomic, readwrite) BOOL ready;
+@property (nonatomic, readwrite, getter=isReady) BOOL ready;
 
 /** Percent completed (elapsed / duration), clamped [0, 1.0]. */
 @property (nonatomic, readwrite) float ratio;
@@ -25,8 +30,8 @@
 /**
  * Implies ready=YES.
  */
-- (id) initWithDuration:(float)duration;
-- (id) initWithDuration:(float)duration andReady:(BOOL)ready;
+- (id) init:(NSString*)name duration:(float)duration;
+- (id) init:(NSString*)name duration:(float)duration ready:(BOOL)ready;
 
 /**
  * Attempts to activate this cooldown, clearing the ready flag and setting elapsed to 0.
@@ -42,7 +47,7 @@
 - (BOOL) tick:(id<QQGameTime>)time;
 
 
-+ (QQCooldown*) cooldownWithDuration:(float)duration;
-+ (QQCooldown*) cooldownWithDuration:(float)duration andReady:(BOOL)ready;
++ (QQCooldown*) cooldown:(NSString*)name duration:(float)duration;
++ (QQCooldown*) cooldown:(NSString*)name duration:(float)duration ready:(BOOL)ready;
 
 @end
index 0949e5d..432d1d9 100644 (file)
@@ -5,10 +5,11 @@
 
 /// properties
 
+@synthesize name = _name;
 @synthesize duration = _duration;
 @synthesize elapsed = _elapsed;
 
-- (BOOL) ready { return (self.elapsed >= self.duration); }
+- (BOOL) isReady { return (self.elapsed >= self.duration); }
 - (void) setReady:(BOOL)newReady {
     if (newReady == self.ready)
         return;
@@ -18,7 +19,7 @@
         self.elapsed = 0;
 }
 
-- (float) ratio { return fminf(1.0f, self.elapsed / self.duration); }
+- (float) ratio { return MIN(1.0f, self.elapsed / self.duration); }
 - (void) setRatio:(float)newRatio {
     if (newRatio >= 1.0f)
         self.elapsed = self.duration;
 
 /// initializers
 
-- (id) initWithDuration:(float)duration {
-    return [self initWithDuration:duration andReady:YES];
+- (id) init:(NSString*)name duration:(float)duration {
+    return [self init:name duration:duration ready:YES];
 }
 
-- (id) initWithDuration:(float)duration andReady:(BOOL)ready {
-    if ((self = [super init])){
+- (id) init:(NSString*)name duration:(float)duration ready:(BOOL)ready {
+    if ((self = [super init])) {
+        if (duration <= 0.0f) {
+            [self autorelease];
+            [NSException raise:@"InvalidArgumentException" format:@"duration must be positive!"];
+        }
+        self.name = name;
         _duration = duration;
         _elapsed  = (ready ? _duration : 0);
     }
     return self.ready;
 }
 
+- (NSString*) description {
+    return [NSString stringWithFormat:@"<%@: %p> {name=%@, ready=%s (%.3f%% %.3f/%.3f)}",
+            [self class], self, _name, b2s(self.isReady),
+            self.ratio, _elapsed, _duration
+        ];
+}
+
+
 
 /// convenience constructors
 
-+ (QQCooldown*) cooldownWithDuration:(float)duration {
-    return [[[QQCooldown alloc] initWithDuration:duration] autorelease];
++ (QQCooldown*) cooldown:(NSString*)name duration:(float)duration {
+    return [[[QQCooldown alloc] init:name duration:duration] autorelease];
 }
 
-+ (QQCooldown*) cooldownWithDuration:(float)duration andReady:(BOOL)ready {
-    return [[[QQCooldown alloc] initWithDuration:duration andReady:ready] autorelease];
++ (QQCooldown*) cooldown:(NSString*)name duration:(float)duration ready:(BOOL)ready {
+    return [[[QQCooldown alloc] init:name duration:duration ready:ready] autorelease];
 }
 
 
index b5dc695..abc384e 100644 (file)
@@ -1,10 +1,12 @@
 #include <Box2D/Box2D.h>
 
-#import "qq/event/QQNotificationProxy.h"
+#import "Tanks.h"
+#import "qq/event/QQNotifiers.h"
 #import "game/QQThing.h"
 #import "game/QQActive.h"
 #import "game/QQPhysical.h"
 #import "game/QQDisplayable.h"
+#import "game/ability/QQCooldown.h"
 #import "game/unit/QQActorDelegate.h"
 #import "physics/QQWorld.h"
 
     b2Body* _body;
 
 @private
+    id<QQActorDelegate> _delegate;
+    
     BOOL _active;
     BOOL _dirty;
     BOOL _dead;
-    id<QQActorDelegate> _delegate;
-    NSArray* _cooldowns;
+    NSMutableDictionary* _cooldowns;
 }
 
+@property (nonatomic, readwrite, retain) id<QQActorDelegate> delegate;
+
 @property (nonatomic, readonly) QQGame*  game;
 @property (nonatomic, readonly) QQWorld* world;
-@property (nonatomic, readwrite, retain) id<QQActorDelegate> delegate;
-@property (nonatomic, readonly) BOOL dead;
+
+@property (nonatomic, readonly, getter=isDead) BOOL dead;
+@property (nonatomic, readonly, retain) NSMutableDictionary* cooldowns;
+
 
 - (id) initAtX:(float)x y:(float)y;
-- (id) initType:(b2BodyType)type atX:(float)x y:(float)y;
+- (id) initWithType:(b2BodyType)type atX:(float)x y:(float)y;
+- (id) initWithBodyDef:(b2BodyDef*)bd;
 
 - (void) destroy;
 
index 8421992..0237ef0 100644 (file)
@@ -1,5 +1,4 @@
 #import "QQActor.h"
-#import "render/QQSparrowExtensions.h"
 #import "game/QQGame.h"
 
 
@@ -7,34 +6,27 @@
 
 /// properties
 
-@dynamic shape;
-
-@synthesize active    = _active;
-@synthesize dirty     = _dirty;
-@synthesize dead      = _dead;
-@synthesize delegate  = _delegate;
-@synthesize cooldowns = _cooldowns;
-
-
 - (QQGame*)  game  { return QQGame.current; }
 - (QQWorld*) world { return self.game.world; }
 
 - (b2Body*) body { return _body; }
 - (b2Fixture*) fixture { return nil; }
 
-- (id) implicitNotificationSender { return self; }
-- (void) setImplicitNotificationSender:(id)sender {}
 
-- (id<QQObservableNotifier>) proxiedNotifier { return self.game; }
-- (void) setProxiedNotifier:(id<QQObservableNotifier>)notifier {}
+@synthesize delegate  = _delegate;
+@synthesize cooldowns = _cooldowns;
 
+@synthesize dead      = _dead;
+@synthesize dirty     = _dirty;
+@synthesize active    = _active;
+
+- (BOOL) isSleeping { return _active; }
+- (void) setSleeping:(BOOL)v { _active = v; }
 
 - (float) x             { return self.body->GetPosition().x;    }
 - (void) setX:(float)x  { [self setPositionX:x y:self.y];       }
-
 - (float) y             { return self.body->GetPosition().y;    }
 - (void) setY:(float)y  { [self setPositionX:self.x y:y];       }
-
 - (CGPoint) position {
     b2Vec2 pos = self.body->GetPosition();
     return CGPointMake(pos.x, pos.y);
 - (void) setPositionX:(float)x y:(float)y {
     self.body->SetTransform(b2Vec2(x,y), self.body->GetAngle());
 }
-
 - (float) rotation { return self.body->GetAngle(); }
 - (void) setRotation:(float)r { self.body->SetTransform(self.body->GetPosition(), r); }
 
 
+@dynamic shape;
+
+// sync sparrow with box2d
+
 - (void) updateShapeX:(float)x y:(float)y {
     float px = self.world.scale;
     [self.shape setCenterX:x*px y:y*px];
 }
-
 - (void) updateShapeX:(float)x y:(float)y rotation:(float)r {
     [self updateShapeX:x y:y];
     self.shape.rotation = r;
 }
-
 - (void) updateShape {
     b2Transform trans = self.body->GetTransform();
     [self updateShapeX:trans.position.x y:trans.position.y rotation:trans.GetAngle()];
 
 /// initializers
 
+- (id) init {
+    return [self initAtX:0 y:0];
+}
+
 - (id) initAtX:(float)x y:(float)y {
-    return [self initType:b2_dynamicBody atX:x y:y];
+    return [self initWithType:b2_dynamicBody atX:x y:y];
 }
 
-- (id) initType:(b2BodyType)type atX:(float)x y:(float)y {
+- (id) initWithType:(b2BodyType)type atX:(float)x y:(float)y {
+    b2BodyDef bd;
+    bd.type = type;
+    bd.position = b2Vec2(x,y);
+    bd.userData = self;
+    return [self initWithBodyDef:&bd];
+}
+
+- (id) initWithBodyDef:(b2BodyDef*)bd {
     if ((self = [super init])) {
         _active = YES;
         _dead = NO;
+        
+        self.implicitSender = self;
         self.proxiedNotifier = self.game;
-        self.cooldowns = [NSArray array];
-        [self.game addActor:self];
         
-        b2BodyDef bd;
-        bd.type = type;
-        bd.position = b2Vec2(x, y);
-        bd.userData = self;
-        _body = self.world.world->CreateBody(&bd);
+        _cooldowns = [[NSMutableDictionary alloc] initWithCapacity:2];
+        [self setupPhysics:bd];
+        [self.game addActor:self];
         
         if ([self respondsToSelector:@selector(onCollideBegin:)])
             [self addObserver:self selector:@selector(onCollideBegin:) name:QQ_EVENT_CONTACT_BEGIN];
+        if ([self respondsToSelector:@selector(onCollideEnd:)])
+            [self addObserver:self selector:@selector(onCollideEnd:) name:QQ_EVENT_CONTACT_END];
     }
     return self;
 }
 
 
 
+/// subclassing
+
+- (void) setupShape {
+    // override in subclass
+}
+
+// TODO: you can't create bodies during callbacks
+/// override but call super!
+- (void) setupPhysics:(b2BodyDef*)bd {
+    if (!_body) {
+        _body = self.world.world->CreateBody(bd);
+    }
+}
+
+- (void) act {
+    // override in subclass
+}
+
+
+
 /// methods
 
+- (void) addCooldown:(QQCooldown*)cool {
+    [self.cooldowns setObject:cool forKey:cool.name];
+}
+
 - (void) destroy {
-    if (self.dead) return;
+    if (self.isDead) return;
     
     _dead = YES;
     self.shape = nil;
 }
 
 - (void) tick {
-    if (self.dead) return;
+    if (self.isDead) return;
     
-    [self.cooldowns makeObjectsPerformSelector:@selector(tick:) withObject:self.game.time];
+    [self tickCooldowns];
     if (self.isActive)
         [self act];
 }
 
-- (void) act {}
-
-- (SPDisplayObject*) setupShape {
-    return self.shape;
+- (void) tickCooldowns {
+    [self.cooldowns makeObjectsPerformSelector:@selector(tick:) withObject:self.game.time];
 }
 
 - (void) draw {
-    if (self.dead) return;
-    
+    if (self.isDead) return;
+    if (!self.shape) [self setupShape];
     [self updateShape];
 }
 
-- (void) setupPhysics {}
-
-
+- (void) applyLinearImpulse:(CGPoint)pt {
+    [self applyLinearImpulseX:pt.x y:pt.y];
+}
 - (void) applyLinearImpulseX:(float)xNs y:(float)yNs {
     self.body->ApplyLinearImpulse(b2Vec2(xNs, yNs), self.body->GetPosition());
 }
     b2Transform trans = self.body->GetTransform();
     b2Vec2 pos = trans.position;
     //b2Vec2 v = actor.body->GetLinearVelocity();
-    SPDisplayObject* s = self.shape;
-    return [NSString stringWithFormat:@"[%@ box2d=[ (%f,%f) rotation=%f], shape=%@]",
-        [super description], pos.x,pos.y, trans.GetAngle(), s];
+    return [NSString stringWithFormat:@"\v\t<%@ %p> {\v\t\tbox2d=[ (%f,%f) rotation=%f], \v\t\tshape=%@, \v\t\tcooldowns=%@}",
+        [self class], self, pos.x,pos.y, trans.GetAngle(), self.shape, self.cooldowns];
 }
 
 
index b4a6241..2d11478 100644 (file)
@@ -1,3 +1,4 @@
+#import "Tanks.h"
 #import "game/unit/QQUnit.h"
 
 
index 99b3f42..ea998f7 100644 (file)
@@ -31,8 +31,8 @@
 }
 
 - (void) onCollideBegin:(QQContactNotification*)msg {
-    QQActor* other = (msg.actorA && (msg.actorA != self) ? msg.actorA : 
-                      (msg.actorB && (msg.actorB != self) ? msg.actorB : nil));
+    QQActor* other =  ((msg.actorA && (msg.actorA != self)) ? msg.actorA : 
+                      ((msg.actorB && (msg.actorB != self)) ? msg.actorB : nil));
     if (other) {
         NSLog(@"BOOM! %@", msg);
         [other destroy];
index c4c5971..5850a26 100644 (file)
@@ -1,10 +1,8 @@
 #import "game/unit/QQUnit.h"
-#import "game/ability/QQCooldown.h"
 
 @interface QQTank : QQUnit {
-    QQCooldown* _coolAtk;
+    
 }
 
-@property (nonatomic, readonly, retain) QQCooldown* coolAtk;
 
 @end
index edd130a..edacf1a 100644 (file)
@@ -6,7 +6,6 @@
 
 // private interface
 @interface QQTank ()
-@property (nonatomic, readwrite, retain) QQCooldown* coolAtk;
 - (void) onTouch:(SPTouchEvent*)event;
 @end
 
 
 @implementation QQTank
 
-@synthesize coolAtk = _coolAtk;
 
 - (id) initAtX:(float)x y:(float)y withShape:(SPDisplayObject*)shape {
     if ((self = [super initAtX:x y:y withShape:shape])){
-        self.coolAtk = [QQCooldown cooldownWithDuration:0.5f];
-        self.cooldowns = [self.cooldowns arrayByAddingObject:self.coolAtk];
         [self.game.stage addEventListener:@selector(onTouch:) atObject:self forType:SP_EVENT_TYPE_TOUCH];
     }
     return self;
 
 - (void) dealloc {
     [self.game.stage removeEventListener:@selector(onTouch:) atObject:self forType:SP_EVENT_TYPE_TOUCH];
-    [_coolAtk release];
     [super dealloc];
 }
 
 
 - (void) onTouch:(SPTouchEvent*)event {
     SPTouch* touch = [[event touchesWithTarget:(SPDisplayObject*)self.game.stage] anyObject];
-    if (touch && [self.coolAtk activate]) {
+    if (touch && [[self.cooldowns objectForKey:ATTACK_COOLDOWN_NAME] activate]) {
         // Touch's normal vector in local coords (rel unit origin)
         SPPoint* normVec = [[[touch locationInSpace:self.shape.parent] subtractPoint:self.shape.position] normalize];
         
     }
 }
 
-- (void) _moveOnTouch:(SPTouchEvent*)event {
-    SPTouch* touch = [[event touchesWithTarget:self.shape.parent] anyObject];
-    if (touch) {
-        SPPoint* touchPosition = [touch locationInSpace:self.shape.parent];
-        float x = self.shape.x = touchPosition.x - self.shape.width / 2.0f;
-        float y = self.shape.y = touchPosition.y - self.shape.height / 2.0f;
-        
-        float px = self.world.scale;
-        [self setPositionX:x/px y:y/px];
-        // self.body->SetTransform(b2Vec2(x/px, y/px), self.body->GetAngle());
-    }
-}
 
 @end
\ No newline at end of file
index 6fdee22..ce5bf9e 100644 (file)
@@ -1,10 +1,11 @@
 #include <Box2D/Box2D.h>
 #import "Sparrow.h"
+#import "render/QQSparrowExtensions.h"
 
-#import "physics/QQWorld.h"
+#import "game/ability/QQCooldown.h"
 #import "game/unit/QQActor.h"
 #import "game/unit/QQActorDelegate.h"
-#import "render/QQSparrowExtensions.h"
+
 
 
 @interface QQUnit : QQActor {
 }
 
 /// properties
+
 @property (nonatomic, readonly) BOOL canAttack;
+@property (nonatomic, readwrite, assign) QQCooldown* attackCooldown;
+
 - (void) setShapeFromFile:(NSString*)filename;
 
+
 /// initializers
 - (id) initAtX:(float)x y:(float)y width:(float)w height:(float)h color:(uint)color;
 - (id) initAtX:(float)x y:(float)y withShape:(SPDisplayObject*)shape;
index 0959cfb..557125d 100644 (file)
@@ -1,9 +1,10 @@
 #include <Box2D/Box2D.h>
 #import "Sparrow.h"
+#import "render/QQSparrowExtensions.h"
 
 #import "game/unit/QQUnit.h"
 #import "game/QQGame.h"
-#import "render/QQSparrowExtensions.h"
+#import "game/unit/QQBullet.h"
 
 
 
@@ -20,7 +21,9 @@
 - (float) shapeCenterY {            return self.shape.registrationY; }
 - (void) setShapeCenterY:(float)y { self.shape.registrationY = y; }
 
-- (BOOL) canAttack { return NO; }
+- (QQCooldown*) attackCooldown { return [self.cooldowns objectForKey:ATTACK_COOLDOWN_NAME]; }
+- (void) setAttackCooldown:(QQCooldown*)newAttackCooldown { [self.cooldowns setObject:newAttackCooldown forKey:ATTACK_COOLDOWN_NAME]; }
+- (BOOL) canAttack { return self.attackCooldown.isReady; }
 
 
 /// initializers
@@ -36,6 +39,7 @@
 
 - (id) initAtX:(float)x y:(float)y withShape:(SPDisplayObject*)shape {
     if ((self = [super initAtX:x y:y])) {
+        [self addCooldown:[QQCooldown cooldown:ATTACK_COOLDOWN_NAME duration:0.5f]];
         self.shape = shape;
         
         float dblpx = 2*self.world.scale;
     [self attackTowardX:pt.x y:pt.y];
 }
 - (void) attackTowardX:(float)x y:(float)y {
+    SPPoint* pos = [SPPoint pointFromCGPoint:self.position];
+    SPPoint* target = [SPPoint pointWithX:x y:y];
+    
+    // Touch's normal vector in local coords (rel unit origin)
+    SPPoint* normVec = [[target subtractPoint:pos] normalize];
+    
+    // Bullet starting position
+    float offset = 1.5f + MAX(self.shape.width, self.shape.height) * 1.41421356237f; // bullet_radius + tank_diagonal_length
+    SPPoint* start = [pos addPoint:[normVec scaleBy:offset]];
+    QQBullet* bullet = [[[QQBullet alloc] init:self x:start.x y:start.y] autorelease];
     
+    // Bullet impulse vector
+    SPPoint* imp = [normVec scaleBy:50];
+    [bullet applyLinearImpulseX:imp.x y:imp.y];
+    NSLog(@"[%@ pos:(%f,%f) impulse:(%f,%f)]", bullet, bullet.x,bullet.y, imp.x,imp.y);
 }
 
 
diff --git a/src/qq/Collections+FP.h b/src/qq/Collections+FP.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/qq/Collections+FP.mm b/src/qq/Collections+FP.mm
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/qq/NSArray+QQExtensions.h b/src/qq/NSArray+QQExtensions.h
new file mode 100644 (file)
index 0000000..9a23277
--- /dev/null
@@ -0,0 +1,6 @@
+
+@interface NSArray (QQExtensions)
+
+- (void) makeObjectsPerformSelector:(SEL)aSelector withObject:(id)arg1 withObject:(id)arg2;
+
+@end
diff --git a/src/qq/NSArray+QQExtensions.mm b/src/qq/NSArray+QQExtensions.mm
new file mode 100644 (file)
index 0000000..963735a
--- /dev/null
@@ -0,0 +1,12 @@
+#import "NSArray+QQExtensions.h"
+
+
+@implementation NSArray (QQExtensions)
+
+- (void) makeObjectsPerformSelector:(SEL)aSelector withObject:(id)arg1 withObject:(id)arg2 {
+    for (id value in self)
+        [value performSelector:aSelector withObject:arg1 withObject:arg2];
+}
+
+
+@end
diff --git a/src/qq/NSDictionary+QQExtensions.h b/src/qq/NSDictionary+QQExtensions.h
new file mode 100644 (file)
index 0000000..3a47227
--- /dev/null
@@ -0,0 +1,8 @@
+
+@interface NSDictionary (QQExtensions)
+
+- (void) makeObjectsPerformSelector:(SEL)aSelector;
+- (void) makeObjectsPerformSelector:(SEL)aSelector withObject:(id)arg1;
+- (void) makeObjectsPerformSelector:(SEL)aSelector withObject:(id)arg1 withObject:(id)arg2;
+
+@end
diff --git a/src/qq/NSDictionary+QQExtensions.mm b/src/qq/NSDictionary+QQExtensions.mm
new file mode 100644 (file)
index 0000000..91dd463
--- /dev/null
@@ -0,0 +1,27 @@
+#import "NSDictionary+QQExtensions.h"
+
+
+@implementation NSDictionary (QQExtensions)
+
+- (void) makeObjectsPerformSelector:(SEL)aSelector {
+    for (NSString* key in self) {
+        id value = [self objectForKey:key];
+        [value performSelector:aSelector];
+    }
+}
+
+- (void) makeObjectsPerformSelector:(SEL)aSelector withObject:(id)arg1 {
+    for (NSString* key in self) {
+        id value = [self objectForKey:key];
+        [value performSelector:aSelector withObject:arg1];
+    }
+}
+
+- (void) makeObjectsPerformSelector:(SEL)aSelector withObject:(id)arg1 withObject:(id)arg2 {
+    for (NSString* key in self) {
+        id value = [self objectForKey:key];
+        [value performSelector:aSelector withObject:arg1 withObject:arg2];
+    }
+}
+
+@end
index 80780dd..51dbc01 100644 (file)
@@ -4,5 +4,6 @@
 - (NSSet*) setByRemovingObject:(id)object;
 - (NSSet*) setByRemovingArray:(NSArray*)objects;
 
+- (void) makeObjectsPerformSelector:(SEL)aSelector withObject:(id)arg1 withObject:(id)arg2;
 
 @end
index 6b4d74c..e04a818 100644 (file)
@@ -1,3 +1,5 @@
+#import "NSSet+QQExtensions.h"
+
 @implementation NSSet (QQExtensions)
 
 - (NSSet*) setByRemovingObject:(id)object {
@@ -12,4 +14,9 @@
     }];
 }
 
+- (void) makeObjectsPerformSelector:(SEL)aSelector withObject:(id)arg1 withObject:(id)arg2 {
+    for (id value in self)
+        [value performSelector:aSelector withObject:arg1 withObject:arg2];
+}
+
 @end
index 661d909..520bb35 100644 (file)
@@ -1,16 +1,18 @@
 #import "qq/event/QQNotifier.h"
 
-@interface QQNotificationCenter : NSNotificationCenter <QQObservableNotifier> {
+@interface QQNotificationCenter : NSNotificationCenter <QQBubblingNotifier> {
 @private
     id _implicitNotificationSender;
+    id<QQObservableNotifier> _parentNotifier;
 }
 /** Object used for implicit sender when adding or removing observers. */
-@property (nonatomic, readwrite, retain) id implicitNotificationSender;
+@property (nonatomic, readwrite, assign) id implicitNotificationSender;
 
 /** Initialize with self as implicit sender. */
 - (id) init;
 
 /** Returns a center with given implicit target. A nil target will subscript observers to all objects. */
 + (QQNotificationCenter*) notifierWithTarget:(id)target;
++ (QQNotificationCenter*) notifierWithTarget:(id)target andParent:(id<QQObservableNotifier>)parent;
 
 @end
index 64e5703..da2ce8a 100644 (file)
@@ -6,16 +6,19 @@
 - (id) init {
     if ((self = [super init])){
         _implicitNotificationSender = self;
+        _parentNotifier = nil;
     }
     return self;
 }
 
 - (void) dealloc {
-    [_implicitNotificationSender release];
+    self.implicitNotificationSender = nil;
+    self.parentNotifier = nil;
     [super dealloc];
 }
 
 @synthesize implicitNotificationSender = _implicitNotificationSender;
+@synthesize parentNotifier = _parentNotifier;
 
 
 /// observable
@@ -33,6 +36,7 @@
 }
 
 // Send a notification from this object
+
 - (void) postNotificationName:(NSString*)name {
     [self postNotificationName:name object:self.implicitNotificationSender];
 }
     [super removeObserver:observer];
 }
 
+- (void) postNotification:(NSNotification*)msg {
+    [super postNotification:msg];
+    [self.parentNotifier postNotification:msg];
+}
+
 
 /// NSNotificationCenter (superclass) provides:
 
 
 
 + (QQNotificationCenter*) notifierWithTarget:(id)target {
+    return [QQNotificationCenter notifierWithTarget:target andParent:nil];
+}
++ (QQNotificationCenter*) notifierWithTarget:(id)target andParent:(id<QQObservableNotifier>)parent {
     QQNotificationCenter* notifier = [[[QQNotificationCenter alloc] init] autorelease];
     notifier.implicitNotificationSender = target;
+    notifier.parentNotifier = parent;
     return notifier;
 }
 
index 0030b68..31ad268 100644 (file)
@@ -6,11 +6,15 @@
 @interface QQNotificationProxy : NSObject <QQObservableNotifier> {
 @private
     id<QQObservableNotifier> _proxiedNotifier;
-    id _implicitNotificationSender;
+    id<QQObservableNotifier> _parentNotifier;
+    id _implicitSender;
 }
 
+@property (nonatomic, readwrite, assign) id implicitSender;
+@property (nonatomic, readwrite, retain) id<QQObservableNotifier> parentNotifier;
 @property (nonatomic, readwrite, retain) id<QQObservableNotifier> proxiedNotifier;
 
 - (id) initWithNotifier:(id<QQObservableNotifier>)notifier;
+- (id) initWithNotifier:(id<QQObservableNotifier>)notifier andParent:(id<QQObservableNotifier>)parent;
 
 @end
index 3d2c3ee..5a2efd0 100644 (file)
@@ -1,44 +1,52 @@
 #import "qq/event/QQNotificationProxy.h"
+#import "qq/event/QQNotification.h"
 
 
 @implementation QQNotificationProxy
 
 @synthesize proxiedNotifier = _proxiedNotifier;
-@synthesize implicitNotificationSender = _implicitNotificationSender;
+@synthesize parentNotifier = _parentNotifier;
+@synthesize implicitSender = _implicitSender;
 
 
 - (id) initWithNotifier:(id<QQObservableNotifier>)notifier {
+    return [self initWithNotifier:notifier andParent:nil];
+}
+
+- (id) initWithNotifier:(id<QQObservableNotifier>)notifier andParent:(id<QQObservableNotifier>)parent {
     if ((self = [super init])){
         self.proxiedNotifier = notifier;
+        self.parentNotifier = parent;
     }
     return self;
 }
 
 - (void) dealloc {
     self.proxiedNotifier = nil;
+    self.parentNotifier = nil;
     [super dealloc];
 }
 
 /// observable
 
 - (void) addObserver:(id)observer selector:(SEL)selector name:(NSString*)event {
-    [self addObserver:observer selector:selector name:event object:self.implicitNotificationSender];
+    [self addObserver:observer selector:selector name:event object:self.implicitSender];
 }
 
 // Remove a listener from this object
 - (void) removeObserver:(id)observer {
-    [self removeObserver:observer name:nil object:self.implicitNotificationSender];
+    [self removeObserver:observer name:nil object:self.implicitSender];
 }
 - (void) removeObserver:(id)observer name:(NSString*)event {
-    [self removeObserver:observer name:event object:self.implicitNotificationSender];
+    [self removeObserver:observer name:event object:self.implicitSender];
 }
 
 // Send a notification from this object
 - (void) postNotificationName:(NSString*)name {
-    [self postNotificationName:name object:self.implicitNotificationSender];
+    [self postNotificationName:name object:self.implicitSender userInfo:nil];
 }
 - (void) postNotificationName:(NSString*)name userInfo:(NSDictionary*)info {
-    [self postNotificationName:name object:self.implicitNotificationSender userInfo:info];
+    [self postNotificationName:name object:self.implicitSender userInfo:info];
 }
 
 
 
 - (void) postNotification:(NSNotification*)msg {
     [self.proxiedNotifier postNotification:msg];
+    [self.parentNotifier postNotification:msg];
 }
 - (void) postNotificationName:(NSString*)name object:(id)sender {
-    [self.proxiedNotifier postNotificationName:name object:sender];
+    [self postNotificationName:name object:sender userInfo:nil];
 }
 - (void) postNotificationName:(NSString*)name object:(id)sender userInfo:(NSDictionary*)info {
-    [self.proxiedNotifier postNotificationName:name object:sender userInfo:info];
+    QQNotification* msg = [QQNotification notification:name object:sender userInfo:info];
+    [self postNotification:msg];
 }
 
 
index 445d501..0651091 100644 (file)
 - (void) postNotificationName:(NSString*)name object:(id)sender;
 - (void) postNotificationName:(NSString*)name object:(id)sender userInfo:(NSDictionary*)info;
 
-
 @end
 
+
 @protocol QQObservableNotifier <QQObservable, QQNotifier>
+@end
+
+
+@protocol QQBubblingNotifier <QQObservableNotifier>
+
+@property (nonatomic, readwrite, retain) id<QQObservableNotifier> parentNotifier;
+
+@end
 
-@end
\ No newline at end of file
index 8eeab9a..55b852c 100644 (file)
@@ -4,43 +4,3 @@
 #import "qq/event/QQNotificationCenter.h"
 #import "qq/event/QQNotificationProxy.h"
 
-
-
-/**
- * As a QQNotificationProxy, but via encapsulation.
- */
-#define qqNotifierProxy(__target, __notifier)                                                      \
-- (void) addObserver:(id)observer selector:(SEL)selector name:(NSString*)event {                   \
-    [self addObserver:observer selector:selector name:event object:__target];                      \
-}                                                                                                  \
-- (void) removeObserver:(id)observer {                                                             \
-    [self removeObserver:observer name:nil object:__target];                                       \
-}                                                                                                  \
-- (void) removeObserver:(id)observer name:(NSString*)event {                                       \
-    [self removeObserver:observer name:event object:__target];                                     \
-}                                                                                                  \
-- (void) postNotificationName:(NSString*)name {                                                    \
-    [self postNotificationName:name object:__target];                                              \
-}                                                                                                  \
-- (void) postNotificationName:(NSString*)name userInfo:(NSDictionary*)info {                       \
-    [self postNotificationName:name object:__target userInfo:info];                                \
-}                                                                                                  \
-- (void) addObserver:(id)observer selector:(SEL)selector name:(NSString*)event object:(id)sender { \
-    [__notifier addObserver:observer selector:selector name:event object:sender];                  \
-}                                                                                                  \
-- (void) removeObserver:(id)observer name:(NSString*)event object:(id)sender {                     \
-    [__notifier removeObserver:observer name:event object:sender];                                 \
-}                                                                                                  \
-- (void) removeObservers:(id)observer {                                                            \
-    [__notifier removeObserver:observer];                                                          \
-}                                                                                                  \
-- (void) postNotification:(NSNotification*)msg {                                                   \
-    [__notifier postNotification:msg];                                                             \
-}                                                                                                  \
-- (void) postNotificationName:(NSString*)name object:(id)sender {                                  \
-    [__notifier postNotificationName:name object:sender];                                          \
-}                                                                                                  \
-- (void) postNotificationName:(NSString*)name object:(id)sender userInfo:(NSDictionary*)info {     \
-    [__notifier postNotificationName:name object:sender userInfo:info];                            \
-}
-
index 8814775..5f56475 100644 (file)
@@ -5,8 +5,6 @@
  */
 @protocol QQObservable
 
-@property (nonatomic, readwrite, retain) id implicitNotificationSender;
-
 //- (void) observe:(NSString*)event notify:(id)observer selector:(SEL)selector;
 
 /** Adds an observer of this object. */
index 8bd63cc..78525df 100644 (file)
                499F65E9139CBCBA00309DE4 /* QQUnit.h in Headers */ = {isa = PBXBuildFile; fileRef = 499F65DF139CBCBA00309DE4 /* QQUnit.h */; };
                499F65EA139CBCBA00309DE4 /* QQUnit.mm in Sources */ = {isa = PBXBuildFile; fileRef = 499F65E0139CBCBA00309DE4 /* QQUnit.mm */; };
                499F65EC139CBCC000309DE4 /* QQGameTime.h in Headers */ = {isa = PBXBuildFile; fileRef = 499F65EB139CBCC000309DE4 /* QQGameTime.h */; };
+               499F65FD139CFD3800309DE4 /* NSArray+QQExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = 499F65F9139CFD3700309DE4 /* NSArray+QQExtensions.h */; };
+               499F65FE139CFD3800309DE4 /* NSArray+QQExtensions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 499F65FA139CFD3700309DE4 /* NSArray+QQExtensions.mm */; };
+               499F65FF139CFD3800309DE4 /* NSDictionary+QQExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = 499F65FB139CFD3700309DE4 /* NSDictionary+QQExtensions.h */; };
+               499F6600139CFD3800309DE4 /* NSDictionary+QQExtensions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 499F65FC139CFD3800309DE4 /* NSDictionary+QQExtensions.mm */; };
                49D8645D1392DB2800BC341C /* QQShape.h in Headers */ = {isa = PBXBuildFile; fileRef = 49D8645B1392DB2800BC341C /* QQShape.h */; };
                49D8645E1392DB2800BC341C /* QQShape.mm in Sources */ = {isa = PBXBuildFile; fileRef = 49D8645C1392DB2800BC341C /* QQShape.mm */; };
                49DA67D4137847A7004841E9 /* QQWorld.h in Headers */ = {isa = PBXBuildFile; fileRef = 49DA67D2137847A7004841E9 /* QQWorld.h */; };
                499F65DF139CBCBA00309DE4 /* QQUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QQUnit.h; sourceTree = "<group>"; };
                499F65E0139CBCBA00309DE4 /* QQUnit.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = QQUnit.mm; sourceTree = "<group>"; };
                499F65EB139CBCC000309DE4 /* QQGameTime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QQGameTime.h; sourceTree = "<group>"; };
+               499F65F9139CFD3700309DE4 /* NSArray+QQExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+QQExtensions.h"; sourceTree = "<group>"; };
+               499F65FA139CFD3700309DE4 /* NSArray+QQExtensions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSArray+QQExtensions.mm"; sourceTree = "<group>"; };
+               499F65FB139CFD3700309DE4 /* NSDictionary+QQExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+QQExtensions.h"; sourceTree = "<group>"; };
+               499F65FC139CFD3800309DE4 /* NSDictionary+QQExtensions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSDictionary+QQExtensions.mm"; sourceTree = "<group>"; };
                49D8645B1392DB2800BC341C /* QQShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QQShape.h; sourceTree = "<group>"; };
                49D8645C1392DB2800BC341C /* QQShape.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = QQShape.mm; sourceTree = "<group>"; };
                49DA67D2137847A7004841E9 /* QQWorld.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QQWorld.h; sourceTree = "<group>"; };
                        isa = PBXGroup;
                        children = (
                                499F65BF139CBC0C00309DE4 /* event */,
+                               499F65F9139CFD3700309DE4 /* NSArray+QQExtensions.h */,
+                               499F65FA139CFD3700309DE4 /* NSArray+QQExtensions.mm */,
+                               499F65FB139CFD3700309DE4 /* NSDictionary+QQExtensions.h */,
+                               499F65FC139CFD3800309DE4 /* NSDictionary+QQExtensions.mm */,
                                49E3C5D0139A73E700A3958A /* NSSet+QQExtensions.h */,
                                49E3C5D1139A73E700A3958A /* NSSet+QQExtensions.mm */,
                        );
                499F65D6139CBCBA00309DE4 /* unit */ = {
                        isa = PBXGroup;
                        children = (
+                               499F65DA139CBCBA00309DE4 /* QQActors.h */,
+                               499F65D9139CBCBA00309DE4 /* QQActorDelegate.h */,
                                499F65D7139CBCBA00309DE4 /* QQActor.h */,
                                499F65D8139CBCBA00309DE4 /* QQActor.mm */,
-                               499F65D9139CBCBA00309DE4 /* QQActorDelegate.h */,
-                               499F65DA139CBCBA00309DE4 /* QQActors.h */,
                                499F65DB139CBCBA00309DE4 /* QQBullet.h */,
                                499F65DC139CBCBA00309DE4 /* QQBullet.mm */,
                                499F65DD139CBCBA00309DE4 /* QQTank.h */,
                                499F65E7139CBCBA00309DE4 /* QQTank.h in Headers */,
                                499F65E9139CBCBA00309DE4 /* QQUnit.h in Headers */,
                                499F65EC139CBCC000309DE4 /* QQGameTime.h in Headers */,
+                               499F65FD139CFD3800309DE4 /* NSArray+QQExtensions.h in Headers */,
+                               499F65FF139CFD3800309DE4 /* NSDictionary+QQExtensions.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                499F65E6139CBCBA00309DE4 /* QQBullet.mm in Sources */,
                                499F65E8139CBCBA00309DE4 /* QQTank.mm in Sources */,
                                499F65EA139CBCBA00309DE4 /* QQUnit.mm in Sources */,
+                               499F65FE139CFD3800309DE4 /* NSArray+QQExtensions.mm in Sources */,
+                               499F6600139CFD3800309DE4 /* NSDictionary+QQExtensions.mm in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };