#ifndef TANKS_H
#define TANKS_H
+#ifdef DEBUG
+#define TANKS_DEBUG_LOG 1
+#else
#define TANKS_DEBUG_LOG 0
+#endif // DEBUG
-#endif
+#endif // TANKS_H
#import "TanksMacros.h"
+#import "qq/NSSet+QQExtensions.h"
#import "render/QQSparrowExtensions.h"
#ifndef TANKS_MACROS_H
#define TANKS_MACROS_H
-#define qqBoolToString(__val) ((__val)?("YES"):("NO"))
+#define b2s(__val) ((__val)?("YES"):("NO"))
#endif
\ No newline at end of file
#import "Sparrow.h"
-#import "qq/QQNotificationCenter.h"
+#import "qq/event/QQNotificationCenter.h"
+
#import "physics/QQWorld.h"
#import "physics/debug/QQPhysicsDebugView.h"
+
#import "game/QQGameTime.h"
-#import "game/actor/QQActor.h"
+#import "game/unit/QQActor.h"
#import "game/map/QQLevel.h"
+
@interface QQGame : QQNotificationCenter <QQGameTime> {
@private
float _now;
float _elapsed;
long _ticks;
- long _realtime;
BOOL _running;
BOOL _debugDrawingEnabled;
@property (nonatomic, readonly, retain) NSSet* actors;
-- (void) tick;
+- (void) tick:(float)elapsed;
+/** Alerts the game to a new actor. */
- (QQGame*) addActor:(QQActor*)actor;
-// - (QQGame*) addActorAndShape:(QQActor*)actor;
- (QQGame*) removeActor:(QQActor*)actor;
-- (QQGame*) destroyActor:(QQActor*)actor;
+/** Starts/unpauses the game. */
- (void) start;
+
+/** Pauses the game. */
- (void) stop;
#import <Box2D/Box2D.h>
#import "Tanks.h"
-#import "qq/NSSet+QQExtensions.h"
#import "game/QQGame.h"
-#import "game/actor/QQActors.h"
+#import "game/unit/QQActors.h"
#import "physics/event/QQContactNotification.h"
-static QQGame* _CurrentGame = NULL;
-
-
-
@interface QQGame ()
@property (nonatomic, readwrite, retain) NSSet* actors;
@end
+static QQGame* _CurrentGame = NULL;
+
@implementation QQGame
++ (QQGame*) current {
+ if (!_CurrentGame)
+ [[[QQGame alloc] init] // init assigns to singleton, but singleton is a weakref,
+ autorelease]; // XXX: so game will still be released if not retained
+ return _CurrentGame;
+}
+
- (id) init {
if (_CurrentGame) {
[self release];
}
if ( (self = [super init]) ){
+ // We set the singleton here, in init, in case someone referenced during initialization
+ // asks for the current game (causing a loop).
_CurrentGame = self;
_now = 0;
_ticks = 0;
[[[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
}
return self;
}
/// methods
+- (void) tick:(float)elapsed {
+ if (!self.isPaused) return;
+ _ticks++;
+ _elapsed = elapsed;
+ _now += elapsed;
+
+ for (QQActor* actor in self.actors)
+ [actor tick];
+ [self.world step];
+ for (QQActor* actor in self.actors)
+ [actor draw];
+}
+
- (QQGame*) addActor:(QQActor*)actor {
+ // Create a new copy of the mutated set on change to avoid the need to copy
+ // on every iteration, which happens WAAAY more often
self.actors = [self.actors setByAddingObject:actor];
// if (actor.isActive)
// _awake = [_awake setByAddingObject:actor];
}
- (QQGame*) removeActor:(QQActor*)actor {
+ // Create a new copy of the mutated set on change to avoid the need to copy
+ // on every iteration, which happens WAAAY more often
self.actors = [self.actors setByRemovingObject:actor];
// if (actor.isActive)
// _awake = [_awake setByRemovingObject:actor];
// _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 {
-#if TANKS_DEBUG_LOG
- if ((_ticks % 100) == 0) {
- 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 self.actors)
- [actor tick];
- [self.world step];
- for (QQActor* actor in self.actors)
- if (!actor.dead) [actor draw];
+ return self;
}
-
- (void) start {
- if (!_running) {
- _running = YES;
- [_stage addEventListener:@selector(onEnterFrame:) atObject:self forType:SP_EVENT_TYPE_ENTER_FRAME];
- }
+ if (_running) return;
+ _running = YES;
+ [_stage addEventListener:@selector(onEnterFrame:) atObject:self forType:SP_EVENT_TYPE_ENTER_FRAME];
}
- (void) stop {
- if (_running) {
- [_stage removeEventListener:@selector(onEnterFrame:) atObject:self forType:SP_EVENT_TYPE_ENTER_FRAME];
- _running = NO;
- }
+ if (!_running) return;
+ [_stage removeEventListener:@selector(onEnterFrame:) atObject:self forType:SP_EVENT_TYPE_ENTER_FRAME];
+ _running = NO;
}
/// event handlers
- (void) onEnterFrame:(SPEnterFrameEvent*)event {
- if (_running) {
- _ticks++;
- _elapsed = event.passedTime;
- _now += _elapsed;
- [self tick];
- }
+ [self tick:event.passedTime];
}
- (void) onCollide:(QQContactNotification*)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);
}
+
- (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],
+ 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];
}
-+ (QQGame*) current {
- if (!_CurrentGame)
- [[[QQGame alloc] init] // init assigns to singleton, but singleton is a weakref,
- autorelease]; // XXX: so game will still be released if not retained...
- return _CurrentGame;
-}
-
-
@end
\ No newline at end of file
-#import "qq/QQObservable.h"
+#import "qq/event/QQObservable.h"
@class QQGame;
@class QQWorld;
+++ /dev/null
-#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"
+++ /dev/null
-#import "game/actor/QQActor.h"
-#import "game/QQThing.h"
-
-
-@protocol QQUnit <QQThing>
-
-@property (nonatomic, readonly) BOOL canAttack;
-
-- (void) attackTarget:(QQActor*)actor;
-- (void) attackToward:(CGPoint)point;
-- (void) attackTowardX:(float)x y:(float)y;
-
-
-@end
-
-//typedef id<QQUnit> QQUnit;
#include <Box2D/Box2D.h>
-#import "qq/QQNotificationProxy.h"
+#import "qq/event/QQNotificationProxy.h"
#import "game/QQThing.h"
#import "game/QQActive.h"
#import "game/QQPhysical.h"
#import "game/QQDisplayable.h"
-#import "game/actor/QQActorDelegate.h"
+#import "game/unit/QQActorDelegate.h"
#import "physics/QQWorld.h"
@class QQGame;
/// methods
- (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);
- }
+ if (self.dead) return;
+
+ _dead = YES;
+ self.shape = nil;
+ [self.game removeActor:self];
}
- (void) tick {
- if (!self.dead) {
- [self.cooldowns makeObjectsPerformSelector:@selector(tick:)withObject:self.game.time];
- if (self.isActive) [self act];
- }
+ if (self.dead) return;
+
+ [self.cooldowns makeObjectsPerformSelector:@selector(tick:) withObject:self.game.time];
+ if (self.isActive)
+ [self act];
}
- (void) act {}
}
- (void) draw {
+ if (self.dead) return;
+
[self updateShape];
}
--- /dev/null
+#import "game/unit/QQActor.h"
+#import "game/unit/QQActorDelegate.h"
+#import "game/unit/QQUnit.h"
+#import "game/unit/QQBullet.h"
+#import "game/unit/QQTank.h"
-#import "game/actor/QQUnit.h"
+#import "game/unit/QQUnit.h"
@interface QQBullet : QQUnit {
-#import "game/actor/QQUnit.h"
+#import "game/unit/QQUnit.h"
#import "game/ability/QQCooldown.h"
@interface QQTank : QQUnit {
#import "QQTank.h"
#import "render/QQSparrowExtensions.h"
#import "game/QQGame.h"
-#import "game/actor/bullet/QQBullet.h"
+#import "game/unit/QQBullet.h"
// private interface
#import "Sparrow.h"
#import "physics/QQWorld.h"
-#import "game/actor/QQActor.h"
-#import "game/actor/QQActorDelegate.h"
+#import "game/unit/QQActor.h"
+#import "game/unit/QQActorDelegate.h"
#import "render/QQSparrowExtensions.h"
#include <Box2D/Box2D.h>
#import "Sparrow.h"
-#import "game/actor/QQUnit.h"
+#import "game/unit/QQUnit.h"
#import "game/QQGame.h"
#import "render/QQSparrowExtensions.h"
#include <Box2D/Box2D.h>
-#import "qq/QQNotifier.h"
-#import "qq/QQNotificationProxy.h"
+#import "qq/event/QQNotifier.h"
+#import "qq/event/QQNotificationProxy.h"
#import "physics/event/QQPhysicalEvents.h"
#import "physics/debug/QQGLESDebugDraw.h"
#import "game/QQPhysical.h"
-#include "qq/QQNotification.h"
#include <Box2D/Box2D.h>
-#include "game/actor/QQActor.h"
+
+#import "qq/event/QQNotification.h"
+#import "game/unit/QQActor.h"
@interface QQContactNotification : QQNotification {
b2Contact* _contact;
}
-- (id) initWithName:(NSString*)name contact:(b2Contact*)contact;
-- (id) initWithName:(NSString*)name object:(id)obj contact:(b2Contact*)contact;
-- (id) initWithName:(NSString*)name object:(id)obj userInfo:(NSDictionary*)info contact:(b2Contact*)contact;
-
@property (nonatomic, readonly) b2Contact* contact;
@property (nonatomic, readonly) QQActor* actorA;
@property (nonatomic, readonly) b2Body* bodyB;
+- (id) initWithName:(NSString*)name contact:(b2Contact*)contact;
+- (id) initWithName:(NSString*)name object:(id)obj contact:(b2Contact*)contact;
+- (id) initWithName:(NSString*)name object:(id)obj userInfo:(NSDictionary*)info contact:(b2Contact*)contact;
+
+
+ (QQContactNotification*) notification:(NSString*)name contact:(b2Contact*)contact;
+ (QQContactNotification*) notification:(NSString*)name object:(id)obj contact:(b2Contact*)contact;
+ (QQContactNotification*) notification:(NSString*)name object:(id)obj userInfo:(NSDictionary*)info contact:(b2Contact*)contact;
-#include "QQPhysicalEvents.h"
+#import "QQPhysicalEvents.h"
void QQContactListener::BeginContact(b2Contact* contact) {
-#include "qq/QQNotification.h"
+#import "qq/event/QQNotification.h"
@implementation QQNotification
-#import "qq/QQNotifier.h"
+#import "qq/event/QQNotifier.h"
@interface QQNotificationCenter : NSNotificationCenter <QQObservableNotifier> {
@private
-#import "qq/QQNotificationCenter.h"
+#import "qq/event/QQNotificationCenter.h"
@implementation QQNotificationCenter