Мне нужна помощь в создании 2д физического движка на java

я пытался сделать физический 2д движок для своего игрового движка у меня получилось это:

package Engine;

public class Physics {
    public ArrayList<entity> entities = new ArrayList<>();

    // --- Константы Физики ---
    private static final float GRAVITY = 0.15f;
    private static final float FRICTION = 0.8f;
    private static final float TERMINAL_VELOCITY = 15.0f;
    private static final float MIN_VELOCITY_THRESHOLD = 0.001f;

    public void update() {
        for (entity a : entities) {

            a.isOnGround = false;

            if (a.isStatic) continue;
            if (a.mass <= 0) a.mass = 1.0f;

            // 1. Гравитация
            a.vY += GRAVITY;
            if (a.vY > TERMINAL_VELOCITY) a.vY = TERMINAL_VELOCITY;
            else if (a.vY < -TERMINAL_VELOCITY) a.vY = -TERMINAL_VELOCITY;

            // 2. Предварительное смещение
            float newX = a.getX() + a.vX;
            float newY = a.getY() + a.vY;

            boolean tempIsOnGround = false;

            // --- 3. Обработка столкновений по оси X ---
            for (entity b : entities) {
                if (a == b) continue;
                if (b.mass <= 0) b.mass = 1.0f;

                float tempX = newX;
                float tempY = a.getY();

                boolean yOverlap = (tempY < b.getY() + b.getH() && tempY + a.getH() > b.getY());

                if (yOverlap) {
                    boolean xCollision = (tempX < b.getX() + b.getW() && tempX + a.getW() > b.getX());

                    if (xCollision) {

                        // Движение ВПРАВО
                        if (a.vX > 0 && newX + a.getW() >= b.getX() && a.getX() + a.getW() <= b.getX()) {

                            if (b.isStatic) {
                                newX = b.getX() - a.getW();
                                a.vX = -1*a.u;
                            } else {
                                // Динамическое столкновение X
                                float vA1 = a.vX;
                                float vB1 = b.vX;
                                float mA = a.mass;
                                float mB = b.mass;

                                float vA2 = (vA1 * (mA - mB) + (2 * mB * vB1)) / (mA + mB);
                                float vB2 = (vB1 * (mB - mA) + (2 * mA * vA1)) / (mA + mB);

                                a.vX = vA2;
                                b.vX = vB2;

                                // Позиционная коррекция A и B
                                float penetration = (newX + a.getW()) - b.getX();
                                float separation = penetration / 2.0f;
                                newX -= separation;
                                b.setX(b.getX() + separation);

                                // *** АНТИ-ПРОНИКНОВЕНИЕ (ИСПРАВЛЕНИЕ РЕГРЕССИИ) ***
                                for (entity c : entities) {
                                    if (c == a || c == b) continue;
                                    if (c.isStatic) {
                                        boolean xOverlapC = (b.getX() < c.getX() + c.getW() && b.getX() + b.getW() > c.getX());
                                        boolean yOverlapC = (b.getY() < c.getY() + c.getH() && b.getY() + b.getH() > c.getY());

                                        if (xOverlapC && yOverlapC) {
                                            // B проникло в статичный C. Откатываем B до границы C.
                                            float overlapAmount = (b.getX() + b.getW()) - c.getX();

                                            b.setX(b.getX() - overlapAmount);
                                            b.vX = 0; // B не может двигаться дальше
                                            a.vX = 0; // A также должен остановиться
                                            newX = a.getX(); // A не двигается (останавливается у B)
                                            break;
                                        }
                                    }
                                }
                                // **************************************************
                            }
                        }

                        // Движение ВЛЕВО
                        else if (a.vX < 0 && newX <= b.getX() + b.getW() && a.getX() >= b.getX() + b.getW()) {

                            if (b.isStatic) {
                                newX = b.getX() + b.getW();
                                a.vX = 1*a.u;
                            } else {
                                // Динамическое столкновение X
                                float vA1 = a.vX;
                                float vB1 = b.vX;
                                float mA = a.mass;
                                float mB = b.mass;

                                float vA2 = (vA1 * (mA - mB) + (2 * mB * vB1)) / (mA + mB);
                                float vB2 = (vB1 * (mB - mA) + (2 * mA * vA1)) / (mA + mB);

                                a.vX = vA2;
                                b.vX = vB2;

                                // Позиционная коррекция A и B
                                float penetration = (b.getX() + b.getW()) - newX;
                                float separation = penetration / 2.0f;
                                newX += separation;
                                b.setX(b.getX() - separation);

                                // *** АНТИ-ПРОНИКНОВЕНИЕ (ИСПРАВЛЕНИЕ РЕГРЕССИИ) ***
                                for (entity c : entities) {
                                    if (c == a || c == b) continue;
                                    if (c.isStatic) {
                                        boolean xOverlapC = (b.getX() < c.getX() + c.getW() && b.getX() + b.getW() > c.getX());
                                        boolean yOverlapC = (b.getY() < c.getY() + c.getH() && b.getY() + b.getH() > c.getY());

                                        if (xOverlapC && yOverlapC) {
                                            // B проникло в статичный C. Откатываем B до границы C.
                                            float overlapAmount = (c.getX() + c.getW()) - b.getX();

                                            b.setX(b.getX() + overlapAmount);
                                            b.vX = 0;
                                            a.vX = 0;
                                            newX = a.getX();
                                            break;
                                        }
                                    }
                                }
                                // **************************************************
                            }
                        }
                    }
                }
            }

            // --- 4. Обработка столкновений по оси Y ---
            // Логика по Y остается прежней...
            for (entity b : entities) {
                if (a == b) continue;

                boolean xOverlap = (newX < b.getX() + b.getW() && newX + a.getW() > b.getX());

                if (xOverlap) {

                    // 1. Столкновение с ПОЛОМ
                    if (a.vY > 0 &&
                        newY + a.getH() >= b.getY() &&
                        a.getY() + a.getH() <= b.getY())
                    {
                        newY = b.getY() - a.getH();
                        a.vY = -a.vY*a.u + -a.vY*b.u;
                        tempIsOnGround = true;
                    }

                    // 2. Столкновение с ПОТОЛКОМ
                    else if (a.vY < 0 &&
                        newY <= b.getY() + b.getH() &&
                        a.getY() >= b.getY() + b.getH())
                    {
                        newY = b.getY() + b.getH();
                        a.vY = -a.vY*a.u + a.vY*b.u;
                    }
                }
            }

            // 5. Трение
            if (tempIsOnGround) {
                a.vX *= FRICTION;
                if (Math.abs(a.vX) < MIN_VELOCITY_THRESHOLD) {
                    a.vX = 0;
                }
            }

            // 6. Применяем окончательную позицию
            a.isOnGround = tempIsOnGround;
            a.setX(newX);
            a.setY(newY);
        }
    }

