float mAlpha;
BOOL mVisible;
BOOL mTouchable;
+ BOOL mAutoUpdateReg;
SPDisplayObjectContainer *mParent;
double mLastTouchTimestamp;
/// The y coordinate of the object's rotational origin in local coordinates.
@property (nonatomic, assign) float registrationY;
+/// Automatically updates registration to be half the object's size if concrete width or height changes.
+/// True by default; note that changes to scale do not effect concrete size.
+@property (nonatomic, readwrite, assign) BOOL autoUpdateReg;
+
/// The rotation of the object in radians. (In Sparrow, all angles are measured in radians.)
@property (nonatomic, assign) float rotation;
@synthesize scaleY = mScaleY;
@synthesize registrationX = mRegX;
@synthesize registrationY = mRegY;
+@synthesize autoUpdateReg = mAutoUpdateReg;
@synthesize rotation = mRotationZ;
@synthesize parent = mParent;
@synthesize alpha = mAlpha;
{
[self release];
[NSException raise:SP_EXC_ABSTRACT_CLASS
- format:@"Attempting to initialize abstract class SPDisplayObject."];
+ format:@"Attempting to initialize abstract class SPDisplayObject."];
return nil;
}
#endif
mScaleY = 1.0f;
mRegX = 0;
mRegY = 0;
+ mAutoUpdateReg = YES;
mRotationZ = 0;
mVisible = YES;
mTouchable = YES;
return [matrix autorelease];
}
+- (NSString*) description {
+ return [NSString stringWithFormat:@"[%@ pos=(%f,%f), rotation=%f @ (%f,%f), scale=(%f,%f)]",
+ [super description], self.x,self.y, self.rotation, self.registrationX,self.registrationY, self.scaleX,self.scaleY];
+}
+
+
@end
// -------------------------------------------------------------------------------------------------
{
if ((self = [super init]))
{
- mVertexCoords[2] = width;
+ mVertexCoords[2] = width;
mVertexCoords[5] = height;
mVertexCoords[6] = width;
mVertexCoords[7] = height;
self.color = color;
+ if (self.autoUpdateReg) {
+ self.registrationX = width * 0.5f;
+ self.registrationY = height * 0.5f;
+ }
}
- return self;
+ return self;
}
- (id)initWithWidth:(float)width height:(float)height
float mCenterRotation;
}
-@property (nonatomic, assign) float centerX;
-@property (nonatomic, assign) float centerY;
@property (nonatomic, assign) float radiusX;
@property (nonatomic, assign) float radiusY;
@property (nonatomic, assign) BOOL fill;
mWidth = width;
mHeight = height;
+ if (self.autoUpdateReg) {
+ self.registrationX = width * 0.5f;
+ self.registrationY = height * 0.5f;
+ }
+
+
mFill = YES;
self.color = SP_WHITE;
mBorder = NO;
return [SPRectangle rectangleWithX:minX y:minY width:maxX-minX height:maxY-minY];
}
-- (void)setCenterX:(float)centerX {
- self.x = centerX - (mWidth/2);
-}
-
-- (float)centerX {
- return self.x + (mWidth/2);
-}
-
-- (void)setCenterY:(float)centerY {
- self.y = centerY - (mHeight/2);
-}
-
-- (float)centerY {
- return self.y + (mHeight/2);
-}
-
- (void)setRadiusX:(float)radiusX {
self.width = radiusX*2;
}
- (void)setWidth:(float)width {
mWidth = width;
+ if (self.autoUpdateReg) self.registrationX = width * 0.5f;
[self drawVertices];
[super setWidth:mWidth];
}
- (void)setHeight:(float)height {
mHeight = height;
+ if (self.autoUpdateReg) self.registrationY = height * 0.5f;
[self drawVertices];
[super setHeight:mHeight];
}
+#ifndef TANKS_H
+#define TANKS_H
+#define TANKS_DEBUG_LOG 1
+#endif
#import "render/QQSparrowExtensions.h"
*/
@protocol QQActive <QQThing>
-@property (nonatomic, getter=isActive) BOOL active;
+@property (nonatomic, readwrite, getter=isActive) BOOL active;
+// @property (nonatomic, readwrite, getter=isSleeping) BOOL sleeping;
- (void) tick:(float)elapsed;
- (void) act;
@property (nonatomic, readwrite, assign, getter=isDirty) BOOL dirty; // TODO: implement this and fix various [shape setPosition] calls
@property (nonatomic, readwrite, retain) SPDisplayObject* shape;
-/** Intended center of the shape in points. */
-@property (nonatomic, readwrite, assign) float shapeCenterX;
-@property (nonatomic, readwrite, assign) float shapeCenterY;
-
/**
* Called to setup the Sparrow shape.
*/
-#import "QQGame.h"
-#import "game/actor/unit/QQTank.h"
-#import "game/actor/QQUnit.h"
#import <Box2D/Box2D.h>
+#import "game/QQGame.h"
+#import "game/actor/QQActors.h"
+
static QQGame* _CurrentGame = NULL;
@interface QQGame ()
+
- (void) onEnterFrame:(SPEnterFrameEvent*)event;
+
@end
@implementation QQGame
-@synthesize world = _world;
-@synthesize level = _level;
-@synthesize actors = _actors;
-
-@synthesize ticks = _ticks;
-@synthesize paused = _running;
-@synthesize debugDrawingEnabled = _debugDrawingEnabled;
-
- (id) init {
if (_CurrentGame) {
[_root addChild:_debugView];
self.debugDrawingEnabled = YES;
- _actors = [[NSMutableArray alloc] initWithCapacity:10];
+ _actors = [[NSMutableSet alloc] initWithCapacity:10];
+ _awake = [[NSMutableSet alloc] initWithCapacity:10];
+ _units = [[NSMutableSet alloc] initWithCapacity:10];
+ _bullets = [[NSMutableSet alloc] initWithCapacity:10];
CGSize frame = [UIScreen mainScreen].applicationFrame.size;
float wMax = frame.width / _world.scale;
[self removeEventListener:@selector(onEnterFrame:) atObject:self forType:SP_EVENT_TYPE_ENTER_FRAME];
[self removeAllChildren];
- [_actors removeAllObjects];
- [_actors release];
+ NSMutableSet* sets[] = {_actors, _awake, _units, _bullets};
+ for (int i = 0; i < 4; i++) {
+ NSMutableSet* set = sets[i];
+ [set removeAllObjects];
+ [set release];
+ }
[_level release];
[_debugView release];
+ [_root release];
[_world release];
_CurrentGame = NULL;
/// properties
+@synthesize world = _world;
+@synthesize level = _level;
+
+@synthesize actors = _actors;
+
+@synthesize ticks = _ticks;
+@synthesize paused = _running;
+
+@synthesize debugDrawingEnabled = _debugDrawingEnabled;
+
- (void) setDebugDrawingEnabled:(BOOL)enable {
_debugDrawingEnabled = _debugView.visible = enable;
}
/// methods
-- (void) start {
- if (!_running) {
- _running = YES;
- [self 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];
- _running = NO;
- }
-}
-
- (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];
return self;
}
- (QQGame*) removeActor:(QQActor*)actor {
- [_actors removeObject:actor];
+ [_actors removeObject:actor];
+ [_awake removeObject:actor];
+ [_units removeObject:actor];
+ [_bullets removeObject:actor];
return self;
}
- (void) tick:(float)elapsed {
_ticks++;
-#ifdef DEBUG_LOG
+#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) {
}
#endif
- for (QQActor* actor in self.actors) [actor tick:elapsed]; // XXX: self.awakeAgents
+ for (QQActor* actor in _awake) [actor tick:elapsed];
[self.world step];
- for (QQActor* actor in self.actors) [actor draw]; // XXX: self.drawableAgents
+ for (QQActor* actor in self.actors) [actor draw];
+}
+
+
+- (void) start {
+ if (!_running) {
+ _running = YES;
+ [self 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];
+ _running = NO;
+ }
+}
+
+
+
+ (QQGame*) current {
if (!_CurrentGame)
[[[QQGame alloc] init] // init assigns to singleton, but singleton is a weakref,
/// The y coordinate in the simulation.
@property (nonatomic, readwrite, assign) float y;
+
@property (nonatomic, readwrite) CGPoint position;
- (void) setPositionX:(float)x y:(float)y;
@synthesize dirty = _dirty;
@synthesize delegate = _delegate;
-@dynamic shapeCenterX;
-@dynamic shapeCenterY;
+@dynamic shape;
- (QQGame*) game { return QQGame.current; }
- (QQWorld*) world { return self.game.world; }
-- (SPDisplayObject*) shape { return nil; }
-- (void) setShape:(SPDisplayObject*)newShape {}
-
- (b2Body*) body { return _body; }
- (b2Fixture*) fixture { return nil; }
- (void) updateShapeX:(float)x y:(float)y rotation:(float)r {
[self updateShapeX:x y:y];
- SPDisplayObject* shape = self.shape;
- shape.registrationX = self.shapeCenterX;
- shape.registrationY = self.shapeCenterY;
- shape.rotation = r;
+ // SPDisplayObject* shape = self.shape;
+ // shape.registrationX = self.shapeCenterX;
+ // shape.registrationY = self.shapeCenterY;
+ self.shape.rotation = r;
}
- (void) updateShape {
- (void) setupPhysics {}
-- (NSString *)description {
+- (NSString*) description {
b2Transform trans = self.body->GetTransform();
b2Vec2 pos = trans.position;
//b2Vec2 v = actor.body->GetLinearVelocity();
SPDisplayObject* s = self.shape;
- return [NSString stringWithFormat:@"[%@ w=%f, h=%f, pos=(%f,%f), rotation=%f @ (%f,%f), scale=(%f,%f), shape=[%@ center=(%f,%f)]]",
- [super description], s.width,s.height, pos.x,pos.y, trans.GetAngle(), s.registrationX,s.registrationY,
- s.scaleX,s.scaleY, s, self.shapeCenterX,self.shapeCenterY];
+ return [NSString stringWithFormat:@"[%@ box2d=[ (%f,%f) rotation=%f], shape=%@]",
+ [super description], pos.x,pos.y, trans.GetAngle(), s];
}
--- /dev/null
+#import "QQActor.h"
+#import "QQActorDelegate.h"
+#import "QQUnit.h"
+#import "bullet/QQBullet.h"
+#import "unit/QQTank.h"
@private
SPDisplayObject* _shape;
- float _shapeCenterX;
- float _shapeCenterY;
}
/// properties
@dynamic game;
@synthesize shape = _shape;
-@synthesize shapeCenterX = _shapeCenterX;
-@synthesize shapeCenterY = _shapeCenterY;
+- (float) shapeCenterX { return self.shape.registrationX; }
+- (void) setShapeCenterX:(float)x { self.shape.registrationX = x; }
+- (float) shapeCenterY { return self.shape.registrationY; }
+- (void) setShapeCenterY:(float)y { self.shape.registrationY = y; }
- (BOOL) canAttack { return NO; }
}
- (id) initAtX:(float)x y:(float)y width:(float)w height:(float)h color:(uint)color {
- return [self initAtX:x y:y withShape:[SPQuad quadWithWidth:w height:h color:color]];
+ SPQuad* shape = [SPQuad quadWithWidth:w height:h color:color];
+ return [self initAtX:x y:y withShape:shape];
}
- (id) initAtX:(float)x y:(float)y withShape:(SPDisplayObject*)shape {
[_shape release];
_shape = [newShape retain];
- _shapeCenterX = _shape.width * 0.5f;
- _shapeCenterY = _shape.height * 0.5f;
[self updateShape];
[self.game.level addChild:_shape];
}
- (void) draw {
[super draw];
- if ((self.game.ticks % 50) == 0) NSLog(@"%@", self);
}
}
- (void) onTouch:(SPTouchEvent*)event {
- SPTouch* touch = [[event touchesWithTarget:self.shape.parent] anyObject];
+ SPTouch* touch = [[event touchesWithTarget:(SPDisplayObject*)self.game] 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];
- (float) centerY { return self.y + self.registrationY; }
- (void) setCenterY:(float)y { self.y = y - self.registrationY; }
-/** Sets coordinates of the object relative to the local coordinates of the parent. */
+/** Sets coordinates of the object relative to the local coordinates of the parent, modified by the registration point. */
- (id) setCenterX:(float)x y:(float)y {
self.centerX = x;
self.centerY = y;
492D8115138C07540042D918 /* SXFPSMeter.h in Headers */ = {isa = PBXBuildFile; fileRef = 492D810A138C07540042D918 /* SXFPSMeter.h */; };
492D8116138C07540042D918 /* SXFPSMeter.m in Sources */ = {isa = PBXBuildFile; fileRef = 492D810B138C07540042D918 /* SXFPSMeter.m */; };
494DE9971376927C00FDB3D7 /* libBox2D.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 494DE9961376927C00FDB3D7 /* libBox2D.a */; };
+ 4978AD0E1395E5CE00930447 /* QQActors.h in Headers */ = {isa = PBXBuildFile; fileRef = 4978AD0D1395E5CE00930447 /* QQActors.h */; };
4995ABB213816CCE00334646 /* QQGame.h in Headers */ = {isa = PBXBuildFile; fileRef = 49E834A513812427007A6598 /* QQGame.h */; };
4995ABB313816CD400334646 /* QQUnit.h in Headers */ = {isa = PBXBuildFile; fileRef = 49E834A213812427007A6598 /* QQUnit.h */; };
4995ABF91381C46B00334646 /* Icon-iPad.png in Resources */ = {isa = PBXBuildFile; fileRef = 4995ABCA1381C46B00334646 /* Icon-iPad.png */; };
492D810A138C07540042D918 /* SXFPSMeter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SXFPSMeter.h; sourceTree = "<group>"; };
492D810B138C07540042D918 /* SXFPSMeter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SXFPSMeter.m; sourceTree = "<group>"; };
494DE9961376927C00FDB3D7 /* libBox2D.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libBox2D.a; sourceTree = SOURCE_ROOT; };
+ 4978AD0D1395E5CE00930447 /* QQActors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QQActors.h; sourceTree = "<group>"; };
4995ABCA1381C46B00334646 /* Icon-iPad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-iPad.png"; sourceTree = "<group>"; };
4995ABCB1381C46B00334646 /* Icon-iPhone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-iPhone.png"; sourceTree = "<group>"; };
4995ABCC1381C46B00334646 /* Icon-iPhone@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-iPhone@2x.png"; sourceTree = "<group>"; };
492D80E9138BA4B40042D918 /* QQTank.h */,
492D80EA138BA4B40042D918 /* QQTank.mm */,
);
- name = unit;
- path = actor/unit;
+ path = unit;
sourceTree = "<group>";
};
492D80ED138BA4BC0042D918 /* bullet */ = {
492D80EE138BA4BC0042D918 /* QQBullet.h */,
492D80EF138BA4BC0042D918 /* QQBullet.mm */,
);
- name = bullet;
- path = actor/bullet;
+ path = bullet;
sourceTree = "<group>";
};
492D8100138C07540042D918 /* Extras */ = {
isa = PBXGroup;
children = (
49193BEE139280180005B3DD /* map */,
- 492D80ED138BA4BC0042D918 /* bullet */,
- 492D80E8138BA4B40042D918 /* unit */,
492D80DB138BA4910042D918 /* ability */,
49E8349F13812427007A6598 /* actor */,
+ 492D80F2138BA4CE0042D918 /* QQThing.h */,
49E8349E13812427007A6598 /* QQActive.h */,
49E834A413812427007A6598 /* QQDisplayable.h */,
492D80CB138B231B0042D918 /* QQPhysical.h */,
- 492D80F2138BA4CE0042D918 /* QQThing.h */,
49E834A513812427007A6598 /* QQGame.h */,
49E834A613812427007A6598 /* QQGame.mm */,
);
49E8349F13812427007A6598 /* actor */ = {
isa = PBXGroup;
children = (
- 492D80FE138BCC9F0042D918 /* QQActorDelegate.h */,
+ 492D80ED138BA4BC0042D918 /* bullet */,
+ 492D80E8138BA4B40042D918 /* unit */,
+ 4978AD0D1395E5CE00930447 /* QQActors.h */,
49E834A013812427007A6598 /* QQActor.h */,
49E834A113812427007A6598 /* QQActor.mm */,
+ 492D80FE138BCC9F0042D918 /* QQActorDelegate.h */,
49E834A213812427007A6598 /* QQUnit.h */,
492D80FC138BCA840042D918 /* QQUnit.mm */,
);
49F2D9B313764666000B6B8C /* render */ = {
isa = PBXGroup;
children = (
+ 4B8B2A4D137D090D00CA4076 /* animation */,
49D8645B1392DB2800BC341C /* QQShape.h */,
49D8645C1392DB2800BC341C /* QQShape.mm */,
- 4B8B2A4D137D090D00CA4076 /* animation */,
49E834D1138166A6007A6598 /* QQSparrowExtensions.h */,
49E834D2138166A6007A6598 /* QQSparrowExtensions.mm */,
);
492D80FF138BCC9F0042D918 /* QQActorDelegate.h in Headers */,
49193BF5139280180005B3DD /* QQLevel.h in Headers */,
49D8645D1392DB2800BC341C /* QQShape.h in Headers */,
+ 4978AD0E1395E5CE00930447 /* QQActors.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};