diff --git a/build.gradle b/build.gradle index 7a9ebbbe7c..267503915a 100644 --- a/build.gradle +++ b/build.gradle @@ -200,7 +200,6 @@ project(":desktop"){ dependencies{ implementation project(":core") - implementation arcModule("natives:natives-box2d-desktop") implementation arcModule("natives:natives-desktop") implementation arcModule("natives:natives-freetype-desktop") implementation 'com.github.MinnDevelopment:java-discord-rpc:v2.0.1' @@ -239,7 +238,6 @@ project(":ios"){ implementation arcModule("natives:natives-ios") implementation arcModule("natives:natives-freetype-ios") - implementation arcModule("natives:natives-box2d-ios") implementation arcModule("backends:backend-robovm") compileOnly project(":annotations") @@ -282,7 +280,6 @@ project(":core"){ api "org.lz4:lz4-java:1.4.1" api arcModule("arc-core") api arcModule("extensions:freetype") - api arcModule("extensions:box2d") api arcModule("extensions:g3d") api arcModule("extensions:fx") api arcModule("extensions:arcnet") @@ -299,7 +296,6 @@ project(":server"){ dependencies{ implementation project(":core") - implementation arcModule("natives:natives-box2d-desktop") implementation arcModule("backends:backend-headless") } } @@ -312,7 +308,6 @@ project(":tests"){ testImplementation "org.junit.jupiter:junit-jupiter-params:5.3.1" testImplementation "org.junit.jupiter:junit-jupiter-api:5.3.1" testImplementation arcModule("backends:backend-headless") - testImplementation arcModule("natives:natives-box2d-desktop") testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.3.1" } @@ -334,7 +329,6 @@ project(":tools"){ implementation arcModule("natives:natives-desktop") implementation arcModule("natives:natives-freetype-desktop") - implementation arcModule("natives:natives-box2d-desktop") implementation arcModule("backends:backend-headless") } } diff --git a/core/src/mindustry/ai/types/FormationAI.java b/core/src/mindustry/ai/types/FormationAI.java index e2680b4f2b..2c91f950a1 100644 --- a/core/src/mindustry/ai/types/FormationAI.java +++ b/core/src/mindustry/ai/types/FormationAI.java @@ -73,7 +73,7 @@ public class FormationAI extends AIController implements FormationMember{ //TODO return formation size //eturn ((Commanderc)unit).formation(). } - return unit.hitSize * 1f; + return unit.hitSize * 0.65f; } @Override diff --git a/core/src/mindustry/async/PhysicsProcess.java b/core/src/mindustry/async/PhysicsProcess.java index 05c2665baf..c78b0b5769 100644 --- a/core/src/mindustry/async/PhysicsProcess.java +++ b/core/src/mindustry/async/PhysicsProcess.java @@ -1,31 +1,19 @@ package mindustry.async; -import arc.box2d.*; -import arc.box2d.BodyDef.*; +import arc.math.*; import arc.math.geom.*; +import arc.math.geom.QuadTree.*; import arc.struct.*; +import mindustry.*; import mindustry.entities.*; +import mindustry.async.PhysicsProcess.PhysicsWorld.*; import mindustry.gen.*; public class PhysicsProcess implements AsyncProcess{ - private Physics physics; + private PhysicsWorld physics; private Seq refs = new Seq<>(false); - private BodyDef def; - - private EntityGroup group; - private Filter flying = new Filter(){{ - maskBits = categoryBits = 2; - }}, ground = new Filter(){{ - maskBits = categoryBits = 1; - }}; - - public PhysicsProcess(){ - def = new BodyDef(); - def.type = BodyType.dynamicBody; - - //currently only enabled for units - group = Groups.unit; - } + //currently only enabled for units + private EntityGroup group = Groups.unit; @Override public void begin(){ @@ -34,7 +22,7 @@ public class PhysicsProcess implements AsyncProcess{ //remove stale entities refs.removeAll(ref -> { if(!ref.entity.isAdded()){ - physics.destroyBody(ref.body); + physics.remove(ref.body); ref.entity.physref(null); return true; } @@ -44,37 +32,29 @@ public class PhysicsProcess implements AsyncProcess{ //find entities without bodies and assign them for(Physicsc entity : group){ boolean grounded = entity.isGrounded(); - int bits = grounded ? ground.maskBits : flying.maskBits; if(entity.physref() == null){ - //add bodies to entities that have none - FixtureDef fd = new FixtureDef(); - fd.shape = new CircleShape(entity.hitSize() / 2f); - fd.density = 5f; - fd.restitution = 0.0f; - fd.filter.maskBits = fd.filter.categoryBits = (grounded ? ground : flying).maskBits; - - def.position.set(entity); - - Body body = physics.createBody(def); - body.createFixture(fd); + PhysicsBody body = new PhysicsBody(); + body.x = entity.x(); + body.y = entity.y(); + body.mass = entity.mass(); + body.radius = entity.hitSize() / 2f; + body.flag = grounded ? 1 : 0; PhysicRef ref = new PhysicRef(entity, body); refs.add(ref); entity.physref(ref); + + physics.add(body); } //save last position PhysicRef ref = entity.physref(); - if(ref.body.getFixtureList().any() && ref.body.getFixtureList().first().getFilterData().categoryBits != bits){ - //set correct filter - ref.body.getFixtureList().first().setFilterData(grounded ? ground : flying); - } - - ref.velocity.set(entity.deltaX(), entity.deltaY()); - ref.position.set(entity); + ref.body.flag = grounded ? 1 : 0; + ref.x = entity.x(); + ref.y = entity.y(); } } @@ -85,26 +65,11 @@ public class PhysicsProcess implements AsyncProcess{ //get last position vectors before step for(PhysicRef ref : refs){ //force set target position - ref.body.setPosition(ref.position.x, ref.position.y); - - //save last position for delta - ref.lastPosition.set(ref.body.getPosition()); - - //write velocity - ref.body.setLinearVelocity(ref.velocity); - - ref.lastVelocity.set(ref.velocity); + ref.body.x = ref.x; + ref.body.y = ref.y; } - physics.step(1f/45f, 5, 8); - - //get delta vectors - for(PhysicRef ref : refs){ - //get delta vector - ref.delta.set(ref.body.getPosition()).sub(ref.lastPosition); - - ref.velocity.set(ref.body.getLinearVelocity()); - } + physics.update(); } @Override @@ -115,13 +80,8 @@ public class PhysicsProcess implements AsyncProcess{ for(PhysicRef ref : refs){ Physicsc entity = ref.entity; - entity.move(ref.delta.x, ref.delta.y); - - //save last position - ref.position.set(entity); - - //add delta velocity - this doesn't work very well yet - //entity.vel().add(ref.velocity).sub(ref.lastVelocity); + //move by delta + entity.move(ref.body.x - ref.x, ref.body.y - ref.y); } } @@ -129,7 +89,6 @@ public class PhysicsProcess implements AsyncProcess{ public void reset(){ if(physics != null){ refs.clear(); - physics.dispose(); physics = null; } } @@ -138,17 +97,83 @@ public class PhysicsProcess implements AsyncProcess{ public void init(){ reset(); - physics = new Physics(new Vec2(), true); + physics = new PhysicsWorld(Vars.world.getQuadBounds(new Rect())); } public static class PhysicRef{ public Physicsc entity; - public Body body; - public Vec2 lastPosition = new Vec2(), delta = new Vec2(), velocity = new Vec2(), lastVelocity = new Vec2(), position = new Vec2(); + public PhysicsBody body; + public float x, y; - public PhysicRef(Physicsc entity, Body body){ + public PhysicRef(Physicsc entity, PhysicsBody body){ this.entity = entity; this.body = body; } } + + //world for simulating physics in a different thread + public static class PhysicsWorld{ + //how much to soften movement by + private static final float scl = 1.25f; + + private final QuadTree tree; + private final Seq bodies = new Seq<>(false, 16, PhysicsBody.class); + private final Rect rect = new Rect(); + private final Vec2 vec = new Vec2(); + + public PhysicsWorld(Rect bounds){ + tree = new QuadTree<>(new Rect(bounds)); + } + + public void add(PhysicsBody body){ + bodies.add(body); + } + + public void remove(PhysicsBody body){ + bodies.remove(body); + } + + public void update(){ + tree.clear(); + for(int i = 0; i < bodies.size; i++){ + PhysicsBody body = bodies.items[i]; + body.collided = false; + tree.insert(body); + } + + for(int i = 0; i < bodies.size; i++){ + PhysicsBody body = bodies.items[i]; + body.hitbox(rect); + tree.intersect(rect, other -> { + if(other.flag != body.flag || other == body || other.collided) return; + + float rs = body.radius + other.radius; + float dst = Mathf.dst(body.x, body.y, other.x, other.y); + + if(dst < rs){ + vec.set(body.x - other.x, body.y - other.y).setLength(rs - dst); + float ms = body.mass + other.mass; + float m1 = other.mass / ms, m2 = body.mass / ms; + + body.x += vec.x * m1 / scl; + body.y += vec.y * m1 / scl; + other.x -= vec.x * m2 / scl; + other.y -= vec.y * m2 / scl; + } + }); + body.collided = true; + } + } + + public static class PhysicsBody implements QuadTreeObject{ + public float x, y, radius, mass; + public int flag = 0; + public boolean collided = false; + + @Override + public void hitbox(Rect out){ + out.setCentered(x, y, radius * 2, radius * 2); + } + } + } } diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index cc377c833b..83965387a0 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -304,7 +304,7 @@ public class UnitTypes implements ContentList{ mineTier = 2; mineSpeed = 5f; - commandLimit = 15; + commandLimit = 8; abilities.add(new ShieldFieldAbility(20f, 40f, 60f * 5, 60f)); ammoType = AmmoTypes.power; @@ -347,7 +347,7 @@ public class UnitTypes implements ContentList{ armor = 9f; landShake = 2f; - commandLimit = 18; + commandLimit = 10; mechFrontSway = 0.55f; ammoType = AmmoTypes.power; @@ -402,7 +402,7 @@ public class UnitTypes implements ContentList{ canBoost = true; landShake = 4f; - commandLimit = 20; + commandLimit = 8; weapons.add(new Weapon("vela-weapon"){{ mirror = false; @@ -452,7 +452,7 @@ public class UnitTypes implements ContentList{ landShake = 1.5f; rotateSpeed = 1.5f; - commandLimit = 20; + commandLimit = 8; legCount = 4; legLength = 14f; @@ -1312,7 +1312,7 @@ public class UnitTypes implements ContentList{ payloadCapacity = (5.3f * 5.3f) * tilePayload; buildSpeed = 4f; drawShields = false; - commandLimit = 25; + commandLimit = 6; abilities.add(new ForceFieldAbility(140f, 4f, 7000f, 60f * 8), new HealFieldAbility(130f, 60f * 2, 140f)); }}; diff --git a/core/src/mindustry/entities/PhysicsWorld.java b/core/src/mindustry/entities/PhysicsWorld.java deleted file mode 100644 index 0dc918f7a2..0000000000 --- a/core/src/mindustry/entities/PhysicsWorld.java +++ /dev/null @@ -1,48 +0,0 @@ -package mindustry.entities; - -import arc.math.geom.*; -import arc.math.geom.QuadTree.*; -import arc.struct.*; - -public class PhysicsWorld{ - private QuadTree tree; - private Seq bodies = new Seq<>(false, 16, PhysicsBody.class); - private Rect rect = new Rect(); - - public PhysicsWorld(Rect bounds){ - tree = new QuadTree<>(new Rect(bounds)); - } - - public void add(PhysicsBody body){ - bodies.add(body); - } - - public void remove(PhysicsBody body){ - bodies.remove(body); - } - - public void update(){ - tree.clear(); - for(int i = 0; i < bodies.size; i++){ - tree.insert(bodies.items[i]); - } - - for(int i = 0; i < bodies.size; i++){ - PhysicsBody body = bodies.items[i]; - body.hitbox(rect); - tree.intersect(rect, other -> { - - }); - } - } - - public static class PhysicsBody implements QuadTreeObject{ - public float x, y, xv, yv, radius, mass; - public int flag = 0; - - @Override - public void hitbox(Rect out){ - out.setCentered(x, y, radius * 2, radius * 2); - } - } -} diff --git a/core/src/mindustry/entities/comp/CommanderComp.java b/core/src/mindustry/entities/comp/CommanderComp.java index 354581654b..99bca89cf9 100644 --- a/core/src/mindustry/entities/comp/CommanderComp.java +++ b/core/src/mindustry/entities/comp/CommanderComp.java @@ -73,7 +73,7 @@ abstract class CommanderComp implements Unitc{ void command(Formation formation, Seq units){ clearCommand(); - float spacing = hitSize() * 1f; + float spacing = hitSize() * 0.65f; minFormationSpeed = type().speed; controlling.addAll(units); diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index 8f89385640..5666789a88 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -317,7 +317,7 @@ public class UnitType extends UnlockableContent{ public void draw(Unit unit){ Mechc mech = unit instanceof Mechc ? (Mechc)unit : null; - float z = unit.elevation > 0.5f ? (lowAltitude ? Layer.flyingUnitLow : Layer.flyingUnit) : groundLayer + Mathf.clamp(hitSize /4000f, 0, 0.01f); + float z = unit.elevation > 0.5f ? (lowAltitude ? Layer.flyingUnitLow : Layer.flyingUnit) : groundLayer + Mathf.clamp(hitSize / 4000f, 0, 0.01f); if(unit.controller().isBeingControlled(player.unit())){ drawControl(unit); diff --git a/settings.gradle b/settings.gradle index b0aa7f6e3e..a8dfd17399 100644 --- a/settings.gradle +++ b/settings.gradle @@ -33,7 +33,6 @@ if(!hasProperty("release")){ ':Arc:extensions:recorder', ':Arc:extensions:arcnet', ':Arc:extensions:packer', - ':Arc:extensions:box2d', ':Arc:extensions:g3d', ':Arc:extensions:fx', ':Arc:natives', @@ -43,9 +42,6 @@ if(!hasProperty("release")){ ':Arc:natives:natives-freetype-desktop', ':Arc:natives:natives-freetype-android', ':Arc:natives:natives-freetype-ios', - ':Arc:natives:natives-box2d-desktop', - ':Arc:natives:natives-box2d-android', - ':Arc:natives:natives-box2d-ios', ':Arc:backends', ':Arc:backends:backend-sdl', ':Arc:backends:backend-android',