精灵与贴图的碰撞

Sprite collision with tile map

本文关键字:碰撞 精灵      更新时间:2023-10-16

所以,我尝试着创造自己的游戏引擎,我的第一个项目便是创造一个《吃豆人》的克隆版本。我已经知道如何创建贴图并在上面移动吃豆人。但我在创建碰撞检测器时遇到了一些问题。特别的问题是,碰撞检测到当前位置以北的任何瓷砖都很好,但它认为当前位置以下的瓷砖实际上比正常情况大1个瓷砖。在当前位置的东面和西面的贴图不存在碰撞。我很困惑,因为碰撞适用于北瓦…但是我对其他方向使用了相同的逻辑,它不起作用。

我使用的逻辑是"ok"瓷砖移动到值为0。任何其他贴图都不能移动

下面是我用于实际墙壁碰撞的代码:

//checks for a sprite colliding with a wall tile
//direction refers to 1=North, 2=South, 3=West, 4=East
bool Wall_Collision(SPRITE sprite, int direction)
{
    //grab center of sprite
    Posx = sprite.x + Sprite_Radius;
    Posy = sprite.y + Sprite_Radius;
    //create rectangle for the sprite
    RECT spriteRect;
    spriteRect.left = (long)sprite.x;
    spriteRect.top = (long)sprite.y;
    spriteRect.right = (long)sprite.x + sprite.width * sprite.scaling;
    spriteRect.bottom = (long)sprite.y + sprite.height * sprite.scaling;
    //recover North tile info
    int N_posx, N_posy;
    int N_tilex, N_tiley;
    int N_tilevalue;
    N_posx = Posx / TILEWIDTH;
    N_posy = (Posy - TILEHEIGHT) / TILEHEIGHT;
    N_tilex = N_posx * TILEWIDTH;
    N_tiley = N_posy * TILEHEIGHT;
    N_tilevalue = MAPDATA[(N_posy * MAPWIDTH + N_posx)];
    //create rectangle for tile North of sprite center
    RECT northRect;
    northRect.left = N_tilex;
    northRect.top = N_tiley;
    northRect.right = N_tilex + TILEWIDTH;
    northRect.bottom = N_tiley + TILEHEIGHT;
    //recover South tile info
    int S_posx, S_posy;
    int S_tilex, S_tiley;
    int S_tilevalue;
    S_posx = Posx / TILEWIDTH;
    S_posy = (Posy + TILEHEIGHT) / TILEHEIGHT;
    S_tilex = S_posx * TILEWIDTH;
    S_tiley = S_posy * TILEHEIGHT;
    S_tilevalue = MAPDATA[(S_posy * MAPWIDTH + S_posx)];
    //create rectangle for tile South of sprite center
    RECT southRect;
    southRect.left = S_tilex;
    southRect.top = S_tiley;
    southRect.right = S_tilex + TILEWIDTH;
    southRect.bottom = S_tiley + TILEHEIGHT;
    //recover West tile info
    int W_posx, W_posy;
    int W_tilex, W_tiley;
    int W_tilevalue;
    W_posx = (Posx - TILEWIDTH) / TILEWIDTH;
    W_posy = Posy / TILEHEIGHT;
    W_tilex = W_posx * TILEWIDTH;
    W_tiley = W_posy * TILEHEIGHT;
    W_tilevalue = MAPDATA[(W_posy * MAPWIDTH + W_posx)];
    //create rectangle for tile West of sprite center
    RECT westRect;
    westRect.left = W_tilex;
    westRect.top = W_tiley;
    westRect.right = W_tilex + TILEWIDTH;
    westRect.bottom = W_tiley + TILEHEIGHT;
    //recover East tile info
    int E_posx, E_posy;
    int E_tilex, E_tiley;
    int E_tilevalue;
    E_posx = (Posx + TILEWIDTH) / TILEWIDTH;
    E_posy = Posy / TILEHEIGHT;
    E_tilex = E_posx * TILEWIDTH;
    E_tiley = E_posy * TILEHEIGHT;
    E_tilevalue = MAPDATA[(E_posy * MAPWIDTH + E_posx)];
    //create rectangle for tile East of sprite center
    RECT eastRect;
    eastRect.left = E_tilex;
    eastRect.top = E_tiley;
    eastRect.right = E_tilex + TILEWIDTH;
    eastRect.bottom = E_tiley + TILEHEIGHT;
    RECT dest; //ignored
    //check North collision
    if (direction == 1 && N_tilevalue != 0)
    {
        return IntersectRect(&dest, &spriteRect, &northRect);
    }
    else return false;
    //check South collision
    if (direction == 2 && S_tilevalue != 0)
    {
        return IntersectRect(&dest, &spriteRect, &southRect);
    }
    else return false;
    //check West collision
    if (direction == 3 && W_tilevalue != 0)
    {
        return IntersectRect(&dest, &spriteRect, &westRect);
    }
    else return false;
    //check East collision
    if (direction == 4 && E_tilevalue != 0)
    {
        return IntersectRect(&dest, &spriteRect, &eastRect);
    }
    else return false;
}

