Проблемы обнаружения столкновений на основе плитки в 2-D игре для iPhone - PullRequest
0 голосов
/ 01 октября 2009

SETUP:
Я работаю над двумерной игрой на основе плиток (с высоты птичьего полета) для iPhone. Приложение считывает файл тайла map-d (.tbx) тайлов со свойством «заблокировано», равным true или false, чтобы показать, может ли герой пройти по тайлу. Я перебираю каждый элемент мозаики на карте и создаю двумерный массив C, представляющий строки и столбцы элементов мозаичного изображения для хранения заблокированного свойства (true / false) каждой плитки. Когда я перемещаю героя по доске, я проверяю положение героя с помощью массива, чтобы увидеть, заблокирован ли тайл, на котором он двигался, или нет. Если заблокировано, позиция героя меняется на столько, насколько она была продвинута.

ВЕРОЯТНОСТЬ:
Проблема в том, что когда герой наступил на заблокированную плитку, он не может от нее оторваться. Позиции тайлов правильны в том смысле, что заблокированные тайлы обнаруживаются там, где они должны быть, но герой все же застрял. Герой продвигается «по пикселю», а не «по плитке». Это обо всем. Осталось только показать код: (Hero размером 28 на 36 пикселей)

//Code from GameScreen.m





-(void)generateCollisionMap
{




for(int layer=0; layer < 2; layer++) {
            for(int yy=0; yy < _screenTilesHeight; yy++) {

                NSLog(@"Row %i", yy);

                for(int xx=0; xx < _screenTilesWide; xx++) {
                    int _globalTileID = [[[tileMap layers] objectAtIndex:layer] getGlobalTileIDAtX:xx y:yy];
                    NSString *_value = [tileMap getTilePropertyForGlobalTileID:_globalTileID key:@"blocked" defaultValue:@"false"];
                    if([_value isEqualToString:@"true"]) {

                        _blocked[xx][yy] = YES;
                        NSLog(@"Cell %i = YES", xx);

                    }else{

                        if(_blocked[xx][yy] == YES){
                        NSLog(@"Leaving Cell %i as = YES", xx);
                            //Leave As Is

                        }else{

                         _blocked[xx][yy] = NO;
                        NSLog(@"Cell %i = NO", xx);

                        }

                    }
                }
            }
            }
}





//Code from Hero.m


-(void)moveHero
{

            // Up

            if(moveDirection == 1 && !doesNeedShiftWorld) {
                heroY += _playerSpeed;
                [self checkBlocked:1];
                _currentAnimation = _upAnimation;
                _moving = YES;
            }

            // Down
            if(moveDirection == 2 && !doesNeedShiftWorld) {
                heroY -= _playerSpeed;
                [self checkBlocked:2];
                _currentAnimation = _downAnimation;
                _moving = YES;
            }

            // Left
            if(moveDirection == 3 && !doesNeedShiftWorld) {
                heroX -= _playerSpeed;
                [self checkBlocked:3];
                _currentAnimation = _leftAnimation;
                _moving = YES;
            }

            // Right
            if(moveDirection == 4 && !doesNeedShiftWorld) {
                heroX += _playerSpeed;
                [self checkBlocked:4];
               _currentAnimation = _rightAnimation;
                _moving = YES;
            }



}   



//  ... 


- (void) checkBlocked:(int)checkDirection
{

    float xx = (heroX+160.0f+_tileWidth) / _tileWidth;
    float yy = 11-((heroY+300.0f+_tileHeight) / _tileHeight); 


    switch (checkDirection) {

        case 1:

            yy -= 1;

            if([_scene isBlocked:xx y:yy] ||
               [_scene isBlocked:(heroX+160.0f) y:yy]) {
                NSLog(@"Scene Blocked at %i, %i!", (int)xx, (int)yy);
                heroY -= _playerSpeed;

            }else{

                NSLog(@"Clear at %i, %i!", (int)xx, (int)yy);

            }

            break;

        case 2:


            if([_scene isBlocked:xx y:yy] ||
               [_scene isBlocked:xx y:(heroY+300.0f)] ||
               [_scene isBlocked:(heroX+160.0f) y:(heroY+300.0f)]) {
                NSLog(@"Scene Blocked at %i, %i!", (int)xx, (int)yy);
                heroY += _playerSpeed;

            }else{

                NSLog(@"Clear at %i, %i!", (int)xx, (int)yy);

            }


            break;

        case 3:

            xx += 1;

            if([_scene isBlocked:xx y:yy] ||
               [_scene isBlocked:(heroX+160.0f) y:yy] || 
               [_scene isBlocked:(heroX+160.0f) y:(heroY+300.0f)]) {
                NSLog(@"Scene Blocked at %i, %i!", (int)xx, (int)yy);
                heroX += _playerSpeed;

            }else{

                NSLog(@"Clear at %i, %i!", (int)xx, (int)yy);

            }


            break;

        case 4:


            if([_scene isBlocked:xx y:yy] || 
               [_scene isBlocked:xx y:(heroY+300.0f)]) {
                NSLog(@"Scene Blocked at %i, %i!", (int)xx, (int)yy);
                heroX -= _playerSpeed;

            }else{

                NSLog(@"Clear at %i, %i!", (int)xx, (int)yy);

            }


            break;

    }

}

Ответы [ 2 ]

4 голосов
/ 01 октября 2009

Ваша проблема в том, что вы перемещаете игрока, затем проверяет, не заблокировано ли пространство, в которое он переехал. Вместо этого вы хотите выяснить позицию, в которую он собирается перейти, посмотреть, заблокирована ли она, а затем перемещать его, только если она не заблокирована. Также вы всегда можете добавить предложение, чтобы исключить его текущее пространство. то есть, пока ваш персонаж не меняет пространства сетки, он может всегда двигаться, но как только он собирается изменить пространства сетки, вам следует проверить, не столкнется ли он с чем-то.

Вот ваш код ниже:

if(moveDirection == 1 && !doesNeedShiftWorld) {
    heroY += _playerSpeed;
    [self checkBlocked:1];
    _currentAnimation = _upAnimation;
    _moving = YES;
}

Это должно быть примерно так:

if(moveDirection == 1 && !doesNeedShiftWorld)
{
    //Figure out if the player is changing grid spaces.
    BOOL isChangingSpaces = ((int)((heroY + _playerSpeed) / myGridSizeVariable) != (int)(heroY / myGridSizeVariable));

    //The player should be able to move either if he isn't
    //changing grid spaces or if his destination space is free.
    if ( !isChangingSpaces || (spaceIsOpenAtX:heroX andY:heroY+_playerSpeed) )
    {
        heroY += _playerSpeed;
        _currentAnimation = _upAnimation;
        _moving = YES;
    }
}

И вы действительно должны попытаться сделать свой код намного более объектно-ориентированным. На данный момент, это кажется полностью процедурным, и все ваши переменные являются глобальными, что определенно не очень хороший путь. «checkBlocked» следует переписать как «spaceIsOpenAtX: andY:», потому что тогда вы можете поместить любые координаты X и Y по своему желанию, чтобы увидеть, заблокирована ли эта позиция. Поскольку вы сделали это сейчас, ваш код слишком абстрактен (передавая целые числа без указания того, что они означают , кроме вашего фактического выражения if), и его нельзя применять ни для какой ситуации, кроме как от единственного использования, которое вы дали.

Действительно, у вас должны быть player.speed и player.animation и [maze spaceIsOpen] и т. Д. Вы используете Objective-C, а не просто C. И даже если вы используете C, было бы лучше сделать это в ОО пути.

0 голосов
/ 01 октября 2009

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

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

...