C # / XNA - 2D сбой двигателя столкновения - PullRequest
3 голосов
/ 17 марта 2012

У меня здесь довольно много кода, но это относительно просто.

Это все фрагменты из разных классов, все ссылки верны, но я думаю, что где-то допустил математическую ошибку и не могу ее найти. Он всегда находит столкновение по оси Y на пиксель раньше, чем должен. Я не пробовал его с разными позициями оси X, но кажется, что он хорошо падает за соседние блоки.

Структура mapSection содержит только два вектора: левый верхний блок и нижний левый блок координат.

tileManager.def_ts - это ширина и высота плитки по умолчанию (32). Размер плеера 32х64.

Функция toWorldSpace сейчас не делает ничего, кроме возврата, так что это не проблема.

Когда я говорю координату блока, я имею в виду, какой индекс блока в массиве плиток (Пример 0, 0 - первый блок, 0, 1 - второй блок по оси Y, 1, 3 - 1 блок в Ось X и 3 на оси Y, я не имею в виду фактические пиксели.)

Из класса двигателя плитки:

    public mapSection toMapMinMax(Vector2 position, Vector2 size)
    {
        position = toWorldSpace(position);

        position.X = (float)Math.Floor(position.X / tileManager.def_ts);
        position.Y = (float)Math.Floor(position.Y / tileManager.def_ts);

        size.X = (float)Math.Floor(size.X / tileManager.def_ts);
        size.Y = (float)Math.Floor(size.Y / tileManager.def_ts);

        return new mapSection(position, position + size);
    }

    public bool collision(Vector2 screenPosition, Vector2 size)
    {
        mapSection mapCollisionPossibilities = toMapMinMax(screenPosition, size);

        for (int y = (int)mapCollisionPossibilities.topLeft.Y; y <= mapCollisionPossibilities.bottomRight.Y; y++)
        {
            for (int x = (int)mapCollisionPossibilities.topLeft.X; x <= mapCollisionPossibilities.bottomRight.X; x++)
            {
                if (x >= 0 && y >= 0 && y < tiles.Count && x < tiles[y].Count)
                {
                    if (tileManager.tileTypes[tiles[y][x]].collideable == true)
                    {
                        return true;
                    }
                }
            }
        }

        return false;
    }

А это код класса игрока:

        if (!tEngine.collision(position + new Vector2(0, 1), new Vector2(32, 64)))
        {
            position.Y += 1;
        }

Я добавляю «Vector2 (0, 1)», потому что я хочу видеть, есть ли столкновение на пиксель ниже; так что он падает, пока не ударяет что-то. Сейчас это очень просто, но это только для проверки двигателя столкновения, который не работает.

enter image description here

Есть изображение ошибки. Вы можете видеть, что у игрока слишком высокий пиксель.

На рисунке «X:» - это верхняя левая координата блока по оси X, «X2:» - это нижняя правая координата блока по оси X, и то же самое с «Y:» и «Y2: кроме Ось Y. Они считываются непосредственно с карты.

Если кто-то может заметить, почему это происходит, это было бы очень полезно.

Спасибо.

Если вы не можете понять какой-либо раздел кода, просто напишите в комментариях, и я с удовольствием объясню, или если вы думаете, что я был слишком неопределенным в какой-то части этого поста.

1 Ответ

3 голосов
/ 18 марта 2012

РЕДАКТИРОВАТЬ : Для определения координат плиток ваш код toMapMinMax должен выглядеть примерно так:

EDIT2 : вычесть (1, 1) из bottomRight,так как это размер, который мы добавляем.

public mapSection toMapMinMax(Vector2 position, Vector2 size)
{
    Vector2 topLeft = position;
    Vector2 bottomRight = position + size - new Vector2(1, 1);

    topLeft.X = (float)Math.Floor(topLeft.X / tileManager.def_ts);
    topLeft.Y = (float)Math.Floor(topLeft.Y / tileManager.def_ts);
    bottomRight.X = (float)Math.Floor(bottomRight.X / tileManager.def_ts);
    bottomRight.Y = (float)Math.Floor(bottomRight.Y / tileManager.def_ts);

    return new mapSection(topLeft, bottomRight);
}

Кроме того, я ошибся в своем комментарии выше;вы хотите, чтобы <= знаками в ваших двух для циклов, потому что большую часть времени вы будете проверять 6 плиток. </p>

для проблемы с одним пикселем:

Для того, чтобычтобы увидеть символ на некоторое количество пикселей, код отрисовки и код столкновения должны отличаться.Если бы они были идентичны, например, если они оба были отключены на 15 пикселей (вы сталкиваетесь на 15 пикселей раньше, но вы также рисуете на 15 пикселей вперед), вы не увидите никаких изменений.

1 пиксельРазрыв указывает на разницу в 1 пиксель между вычислением координат отрисовки и вычислением координат столкновения.Эта разница в 1 пиксель, скорее всего, вызвана различиями в округлении, возможно, вы вызываете Math.Floor в коде столкновения, но не округляете координаты в коде рисования.(Я предполагаю, что вы, вероятно, просто передаете позицию Vector2 прямо в метод SpriteBatch.Draw).

...