-#import <Box2D/Box2D.h>
+ #import <Box2D/Box2D.h>
#import "game/QQGame.h"
#import "game/unit/QQActors.h"
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];
+ [[[QQPlayer alloc] initNamed:@"Pink" atX:wMax/6 y:hMax/6 width:50 height:50 color:0xFF0071] autorelease];
+ [[[QQUnit alloc] initNamed:@"Blue" atX: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];
_elapsed = elapsed;
_now += elapsed;
+ if (_ticks == 1)
+ NSLog(@"%@", self);
+
for (QQActor* actor in self.actors)
[actor tick];
[self.world step];
- (void) logEvent:(SPEvent*)evt {
// ignore enter-frame events, as they happen constantly
if ([evt.type isEqualToString:SP_EVENT_TYPE_ENTER_FRAME]) return;
- NSLog(@"\v\t%@", evt);
+ // NSLog(@"\v\t%@", evt);
}
- (NSString*) description {
- 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
+ return [NSString stringWithFormat:@"<%@: %p> {running=%s, #actors=%i, time={now=%f, ticks=%i, elapsed=%f}, %@}",
+ [self class], self,
+ b2s(self.isRunning), (self.actors ? [self.actors count] : 0),
+ self.now, self.ticks, self.elapsed,
+ self.stage
];
}
@class QQContactNotification;
+typedef b2Vec2 Vec;
/**
* Anything that has a physics representation.
@property (nonatomic, readwrite, assign) float y;
/// Simulation coordinates
-@property (nonatomic, readwrite) CGPoint position;
+@property (nonatomic, readwrite) Vec position;
- (void) setPositionX:(float)x y:(float)y;
@property (nonatomic, readwrite, assign) float rotation;
*/
- (void) setupPhysics:(b2BodyDef*)bd;
-- (void) applyLinearImpulse:(CGPoint)vec;
+- (void) applyLinearImpulse:(Vec)vec;
- (void) applyLinearImpulseX:(float)xNs y:(float)yNs;
- (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();
- return CGPointMake(pos.x, pos.y);
+- (Vec) position {
+ return self.body->GetPosition();
+ // return CGPointMake(pos.x, pos.y);
}
-- (void) setPosition:(CGPoint)pos {
- [self setPositionX:pos.x y:pos.y];
+- (void) setPosition:(Vec)pos {
+ self.body->SetTransform(pos, self.body->GetAngle());
}
- (void) setPositionX:(float)x y:(float)y {
- self.body->SetTransform(b2Vec2(x,y), self.body->GetAngle());
+ [self setPosition:Vec(x,y)];
}
- (float) rotation { return self.body->GetAngle(); }
- (void) setRotation:(float)r { self.body->SetTransform(self.body->GetPosition(), r); }
[self updateShape];
}
-- (void) applyLinearImpulse:(CGPoint)pt {
- [self applyLinearImpulseX:pt.x y:pt.y];
+- (void) applyLinearImpulse:(Vec)pt {
+ self.body->ApplyLinearImpulse(pt, self.body->GetPosition());
}
- (void) applyLinearImpulseX:(float)xNs y:(float)yNs {
- self.body->ApplyLinearImpulse(b2Vec2(xNs, yNs), self.body->GetPosition());
+ [self applyLinearImpulse:Vec(xNs, yNs)];
}
#import "game/unit/QQActorDelegate.h"
#import "game/unit/QQUnit.h"
#import "game/unit/QQBullet.h"
-#import "game/unit/QQTank.h"
+#import "game/unit/QQPlayer.h"
@interface QQBullet : QQUnit {
@private
QQUnit* _owner;
+ float _speed;
}
@property (nonatomic, readonly) QQUnit* owner;
+@property (nonatomic, readwrite, assign) float speed;
- (id) init:(QQUnit*)owner x:(float)x y:(float)y;
+- (id) init:(QQUnit*)owner x:(float)x y:(float)y towardX:(float)tx y:(float)ty;
@end
+
@implementation QQBullet
@synthesize owner = _owner;
+@synthesize speed = _speed;
- (id) init:(QQUnit*)owner x:(float)x y:(float)y {
if ((self = [super initAtX:x y:y])){
_owner = owner;
+ _speed = 50.0f;
float px = self.world.scale;
float radius = 1.5f;
return self;
}
+- (id) init:(QQUnit*)owner x:(float)x y:(float)y towardX:(float)tx y:(float)ty {
+ if ((self = [self init:owner x:x y:y])) {
+ Vec imp = Vec(tx,ty);
+ imp.Normalize();
+ imp *= self.speed;
+ [self applyLinearImpulse:imp];
+ }
+ return self;
+}
+
- (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);
+ NSLog(@"BOOM!");
[other destroy];
[self destroy];
}
#import "game/unit/QQUnit.h"
-@interface QQTank : QQUnit {
+@interface QQPlayer : QQUnit {
}
--- /dev/null
+#import "QQPlayer.h"
+#import "render/QQSparrowExtensions.h"
+#import "game/QQGame.h"
+#import "game/unit/QQBullet.h"
+
+
+// private interface
+@interface QQPlayer ()
+- (void) onTouch:(SPTouchEvent*)event;
+@end
+
+
+
+@implementation QQPlayer
+
+
+- (id) initAtX:(float)x y:(float)y withShape:(SPDisplayObject*)shape {
+ if ((self = [super initAtX:x y:y withShape:shape])){
+ [self.shape addEventListener:@selector(onSelfTouch:) atObject:self forType:SP_EVENT_TYPE_TOUCH];
+ [self.game.stage addEventListener:@selector(attackOnTouch:) atObject:self forType:SP_EVENT_TYPE_TOUCH];
+ }
+ return self;
+}
+
+- (void) dealloc {
+ [self.game.stage removeEventListener:@selector(onTouch:) atObject:self forType:SP_EVENT_TYPE_TOUCH];
+ [super dealloc];
+}
+
+- (void) onSelfTouch:(SPTouchEvent*)event {
+ SPTouch* touch = [[event touchesWithTarget:(SPDisplayObject*)self.shape] anyObject];
+ NSLog(@">>>>> onSelfTouch! <<<<< \v\ttouch=%@ \v\tevent=%@ \v\tshape=%@ \v\tstage=%@\v", touch, event, self.shape, self.game.stage);
+}
+
+- (void) onTouch:(SPTouchEvent*)event {
+ SPTouch* touch = [[event touchesWithTarget:(SPDisplayObject*)self.game.stage] anyObject];
+ NSString* msg = [NSString stringWithFormat:@"onTouch! \vtouch=%@\v", touch];
+ msg = [msg stringByAppendingFormat:@"\t- %@\v", self.shape];
+ msg = [msg stringByAppendingFormat:@"\t- %@\v", self.game.stage];
+// SPDisplayObject* obj = self.shape;
+// do {
+// msg = [msg stringByAppendingFormat:@"\t- %@\v", obj];
+// } while ((obj = obj.parent));
+ NSLog(msg);
+}
+
+- (void) attackOnTouch:(SPTouchEvent*)event {
+ NSLog(@"onTouch: \v\t%@ \v\t%@", self, event);
+ SPTouch* touch = [[event touchesWithTarget:(SPDisplayObject*)self.game.stage] anyObject];
+ if (touch && [[self.cooldowns objectForKey:ATTACK_COOLDOWN_NAME] activate]) {
+ // [self attackToward:[[touch locationInSpace:self.shape.parent] scaleBy:1.0f/self.world.scale]];
+
+ // Touch's normal vector in local coords (rel unit origin)
+ SPPoint* normVec = [[[touch locationInSpace:self.shape.parent] subtractPoint:self.shape.position] normalize];
+
+ // Bullet starting position
+ float offset = 7.5f + fmaxf(self.shape.width, self.shape.height) * 1.41421356237f; // bullet_radius + tank_diagonal_length
+ SPPoint* start = [[self.shape.position addPoint:[normVec scaleBy:offset]] scaleBy:1.0f/self.world.scale];
+ QQBullet* bullet = [[[QQBullet alloc] init:self x:start.x y:start.y] autorelease];
+
+ // Bullet impulse vector
+ SPPoint* imp = [normVec scaleBy:50];
+ [bullet applyLinearImpulseX:imp.x y:imp.y];
+ // NSLog(@"[%@ pos:(%f,%f) impulse:(%f,%f)]", bullet, bullet.x,bullet.y, imp.x,imp.y);
+ }
+}
+
+- (void) _moveOnTouch:(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 setPositionX:x/px y:y/px];
+ // self.body->SetTransform(b2Vec2(x/px, y/px), self.body->GetAngle());
+ }
+}
+
+// - (NSString*) description {
+// return [NSString stringWithFormat:@"%@ bounds=%@",
+// [super description], self.bounds];
+// }
+
+
+@end
\ No newline at end of file
+++ /dev/null
-#import "QQTank.h"
-#import "render/QQSparrowExtensions.h"
-#import "game/QQGame.h"
-#import "game/unit/QQBullet.h"
-
-
-// private interface
-@interface QQTank ()
-- (void) onTouch:(SPTouchEvent*)event;
-@end
-
-
-
-@implementation QQTank
-
-
-- (id) initAtX:(float)x y:(float)y withShape:(SPDisplayObject*)shape {
- if ((self = [super initAtX:x y:y withShape:shape])){
- [self.game.stage addEventListener:@selector(onTouch:) atObject:self forType:SP_EVENT_TYPE_TOUCH];
- }
- return self;
-}
-
-- (void) dealloc {
- [self.game.stage removeEventListener:@selector(onTouch:) atObject:self forType:SP_EVENT_TYPE_TOUCH];
- [super dealloc];
-}
-
-
-- (void) onTouch:(SPTouchEvent*)event {
- SPTouch* touch = [[event touchesWithTarget:(SPDisplayObject*)self.game.stage] anyObject];
- if (touch && [[self.cooldowns objectForKey:ATTACK_COOLDOWN_NAME] activate]) {
- // Touch's normal vector in local coords (rel unit origin)
- SPPoint* normVec = [[[touch locationInSpace:self.shape.parent] subtractPoint:self.shape.position] normalize];
-
- // Bullet starting position
- float offset = 7.5f + fmaxf(self.shape.width, self.shape.height) * 1.41421356237f; // bullet_radius + tank_diagonal_length
- SPPoint* start = [[self.shape.position addPoint:[normVec scaleBy:offset]] scaleBy:1.0f/self.world.scale];
- QQBullet* bullet = [[[QQBullet alloc] init:self x:start.x y:start.y] autorelease];
-
- // Bullet impulse vector
- SPPoint* imp = [normVec scaleBy:50];
- [bullet applyLinearImpulseX:imp.x y:imp.y];
- NSLog(@"[%@ pos:(%f,%f) impulse:(%f,%f)]", bullet, bullet.x,bullet.y, imp.x,imp.y);
- }
-}
-
-
-@end
\ No newline at end of file
#import "game/unit/QQActor.h"
#import "game/unit/QQActorDelegate.h"
-
+@class QQBullet;
@interface QQUnit : QQActor {
/// initializers
-- (id) initAtX:(float)x y:(float)y width:(float)w height:(float)h color:(uint)color;
+- (id) initNamed:(NSString*)name atX:(float)x y:(float)y width:(float)w height:(float)h color:(uint)color;
- (id) initAtX:(float)x y:(float)y withShape:(SPDisplayObject*)shape;
/// methods
-- (void) attack:(QQActor*)actor;
-- (void) attackToward:(CGPoint)point;
-- (void) attackTowardX:(float)x y:(float)y;
+- (QQBullet*) attack:(QQActor*)actor;
+- (QQBullet*) attackToward:(SPPoint*)point;
+- (QQBullet*) attackTowardX:(float)x y:(float)y;
@end
#include <Box2D/Box2D.h>
#import "Sparrow.h"
#import "render/QQSparrowExtensions.h"
+#import "render/QQQuad.h"
#import "game/unit/QQUnit.h"
#import "game/QQGame.h"
/// initializers
- (id) init {
- return [self initAtX:50 y:50 width:50 height:50 color:0xff0071];
+ return [self initNamed:nil atX:50 y:50 width:50 height:50 color:0xff0071];
}
-- (id) initAtX:(float)x y:(float)y width:(float)w height:(float)h color:(uint)color {
+- (id) initNamed:(NSString*)name atX:(float)x y:(float)y width:(float)w height:(float)h color:(uint)color {
SPQuad* shape = [SPQuad quadWithWidth:w height:h color:color];
+ shape.name = name;
return [self initAtX:x y:y withShape:shape];
}
}
- (void) act {
- if ((self.game.ticks % 50) == 0) {
- self.rotation += b2_pi / 8;
+ if ((self.game.ticks % 100) == 0) {
+ self.rotation += b2_pi / 4;
}
}
}
-- (void) attack:(QQActor*)actor {
- [self attackTowardX:actor.x y:actor.y];
+- (QQBullet*) attack:(QQActor*)actor {
+ return [self attackTowardX:actor.x y:actor.y];
}
-- (void) attackToward:(CGPoint)pt {
- [self attackTowardX:pt.x y:pt.y];
+- (QQBullet*) attackTowardX:(float)x y:(float)y {
+ return [self attackToward:[SPPoint pointWithX:x y:y]];
}
-- (void) attackTowardX:(float)x y:(float)y {
- SPPoint* pos = [SPPoint pointFromCGPoint:self.position];
- SPPoint* target = [SPPoint pointWithX:x y:y];
+- (QQBullet*) attackToward:(SPPoint*)target {
+ SPPoint* pos = [SPPoint pointFromVec:self.position];
// Touch's normal vector in local coords (rel unit origin)
- SPPoint* normVec = [[target subtractPoint:pos] normalize];
+ SPPoint* norm = [[target subtractPoint:pos] normalize];
// Bullet starting position
+ // FIXME: GAH, unit size is wrong
float offset = 1.5f + MAX(self.shape.width, self.shape.height) * 1.41421356237f; // bullet_radius + tank_diagonal_length
- SPPoint* start = [pos addPoint:[normVec scaleBy:offset]];
- QQBullet* bullet = [[[QQBullet alloc] init:self x:start.x y:start.y] autorelease];
+ SPPoint* start = [pos addPoint:[norm scaleBy:offset]];
+ QQBullet* bullet = [[[QQBullet alloc] init:self x:start.x y:start.y towardX:norm.x y:norm.y] autorelease];
// Bullet impulse vector
- SPPoint* imp = [normVec scaleBy:50];
- [bullet applyLinearImpulseX:imp.x y:imp.y];
- NSLog(@"[%@ pos:(%f,%f) impulse:(%f,%f)]", bullet, bullet.x,bullet.y, imp.x,imp.y);
+ NSLog(@"[%@ pos:(%f,%f) impulse:(%f,%f)]", bullet, bullet.x,bullet.y, norm.x*50,norm.y*50);
+ return bullet;
}
#import "Tanks.h"
-int main(int argc, char *argv[])
-{
+int main(int argc, char *argv[]) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ // int retVal = 0;
int retVal = UIApplicationMain(argc, argv, nil, nil);
[pool release];
return retVal;
- (NSString*) description {
- return [NSString stringWithFormat:@"[%@ \v\tactorA=%@, \v\tactorB=%@]",
+ return [NSString stringWithFormat:@"\v\t[%@ \v\tactorA=%@, \v\tactorB=%@]",
[super description], self.actorA, self.actorB];
}
--- /dev/null
+#import "Sparrow.h"
+
+
+@interface QQQuad : SPQuad
+
+- (id)initWithWidth:(float)width height:(float)height color:(uint)color;
+
++ (QQQuad*)quadWithWidth:(float)width height:(float)height;
++ (QQQuad*)quadWithWidth:(float)width height:(float)height color:(uint)color;
+
+@end
--- /dev/null
+#import "QQQuad.h"
+
+
+@implementation QQQuad
+
+- (id)initWithWidth:(float)width height:(float)height color:(uint)color {
+ if ((self = [super init])) {
+ self.autoUpdateReg = YES;
+
+ float halfW = width *0.5f;
+ float halfH = height *0.5f;
+
+ mVertexCoords[0] = -halfW;
+ mVertexCoords[1] = -halfH;
+
+ mVertexCoords[2] = halfW;
+ mVertexCoords[3] = -halfH;
+
+ mVertexCoords[4] = -halfW;
+ mVertexCoords[5] = halfH;
+
+ mVertexCoords[6] = halfW;
+ mVertexCoords[7] = halfH;
+
+ self.color = color;
+ self.registrationX = 0;
+ self.registrationY = 0;
+ }
+ return self;
+}
+
++ (QQQuad*)quadWithWidth:(float)width height:(float)height {
+ return [[[QQQuad alloc] initWithWidth:width height:height] autorelease];
+}
+
++ (QQQuad*)quadWithWidth:(float)width height:(float)height color:(uint)color {
+ return [[[QQQuad alloc] initWithWidth:width height:height color:color] autorelease];
+}
+
+@end
@interface SPPoint (QQSparrowExtensions)
- (CGPoint) toCGPoint;
+- (b2Vec2) toVec;
+ (SPPoint*) pointFromCGPoint:(CGPoint)pt;
-+ (SPPoint*) pointFromB2Vec2:(b2Vec2)vec;
++ (SPPoint*) pointFromVec:(b2Vec2)vec;
@end
@implementation SPPoint (QQSparrowExtensions)
- (CGPoint) toCGPoint {
- return CGPointMake(mX, mY);
+ return CGPointMake(mX,mY);
+}
+- (b2Vec2) toVec {
+ return b2Vec2(mX,mY);
}
+ (SPPoint*) pointFromCGPoint:(CGPoint)pt {
return [SPPoint pointWithX:pt.x y:pt.y];
}
-+ (SPPoint*) pointFromB2Vec2:(b2Vec2)vec {
++ (SPPoint*) pointFromVec:(b2Vec2)vec {
return [SPPoint pointWithX:vec.x y:vec.y];
}