1
votes

I am in the process of learning cocos2d-android. I have been following a tutorial that ported some of Ray Wenderlich's iOS tutorials to Android. I have the first tutorials finished and wanted to continue on by converting the next Ray Wenderlich tutorial to Android by myself as an exercise in learning.

The original iOS tutorial can be found here http:// www raywenderlich com/1163/how-to-make-a-tile-based-game-with-cocos2d

I have converted the application to android but am having some trouble with the way its behaving.

My code is here:

public class GameLayer extends CCLayer{

private CGSize _winSize;
protected ArrayList<CCSprite> _targets;
protected ArrayList<CCSprite> _projectiles;
protected int _projectilesDestroyed;
protected CCSprite _player;
protected CCSprite _nextProjectile;
protected CCTMXTiledMap _map;
protected CCTMXLayer _background;
protected CCTMXObjectGroup _objects;
protected HashMap<String, String> _spawnPoint;

protected GameLayer() {
    super();
    _winSize = CCDirector.sharedDirector().displaySize();
    _targets = new ArrayList<CCSprite>();
    _projectiles = new ArrayList<CCSprite>();
    _projectilesDestroyed = 0;

    // Get TMX Map and associated layers/groups
    _map = CCTMXTiledMap.tiledMap("TileMap.tmx");
    _background = _map.layerNamed("Background");
    _objects = _map.objectGroupNamed("Objects");

    // Add my background layer
    // TODO: Position layer in the correct spot.
    addChild(_background);

    _spawnPoint = _objects.objectNamed("SpawnPoint");

    _player = CCSprite.sprite("Player3.png");

    setPlayerPosition(CGPoint.ccp (100.0f, 100.0f));

    addChild(_player);
    setViewPointCentered(_player.getPosition());

    Context context = CCDirector.sharedDirector().getActivity();
    SoundEngine.sharedEngine().preloadEffect(context, R.raw.pew_pew_lei);
    SoundEngine.sharedEngine().playSound(context, R.raw.background_music_aac, true);

    this.setIsTouchEnabled(true);
    this.schedule("update");
}

public void setViewPointCentered(CGPoint pos) {
    float x = 0.0f;
    float y = 0.0f;

    x = Math.max(pos.x, _winSize.width / 2);
    y = Math.max(pos.y, _winSize.height / 2);

    x = Math.min(x,  (_map.getMapSize().width * _map.getTileSize().width) - _winSize.width / 2 );
    y = Math.min(y, (_map.getMapSize().height * _map.getTileSize().height) - _winSize.height / 2);

    CGPoint actualPos = CGPoint.ccp(x, y);

    CGPoint centerOfView = CGPoint.ccp(_winSize.width / 2, _winSize.height / 2);
    CGPoint viewPoint = CGPoint.ccpSub(centerOfView, actualPos);

    _background.setPosition(viewPoint);
}

public static CCScene scene() {
    CCScene scene = CCScene.node();
    CCLayer layer = new GameLayer();

    scene.addChild(layer);

    return scene;
}

@Override
public boolean ccTouchesBegan(MotionEvent event) {
    return true;

}

void setPlayerPosition(CGPoint position) {
    _player.setPosition(position);
}

@Override
public boolean ccTouchesEnded(MotionEvent event) {

    // Choose one of the touches to work with
    CGPoint touchLocation = CGPoint.ccp(event.getX(), event.getY());
    touchLocation = CCDirector.sharedDirector().convertToGL(touchLocation);
    touchLocation = this.convertToNodeSpace(touchLocation);

    CGPoint playerPosition = _player.getPosition();
    CGPoint diff = CGPoint.ccpSub(touchLocation, playerPosition);

    if (Math.abs(diff.x) > Math.abs(diff.y)) {
        if (diff.x > 0) {
            playerPosition.x += _map.getTileSize().width;
        } else {
            playerPosition.x -= _map.getTileSize().width;
        }
    } else {
        if (diff.y > 0) {
            playerPosition.y += _map.getTileSize().height;
        } else {
            playerPosition.y -= _map.getTileSize().height;
        }
    }

    if (playerPosition.x <= (_map.getMapSize().width * _map.getTileSize().width) &&
        playerPosition.y <= (_map.getMapSize().height * _map.getTileSize().height) &&
        playerPosition.y >= 0 &&
        playerPosition.x >= 0 ) {
        setPlayerPosition(playerPosition);
    }

    setViewPointCentered(_player.getPosition());

    return true;

}

public void finishShoot() {
    addChild(_nextProjectile);
    _projectiles.add(_nextProjectile);
}

public void update(float dt) {
    ArrayList<CCSprite> projectilesToDelete = new ArrayList<CCSprite>();

    for (CCSprite projectile : _projectiles) {
        CGRect projectileRect = CGRect.make(projectile.getPosition().x - (projectile.getContentSize().width / 2.0f),
                projectile.getPosition().y - (projectile.getContentSize().height / 2.0f),
                projectile.getContentSize().width,
                projectile.getContentSize().height);

        ArrayList<CCSprite> targetsToDelete = new ArrayList<CCSprite>();
        for (CCSprite target : _targets) {
            CGRect targetRect = CGRect.make(target.getPosition().x - (target.getContentSize().width),
                    target.getPosition().y - (target.getContentSize().height),
                    target.getContentSize().width,
                    target.getContentSize().height);

            if (CGRect.intersects(projectileRect, targetRect)) {
                targetsToDelete.add(target);
            }
        }

        for (CCSprite target : targetsToDelete) {
            _targets.remove(target);
            removeChild(target, true);
        }

        if (targetsToDelete.size() > 0) {
            projectilesToDelete.add(projectile);
        }
    }

    for (CCSprite projectile : projectilesToDelete) {
        _projectiles.remove(projectile);
        removeChild(projectile, true);
        if (++_projectilesDestroyed > 30) {
            _projectilesDestroyed = 0;
            CCDirector.sharedDirector().replaceScene(GameOverLayer.scene("You Win!"));
        }
    }
}

}

