Skip to content

Instantly share code, notes, and snippets.

@pixelrevision
Created June 24, 2012 16:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pixelrevision/2983946 to your computer and use it in GitHub Desktop.
Save pixelrevision/2983946 to your computer and use it in GitHub Desktop.
A very simple character class for use with cocos2D iphone. Will perform basic collision testing with a orthogonal CCTMXTiledMap. Very useful if wanting to get something up and running quickly without wrestling with box2d or chipmunk.
#import <Foundation/Foundation.h>
#import "cocos2d.h"
@interface CCTMXMapCharacter : CCNode {
CCTMXTiledMap *_map;
CCTMXLayer *_collidersLayer;
CGRect _collisionRect;
CGSize _mapSize;
CGSize _tileSize;
CGSize _actualMapSize;
CGPoint _movement;
CGPoint _velocity;
CGPoint _maxVelocity;
CGPoint _acceleration;
BOOL _touchingTop;
BOOL _touchingBottom;
BOOL _touchingLeft;
BOOL _touchingRight;
BOOL _oversizedCollisionRect;
int _oversizedStepsX;
int _oversizedStepsY;
float _padding;
}
@property (nonatomic, retain) CCTMXTiledMap *map;
@property (nonatomic, assign) CGPoint velocity;
@property (nonatomic, assign) CGRect collisionRect;
@property (nonatomic, assign) CGPoint maxVelocity;
@property (nonatomic, assign) CGPoint acceleration;
- (void)moveRight:(float)amount;
- (void)moveLeft:(float)amount;
- (void)moveUp:(float)amount;
- (void)moveDown:(float)amount;
- (void)normalizeVelocity;
- (void)update:(ccTime)deltaTime;
- (CGPoint)validateTile:(CGPoint)tile;
- (void)resetCollisionFlags;
- (void)checkForOversizedCollisionRect;
- (BOOL)overlapsCharacter:(CCTMXMapCharacter*)character;
@end
#import "CCTMXMapCharacter.h"
@implementation CCTMXMapCharacter
@synthesize map = _map;
@synthesize velocity = _velocity;
@synthesize collisionRect = _collisionRect;
@synthesize maxVelocity = _maxVelocity;
@synthesize acceleration = _acceleration;
- (id)init{
self = [super init];
_padding = 0.1f;
_velocity = CGPointMake(0.0f, 0.0f);
_maxVelocity = CGPointMake(1000.0f, 1000.0f);
_collisionRect = CGRectMake(100.0f, 300.0f, 16.0f, 16.0f);
[self schedule:@selector(update:)];
return self;
}
- (void)setMap:(CCTMXTiledMap *)m{
if(_map){
[_map release];
_map = nil;
}
if(m){
_map = [m retain];
}
if(_map){
_mapSize = [_map mapSize];
_tileSize = [_map tileSize];
_actualMapSize = CGSizeMake(_mapSize.width * _tileSize.width, _mapSize.height * _tileSize.height);
_collidersLayer = [_map layerNamed:@"colliders"];
[self checkForOversizedCollisionRect];
}
}
- (void)setCollisionRect:(CGRect)collRect{
_collisionRect = collRect;
[self checkForOversizedCollisionRect];
}
- (void)checkForOversizedCollisionRect{
_oversizedCollisionRect = NO;
_oversizedStepsX = 1;
_oversizedStepsY = 1;
if(_collisionRect.size.width > _tileSize.width){
_oversizedStepsX = ceil(_collisionRect.size.width/_tileSize.width);
_oversizedCollisionRect = YES;
}
if(_collisionRect.size.height > _tileSize.height){
_oversizedStepsY = ceil(_collisionRect.size.height/_tileSize.height);
_oversizedCollisionRect = YES;
}
}
- (void)moveRight:(float)amount{
if(!_collidersLayer){
_collisionRect.origin.x = _collisionRect.origin.x + amount;
return;
}
float right = floor((_collisionRect.origin.x + _collisionRect.size.width + amount)/_tileSize.width);
float nextOffset = 0.0f;
int numSteps = ceil(_collisionRect.size.height/_map.tileSize.height);
float incSize = _collisionRect.size.height/numSteps;
for(int y=0; y<=numSteps; y++) {
CGPoint next = CGPointMake(right, floor((_collisionRect.origin.y + nextOffset)/_tileSize.height) );
if ([_collidersLayer tileAt:next]) {
_touchingRight = YES;
_collisionRect.origin.x = (next.x * _tileSize.width) - _collisionRect.size.width - _padding;
return;
}
nextOffset += incSize;
}
_collisionRect.origin.x = _collisionRect.origin.x + amount;
}
- (void)moveLeft:(float)amount{
if(!_collidersLayer){
_collisionRect.origin.x = _collisionRect.origin.x + amount;
return;
}
float left = floor((_collisionRect.origin.x + amount)/_tileSize.width);
float nextOffset = 0.0f;
int numSteps = ceil(_collisionRect.size.height/_map.tileSize.height);
float incSize = _collisionRect.size.height/numSteps;
for(int y=0; y<=numSteps; y++) {
CGPoint next = CGPointMake(left, floor((_collisionRect.origin.y + nextOffset)/_tileSize.height) );
if ([_collidersLayer tileAt:next]) {
_touchingLeft = YES;
_collisionRect.origin.x = (next.x * _tileSize.width) + _tileSize.width + _padding;
return;
}
nextOffset += incSize;
}
_collisionRect.origin.x = _collisionRect.origin.x + amount;
}
- (void)moveUp:(float)amount{
if(!_collidersLayer){
_collisionRect.origin.y = _collisionRect.origin.y + amount;
return;
}
float top = floor((_collisionRect.origin.y + amount)/_tileSize.height);
float nextOffset = 0.0f;
int numSteps = ceil(_collisionRect.size.width/_map.tileSize.width);
float incSize = _collisionRect.size.width/numSteps;
for(int x=0; x<=numSteps; x++){
CGPoint next = CGPointMake(floor((_collisionRect.origin.x + nextOffset)/_tileSize.width), top);
if ([_collidersLayer tileAt:next]) {
_touchingTop = YES;
_collisionRect.origin.y = (next.y * _tileSize.height) + _tileSize.height + _padding;
return;
}
nextOffset += incSize;
}
_collisionRect.origin.y = _collisionRect.origin.y + amount;
}
- (void)moveDown:(float)amount{
if(!_collidersLayer){
_collisionRect.origin.y = _collisionRect.origin.y + amount;
return;
}
float bottom = floor((_collisionRect.origin.y + _collisionRect.size.height + amount)/_tileSize.height);
float nextOffset = 0.0f;
int numSteps = ceil(_collisionRect.size.width/_map.tileSize.width);
float incSize = _collisionRect.size.width/numSteps;
for(int x=0; x<=numSteps; x++) {
CGPoint next = CGPointMake(floor((_collisionRect.origin.x + nextOffset)/_tileSize.width), bottom);
if ([_collidersLayer tileAt:next]) {
_touchingBottom = YES;
_collisionRect.origin.y = (next.y * _tileSize.height) - _collisionRect.size.height - _padding;
return;
}
nextOffset += incSize;
}
_collisionRect.origin.y = _collisionRect.origin.y + amount;
}
- (CGPoint)validateTile:(CGPoint)tile{
if(tile.x < 0){
tile.x = 0;
}
if(tile.x >= _mapSize.width){
tile.x = _mapSize.width - 1;
}
if(tile.y < 0){
tile.y = 0;
}
if(tile.y >= _mapSize.height){
tile.y = _mapSize.height - 1;
}
return tile;
}
- (void)normalizeVelocity{
if(_velocity.x > _maxVelocity.x){
_velocity.x = _maxVelocity.x;
}else if(_velocity.x < -_maxVelocity.x){
_velocity.x = -_maxVelocity.x;
}
if(_velocity.y > _maxVelocity.y){
_velocity.y = _maxVelocity.y;
}else if(_velocity.y < -_maxVelocity.y){
_velocity.y = -_maxVelocity.y;
}
}
- (void)resetCollisionFlags{
_touchingRight = NO;
_touchingLeft = NO;
_touchingTop = NO;
_touchingBottom = NO;
}
- (BOOL)overlapsCharacter:(CCTMXMapCharacter*)character{
return CGRectIntersectsRect(_collisionRect, character.collisionRect);
}
- (void)update:(ccTime)deltaTime{
[self resetCollisionFlags];
// apply acceleration
if(_acceleration.x > 0 || _acceleration.x < 0){
_velocity.x = _velocity.x + (_acceleration.x * deltaTime);
}
if(_acceleration.y > 0 || _acceleration.y < 0){
_velocity.y = _velocity.y + (_acceleration.y * deltaTime);
}
// apply velocity
[self normalizeVelocity];
if(_velocity.x > 0.0f){
[self moveRight:_velocity.x * deltaTime];
}else if(_velocity.x < 0.0f){
[self moveLeft:_velocity.x * deltaTime];
}
if(_velocity.y > 0.0f){
[self moveDown:_velocity.y * deltaTime];
}else if(_velocity.y < 0.0f){
[self moveUp:_velocity.y * deltaTime];
}
// coordinate use top left to work well with the tile map
CGPoint newPos = CGPointMake(_collisionRect.origin.x + (_collisionRect.size.width/2), _actualMapSize.height - (_collisionRect.origin.y + (_collisionRect.size.height/2) ));
[self setPosition:newPos];
}
- (void)dealloc{
self.map = nil;
[self unschedule:@selector(update:)];
[super dealloc];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment