cocos2d-android (версия на github) Как сохранить спрайт «игрока» в центре экрана при перемещении фонового слоя?

Я нахожусь в процессе изучения cocos2d-android. Я следил за учебным пособием, которое перенесло некоторые учебные пособия Рэя Вендерлиха по iOS на Android. Я закончил первые уроки и хотел бы продолжить, самостоятельно преобразовав следующий учебник Рэя Вендерлиха в Android в качестве упражнения в обучении.

Оригинальный учебник для iOS можно найти здесь http://www raywenderlich com/1163/how-to-make-a-tile-based-game-with-cocos2d.

Я преобразовал приложение в Android, но у меня возникли проблемы с тем, как оно себя ведет.

Мой код здесь:

открытый класс GameLayer расширяет 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!"));
        }
    }
}

}

Сначала я беру размер экрана и создаю мозаичную карту из файла TMX. Я получаю свой фоновый слой и добавляю его как дочерний. Затем я беру слой с объектами и вытаскиваю объект точки появления из карты (я переопределяю эту точку появления на 100, 100 для целей тестирования). Я беру спрайт своего игрока и устанавливаю позицию своего игрока на координаты 100, 100. Затем я добавляю игрока в качестве ребенка.

Затем я вызываю setViewPointCentered, чтобы переместить мою карту в подходящую позицию в зависимости от позиции моих игроков. Эта часть работает просто отлично, и моя карта размещается так, что нижний левый угол (0,0) помещается в нижний левый угол (0,0) моего экрана, а мой персонаж находится на 100 100 немного левее и ниже центра экрана. .

Проблема возникает, когда я начинаю двигаться вверх или вправо. Как только я прохожу центр экрана, я ожидаю, что спрайт игрока останется в центре экрана, а фон будет двигаться в противоположном направлении, пока я продолжаю двигаться. Однако и игрок, и фон перемещаются, поэтому в конце концов мой игрок подходит к правому или верхнему краю экрана, и я больше не могу двигаться вверх или вправо, хотя на карте осталось много места.

Обратите внимание на игрока в левом верхнем углу карты.

Игрок достигает верхней части экрана и не остается в центре, как ожидалось

Обратите внимание на игрока в правом нижнем углу карты.

Игрок достигает правого края экрана и не остается в центре, как ожидалось

Метод «public boolean ccTouchesEnded (событие MotionEvent)» и метод «public void setViewPointCentered (CGPoint pos)» обрабатывают проигрыватель и позиционирование просмотра, но я не думаю, что они работают правильно.

Мой друг занимается программированием iOS и создал приложение на своем iPhone, и оно работает, как и ожидалось, поэтому мне интересно, есть ли ошибка в порте cocos2d для Android.

У кого-нибудь есть идеи, почему персонаж не остается в центре экрана, когда я добираюсь до середины и продолжаю двигаться вправо или вверх по карте?

Спасибо за любой вклад, который вы можете предоставить. Я два дня бился головой о стол, пытаясь понять это.


person MySkippy    schedule 29.02.2012    source источник


Ответы (2)


Хорошо, я понял это.

В этом фрагменте кода:

// 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);

Я добавляю свой слой _background, но на самом деле я хочу добавить вместо него свою _map:

// 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);

Теперь мой игровой персонаж остается в центре моего видимого экрана во время ходьбы, пока я не доберусь до края карты.

person MySkippy    schedule 02.03.2012

Каждый раз, когда касание заканчивается, игрок перемещается на ширину карты или высоту. Вы должны переместить позицию с помощью diff. Пытаться

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;
    }
}
person user936414    schedule 29.02.2012
comment
Спасибо за ваше предложение, однако я не верю, что вы правы. Цель щелчка — переместить игрока на один тайл карты в направлении щелчка, а не на разницу в расстоянии между игроком и местом щелчка. Мне кажется, я этим и занимаюсь. с помощью _map.getTileSize().width я использую ширину одной плитки на карте (32x32 px), а не всю ширину карты. В любом случае, когда я вернусь домой сегодня вечером, я внесу это изменение и посмотрю, будет ли это иметь какое-то значение. Спасибо! - person MySkippy; 29.02.2012
comment
Я попробовал ваше предложение, но, как я подозревал, это не то, что я искал. Ваше решение будет перемещать игрока на то же расстояние, что и разница между исходной позицией игроков и касанием, но у него все еще есть проблема, заключающаяся в том, что игрок не остается в центре экрана. Я хочу, чтобы игрок перемещал 1 плитку карты (32 пикселя) каждый раз, когда я касаюсь экрана. Как только игрок достигает середины экрана, я хочу, чтобы он оставался в центре экрана, и я хочу, чтобы карта переместилась на 1 тайл карты (32 пикселя) в противоположном направлении, чтобы означать, что игрок двигался. Спасибо хоть. - person MySkippy; 01.03.2012