implementing accelerometer in tiled map

Discussion in 'iOS Programming' started by animefan32, Dec 9, 2011.

  1. animefan32 macrumors newbie

    Joined:
    Aug 26, 2011
    #1
    i have been trying to make a game using cocos2d. The map i'm using is made using Tiled and i'm trying to implement movement of character using accelerometer. I have tried myself but it didnt work. The movement is not smooth and very jumpy. Here is my code so far:

    Code:
    #import "HelloWorldLayer.h"
    #import "SimpleAudioEngine.h"
    #define kFilterFactor 0.05
    
    @implementation HelloWorldHud
    
     -(id) init
     {
        if ((self = [super init])) {
            CGSize winSize = [[CCDirector sharedDirector] winSize];
            label = [CCLabelTTF labelWithString:@"0" dimensions:CGSizeMake(50, 20) alignment:UITextAlignmentRight fontName:@"Verdana-Bold"  fontSize:18.0];
            label.color = ccc3(0,0,0);
            int margin = 10;
            label.position = ccp(winSize.width - (label.contentSize.width/2) - margin, label.contentSize.height/2 + margin);
            [self addChild:label];
    
            totalTime = 60;
            timeLabel = [CCLabelTTF labelWithString:@"60" fontName:@"Arial" fontSize:18];
            timeLabel.color = ccc3(0, 0, 0);
            timeLabel.position = CGPointMake(winSize.width/2, winSize.height);
            timeLabel.anchorPoint = CGPointMake(0.5f, 1.0f);
            [self addChild:timeLabel];
    
            [self schedule: @selector(update:)];
        }
        return self;
     }
    
    - (void)numCollectedChanged:(int)numCollected {
        [label setString:[NSString stringWithFormat:@"%d", numCollected]];
    }
    
    -(void)update:(ccTime)dt
    {
        totalTime -= dt;
        currentTime = (int)totalTime;
        if(totalTime > currentTime)
        {
            //myTime = currentTime;
            [timeLabel setString:[NSString stringWithFormat:@"%02d:%02d", currentTime/60, currentTime%60]];
        }
    }
    
    @end
    
    // HelloWorldLayer implementation
    @implementation HelloWorldLayer
    
    @synthesize tileMap = _tileMap;
    @synthesize background = _background;
    @synthesize player = _player;
    @synthesize meta = _meta;
    @synthesize foreground = _foreground;
    @synthesize numCollected = _numCollected;
    @synthesize hud = _hud;
    
    +(CCScene *) scene
    {
    	// 'scene' is an autorelease object.
    	CCScene *scene = [CCScene node];
    
    	// 'layer' is an autorelease object.
    	HelloWorldLayer *layer = [HelloWorldLayer node];
    
    	// add layer as a child to scene
    	[scene addChild: layer];
        layer.tag = 1;
    
        HelloWorldHud *hud = [HelloWorldHud node];
        [scene addChild:hud];
    
        layer.hud = hud;
    
    	// return the scene
    	return scene;
    }
    
    // on "init" you need to initialize your instance
    -(id) init
    {
    	// always call "super" init
    	// Apple recommends to re-assign "self" with the "super" return value
    	if( (self=[super init])) {
    
    		[[SimpleAudioEngine sharedEngine] preloadEffect:@"pickup.caf"];
            [[SimpleAudioEngine sharedEngine] preloadEffect:@"hit.caf"];
            [[SimpleAudioEngine sharedEngine] preloadEffect:@"move.caf"];
            [[SimpleAudioEngine sharedEngine] playBackgroundMusic:@"TileMap.caf"];
    
            //self.isTouchEnabled = YES;
            self.isAccelerometerEnabled = YES;
            UIAccelerometer *accel = [UIAccelerometer sharedAccelerometer];
            accel.delegate = self;
            accel.updateInterval = 1.0f/60.0f;
    
            //load background
            self.tileMap = [CCTMXTiledMap tiledMapWithTMXFile:@"TileMap.tmx"];
            self.background = [_tileMap layerNamed:@"Background"];
            self.foreground = [_tileMap layerNamed:@"Foreground"];
    
            //load collidable tile
            self.meta = [_tileMap layerNamed:@"Meta"];
            _meta.visible = NO;
    
            //starting point
            CCTMXObjectGroup *objects = [_tileMap objectGroupNamed:@"Objects"];
            NSAssert(objects !=nil, @"'Objects' object group not found");
            NSMutableDictionary *spawnPoint = [objects objectNamed:@"SpawnPoint"];
            NSAssert(spawnPoint !=nil, @"SpawnPoint object not found");
            int x = [[spawnPoint valueForKey:@"x"] intValue];
            int y = [[spawnPoint valueForKey:@"y"] intValue];
            int tileSpawnWidth = _tileMap.tileSize.width;
            int tileSpawnHeight = _tileMap.tileSize.height;
            x = (x - (x % tileSpawnWidth)) + (tileSpawnWidth/2);
            y = (y - (y % tileSpawnHeight)) + (tileSpawnHeight/2);
    
            //load player
    		self.player = [CCSprite spriteWithFile:@"Player.png"];
            _player.position = ccp(x, y);
            _player.tag = 2;
            [self addChild:_player];
    
            id setCamera = [CCFollow actionWithTarget:_player];
            [self runAction:setCamera];
            [self addChild: _tileMap z:-1];
    
    	}
    	return self;
    }
    
    -(CGPoint) tileCoordForPosition: (CGPoint)position {
        int x = position.x / _tileMap.tileSize.width;
        int y = ((_tileMap.mapSize.height * _tileMap.tileSize.height) - position.y) / _tileMap.tileSize.height;
        return ccp(x,y);
    }
    
    -(void) registerWithTouchDispatcher
    {
        [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
    }
    
    -(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
    {
        return YES;
    }
    
    -(void) setPlayerPosition:(CGPoint)position
    {
        //Convert x, y coordinate of player into tile coordinate
        CGPoint tileCoord = [self tileCoordForPosition:position];
        int tileGid = [_meta tileGIDAt:tileCoord];
        if(tileGid) {
            NSDictionary *properties = [_tileMap propertiesForGID:tileGid];
            if(properties) {
                //Check if collide with wall/stone
                NSString *collision = [properties valueForKey:@"Collidable"];
                if(collision && [collision compare: @"True"] == NSOrderedSame) {
                    [[SimpleAudioEngine sharedEngine] playEffect:@"hit.caf"];
                    return;
                }
                //Check if collide with collectable item
                NSString *collectable = [properties valueForKey:@"Collectable"];
                if(collectable && [collectable compare:@"True"] == NSOrderedSame) {
                    [_meta removeTileAt:tileCoord];
                    [_foreground removeTileAt:tileCoord];
                    self.numCollected++;
                    [_hud numCollectedChanged:_numCollected];
                    [[SimpleAudioEngine sharedEngine] playEffect:@"pickup.caf"];
                }
            }
        }
        [[SimpleAudioEngine sharedEngine] playEffect:@"move.caf"];
        //_player.position = position;
        ccTime moveDuration = 0.3;
        id playerMove = [CCMoveTo actionWithDuration:moveDuration position:position];
        id cameraMove = [CCFollow actionWithTarget:_player worldBoundary:CGRectMake(0, 0, (_tileMap.mapSize.width * _tileMap.tileSize.width), (_tileMap.mapSize.height * _tileMap.tileSize.height))];
        [_player runAction:playerMove];
    
        [self runAction:cameraMove];
    }
    
    -(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event
    {
        CGPoint touchLocation = [touch locationInView:[touch view]];
        touchLocation = [[CCDirector sharedDirector] convertToGL:touchLocation];
        touchLocation = [self convertToNodeSpace:touchLocation];
    
        CGPoint playerPos = _player.position;
        CGPoint diff = ccpSub(touchLocation, playerPos);
        if(abs(diff.x) > abs(diff.y))
        {
            if(diff.x > 0)
            {
                playerPos.x += _tileMap.tileSize.width;
            }
            else
            {
                playerPos.x -= _tileMap.tileSize.width;
            }
        }
        else
        {
            if(diff.y > 0)
            {
                playerPos.y += _tileMap.tileSize.height;
            }
            else
            {
                playerPos.y -= _tileMap.tileSize.height;
            }
        }
    
        if(playerPos.x <= (_tileMap.mapSize.width * _tileMap.tileSize.width) &&
           playerPos.y <= (_tileMap.mapSize.height * _tileMap.tileSize.height) &&
           playerPos.y >= 0 &&
           playerPos.x >= 0 )
        {
            [self setPlayerPosition:playerPos];
        }
    
    }
    
    #define kPlayerSpeed 100
    #define kHeroMovementAction 1
    -(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
    {
        //UIAccelerationValue accelX, accelY;
        //accelX = (acceleration.x*kFilterFactor) + (accelX*(1.0 - kFilterFactor));
        //accelY = (acceleration.y*kFilterFactor) + (accelY*(1.0 - kFilterFactor));
        HelloWorldLayer *layer = (HelloWorldLayer *) [[[CCDirector sharedDirector] runningScene] getChildByTag:1];
        CCSprite *playerSprite = (CCSprite *) [layer getChildByTag:2];
        CGPoint playerPos;
    
        float destX, destY;
        BOOL shouldMove = NO;
    
        float currentX = playerSprite.position.x;
        float currentY = playerSprite.position.y;
    
        if(acceleration.x > 0.25)
        {
            destX = currentX - (acceleration.y * kPlayerSpeed);
            destY = currentY + (acceleration.x * kPlayerSpeed);
            shouldMove = YES;
        } else
        if(acceleration.x < -0.25)
        {
            destX = currentX - (acceleration.y * kPlayerSpeed);
            destY = currentY + (acceleration.x * kPlayerSpeed);
            shouldMove = YES;
        } else
        if(acceleration.y < -0.25)
        {
            destX = currentX - (acceleration.y * kPlayerSpeed);
            destY = currentY + (acceleration.x * kPlayerSpeed);
            shouldMove = YES;
        } else
        if(acceleration.y > 0.25)
        {
            destX = currentX - (acceleration.y * kPlayerSpeed);
            destY = currentY + (acceleration.x * kPlayerSpeed);
            shouldMove = YES;
        } else
        {
            destX = currentX;
            destY = currentY;
        }
    
        playerPos.x = destX;
        playerPos.y = destY;
    
        if(shouldMove)
        {
            CGSize wins = [[CCDirector sharedDirector] winSize];
            if(destX < 30 || destX > wins.width - 30 || destY < 30 || destY > wins.height - 100)
            {
                [self setPlayerPosition:playerPos];
            }
            else
            {
                CCAction *action = [CCMoveTo actionWithDuration:1 position:CGPointMake(destX, destY)];
                [action setTag:kHeroMovementAction];
                [playerSprite runAction:action];
            }
        }
        else
        {
            [playerSprite stopActionByTag:kHeroMovementAction];
        }
    }
    
    // on "dealloc" you need to release all your retained objects
    - (void) dealloc
    {
    	// in case you have something to dealloc, do it in this method
    	// in this particular example nothing needs to be released.
    	// cocos2d will automatically release all the children (Label)
    
    	// don't forget to call "super dealloc"
        self.tileMap = nil;
        self.background = nil;
        self.player = nil;
        self.meta = nil;
        self.foreground = nil;
        self.hud = nil;
    	[super dealloc];
    }
    @end
    
    Hope someone can help me fix this...
     
  2. ArtOfWarfare macrumors 604

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #2
    I'm not sure we have people here that use Cocos2D much... The cocos2D forums might be a better place to ask.
     
  3. animefan32 thread starter macrumors newbie

    Joined:
    Aug 26, 2011
    #3
    well i'm asking at cocos2d forum as well but no reply..so i might try my luck here...
     
  4. ArtOfWarfare macrumors 604

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #4
    Alright... well... your issue is with the accelerometer itself, I suppose.

    You might consider reducing the code you're showing to only have what changes accelerometer motion into character motion to help other people help you.

    But I've already looked through your code now... and... I can't help you. The accelerometer is kind of difficult to work with. The numbers it gives tend to jump around. You just need to play with what it gives you and manipulate it to reduce the noise... I don't really know how to do this, thus why I've yet to actually release an app where I use the accelerometer (I have plenty of apps I wrote for my own iPhone where I played with the accelerometer... none of them were good enough at filtering out noise...)
     
  5. lloyddean macrumors 6502a

    Joined:
    May 10, 2009
    Location:
    Des Moines, WA
    #5
    Yes you'll need to filter the accelorometer data. Apple has an some example code to illustrate what might be done at <http://developer.apple.com/library/ios/#samplecode/AccelerometerGraph/Introduction/Intro.html>
     

Share This Page