diff --git a/core/src/mindustry/ai/types/GroundAI.java b/core/src/mindustry/ai/types/GroundAI.java index 4ebdfe1595..05358ae5e8 100644 --- a/core/src/mindustry/ai/types/GroundAI.java +++ b/core/src/mindustry/ai/types/GroundAI.java @@ -2,7 +2,6 @@ package mindustry.ai.types; import arc.math.*; import mindustry.ai.*; -import mindustry.entities.*; import mindustry.entities.units.*; import mindustry.gen.*; import mindustry.world.*; @@ -49,13 +48,6 @@ public class GroundAI extends AIController{ unit.elevation = Mathf.approachDelta(unit.elevation, 0f, unit.type.riseSpeed); } - if(!Units.invalidateTarget(target, unit, unit.range()) && unit.type.rotateShooting){ - if(unit.type.hasWeapons()){ - unit.lookAt(Predict.intercept(unit, target, unit.type.weapons.first().bullet.speed)); - } - }else if(unit.moving()){ - unit.lookAt(unit.vel().angle()); - } - + faceTarget(); } } diff --git a/core/src/mindustry/ai/types/HugAI.java b/core/src/mindustry/ai/types/HugAI.java index 76acdec8c8..70d2bce36e 100644 --- a/core/src/mindustry/ai/types/HugAI.java +++ b/core/src/mindustry/ai/types/HugAI.java @@ -47,10 +47,10 @@ public class HugAI extends AIController{ })){ if(unit.within(target, (unit.hitSize + (target instanceof Sized s ? s.hitSize() : 1f)) * 0.6f)){ //circle target - unit.moveAt(vec.set(target).sub(unit).rotate(90f).setLength(unit.speed())); + unit.movePref(vec.set(target).sub(unit).rotate(90f).setLength(unit.speed())); }else{ //move toward target in a straight line - unit.moveAt(vec.set(target).sub(unit).limit(unit.speed())); + unit.movePref(vec.set(target).sub(unit).limit(unit.speed())); } }else if(move){ pathfind(Pathfinder.fieldCore); @@ -69,13 +69,6 @@ public class HugAI extends AIController{ unit.elevation = Mathf.approachDelta(unit.elevation, 0f, unit.type.riseSpeed); } - if(!Units.invalidateTarget(target, unit, unit.range()) && unit.type.rotateShooting){ - if(unit.type.hasWeapons()){ - unit.lookAt(Predict.intercept(unit, target, unit.type.weapons.first().bullet.speed)); - } - }else if(unit.moving()){ - unit.lookAt(unit.vel().angle()); - } - + faceTarget(); } } diff --git a/core/src/mindustry/ai/types/SuicideAI.java b/core/src/mindustry/ai/types/SuicideAI.java index 1db94b95b0..70e365e775 100644 --- a/core/src/mindustry/ai/types/SuicideAI.java +++ b/core/src/mindustry/ai/types/SuicideAI.java @@ -41,10 +41,6 @@ public class SuicideAI extends GroundAI{ shoot = unit.within(target, unit.type.weapons.first().bullet.range() + (target instanceof Building b ? b.block.size * Vars.tilesize / 2f : ((Hitboxc)target).hitSize() / 2f)); - if(unit.type.hasWeapons()){ - unit.aimLook(Predict.intercept(unit, target, unit.type.weapons.first().bullet.speed)); - } - //do not move toward walls or transport blocks if(!(target instanceof Building build && !(build.block instanceof CoreBlock) && ( build.block.group == BlockGroup.walls || @@ -76,7 +72,7 @@ public class SuicideAI extends GroundAI{ if(!blocked){ moveToTarget = true; //move towards target directly - unit.moveAt(vec.set(target).sub(unit).limit(unit.speed())); + unit.movePref(vec.set(target).sub(unit).limit(unit.speed())); } } } @@ -103,11 +99,11 @@ public class SuicideAI extends GroundAI{ pathfind(Pathfinder.fieldCore); } } - - if(unit.moving()) unit.lookAt(unit.vel().angle()); } unit.controlWeapons(rotate, shoot); + + faceTarget(); } @Override diff --git a/core/src/mindustry/entities/comp/MechComp.java b/core/src/mindustry/entities/comp/MechComp.java index e8ed72974d..bd822d523b 100644 --- a/core/src/mindustry/entities/comp/MechComp.java +++ b/core/src/mindustry/entities/comp/MechComp.java @@ -76,6 +76,17 @@ abstract class MechComp implements Posc, Flyingc, Hitboxc, Unitc, Mechc, Elevati return raw; } + @Override + @Replace + public void rotateMove(Vec2 vec){ + //mechs use baseRotation to rotate, not rotation. + moveAt(Tmp.v2.trns(baseRotation, vec.len())); + + if(!vec.isZero()){ + baseRotation = Angles.moveToward(baseRotation, vec.angle(), type.rotateSpeed * Math.max(Time.delta, 1)); + } + } + @Override public void moveAt(Vec2 vector, float acceleration){ //mark walking state when moving in a controlled manner diff --git a/core/src/mindustry/entities/comp/UnitComp.java b/core/src/mindustry/entities/comp/UnitComp.java index ae4001d25f..ca168362d2 100644 --- a/core/src/mindustry/entities/comp/UnitComp.java +++ b/core/src/mindustry/entities/comp/UnitComp.java @@ -51,6 +51,15 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I private transient boolean wasPlayer; private transient boolean wasHealed; + /** Move based on preferred unit movement type. */ + public void movePref(Vec2 movement){ + if(type.omniMovement){ + moveAt(movement); + }else{ + rotateMove(movement); + } + } + public void moveAt(Vec2 vector){ moveAt(vector, type.accel); } diff --git a/core/src/mindustry/entities/units/AIController.java b/core/src/mindustry/entities/units/AIController.java index 583691adaa..c06fe06d88 100644 --- a/core/src/mindustry/entities/units/AIController.java +++ b/core/src/mindustry/entities/units/AIController.java @@ -76,6 +76,23 @@ public class AIController implements UnitController{ } } + /** For ground units: Looks at the target, or the movement position. Does not apply to non-omni units. */ + public void faceTarget(){ + if(unit.type.omniMovement || unit instanceof Mechc){ + if(!Units.invalidateTarget(target, unit, unit.range()) && unit.type.rotateShooting && unit.type.hasWeapons()){ + unit.lookAt(Predict.intercept(unit, target, unit.type.weapons.first().bullet.speed)); + }else if(unit.moving()){ + unit.lookAt(unit.vel().angle()); + } + } + } + + public void faceMovement(){ + if((unit.type.omniMovement || unit instanceof Mechc) && unit.moving()){ + unit.lookAt(unit.vel().angle()); + } + } + public boolean invalid(Teamc target){ return Units.invalidateTarget(target, unit.team, unit.x, unit.y); } @@ -89,7 +106,7 @@ public class AIController implements UnitController{ if(tile == targetTile || (costType == Pathfinder.costNaval && !targetTile.floor().isLiquid)) return; - unit.moveAt(vec.trns(unit.angleTo(targetTile.worldx(), targetTile.worldy()), unit.speed())); + unit.movePref(vec.trns(unit.angleTo(targetTile.worldx(), targetTile.worldy()), unit.speed())); } public void updateWeapons(){ diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java index acb3795aff..6c247c50cf 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -642,11 +642,7 @@ public class DesktopInput extends InputHandler{ unit.lookAt(unit.prefRotation()); } - if(omni){ - unit.moveAt(movement); - }else{ - unit.rotateMove(movement); - } + unit.movePref(movement); unit.aim(unit.type.faceTarget ? Core.input.mouseWorld() : Tmp.v1.trns(unit.rotation, Core.input.mouseWorld().dst(unit)).add(unit.x, unit.y)); unit.controlWeapons(true, player.shooting && !boosted); diff --git a/core/src/mindustry/input/MobileInput.java b/core/src/mindustry/input/MobileInput.java index 2480cad5ab..be0de31ffa 100644 --- a/core/src/mindustry/input/MobileInput.java +++ b/core/src/mindustry/input/MobileInput.java @@ -919,11 +919,7 @@ public class MobileInput extends InputHandler implements GestureListener{ player.boosting = collisions.overlapsTile(rect) || !unit.within(targetPos, 85f); - if(omni){ - unit.moveAt(movement); - }else{ - unit.rotateMove(movement); - } + unit.movePref(movement); //update shooting if not building + not mining if(!player.unit().activelyBuilding() && player.unit().mineTile == null){