    public void add(entity en){
        entities.add(en);
    }
}

(а ещё как тут нормально выделять код)

вот класс entity:

package game;

public class entity {

    protected float x,y;
    protected int w,h;
    protected float a;
    protected byte type;
    protected Color color;
    protected BufferedImage img;

    public float vX = 0.0f;           // Скорость по оси X (Velocity X)
    public float vY = 0.0f;           // Скорость по оси Y (Velocity Y)
    public float mass = 1.0f;         // Масса (для гравитации и импульса)
    public boolean isStatic = false;
    public boolean isOnGround = false;
    public float u = 0.1f;            //упругость

    public entity(){
        clearProperties();
    }

    //обычные методы
    public void clearProperties(){
        x=0;
        y=0;
        w=0;
        h=0;
        type=0;
    }
    public void setProperties(float x, float y, int w, int h, byte type, Color color){
        setColor(color);
        setX(x);
        setY(y);
        setH(h);
        setW(w);
        setType(type);
    }public void setProperties(int x, int y, int w, int h, byte type){
        setX(x);
        setY(y);
        setH(h);
        setW(w);
        setType(type);
    }public void setProperties(float x, float y, int w, int h){
        setX(x);
        setY(y);
        setH(h);
        setW(w);
    }public void setProperties(int x, int y, int w){
        setX(x);
        setY(y);
        setW(w);
    }public void setProperties(float x, float y){
        setX(x);
        setY(y);
    }public void setProperties(int x){
        setX(x);
    }
    public void loadSprite(String path) {
        try {
            if (path.startsWith("http://") || path.startsWith("https://")) {
                img = ImageIO.read(new URL(path));
            } else {
                img = ImageIO.read(new File(path));
            }
        } catch (IOException e) {
            System.err.println("Ошибка: не удалось загрузить изображение (" + path + ")");
        }
    }
    public void rotate(float angleRad){
        setA(angleRad);
    }
    public void destroy() {
        // Освобождаем тяжелые ресурсы
        this.img = null;
        this.color = null;

        // Обнуляем другие поля
        this.x = this.y = this.w = this.h = 0;
        this.a = 0;
        this.type = 0;
    }

    //гетеры || сетеры
    public void setX(float x){
        this.x = x;
    }
    public void setY(float y){
        this.y = y;
    }
    public float getX(){
        return x;
    }
    public float getY(){
        return y;
    }
    public float getA() {
        return a;
    }
    public void setA(float a) {
        this.a = a;
    }

    public void setW(int w){
        this.w = w;
    }
    public void setH(int h){
        this.h = h;
    }
    public int getW(){
        return w;
    }
    public int getH(){
        return h;
    }

    public void setType(byte type){
        this.type = type;
    }
    public byte getType(){
        return type;
    }

    public void setColor(Color color) {
        this.color = color;
    }
    public Color getColor() {
        return color;
    }
    public void setImg(BufferedImage img) {
        this.img = img;
    }
    public BufferedImage getImg() {
        return img;
    }
}

подскажите формулы ну и пожалуйста на простом языке мне 12, если попросите скинуть другие классы я скину


Ответы (1 шт):

Автор решения: petr

всё я нашёл более менее простой урок, если это так можно называть. Часть 1 Часть 2-4

→ Ссылка