I first grab my display size and create my tiled map from my TMX file. I get my background layer and add it as a child. I then grab my objects layer and pull my spawn point object out of the map (I override this spawn point with 100, 100 for testing purposes). I grab my player sprite and set my player position to the 100, 100 coordinates. I then add the player as a child.

Next I call setViewPointCentered to move my map to an appropriate position based on my players position. This part works just fine and my map gets placed with the lower left corner (0,0) placed in the lower left corner (0,0) of my screen and my character is at 100,100 slightly left and down from the center of the screen.

The problem occurs when I begin moving up or right. Once I pass the center of the screen I would expect to have the player sprite stay centered on the screen and the background move the opposite direction as I continue moving. However both the player and the background move so eventually my player comes to the right or top edge of the screen and I can't move up or right any longer even though there is plenty of map left.

Notice the player in the upper left corner of the map.

Player reaching the top of screen and not staying centered as expected

Notice the player in the lower right corner of the map.

Player reaching the right of screen and not staying centered as expected

The "public boolean ccTouchesEnded(MotionEvent event)" method and the "public void setViewPointCentered(CGPoint pos)" method handle the player and view positioning but I don't think they're working correctly.

A friend of mine does iOS programming and created the app on his iPhone and it's working as expected so I'm wondering if there is a bug in the android port of cocos2d.

Does anyone have any ideas on why the character won't stay centered on the screen when I get to the middle and continue moving right or up on the map?

Thanks for any input you can provide. I've been beating my head against my desk for two days trying to figure this out.

2

2 Answers

1
votes

OK I figured it out.

In this piece of code:

// Get TMX Map and associated layers/groups
_map = CCTMXTiledMap.tiledMap("TileMap.tmx");
_background = _map.layerNamed("Background");
_objects = _map.objectGroupNamed("Objects");

// Add my background layer
// TODO: Position layer in the correct spot.
addChild(_background);

I am adding my _background layer but what I really want to be doing is adding my _map instead:

// Get TMX Map and associated layers/groups
_map = CCTMXTiledMap.tiledMap("TileMap.tmx");
_background = _map.layerNamed("Background");
_objects = _map.objectGroupNamed("Objects");

// Add my background layer
// TODO: Position layer in the correct spot.
addChild(_map);

Now my player character remains in the center of my viewable screen while walking around unless I get to the edge of the map.

0
votes

Each time when the touch ends, the player is moved by mapWidth or height. You should move the position with diff. Try

CGPoint diff = CGPoint.ccpSub(touchLocation, playerPosition);

if (Math.abs(diff.x) > Math.abs(diff.y)) {
    if (diff.x > 0) {
        playerPosition.x += diff.x;
    } else {
        playerPosition.x -= diff.x;
    }
} else {
    if (diff.y > 0) {
        playerPosition.y += diff.y;
    } else {
        playerPosition.y -= diff.y;
    }
}