#ifndef TANKS_H
#define TANKS_H
-#define TANKS_DEBUG_LOG 1
+
+#define TANKS_DEBUG_LOG 0
+
#endif
+#import "TanksMacros.h"
#import "render/QQSparrowExtensions.h"
#ifndef TANKS_MACROS_H
#define TANKS_MACROS_H
-
+#define qqBoolToString(__val) ((__val)?("YES"):("NO"))
#endif
\ No newline at end of file
+#import "game/QQGameTime.h"
#import "game/QQThing.h"
/**
@property (nonatomic, readwrite, getter=isActive) BOOL active;
// @property (nonatomic, readwrite, getter=isSleeping) BOOL sleeping;
+@property (nonatomic, readwrite, retain) NSArray* cooldowns;
-- (void) tick:(float)elapsed;
+- (void) tick;
- (void) act;
@end
\ No newline at end of file
#import "Sparrow.h"
+#import "qq/QQNotificationCenter.h"
#import "physics/QQWorld.h"
#import "physics/debug/QQPhysicsDebugView.h"
+#import "game/QQGameTime.h"
#import "game/actor/QQActor.h"
#import "game/map/QQLevel.h"
-@interface QQGame : SPStage {
-
+@interface QQGame : QQNotificationCenter <QQGameTime> {
@private
- QQWorld* _world;
-
- QQLevel* _level;
- SPSprite* _root;
+ float _now;
+ float _elapsed;
+ long _ticks;
+ long _realtime;
- NSMutableSet* _actors;
- NSMutableSet* _awake;
- NSMutableSet* _units;
- NSMutableSet* _bullets;
+ BOOL _running;
+ BOOL _debugDrawingEnabled;
+ QQWorld* _world;
QQPhysicsDebugView* _debugView;
- BOOL _debugDrawingEnabled;
- long _ticks;
- BOOL _running;
+ SPStage* _stage;
+ SPSprite* _root;
+ QQLevel* _level;
+
+ NSSet* _actors;
+ NSSet* _awake;
+ NSSet* _units;
+ NSSet* _bullets;
}
-@property (nonatomic, readonly) QQWorld* world;
-@property (nonatomic, readonly) QQLevel* level;
-@property (nonatomic, readonly) NSSet* actors;
+@property (nonatomic, readonly) id<QQGameTime> time;
+@property (nonatomic, readonly) float now;
+@property (nonatomic, readonly) float elapsed;
+@property (nonatomic, readonly) long ticks;
-@property (nonatomic, readonly, assign) long ticks;
@property (nonatomic, readonly, getter=isPaused) BOOL paused;
@property (nonatomic, readwrite, assign) BOOL debugDrawingEnabled;
-- (void) start;
-- (void) stop;
+@property (nonatomic, readonly) SPStage* stage;
+@property (nonatomic, readonly) SPDisplayObjectContainer* root;
+@property (nonatomic, readonly) QQLevel* level;
+
+@property (nonatomic, readonly) QQWorld* world;
+
+@property (nonatomic, readonly, retain) NSSet* actors;
-- (void) tick:(float)elapsed;
+- (void) tick;
- (QQGame*) addActor:(QQActor*)actor;
+// - (QQGame*) addActorAndShape:(QQActor*)actor;
- (QQGame*) removeActor:(QQActor*)actor;
+- (QQGame*) destroyActor:(QQActor*)actor;
+
+- (void) start;
+- (void) stop;
+ (QQGame*) current;
#import <Box2D/Box2D.h>
+#import "Tanks.h"
+#import "qq/NSSet+QQExtensions.h"
#import "game/QQGame.h"
#import "game/actor/QQActors.h"
#import "physics/event/QQContactNotification.h"
-
static QQGame* _CurrentGame = NULL;
@interface QQGame ()
+@property (nonatomic, readwrite, retain) NSSet* actors;
+
- (void) onEnterFrame:(SPEnterFrameEvent*)event;
- (void) onCollide:(QQContactNotification*)msg;
@end
@implementation QQGame
-
- (id) init {
if (_CurrentGame) {
[self release];
#ifdef DEBUG
- [NSException raise:@"TooManyGames" format:@"cannot instantiate more than one QQGame at a time!"];
+ [NSException raise:@"WTFTooManyGames" format:@"cannot instantiate more than one QQGame at a time!"];
#else
return _CurrentGame;
#endif
if ( (self = [super init]) ){
_CurrentGame = self;
+ _now = 0;
_ticks = 0;
+ _elapsed = 0;
_running = NO;
+ _stage = [[SPStage alloc] init];
+ _root = [[SPSprite sprite] retain];
+ [_stage addChild:_root];
+
_world = [[QQWorld alloc] init];
- [_world addObserver:self selector:@selector(onCollide:) name:QQ_EVENT_CONTACT_BEGIN];
- [_world addObserver:self selector:@selector(onCollide:) name:QQ_EVENT_CONTACT_END];
+ _world.proxiedNotifier = self;
+ [_world addObserver:self selector:@selector(onCollide:) name:QQ_EVENT_CONTACT_BEGIN object:nil];
+ [_world addObserver:self selector:@selector(onCollide:) name:QQ_EVENT_CONTACT_END object:nil];
- _root = [SPSprite sprite];
- [self addChild:_root];
_level = [[QQLevel alloc] init];
[_root addChild:_level];
_debugView = [[QQPhysicsDebugView alloc] initWithWorld:_world];
[_root addChild:_debugView];
self.debugDrawingEnabled = YES;
- _actors = [[NSMutableSet alloc] initWithCapacity:10];
- _awake = [[NSMutableSet alloc] initWithCapacity:10];
- _units = [[NSMutableSet alloc] initWithCapacity:10];
- _bullets = [[NSMutableSet alloc] initWithCapacity:10];
+ _actors = [[NSSet alloc] init];
+ _awake = [[NSSet alloc] init];
+ _units = [[NSSet alloc] init];
+ _bullets = [[NSSet alloc] init];
CGSize frame = [UIScreen mainScreen].applicationFrame.size;
float wMax = frame.width / _world.scale;
float hMax = frame.height / _world.scale;
[[[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];
+
+ [_stage addEventListener:@selector(logEvent:) atObject:self forType:SP_EVENT_TYPE_ANY];
}
return self;
}
- (void) dealloc {
- [self removeEventListener:@selector(onEnterFrame:) atObject:self forType:SP_EVENT_TYPE_ENTER_FRAME];
- [self removeAllChildren];
+ [_stage removeEventListener:@selector(logEvent:) atObject:self forType:SP_EVENT_TYPE_ANY];
+ [_stage removeEventListener:@selector(onEnterFrame:) atObject:self forType:SP_EVENT_TYPE_ENTER_FRAME];
- NSMutableSet* sets[] = {_actors, _awake, _units, _bullets};
- for (int i = 0; i < 4; i++) {
- NSMutableSet* set = sets[i];
- [set removeAllObjects];
- [set release];
- }
+ [_actors release];
+ [_awake release];
+ [_units release];
+ [_bullets release];
+ [_stage release];
+ [_root release];
[_level release];
+
[_debugView release];
- [_root release];
[_world release];
_CurrentGame = NULL;
/// properties
-@synthesize world = _world;
-@synthesize level = _level;
+@synthesize now = _now;
+@synthesize elapsed = _elapsed;
+@synthesize ticks = _ticks;
-@synthesize actors = _actors;
+- (id<QQGameTime>) time { return self; }
-@synthesize ticks = _ticks;
@synthesize paused = _running;
+@synthesize stage = _stage;
+@synthesize root = _root;
+@synthesize level = _level;
+
+@synthesize world = _world;
+@synthesize actors = _actors;
+
@synthesize debugDrawingEnabled = _debugDrawingEnabled;
- (void) setDebugDrawingEnabled:(BOOL)enable {
/// methods
- (QQGame*) addActor:(QQActor*)actor {
- [_actors addObject:actor];
- [_awake addObject:actor];
- if ([actor isKindOfClass:[QQUnit class]])
- [_units addObject:actor];
- if ([actor isKindOfClass:[QQBullet class]])
- [_bullets addObject:actor];
+ self.actors = [self.actors setByAddingObject:actor];
+// if (actor.isActive)
+// _awake = [_awake setByAddingObject:actor];
+// if ([actor isKindOfClass:[QQUnit class]])
+// _units = [_units setByAddingObject:actor];
+// if ([actor isKindOfClass:[QQBullet class]])
+// _bullets = [_bullets setByAddingObject:actor];
return self;
}
- (QQGame*) removeActor:(QQActor*)actor {
- [_actors removeObject:actor];
- [_awake removeObject:actor];
- [_units removeObject:actor];
- [_bullets removeObject:actor];
+ self.actors = [self.actors setByRemovingObject:actor];
+// if (actor.isActive)
+// _awake = [_awake setByRemovingObject:actor];
+// if ([actor isKindOfClass:[QQUnit class]])
+// _units = [_units setByRemovingObject:actor];
+// if ([actor isKindOfClass:[QQBullet class]])
+// _bullets = [_bullets setByRemovingObject:actor];
return self;
}
+- (QQGame*) destroyActor:(QQActor*)actor {
+ [_world destroy:actor];
+ return [self removeActor:actor];
+}
-- (void) tick:(float)elapsed {
- _ticks++;
-
+
+- (void) tick {
#if TANKS_DEBUG_LOG
if ((_ticks % 100) == 0) {
- NSLog(@"[%ld] Time passed since last 100 frames: %f", _ticks, elapsed);
+ NSLog(@"[%ld] Time passed since last 100 frames: %f", _ticks, _elapsed);
for (QQActor* actor in self.actors) {
b2Vec2 v = actor.body->GetLinearVelocity();
NSLog(@"[%@ impulse:(%f,%f)]", actor, v.x,v.y);
}
#endif
- for (QQActor* actor in _awake) [actor tick:elapsed];
+ for (QQActor* actor in self.actors)
+ [actor tick];
[self.world step];
- for (QQActor* actor in self.actors) [actor draw];
+ for (QQActor* actor in self.actors)
+ if (!actor.dead) [actor draw];
}
- (void) start {
if (!_running) {
_running = YES;
- [self addEventListener:@selector(onEnterFrame:) atObject:self forType:SP_EVENT_TYPE_ENTER_FRAME];
+ [_stage addEventListener:@selector(onEnterFrame:) atObject:self forType:SP_EVENT_TYPE_ENTER_FRAME];
}
}
- (void) stop {
if (_running) {
- [self removeEventListener:@selector(onEnterFrame:) atObject:self forType:SP_EVENT_TYPE_ENTER_FRAME];
+ [_stage removeEventListener:@selector(onEnterFrame:) atObject:self forType:SP_EVENT_TYPE_ENTER_FRAME];
_running = NO;
}
}
-/// event handlers
+/// event handlers
- (void) onEnterFrame:(SPEnterFrameEvent*)event {
- if (_running) [self tick:event.passedTime];
+ if (_running) {
+ _ticks++;
+ _elapsed = event.passedTime;
+ _now += _elapsed;
+ [self tick];
+ }
}
- (void) onCollide:(QQContactNotification*)msg {
NSLog(@"%@", msg);
}
+- (void) logEvent:(SPEvent*)evt {
+ if ([evt.type isEqualToString:SP_EVENT_TYPE_ENTER_FRAME]) return;
+ NSLog(@"%@", evt);
+}
+
+- (NSString*) description {
+ return [NSString stringWithFormat:@"<%@: %x> {running=%s, #actors=%i, time={now=%f, elapsed=%f, ticks=%l}}",
+ [self class], (long)self, qqBoolToString(self.isPaused), [self.actors count],
+ self.now, self.elapsed, self.ticks];
+}
+ (QQGame*) current {
--- /dev/null
+@protocol QQGameTime
+
+@property (nonatomic, readonly) float now;
+@property (nonatomic, readonly) float elapsed;
+@property (nonatomic, readonly) long ticks;
+
+@end
#include <Box2D/Box2D.h>
+@class QQContactNotification;
+
+
/**
* Anything that has a physics representation.
*/
*/
- (void) setupPhysics;
+- (void) applyLinearImpulseX:(float)xNs y:(float)yNs;
+
+
+@optional
+- (void) onCollideBegin:(QQContactNotification*)msg;
+- (void) onCollideEnd:(QQContactNotification*)msg;
+
@end
\ No newline at end of file
+#import "qq/QQObservable.h"
+
@class QQGame;
@class QQWorld;
/**
* Anything in the game-world.
*/
-@protocol QQThing
+@protocol QQThing <QQObservableNotifier>
@property (nonatomic, readonly) QQGame* game;
@property (nonatomic, readonly) QQWorld* world;
+#import "game/QQGameTime.h"
/**
* Advances the timer by {elapsed} milliseconds, updating ready state if necessary.
* @return Ready state.
*/
-- (BOOL) tick:(float)elapsed;
+- (BOOL) tick:(id<QQGameTime>)time;
+ (QQCooldown*) cooldownWithDuration:(float)duration;
* Advances the timer by {elapsed} milliseconds, updating ready state if necessary.
* @return Ready state.
*/
-- (BOOL) tick:(float)elapsed {
+- (BOOL) tick:(id<QQGameTime>)time {
if (self.ready)
return YES;
- self.elapsed += elapsed;
+ self.elapsed += time.elapsed;
return self.ready;
}
#include <Box2D/Box2D.h>
+
+#import "qq/QQNotificationProxy.h"
#import "game/QQThing.h"
#import "game/QQActive.h"
#import "game/QQPhysical.h"
@class QQGame;
-@interface QQActor : NSObject <QQThing, QQActive, QQPhysical, QQDisplayable> {
+@interface QQActor : QQNotificationProxy <QQThing, QQActive, QQPhysical, QQDisplayable> {
@protected
b2Body* _body;
@private
BOOL _active;
BOOL _dirty;
+ BOOL _dead;
id<QQActorDelegate> _delegate;
+ NSArray* _cooldowns;
}
@property (nonatomic, readonly) QQGame* game;
@property (nonatomic, readonly) QQWorld* world;
@property (nonatomic, readwrite, retain) id<QQActorDelegate> delegate;
+@property (nonatomic, readonly) BOOL dead;
- (id) initAtX:(float)x y:(float)y;
- (id) initType:(b2BodyType)type atX:(float)x y:(float)y;
+- (void) destroy;
+
+
/// internal methods
/** Updates the Shape using values from Box2D. */
/// properties
-@synthesize active = _active;
-@synthesize dirty = _dirty;
-@synthesize delegate = _delegate;
-
@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; }
-- (float) rotation { return self.body->GetAngle(); }
-- (void) setRotation:(float)r { self.body->SetTransform(self.body->GetPosition(), r); }
+- (id) implicitNotificationSender { return self; }
+- (void) setImplicitNotificationSender:(id)sender {}
+
+- (id<QQObservableNotifier>) proxiedNotifier { return self.game; }
+- (void) setProxiedNotifier:(id<QQObservableNotifier>)notifier {}
+
+
+- (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();
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); }
+
+
- (void) updateShapeX:(float)x y:(float)y {
float px = self.world.scale;
[self.shape setCenterX:x*px y:y*px];
}
-- (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]; }
-
/// initializers
- (id) initType:(b2BodyType)type atX:(float)x y:(float)y {
if ((self = [super init])) {
+ _active = YES;
+ _dead = NO;
+ self.proxiedNotifier = self.game;
+ self.cooldowns = [NSArray array];
[self.game addActor:self];
b2BodyDef bd;
bd.position = b2Vec2(x, y);
bd.userData = self;
_body = self.world.world->CreateBody(&bd);
+
+ if ([self respondsToSelector:@selector(onCollideBegin:)])
+ [self addObserver:self selector:@selector(onCollideBegin:) name:QQ_EVENT_CONTACT_BEGIN];
}
return self;
}
+- (void) dealloc {
+ self.delegate = nil;
+ [_cooldowns release];
+ [super dealloc];
+}
+
+
/// methods
-- (void) tick:(float)elapsed {
- [self act];
+- (void) destroy {
+ NSLog(@"retainCount=%i", [self retainCount]);
+ if (!self.dead) {
+ _dead = YES;
+ self.shape = nil;
+ [self.game destroyActor:self];
+ NSLog(@"%@ \v\tretainCount=%i \v\tgame=%@", self, [self retainCount], self.game);
+ }
+}
+
+- (void) tick {
+ if (!self.dead) {
+ [self.cooldowns makeObjectsPerformSelector:@selector(tick:)withObject:self.game.time];
+ if (self.isActive) [self act];
+ }
}
- (void) act {}
- (void) setupPhysics {}
+
+- (void) applyLinearImpulseX:(float)xNs y:(float)yNs {
+ self.body->ApplyLinearImpulse(b2Vec2(xNs, yNs), self.body->GetPosition());
+}
+
+
- (NSString*) description {
b2Transform trans = self.body->GetTransform();
b2Vec2 pos = trans.position;
-#import "QQActor.h"
-#import "QQActorDelegate.h"
-#import "QQUnit.h"
-#import "bullet/QQBullet.h"
-#import "unit/QQTank.h"
+#import "game/actor/QQActor.h"
+#import "game/actor/QQActorDelegate.h"
+#import "game/actor/QQUnit.h"
+#import "game/actor/bullet/QQBullet.h"
+#import "game/actor/unit/QQTank.h"
}
- (void) dealloc {
- [self.game removeChild:_shape];
+ [self.game.level removeChild:_shape];
[_shape release];
[super dealloc];
}
[_shape release];
_shape = [newShape retain];
- [self updateShape];
- [self.game.level addChild:_shape];
+ if (_shape) {
+ [self updateShape];
+ [self.game.level addChild:_shape];
+ }
}
}
- (id) init:(QQUnit*)owner x:(float)x y:(float)y;
-- (void) applyLinearImpulseX:(float)xNs y:(float)yNs;
@end
#import "SparrowExtras.h"
#import "QQBullet.h"
+#import "physics/event/QQContactNotification.h"
return self;
}
-- (void) applyLinearImpulseX:(float)xNs y:(float)yNs {
- self.body->ApplyLinearImpulse(b2Vec2(xNs, yNs), self.body->GetPosition());
+- (void) onCollideBegin:(QQContactNotification*)msg {
+ QQActor* other = (msg.actorA && (msg.actorA != self) ? msg.actorA :
+ (msg.actorB && (msg.actorB != self) ? msg.actorB : nil));
+ if (other) {
+ NSLog(@"BOOM! %@", msg);
+ [other destroy];
+ [self destroy];
+ }
+}
+
+- (void) dealloc {
+ [super dealloc];
}
#import "QQTank.h"
#import "render/QQSparrowExtensions.h"
+#import "game/QQGame.h"
#import "game/actor/bullet/QQBullet.h"
- (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.game addEventListener:@selector(onTouch:) atObject:self forType:SP_EVENT_TYPE_TOUCH];
+ 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 removeEventListener:@selector(onTouch:) atObject:self forType:SP_EVENT_TYPE_TOUCH];
+ [self.game.stage removeEventListener:@selector(onTouch:) atObject:self forType:SP_EVENT_TYPE_TOUCH];
+ [_coolAtk release];
[super dealloc];
}
-- (void) tick:(float)elapsed {
- [self.coolAtk tick:elapsed];
- [super tick:elapsed];
-}
- (void) onTouch:(SPTouchEvent*)event {
- SPTouch* touch = [[event touchesWithTarget:(SPDisplayObject*)self.game] anyObject];
+ SPTouch* touch = [[event touchesWithTarget:(SPDisplayObject*)self.game.stage] anyObject];
if (touch && [self.coolAtk 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 {
+- (void) _moveOnTouch:(SPTouchEvent*)event {
SPTouch* touch = [[event touchesWithTarget:self.shape.parent] anyObject];
if (touch) {
SPPoint* touchPosition = [touch locationInSpace:self.shape.parent];
#include <Box2D/Box2D.h>
-#import "qq/QQObservable.h"
#import "qq/QQNotifier.h"
+#import "qq/QQNotificationProxy.h"
#import "physics/event/QQPhysicalEvents.h"
#import "physics/debug/QQGLESDebugDraw.h"
+#import "game/QQPhysical.h"
-@interface QQWorld : NSObject <QQNotifier, QQContactNotifier> {
+
+@interface QQWorld : QQNotificationProxy <QQContactNotifier> {
@private
- QQGLESDebugDraw* _debugDraw;
- QQContactListener _contactListener;
- b2World* _world;
-
- NSNotificationCenter* _center;
-
- NSMutableArray* _walls; // Array of NSValue<b2Body*>
-
float _timestep;
int _velocityIterations;
int _positionIterations;
float _scale;
+
+ b2World* _world;
+ QQContactListener _contactListener;
+ QQGLESDebugDraw* _debugDraw;
+
+ NSMutableArray* _walls; // Array of NSValue<b2Body*>
+ NSMutableSet* _trash;
}
@property (nonatomic, readonly) b2World* world;
- (void) step;
- (void) drawDebug;
+- (void) destroy:(id<QQPhysical>)actor;
@end
#import "physics/event/QQContactNotification.h"
+
+
// private interface
@interface QQWorld ()
+@property (nonatomic, readonly, getter=isDeleteLocked) bool deleteLocked;
+
- (void) postContactNotification:(b2Contact*)contact event:(NSString*)evt;
- (void) createWalls;
@end
_velocityIterations = 10;
_positionIterations = 10;
_scale = 5.0f;
- _center = [[NSNotificationCenter alloc] init];
_world = new b2World(b2Vec2(0.0f, 0.0f), true); // b2World(gravity, doSleep)
_debugDraw->SetAllFlags();
_world->SetDebugDraw(_debugDraw);
+ _trash = [[NSMutableSet alloc] initWithCapacity:4];
_walls = [[NSMutableArray alloc] initWithCapacity:4]; // Array of NSValue<b2Body*>
+
[self createWalls];
}
return self;
}
- (void) dealloc {
- [_walls removeAllObjects];
- [_walls release];
- [_center release];
+ [_walls removeAllObjects]; [_walls release];
+ [_trash removeAllObjects]; [_trash release];
delete _debugDraw;
delete _world; // b2World destructor destroys all physics entities and releases all heap memory.
[super dealloc];
}
}
+- (bool) isDeleteLocked {
+ return _world->IsLocked();
+}
- (void) step {
_world->Step(self.timestep, self.velocityIterations, self.positionIterations);
+ if (self.isDeleteLocked) {
+ NSLog(@"wtf! still delete-locked after step completed!");
+ #ifdef DEBUG
+ [NSException raise:@"WTFWorldStillDeleteLocked" format:@"World still delete-locked after step completed!"];
+ #endif
+ } else if ([_trash count] > 0) {
+ for (id<QQPhysical> actor in _trash)
+ [self destroy:actor];
+ [_trash removeAllObjects];
+ }
}
- (void) drawDebug {
_world->SetGravity(b2Vec2(x,y));
}
+- (void) destroy:(id<QQPhysical>)actor {
+ if (self.isDeleteLocked) {
+ [_trash addObject:actor];
+ } else {
+ if (actor.fixture) {
+ actor.fixture->GetBody()->DestroyFixture(actor.fixture);
+ } else if (actor.body) {
+ _world->DestroyBody(actor.body);
+ } else {
+ NSLog(@"wtf! Cannot destroy actor with no body or fixture! %@", actor);
+ }
+ }
+}
+
/// QQContactNotifier
}
-
-/// observable
-
-- (void) addObserver:(id)observer selector:(SEL)selector name:(NSString*)event {
- [self addObserver:observer selector:selector name:event object:self];
-}
-
-// Remove a listener from this object
-- (void) removeObserver:(id)observer {
- [self removeObserver:observer name:nil object:self];
-}
-- (void) removeObserver:(id)observer name:(NSString*)event {
- [self removeObserver:observer name:event object:self];
-}
-
-// Send a notification from this object
-- (void) postNotificationName:(NSString*)name {
- [self postNotificationName:name object:self];
-}
-- (void) postNotificationName:(NSString*)name userInfo:(NSDictionary*)info {
- [self postNotificationName:name object:self userInfo:info];
-}
-
-
-/// notifier
-
-- (void) addObserver:(id)observer selector:(SEL)selector name:(NSString*)event object:(id)sender {
- [_center addObserver:observer selector:selector name:event object:sender];
-}
-
-- (void) removeObserver:(id)observer name:(NSString*)event object:(id)sender {
- [_center removeObserver:observer name:event object:sender];
-}
-- (void) removeObservers:(id)observer {
- [_center removeObserver:observer];
-}
-
-- (void) postNotification:(NSNotification*)msg {
- [_center postNotification:msg];
-}
-- (void) postNotificationName:(NSString*)name object:(id)sender {
- [_center postNotificationName:name object:sender];
-}
-- (void) postNotificationName:(NSString*)name object:(id)sender userInfo:(NSDictionary*)info {
- [_center postNotificationName:name object:sender userInfo:info];
-}
-
@end
- (id) initWithName:(NSString*)name object:(id)obj userInfo:(NSDictionary*)info contact:(b2Contact*)contact {
if ((self = [super initWithName:name object:obj userInfo:info])) {
_contact = contact;
+ [[self.actorA retain] autorelease];
+ [[self.actorB retain] autorelease];
}
return self;
}
-
@synthesize contact = _contact;
- (QQActor*) actorA {
- (NSString*) description {
- return [NSString stringWithFormat:@"[%@ actorA=%@, actorB=%@]",
+ return [NSString stringWithFormat:@"[%@ \v\tactorA=%@, \v\tactorB=%@]",
[super description], self.actorA, self.actorB];
}
--- /dev/null
+
+@interface NSSet (QQExtensions)
+
+- (NSSet*) setByRemovingObject:(id)object;
+- (NSSet*) setByRemovingArray:(NSArray*)objects;
+
+
+@end
--- /dev/null
+@implementation NSSet (QQExtensions)
+
+- (NSSet*) setByRemovingObject:(id)object {
+ // (BOOL (^)(id obj, BOOL *stop))predicate
+ return [self objectsPassingTest:^(id item, BOOL *stop){
+ return (BOOL) (item != object);
+ }];
+}
+- (NSSet*) setByRemovingArray:(NSArray*)objects {
+ return [self objectsPassingTest:^(id item, BOOL *stop){
+ return (BOOL) ![objects containsObject:item];
+ }];
+}
+
+@end
--- /dev/null
+#import "qq/QQNotifier.h"
+
+@interface QQNotificationCenter : NSNotificationCenter <QQObservableNotifier> {
+@private
+ id _implicitNotificationSender;
+}
+/** Object used for implicit sender when adding or removing observers. */
+@property (nonatomic, readwrite, retain) 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;
+
+@end
--- /dev/null
+#import "qq/QQNotificationCenter.h"
+
+
+@implementation QQNotificationCenter
+
+- (id) init {
+ if ((self = [super init])){
+ _implicitNotificationSender = self;
+ }
+ return self;
+}
+
+- (void) dealloc {
+ [_implicitNotificationSender release];
+ [super dealloc];
+}
+
+@synthesize implicitNotificationSender = _implicitNotificationSender;
+
+
+/// observable
+
+- (void) addObserver:(id)observer selector:(SEL)selector name:(NSString*)event {
+ [self addObserver:observer selector:selector name:event object:self.implicitNotificationSender];
+}
+
+// Remove a listener from this object
+- (void) removeObserver:(id)observer {
+ [self removeObserver:observer name:nil object:self.implicitNotificationSender];
+}
+- (void) removeObserver:(id)observer name:(NSString*)event {
+ [self removeObserver:observer name:event object:self.implicitNotificationSender];
+}
+
+// Send a notification from this object
+- (void) postNotificationName:(NSString*)name {
+ [self postNotificationName:name object:self.implicitNotificationSender];
+}
+- (void) postNotificationName:(NSString*)name userInfo:(NSDictionary*)info {
+ [self postNotificationName:name object:self.implicitNotificationSender userInfo:info];
+}
+
+
+/// notifier
+
+- (void) removeObservers:(id)observer {
+ [super removeObserver:observer];
+}
+
+
+/// NSNotificationCenter (superclass) provides:
+
+// - (void) addObserver:(id)observer selector:(SEL)selector name:(NSString*)event object:(id)sender
+// - (void) removeObserver:(id)observer name:(NSString*)event object:(id)sender
+// - (void) postNotification:(NSNotification*)msg
+// - (void) postNotificationName:(NSString*)name object:(id)sender
+// - (void) postNotificationName:(NSString*)name object:(id)sender userInfo:(NSDictionary*)info
+
+// as well as...
+// - (id)addObserverForName:(NSString *)name object:(id)obj queue:(NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *))block
+
+
++ (QQNotificationCenter*) notifierWithTarget:(id)target {
+ QQNotificationCenter* notifier = [[[QQNotificationCenter alloc] init] autorelease];
+ notifier.implicitNotificationSender = target;
+ return notifier;
+}
+
+@end
--- /dev/null
+#import "qq/QQNotifier.h"
+
+/**
+ * Proxies all QQObservableNotifier calls to another QQObservableNotifier.
+ */
+@interface QQNotificationProxy : NSObject <QQObservableNotifier> {
+@private
+ id<QQObservableNotifier> _proxiedNotifier;
+ id _implicitNotificationSender;
+}
+
+@property (nonatomic, readwrite, retain) id<QQObservableNotifier> proxiedNotifier;
+
+- (id) initWithNotifier:(id<QQObservableNotifier>)notifier;
+
+@end
--- /dev/null
+#import "qq/QQNotificationProxy.h"
+
+
+@implementation QQNotificationProxy
+
+@synthesize proxiedNotifier = _proxiedNotifier;
+@synthesize implicitNotificationSender = _implicitNotificationSender;
+
+
+- (id) initWithNotifier:(id<QQObservableNotifier>)notifier {
+ if ((self = [super init])){
+ self.proxiedNotifier = notifier;
+ }
+ return self;
+}
+
+- (void) dealloc {
+ self.proxiedNotifier = nil;
+ [super dealloc];
+}
+
+/// observable
+
+- (void) addObserver:(id)observer selector:(SEL)selector name:(NSString*)event {
+ [self addObserver:observer selector:selector name:event object:self.implicitNotificationSender];
+}
+
+// Remove a listener from this object
+- (void) removeObserver:(id)observer {
+ [self removeObserver:observer name:nil object:self.implicitNotificationSender];
+}
+- (void) removeObserver:(id)observer name:(NSString*)event {
+ [self removeObserver:observer name:event object:self.implicitNotificationSender];
+}
+
+// Send a notification from this object
+- (void) postNotificationName:(NSString*)name {
+ [self postNotificationName:name object:self.implicitNotificationSender];
+}
+- (void) postNotificationName:(NSString*)name userInfo:(NSDictionary*)info {
+ [self postNotificationName:name object:self.implicitNotificationSender userInfo:info];
+}
+
+
+/// notifier
+
+- (void) addObserver:(id)observer selector:(SEL)selector name:(NSString*)event object:(id)sender {
+ [self.proxiedNotifier addObserver:observer selector:selector name:event object:sender];
+}
+
+- (void) removeObserver:(id)observer name:(NSString*)event object:(id)sender {
+ [self.proxiedNotifier removeObserver:observer name:event object:sender];
+}
+- (void) removeObservers:(id)observer {
+ [self.proxiedNotifier removeObserver:observer];
+}
+
+- (void) postNotification:(NSNotification*)msg {
+ [self.proxiedNotifier postNotification:msg];
+}
+- (void) postNotificationName:(NSString*)name object:(id)sender {
+ [self.proxiedNotifier postNotificationName:name object:sender];
+}
+- (void) postNotificationName:(NSString*)name object:(id)sender userInfo:(NSDictionary*)info {
+ [self.proxiedNotifier postNotificationName:name object:sender userInfo:info];
+}
+
+
+
+@end
#import "qq/QQObservable.h"
-@protocol QQNotifier <QQObservable>
+@protocol QQNotifier
+
+/**
+ * Adds an observer of specified object.
+ *
+ * A nil name means observer will be notified of all events for specified object.
+ * A nil object means observer will be notified of all events for specified name.
+ * An observer specifying nil for both name and object will be notified of all events.
+ */
- (void) addObserver:(id)observer selector:(SEL)selector name:(NSString*)event object:(id)sender;
- (void) removeObserver:(id)observer name:(NSString*)event object:(id)sender;
-- (void) removeObservers:(id)observer; // remove all from all objects
+
+/** Removes observer from all subscribed notices. */
+- (void) removeObservers:(id)observer;
- (void) postNotification:(NSNotification*)msg;
- (void) postNotificationName:(NSString*)name object:(id)sender;
@end
+
+@protocol QQObservableNotifier <QQObservable, QQNotifier>
+
+@end
\ No newline at end of file
--- /dev/null
+/**
+ * Various macros relating to notification dispatch.
+ */
+
+/**
+ * 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]; \
+}
+
+++ /dev/null
-
-
-@interface QQObject : NSObject {
-@private
-
-}
-
-
-
-@end
+++ /dev/null
-#import "QQObject.h"
-
-
-@implementation QQObject
-
-- (id) init {
- if ((self = [super init])){
-
- }
- return self;
-}
-@end
* that would normally take an object if the call was made to an NSNotificationCenter.
*/
@protocol QQObservable
+
+@property (nonatomic, readwrite, retain) id implicitNotificationSender;
+
//- (void) observe:(NSString*)event notify:(id)observer selector:(SEL)selector;
/** Adds an observer of this object. */
@interface QQAppDelegate : NSObject <UIApplicationDelegate> {
@private
- UIApplication* _app;
UIWindow* window;
SPView* sparrowView;
- // QQPhysicsDebugView* _debugView;
QQGame* _game;
}
-@property (nonatomic, retain) IBOutlet UIWindow* window;
-@property (nonatomic, retain) IBOutlet SPView* sparrowView;
-// @property (nonatomic, retain) QQPhysicsDebugView* debugView;
-@property (nonatomic, retain) QQGame* game;
+@property (nonatomic, readwrite, retain) IBOutlet UIWindow* window;
+@property (nonatomic, readwrite, retain) IBOutlet SPView* sparrowView;
+@property (nonatomic, readwrite, retain) QQGame* game;
@end
\ No newline at end of file
@synthesize game = _game;
-- (void) applicationDidFinishLaunching:(UIApplication*)application {
- _app = application;
- _app.statusBarHidden = YES;
-
+- (void) applicationDidFinishLaunching:(UIApplication*)app {
SP_CREATE_POOL(pool);
+ [app setStatusBarHidden:YES];
[SPStage setSupportHighResolutions:YES];
- [SPAudioEngine start];
if ( sparrowView.frameRate != 60.0f )
sparrowView.frameRate = 60.0f;
- self.game = [[[QQGame alloc] init] autorelease];
- sparrowView.stage = _game;
+ self.game = [QQGame current];
+ sparrowView.stage = _game.stage;
[_game start];
[window makeKeyAndVisible];
[sparrowView start];
+ [SPAudioEngine start];
SP_RELEASE_POOL(pool);
}
-- (void) applicationWillResignActive:(UIApplication*)application {
+- (void) applicationWillResignActive:(UIApplication*)app {
[sparrowView stop];
}
-- (void) applicationDidBecomeActive:(UIApplication*)application {
+- (void) applicationDidBecomeActive:(UIApplication*)app {
[sparrowView start];
}
- (void) dealloc {
- _app = nil;
[_game release];
[sparrowView release];
[window release];
49966919136930E8006E8125 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 49966914136930E8006E8125 /* OpenAL.framework */; };
4996691A136930E8006E8125 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 49966915136930E8006E8125 /* OpenGLES.framework */; };
4996691B136930E8006E8125 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 49966916136930E8006E8125 /* QuartzCore.framework */; };
+ 499D6A9C1399BFB8008E4C0D /* QQNotificationCenter.h in Headers */ = {isa = PBXBuildFile; fileRef = 499D6A981399BFB8008E4C0D /* QQNotificationCenter.h */; };
+ 499D6A9D1399BFB8008E4C0D /* QQNotificationCenter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 499D6A991399BFB8008E4C0D /* QQNotificationCenter.mm */; };
+ 499D6A9E1399BFB8008E4C0D /* QQNotificationProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 499D6A9A1399BFB8008E4C0D /* QQNotificationProxy.h */; };
+ 499D6A9F1399BFB8008E4C0D /* QQNotificationProxy.mm in Sources */ = {isa = PBXBuildFile; fileRef = 499D6A9B1399BFB8008E4C0D /* QQNotificationProxy.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 */; };
49DA67D5137847A7004841E9 /* QQWorld.mm in Sources */ = {isa = PBXBuildFile; fileRef = 49DA67D3137847A7004841E9 /* QQWorld.mm */; };
+ 49E3C5D2139A73E700A3958A /* NSSet+QQExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = 49E3C5D0139A73E700A3958A /* NSSet+QQExtensions.h */; };
+ 49E3C5D3139A73E700A3958A /* NSSet+QQExtensions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 49E3C5D1139A73E700A3958A /* NSSet+QQExtensions.mm */; };
+ 49E67E11139B341600DDFC07 /* TanksMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 49E67E10139B341600DDFC07 /* TanksMacros.h */; };
49E834A713812427007A6598 /* QQActive.h in Headers */ = {isa = PBXBuildFile; fileRef = 49E8349E13812427007A6598 /* QQActive.h */; };
49E834A813812427007A6598 /* QQActor.h in Headers */ = {isa = PBXBuildFile; fileRef = 49E834A013812427007A6598 /* QQActor.h */; };
49E834A913812427007A6598 /* QQActor.mm in Sources */ = {isa = PBXBuildFile; fileRef = 49E834A113812427007A6598 /* QQActor.mm */; };
49966914136930E8006E8125 /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = System/Library/Frameworks/OpenAL.framework; sourceTree = SDKROOT; };
49966915136930E8006E8125 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; };
49966916136930E8006E8125 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
+ 499D6A981399BFB8008E4C0D /* QQNotificationCenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QQNotificationCenter.h; sourceTree = "<group>"; };
+ 499D6A991399BFB8008E4C0D /* QQNotificationCenter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = QQNotificationCenter.mm; sourceTree = "<group>"; };
+ 499D6A9A1399BFB8008E4C0D /* QQNotificationProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QQNotificationProxy.h; sourceTree = "<group>"; };
+ 499D6A9B1399BFB8008E4C0D /* QQNotificationProxy.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = QQNotificationProxy.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>"; };
49DA67D3137847A7004841E9 /* QQWorld.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = QQWorld.mm; sourceTree = "<group>"; };
+ 49E3C5D0139A73E700A3958A /* NSSet+QQExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSSet+QQExtensions.h"; sourceTree = "<group>"; };
+ 49E3C5D1139A73E700A3958A /* NSSet+QQExtensions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSSet+QQExtensions.mm"; sourceTree = "<group>"; };
+ 49E67E10139B341600DDFC07 /* TanksMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TanksMacros.h; sourceTree = "<group>"; };
49E8349E13812427007A6598 /* QQActive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QQActive.h; sourceTree = "<group>"; };
49E834A013812427007A6598 /* QQActor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QQActor.h; sourceTree = "<group>"; };
49E834A113812427007A6598 /* QQActor.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = QQActor.mm; sourceTree = "<group>"; };
4978AD1E1396302E00930447 /* qq */ = {
isa = PBXGroup;
children = (
+ 49E3C5D0139A73E700A3958A /* NSSet+QQExtensions.h */,
+ 49E3C5D1139A73E700A3958A /* NSSet+QQExtensions.mm */,
+ 499D6A981399BFB8008E4C0D /* QQNotificationCenter.h */,
+ 499D6A991399BFB8008E4C0D /* QQNotificationCenter.mm */,
+ 499D6A9A1399BFB8008E4C0D /* QQNotificationProxy.h */,
+ 499D6A9B1399BFB8008E4C0D /* QQNotificationProxy.mm */,
4978AD1F1396302F00930447 /* QQNotification.h */,
4978AD201396302F00930447 /* QQNotification.mm */,
4978AD211396302F00930447 /* QQNotifier.h */,
492D80ED138BA4BC0042D918 /* bullet */,
492D80E8138BA4B40042D918 /* unit */,
4978AD0D1395E5CE00930447 /* QQActors.h */,
+ 492D80FE138BCC9F0042D918 /* QQActorDelegate.h */,
49E834A013812427007A6598 /* QQActor.h */,
49E834A113812427007A6598 /* QQActor.mm */,
- 492D80FE138BCC9F0042D918 /* QQActorDelegate.h */,
49E834A213812427007A6598 /* QQUnit.h */,
492D80FC138BCA840042D918 /* QQUnit.mm */,
);
49F2D9B013764666000B6B8C /* main.mm */,
49F2D9B213764666000B6B8C /* prefix.pch */,
4978AD131396139100930447 /* Tanks.h */,
+ 49E67E10139B341600DDFC07 /* TanksMacros.h */,
);
path = src;
sourceTree = "<group>";
4978AD251396302F00930447 /* QQNotification.h in Headers */,
4978AD271396302F00930447 /* QQNotifier.h in Headers */,
4978AD2A1396302F00930447 /* QQObservable.h in Headers */,
+ 499D6A9C1399BFB8008E4C0D /* QQNotificationCenter.h in Headers */,
+ 499D6A9E1399BFB8008E4C0D /* QQNotificationProxy.h in Headers */,
+ 49E3C5D2139A73E700A3958A /* NSSet+QQExtensions.h in Headers */,
+ 49E67E11139B341600DDFC07 /* TanksMacros.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
4978AD1B1396302300930447 /* QQContactNotification.mm in Sources */,
4978AD1D1396302300930447 /* QQPhysicalEvents.mm in Sources */,
4978AD261396302F00930447 /* QQNotification.mm in Sources */,
+ 499D6A9D1399BFB8008E4C0D /* QQNotificationCenter.mm in Sources */,
+ 499D6A9F1399BFB8008E4C0D /* QQNotificationProxy.mm in Sources */,
+ 49E3C5D3139A73E700A3958A /* NSSet+QQExtensions.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};