#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"
#define b2s(__val) ((__val)?("YES"):("NO"))
+#define ATTACK_COOLDOWN_NAME @"attack"
+
+
#endif
\ No newline at end of file
#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
/**
* Called to setup the Sparrow shape.
*/
-- (SPDisplayObject*) setupShape;
+- (void) setupShape;
/**
* Called to update appearance after game actions have occurred
#import "Sparrow.h"
+#import "Tanks.h"
#import "qq/event/QQNotificationCenter.h"
#import "physics/QQWorld.h"
@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;
/** Pauses the game. */
- (void) stop;
+/** Advances the game clock one step and elapsed ms. */
+- (void) tick:(float)elapsed;
+
+ (QQGame*) current;
#import <Box2D/Box2D.h>
-#import "Tanks.h"
#import "game/QQGame.h"
#import "game/unit/QQActors.h"
#import "physics/event/QQContactNotification.h"
- (void) onEnterFrame:(SPEnterFrameEvent*)event;
- (void) onCollide:(QQContactNotification*)msg;
+- (void) logEvent:(SPEvent*)evt;
@end
return _CurrentGame;
}
+
- (id) init {
if (_CurrentGame) {
[self release];
[[[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;
}
- (id<QQGameTime>) time { return self; }
-@synthesize paused = _running;
+@synthesize running = _running;
@synthesize stage = _stage;
@synthesize root = _root;
/// 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];
}
- (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
+ ];
}
/// 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;
-#import "qq/event/QQObservable.h"
+#import "qq/event/QQNotifier.h"
@class QQGame;
@class QQWorld;
+#import "Tanks.h"
#import "game/QQGameTime.h"
*/
@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;
@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;
/**
* 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.
- (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
/// 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;
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];
}
#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;