Проблемы с 2D-столкновением в игре Java

Я работаю над этой игрой с LWJGL уже несколько недель. С тех пор, как я добавил возможность прыгать, столкновение вверх доставляло мне много проблем.

Игра представляет собой сайдскроллер на основе 2D-плиток. В целом, столкновение почти идеальное, за исключением момента, когда игрок прыгает. Сначала я подумал: «О, может быть, мне просто нужно изменить механику прыжков», но потом понял, что это происходит только тогда, когда игроку передается определенная координата x.

Теперь о самой проблеме: если игрок прыгает при прохождении определенной координаты x, он пройдет через плитку, и проверка на столкновение сверху возвращает false.

Это весь класс Player:

package Minecraft2D;

import static Minecraft2D.World.BLOCK_SIZE;
import Minecraft2D.Tools.Tools;
import Minecraft2D.UI.Inventory;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import static Minecraft2D.Boot.*;

import org.lwjgl.util.Rectangle;
import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.opengl.TextureLoader;

public class Player {

private float x;
private float y;
public int width = 32;
public int height = 50;
private float DX = 0;
private float DY = 0;
private Texture left = null;
private Texture right = null;
Texture texture = null;

public boolean direction[] = { false, false, false, false };
public boolean collision = false;
public boolean ground = false;
public boolean jump = false;
public boolean top = false;

public Player(float x, float y) {
    this.x = x;
    this.y = y;
    try {

        this.left = TextureLoader.getTexture("PNG", new FileInputStream(new File(path + "player_left.png")));
        this.right = TextureLoader.getTexture("PNG", new FileInputStream(new File(path + "player_right.png")));
        this.texture = this.right;
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public void draw() {
    Tools.drawTexture((int)x, (int)y, width, height, texture);
}

public void checkCollision(Player player, Block block) {

    if (player.getY() < block.getY() + BLOCK_SIZE && player.getX() < block.getX() + BLOCK_SIZE && player.getY() + this.height > block.getY() && player.getX() + this.width > block.getX() && block.getType() != BlockType.AIR) {
        Rectangle top = new Rectangle();
        top.setBounds((int) player.x + 4, (int) player.y + 1, this.width - 8, 1);
        Rectangle bottom = new Rectangle();
        bottom.setBounds((int) player.x + 4, (int) player.y + this.height, this.width - 8, 1);
        Rectangle left = new Rectangle();
        left.setBounds((int) player.x, (int) player.y + 1, 1, this.height - 5);
        Rectangle right = new Rectangle();
        right.setBounds((int) player.x + player.width, (int) player.y + 1, 1, this.height - 5);
        Rectangle blok = new Rectangle();
        blok.setBounds((int) block.getX(), (int) block.getY(), BLOCK_SIZE, BLOCK_SIZE);
        if (bottom.intersects(blok)) {
            player.setY((block.getY() - this.height - 1));
            ground = true;
            jump = false;
        } else if (top.intersects(blok)) {
            DY = 0;
            this.top = true;
            y -= (player.y) - (block.getY() + BLOCK_SIZE);
        }
        if (!top.intersects(blok)) {
            if (left.intersects(blok)) {
                player.setX(block.getX() + this.width);
            } else if (right.intersects(blok)) {
                player.setX(block.getX() - this.width);
            }
        }

    } else {
        collision = false;
        ground = false;
    }


    if (!collision && !jump) {
        setDY(.003f);
    }
    if (ground && !jump) {
        DY = 0;
    }

    if (jump && DY < 0.003f) {
        DY += 0.0001;
    } else {
        // jump = false;
    }

    if (top) {
        DY = 0f;
        top = false;
    }

    x += DX;
    y += DY;

    if (x > Boot.SCREEN_WIDTH) {
        x = 0;
    }
    if (x < 0) {
        x = Boot.SCREEN_WIDTH;
    }
}

public float getX() {
    return x;
}

public void setX(float x) {
    this.x = x;
}

public float getY() {
    return y;
}

public void setY(float y) {
    this.y = y;
}

public void setDX(float dx) {
    this.DX = dx;
}

public void setDY(float dy) {
    this.DY = dy;
}

public void setJump() {
    if (!jump) {
        jump = true;
        ground = false;
        DY = -0.13f;
        y -= 1;
    }
}

public void setTexture(int tex) {
    if (tex == 0) {
        this.texture = this.left;
    }
    if (tex == 1) {
        this.texture = this.right;
    }
}

}

==============

РЕДАКТИРОВАТЬ: я понятия не имею, почему, но по мере того, как мой персонаж приближается к координате x карты 0, координата y персонажа увеличивается очень медленно. Вероятно, это как-то связано с проблемой, с которой я столкнулся. Я изучаю это, и у меня есть подозрение, что это может иметь какое-то значение, когда я преобразую значения x и y игрока из двойных чисел в целые числа для использования в верхнем, нижнем, левом и правом прямоугольниках.

РЕДАКТИРОВАТЬ снова: я не знаю, имеет ли это значение, но я проверял столкновение следующим образом: (Это в классе «Загрузка».)

private void checkCollision() {
            for (int x = 0; x < BLOCKS_WIDTH - 1; x++) {
              for (int y = 0; y < BLOCKS_HEIGHT - 1; y++) {
                Block blk = grid.getAt(x, y);
                player.checkCollision(blk);
            }
        }
}

person TheElephantSeal    schedule 11.05.2012    source источник
comment
Ну, где-нибудь после 100 работает нормально, но все, что меньше 100, и я получаю эту проблему.   -  person TheElephantSeal    schedule 12.05.2012
comment
предупреждение: класс Player никогда не устанавливает collision в true.   -  person Gunslinger47    schedule 12.05.2012
comment
Переменная столкновения бесполезна, она была только что из теста.   -  person TheElephantSeal    schedule 12.05.2012
comment
@user1333893 user1333893 При подготовке примера кода для прикрепления к подобному вопросу вы должны удалить любой код, который не имеет отношения к вопросу (все равно будет вызывать ошибку). Прохождение этого процесса часто помогает решить проблему, вообще не задавая вопросов.   -  person Oliver    schedule 12.05.2012
comment
Просто как предложение: использование линейного поиска каждый тик не очень эффективно (ваши два цикла for выше). Если вы используете приоритетную очередь, содержащую расстояния между игроком и блоками, вы можете легко найти те, которые являются потенциальными совпадениями, и, возможно, избежать повторения всего. Просто намек :-)   -  person Jens Egholm    schedule 14.05.2012
comment
Спасибо, постараюсь поработать над этим в ближайшее время!   -  person TheElephantSeal    schedule 15.05.2012


Ответы (1)


Почему вы передаете игрока в checkCollision? Кажется, что вы не должны передавать игрока, а вместо этого использовать членов игрока, который вызывает метод checkCollision. Я думаю, что это может привести к некоторому замешательству для вас. Такие как:

y -= (player.y) - (block.getY() + BLOCK_SIZE);

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

y = (block.getY() + BLOCK_SIZE);

Я бы удалил игрока из аргумента функции, переписал бы функцию и посмотрел, что получится. Надеюсь, это поможет.

РЕДАКТИРОВАТЬ

В вашем комментарии сказано, что вы больше не можете передать плеер в функцию. Не уверен насчет вашей точной реализации, но вот как выглядят игры, которые я обычно видел:

 public class Player 
 {
    private int x, y, dx, dy;

    public void checkCollision(Block block)
    {
       if (isTopCollision(block))
         fall(block.getY() + block.getHeight());
    }

    private boolean isTopCollision(Block block)
    {
       return y > block.getY() + block.getSize() && y < block.getY();
    }

    private void fall(int adjustedY)
    {
       y = adjustedY;
       top = true;
       dy = 0;
       // etc
    }
 }

 public class MyGame 
 {
     public void gameloop()
     {
       for (Block b : blocks)
         player.checkCollision(b);
     }
 }
person jeff    schedule 11.05.2012
comment
Хм... Это странно. Теперь, когда я больше не передаю игроку метод checkCollision, игра игнорирует все столкновения после координаты 320x. Верхнее столкновение тоже действует снова... - person TheElephantSeal; 12.05.2012