+#import "game/QQThing.h"
/**
* Anything that takes a turn is QQActive.
*/
-@protocol QQActive
+@protocol QQActive <QQThing>
@property (nonatomic, getter=isActive) BOOL active;
#import "Sparrow.h"
+/**
+ * Anything that has a Sparrow represenation in the display tree.
+ */
@protocol QQDisplayable
@property (nonatomic, retain, readonly) SPDisplayObject* shape;
#import "QQGame.h"
-#import "game/actor/QQUnit.h"
+#import "game/actor/QQTank.h"
-static QQGame* _currentGame = NULL;
+static QQGame* _CurrentGame = NULL;
@implementation QQGame
-@synthesize ticks = _ticks;
-@synthesize world = _world;
+@synthesize ticks = _ticks;
+@synthesize world = _world;
@synthesize actors = _actors;
- (id) init {
- if (_currentGame) {
+ if (_CurrentGame) {
[self release];
[NSException raise:@"TooManyGames" format:@"cannot instantiate more than one QQGame at a time!"];
}
if ( (self = [super init]) ){
- _currentGame = self;
+ _CurrentGame = self;
_ticks = 0l;
_actors = [[NSMutableArray alloc] initWithCapacity:10];
_world = [[QQWorld alloc] init];
- [self addActor:[[[QQUnit alloc] init] autorelease]];
+ [self addActor:[[[QQTank alloc] init] autorelease]];
[self addEventListener:@selector(onEnterFrame:) atObject:self forType:SP_EVENT_TYPE_ENTER_FRAME];
}
[_actors removeAllObjects];
[_actors release];
[_world release];
- _currentGame = NULL;
+ _CurrentGame = NULL;
[super dealloc];
}
+ (QQGame*) current {
- if (!_currentGame)
- [[[QQGame alloc] init] // init assigns to singleton, but singleton is a weakref,
+ 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;
+ return _CurrentGame;
}
*/
@protocol QQPhysical
+// @property (nonatomic, readwrite, assign) float x;
+// @property (nonatomic, readwrite, assign) float y;
+
+
// FIXME: don't expose these, instead aggregate properties from body & fixtures/shapes
@property (nonatomic, readonly) b2Body* body;
@property (nonatomic, readonly) b2Fixture* fixture;
+
@end
\ No newline at end of file
--- /dev/null
+
+
+/**
+ * Cooldown timer.
+ */
+@interface QQCooldown : NSObject {
+@private
+ float _duration;
+ float _elapsed;
+}
+
+/** Duration of this cooldown timer (ms). */
+@property (nonatomic, readwrite, assign) float duration;
+
+/** Elapsed time (ms) since last activated if not ready; otherwise {duration}. */
+@property (nonatomic, readwrite, assign) float elapsed;
+
+/** Whether Cooldown timer is ready to be activated. */
+@property (nonatomic, readwrite, getter=isReady) BOOL ready;
+
+/** Percent completed (elapsed / duration), clamped [0, 1.0]. */
+@property (nonatomic, readwrite) float ratio;
+
+/**
+ * Implies ready=NO.
+ */
+- (id) initWithDuration:(float)duration;
+- (id) initWithDuration:(float)duration andReady:(BOOL)ready;
+
+/**
+ * Attempts to activate this cooldown, clearing the ready flag and setting elapsed to 0.
+ * If not ready, has no effect.
+ * @return Ready state.
+ */
+- (BOOL) activate;
+
+/**
+ * Advances the timer by {elapsed} milliseconds, updating ready state if necessary.
+ * @return Ready state.
+ */
+- (BOOL) tick:(float)elapsed;
+
+
++ (QQCooldown) cooldownWithDuration:(float)duration;
++ (QQCooldown) cooldownWithDuration:(float)duration andReady:(BOOL)ready;
+
+@end
--- /dev/null
+#import "QQCooldown.h"
+
+
+@implementation QQCooldown
+
+/// properties
+
+@synthesize duration = _duration;
+@synthesize elapsed = _elapsed;
+
+- (BOOL) ready { return (self.elapsed >= self.duration); }
+- (void) setReady:(BOOL)newReady {
+ if (newReady == self.ready)
+ return;
+ if (newReady)
+ self.elapsed = self.duration;
+ else
+ self.elapsed = 0f;
+}
+
+- (float) ratio { return fminf(1.0f, self.elapsed / self.duration); }
+- (void) setRatio:(float)newRatio {
+ if (newRatio >= 1.0f)
+ self.elapsed = self.duration;
+ else if (newRatio <= 0.0f)
+ self.elapsed = 0f;
+ else
+ self.elapsed = newRatio * self.duration;
+}
+
+
+/// initializers
+
+- (id) initWithDuration:(float)duration {
+ return [self initWithDuration:duration andReady:NO];
+}
+
+- (id) initWithDuration:(float)duration andReady:(BOOL)ready {
+ if ((self = [super init])){
+ _duration = duration;
+ _elapsed = (ready ? _duration : 0f);
+ }
+ return self;
+}
+
+
+/// methods
+
+/**
+ * Attempts to activate this cooldown, clearing the ready flag and setting elapsed to 0. Otherwise has no effect.
+ * @return Whether activation succeeded.
+ */
+- (BOOL) activate {
+ if (self.ready) {
+ self.ready = NO;
+ return YES;
+ }
+ return NO;
+}
+
+/**
+ * Advances the timer by {elapsed} milliseconds, updating ready state if necessary.
+ * @return Ready state.
+ */
+- (BOOL) tick:(float)elapsed {
+ if (self.ready)
+ return YES;
+ self.elapsed += elapsed;
+ return self.ready;
+}
+
+
+/// convenience constructors
+
++ (QQCooldown) cooldownWithDuration:(float)duration {
+ return [[[QQCooldown alloc] initWithDuration:duration] autorelease];
+}
+
++ (QQCooldown) cooldownWithDuration:(float)duration andReady:(BOOL)ready {
+ return [[[QQCooldown alloc] initWithDuration:duration andReady:ready] autorelease];
+}
+
+
+@end
#include <Box2D/Box2D.h>
+#import "game/QQThing.h"
#import "game/QQActive.h"
#import "game/QQPhysical.h"
#import "game/QQDisplayable.h"
@class QQGame;
-@interface QQActor : NSObject <QQActive, QQPhysical, QQDisplayable> {
+@interface QQActor : NSObject <QQThing, QQActive, QQPhysical, QQDisplayable> {
@protected
b2Body* _body;
-#include <Box2D/Box2D.h>
-#import "Sparrow.h"
-
-#import "render/QQSparrowExtensions.h"
-
#import "game/actor/QQActor.h"
-#import "game/actor/QQUnitDelegate.h"
-
-#import "physics/QQWorld.h"
-
+#import "game/QQThing.h"
-////////////////////////////////////////////////////////////////////////////////////
-@interface QQUnit : QQActor {
-@private
- SPDisplayObject* _shape;
- id<QQUnitDelegate> _delegate;
-}
+@protocol QQUnit <QQThing>
-////////////////////////////////////////////////////////////////////////////////////
-@property (nonatomic, retain, readwrite) SPDisplayObject* shape;
-@property (nonatomic, retain, readwrite) id<QQUnitDelegate> delegate;
+@property (nonatomic, readonly) BOOL canAttack;
-////////////////////////////////////////////////////////////////////////////////////
-- (id) initWithFile:(NSString*)fileName atX:(float)x y:(float)y;
-- (id) initWithShape:(SPDisplayObject*)shape atX:(float)x y:(float)y;
+- (void) attackTarget:(QQActor)actor;
+- (void) attackToward:(NSPoint)point;
+- (void) attackTowardX:(float)x y:(float)y;
-- (void) onTouch:(SPTouchEvent*)event;
@end
+++ /dev/null
-#include <Box2D/Box2D.h>
-#import "Sparrow.h"
-#import "QQUnit.h"
-
-
-////////////////////////////////////////////////////////////////////////////////////
-@implementation QQUnit
-
-////////////////////////////////////////////////////////////////////////////////////
-@synthesize shape = _shape;
-@synthesize delegate = _delegate;
-
-////////////////////////////////////////////////////////////////////////////////////
-- (id) init {
- return [self initWithShape:[SPQuad quadWithWidth:50 height:50 color:0xff0000] atX:15 y:15];
-}
-
-////////////////////////////////////////////////////////////////////////////////////
-- (id) initWithFile:(NSString*)fileName atX:(float)x y:(float)y {
- return [self initWithShape:
- [[[SPImage alloc] autorelease] initWithContentsOfFile:fileName]
- atX:x y:y];
-}
-
-////////////////////////////////////////////////////////////////////////////////////
-- (id) initWithShape:(SPDisplayObject*)shape atX:(float)x y:(float)y {
- if ((self = [super initAtX:x y:y])) {
- float px = self.world.scale;
- self.shape = [shape setPositionX:x*px y:y*px];
-
- b2PolygonShape box;
- box.SetAsBox(shape.width/px, shape.height/px);
- self.body->CreateFixture(&box, 5.0f);
-
- [self.game 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 removeChild:_shape];
- [_shape release];
- [super dealloc];
-}
-
-////////////////////////////////////////////////////////////////////////////////////
-- (void) setShape:(SPDisplayObject*)newShape {
- if (_shape != newShape) {
- [self.game removeChild:_shape];
- [_shape release];
- _shape = [newShape retain];
- [self.game addChild:_shape];
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////////
-- (void) onTouch:(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.body->SetTransform(b2Vec2(x/px, y/px), self.body->GetAngle());
- }
-}
-
-
-@end
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#endif
+
+#import "TanksMacros.h"