Мне нужна помощь в создании 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, если попросите скинуть другие классы я скину