【问题标题】:Tile-based Collision Detection problems in 2-D iPhone game2-D iPhone 游戏中基于图块的碰撞检测问题
【发布时间】:2009-10-01 04:07:55
【问题描述】:

设置:
我正在为 iPhone 开发基于 2-D 瓷砖的游戏(鸟瞰图)。该应用程序读入一个 tile-d (.tbx) tilemap 文件,该文件具有 true 或 false 的“blocked”属性,以表示英雄是否可以通过该图块。我遍历地图中的每个图块并创建一个表示图块行和列的二维 C 数组,以保存每个图块的阻塞属性(真/假)。当我移动英雄时,我用数组检查英雄的位置,看看他移动的棋子是否被阻挡。如果被阻挡,英雄的位置会与前进时一样多。

问题:
问题是,当英雄踩到一块被阻挡的瓷砖时,他无法离开它。瓷砖位置是正确的,因为被阻挡的瓷砖被检测到它们应该在的位置,但英雄仍然被卡住。英雄“按像素”而不是“按图块”前进。这就是全部。剩下的就是显示代码:(Hero 的大小是 28 像素 x 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;

    }

}

【问题讨论】:

    标签: iphone opengl-es collision-detection tiles


    【解决方案1】:

    你的问题是你正在移动玩家,然后检查他移动到的空间是否被阻塞。相反,你想弄清楚他要移动到的位置,看看它是否被阻挡,然后只有在没有被阻挡的情况下才移动他。此外,您始终可以添加一个子句来排除他当前的空间。也就是说,只要你的角色不改变网格空间,他就可以总是移动,但是一旦他要改变网格空间,你应该检查他是否会与什么东西发生碰撞。

    下面是您的代码:

    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,这样做也是一个更好的主意以面向对象的方式。

    【讨论】:

      【解决方案2】:

      我认为问题在于您允许玩家移动到被阻挡的瓷砖上并且他被卡住了。

      在尝试将玩家移动到那里之前,我会检查玩家移动的方向是否被阻挡。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多