Problemas de detecção de colisão 2D baseados em blocos

8

Estou tentando seguir este tutorial http://www.tonypa.pri.ee/tbw/tut05.html para implementar colisões em tempo real em um mundo baseado em blocos.

Eu encontro as coordenadas centrais das minhas entidades graças a estas propriedades:

public float CenterX
{
    get { return X + Width / 2f; }
    set { X = value - Width / 2f; }
}
public float CenterY
{
    get { return Y + Height / 2f; }
    set { Y = value - Height / 2f; }
}

Então, no meu método de atualização, na classe player, que é chamada de cada quadro, tenho este código:

public override void Update()
{
    base.Update();

    int downY = (int)Math.Floor((CenterY + Height / 2f - 1) / 16f);
    int upY = (int)Math.Floor((CenterY - Height / 2f) / 16f);
    int leftX =     (int)Math.Floor((CenterX + Speed * NextX - Width / 2f) / 16f);
    int rightX = (int)Math.Floor((CenterX + Speed * NextX + Width / 2f - 1) / 16f);

    bool upleft = Game.CurrentMap[leftX, upY] != 1;
    bool downleft = Game.CurrentMap[leftX, downY] != 1;
    bool upright = Game.CurrentMap[rightX, upY] != 1;
    bool downright = Game.CurrentMap[rightX, downY] != 1;

    if(NextX == 1)
    {
        if (upright && downright)
           CenterX += Speed;
        else
           CenterX = (Game.GetCellX(CenterX) + 1)*16 - Width / 2f;
    }
 }

downY, upY, leftX e rightX devem, respectivamente, encontrar a posição Y mais baixa, a posição Y mais alta, a posição X mais à esquerda e a posição X mais à direita. Eu adiciono + Speed ​​* NextX, porque no tutorial a função getMyCorners é chamada com estes parâmetros:

getMyCorners (ob.x+ob.speed*dirx, ob.y, ob);

Os métodos GetCellX e GetCellY:

public int GetCellX(float mX)
{
    return (int)Math.Floor(mX / SGame.Camera.TileSize); 
}
public int GetCellY(float mY)
{
    return (int)Math.Floor(mY / SGame.Camera.TileSize); 
}

O problema é que o jogador "pisca" ao bater em uma parede, e a detecção de canto nem funciona corretamente, pois pode sobrepor paredes que atingem apenas um dos cantos. Eu não entendo o que está errado. No tutorial, os campos ob.x e ob.y devem ser iguais às minhas propriedades CenterX e CenterY, e ob.width e ob.height devem ser iguais a Width / 2f e Height / 2f. No entanto, ainda não funciona.

Obrigado pela ajuda.

Vee
fonte
Você está testando a colisão quando o jogador está nesse local e recuperando-a se colidir ou está testando se o próximo movimento é uma colisão?
22411 kyndigs
Eu recomendaria adicionar uma verificação de pressionamento de tecla nessa função de atualização que interromperá o processo atual quando você pressionar a tecla. Em seguida, pressione a tecla quando o jogador está "piscando" e passe pelo depurador. (preste atenção ao que está acontecendo com os números) Tente descobrir o que está acontecendo com os números quando ele pisca.
Michael Coleman

Respostas:

1

Algumas sugestões, embora não tenha certeza de que elas resolverão o problema, pois não tenho código completo para executar e depurar.

Neste código:

if(NextX == 1)
{
    if (upright && downright)
       CenterX += Speed;
    else
       CenterX = (Game.GetCellX(CenterX) + 1)*16 - Width / 2f;
}

a instrução else está movendo o objeto, mesmo que o objeto não deva estar se movendo.
Eu acho que você está tentando fazer o objeto ficar encostado na parede, mas talvez o cálculo esteja incorreto.
Se você comentar a instrução else, o objeto ainda pisca?

O cálculo parece um pouco suspeito, pois subtrai (Width / 2f) e, em seguida, o operador do conjunto CenterX faz a mesma subtração novamente.

Outra coisa que eu gostaria de salientar, apenas para ajudar a clareza do código, é que você fez as propriedades do CenterX calcularem o valor de um lado para outro, mas o código ainda está cheio do mesmo cálculo repetidamente.
Isso pode muito bem ser parte do problema. De qualquer forma, eu sugiro criar mais algumas propriedades e estabelecer um padrão para todas elas. Por exemplo, torne o Centro a propriedade armazenada e calcule os outros:

public float CenterX
{
    get { return X; }
    set { X; }
}

public float LeftX
{
    get { return CenterX - Width / 2f; }
    set { CenterX = value + Width / 2f; }
}

public float RightX
{
    get { return CenterX + Width / 2f; }
    set { CenterX = value - Width / 2f; }
}
Paulo Pinto
fonte