然后是上下文,我使用这个函数来移动玩家精灵:

void MovePacman()
{
    if (Wall_Collision(pacman, 1))
    {
        pacman.y -= pacman.vely;
        pacman.vely = 0.0f;
    }
    else
    {
        if (Key_Down(DIK_UP))
        {
            pacman.vely = -0.2f;
            pacman.velx = 0.0f;
        }
    }
    if (Wall_Collision(pacman, 2))
    {
        pacman.y -= pacman.vely;
        pacman.vely = 0.0f;
    }
    else
    {
        if (Key_Down(DIK_DOWN))
        {
            pacman.vely = 0.2f;
            pacman.velx = 0.0f;
        }
    }
    if (Wall_Collision(pacman, 3))
    {
        pacman.x -= pacman.velx;
        pacman.velx = 0.0f;
    }
    else
    {
        if (Key_Down(DIK_LEFT))
        {
            pacman.velx = -0.2f;
            pacman.vely = 0.0f;
        }
    }
    if (Wall_Collision(pacman, 4))
    {
        pacman.x -= pacman.velx;
        pacman.velx = 0.0f;
    }
    else
    {
        if (Key_Down(DIK_RIGHT))
        {
            pacman.velx = 0.2f;
            pacman.vely = 0.0f;
        }
        else;
    }
    if (pacman.vely < 0)
        Sprite_Animate(pacman.frame, pacman.startframe, 18, 4, pacman.starttime, 250);
    else if (pacman.vely > 0)
        Sprite_Animate(pacman.frame, pacman.startframe, 16, 2, pacman.starttime, 250);
    else if (pacman.velx < 0)
        Sprite_Animate(pacman.frame, pacman.startframe, 17, 3, pacman.starttime, 250);
    else if (pacman.velx > 0)
        Sprite_Animate(pacman.frame, pacman.startframe, 15, 1, pacman.starttime, 250);
    pacman.y += pacman.vely;
    pacman.x += pacman.velx;
}

相信我已经正确地定义了所有未粘贴和链接头的内容。知道我哪里做错了吗?

你只在一种情况下检查碰撞:

//check North collision
if (direction == 1 && N_tilevalue != 0)
{
    return IntersectRect(&dest, &spriteRect, &northRect);
}
else return false;  // <--- this
//check South collision
if (direction == 2 && S_tilevalue != 0)
{
    return IntersectRect(&dest, &spriteRect, &southRect);
}
else return false;  // <--- and this, etc...

请参阅上面突出显示的行。如果它不测试北碰撞(即,如果direction不是1N_tilevalue0),那么函数在所有其他情况下都返回该点。它不能继续做其他的碰撞检查