二维 iPhone 游戏中基于图块的碰撞检测问题

发布于 2024-08-06 12:04:12 字数 4428 浏览 2 评论 0原文

设置:
我正在为 iPhone 开发一款基于图块的 2D 游戏(鸟瞰图)。该应用程序读取图块的tile-d (.tbx) 图块地图文件,其“blocked”属性为 true 或 false,以表示英雄是否可以在图块中移动。我迭代地图中的每个图块,并创建一个表示图块行和列的二维 C 数组,以保存每个图块的阻止属性(真/假)。当我在棋盘上移动英雄时,我用数组检查英雄的位置,看看他移动的方块是否被阻挡。如果被阻挡,英雄的位置将反转与前进的位置一样多。

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

    }

}

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;

    }

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

离鸿 2024-08-13 12:04:12

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

下面是您的代码:

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,在一个哦。

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.

只是一片海 2024-08-13 12:04:12

我认为问题在于,如果你允许玩家移动到被阻挡的方块上,他就会被卡住。

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文