views:

526

answers:

2

SETUP:
I'm working on a 2-D tile-based game (bird's eye view) for iPhone. The app reads in a tile-d (.tbx) tilemap file of tiles with a 'blocked' property of either true or false to represent whether or not the hero can move through the tile. I iterate over each tile in the map and create a 2-dimensional C array representing tile rows and cols to hold the blocked property (true/false) of each tile. When I move the hero across the board, I check the hero's position with the array to see if the tile he moved on is blocked or not. If blocked, the hero's position is reversed by as much as it was advanced.

PROB:
Problem is, when a hero has stepped on a blocked tile, he cannot move off of it. Tile positions are correct in the sense that blocked tiles are detected where they should be but hero is stuck nonetheless. Hero advances 'by pixel' and not ' by tile'. That's about all. Only thing left is to show code: (Hero is 28 pixels by 36 pixels in size)

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

    }

}
A: 

I think the problem is that you allow the player to move onto the blocked tile and he gets stuck.

I would check to see if the direction the player is moving is blocked before attempting to move the player there.

Aaron M
+4  A: 

Your problem is that you're moving the player, then checking to see if the space he moved to is blocked. Instead, you want to figure out the position that he's going to want to move to, see if it's blocked, and then only move him if it isn't blocked. Also, you can always add in a clause to exclude his current space. i.e. as long as your character isn't changing grid spaces, he can always move, but once he is about to change grid spaces you should check to see if he will collide with something.

Here is your code below:

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

It should be something like this:

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;
    }
}

And you really should try to make your code much more object-oriented. At this point, it seems to be completely procedural and all your variables are globals, which is definitely not a good way to go. "checkBlocked" should be rewritten as "spaceIsOpenAtX: andY:" because then you can put any X and Y coordinate in that you want in order to see if that position is blocked. As you've done it now, your code is too abstract (passing around integers with no indication of what they mean other than your actual if statement checks) and it can't be applied for any situation whatsoever aside from the single use you gave it.

Really, you should have player.speed and player.animation and [maze spaceIsOpen], etc. You're using Objective-C, not just C. And even if you were using C it would be a better idea to do it in an OO way.

Eli