summaryrefslogtreecommitdiff
path: root/core/src/org
diff options
context:
space:
mode:
authorDmitri Morozov <snoopdesigns@gmail.com>2024-02-09 14:44:02 +0100
committerue86388 <dmitrii.morozov@sbb.ch>2024-02-09 14:44:02 +0100
commit6fec228efbc3534b7464e70e0791e0afdd94d4f6 (patch)
treeb092848c94fcf71e7b2f8796709f551ffb80c610 /core/src/org
parentee3e8ec9883c1f78c73493526b493cef33bd9fc7 (diff)
Smart pursue for enemy shipsHEADmaster
Diffstat (limited to 'core/src/org')
-rw-r--r--core/src/org/snoopdesigns/endless/physics/PhysicalBody.java1
-rw-r--r--core/src/org/snoopdesigns/endless/world/ObjectsRenderer.java2
-rw-r--r--core/src/org/snoopdesigns/endless/world/ship/SteerableEnemyShip.java183
-rw-r--r--core/src/org/snoopdesigns/endless/world/steering/ChaseSteering.java108
-rw-r--r--core/src/org/snoopdesigns/endless/world/steering/Steering.java5
-rw-r--r--core/src/org/snoopdesigns/endless/world/steering/SteeringApplicator.java9
6 files changed, 164 insertions, 144 deletions
diff --git a/core/src/org/snoopdesigns/endless/physics/PhysicalBody.java b/core/src/org/snoopdesigns/endless/physics/PhysicalBody.java
index 914d06a..31204a9 100644
--- a/core/src/org/snoopdesigns/endless/physics/PhysicalBody.java
+++ b/core/src/org/snoopdesigns/endless/physics/PhysicalBody.java
@@ -37,7 +37,6 @@ public abstract class PhysicalBody {
public void limitVelocity() {
if (getBody().getLinearVelocity().len() > getMaxVelocity()) {
- System.out.println("Limit velocity" + getMaxVelocity());
getBody().setLinearVelocity(getBody().getLinearVelocity().limit(getMaxVelocity()));
}
}
diff --git a/core/src/org/snoopdesigns/endless/world/ObjectsRenderer.java b/core/src/org/snoopdesigns/endless/world/ObjectsRenderer.java
index 3afea26..3055532 100644
--- a/core/src/org/snoopdesigns/endless/world/ObjectsRenderer.java
+++ b/core/src/org/snoopdesigns/endless/world/ObjectsRenderer.java
@@ -20,7 +20,7 @@ public class ObjectsRenderer implements Renderer {
batch = new SpriteBatch();
renderables.add(Context.getInstance().getPlayerShip());
- IntStream.range(0, 1).forEach(i ->
+ IntStream.range(0, 3).forEach(i ->
renderables.add(new SteerableEnemyShip()));
renderables.forEach(Renderable::create);
diff --git a/core/src/org/snoopdesigns/endless/world/ship/SteerableEnemyShip.java b/core/src/org/snoopdesigns/endless/world/ship/SteerableEnemyShip.java
index 6db087e..e8d429c 100644
--- a/core/src/org/snoopdesigns/endless/world/ship/SteerableEnemyShip.java
+++ b/core/src/org/snoopdesigns/endless/world/ship/SteerableEnemyShip.java
@@ -1,14 +1,6 @@
package org.snoopdesigns.endless.world.ship;
-import java.util.List;
-
import com.badlogic.gdx.Gdx;
-import com.badlogic.gdx.ai.steer.SteeringAcceleration;
-import com.badlogic.gdx.ai.steer.SteeringBehavior;
-import com.badlogic.gdx.ai.steer.behaviors.Arrive;
-import com.badlogic.gdx.ai.steer.behaviors.BlendedSteering;
-import com.badlogic.gdx.ai.steer.behaviors.Face;
-import com.badlogic.gdx.ai.utils.Location;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
@@ -17,28 +9,18 @@ import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.FixtureDef;
-import org.snoopdesigns.endless.context.Context;
-import org.snoopdesigns.endless.physics.Box2DLocation;
import org.snoopdesigns.endless.physics.SteerablePhysicalBody;
import org.snoopdesigns.endless.world.Renderable;
import org.snoopdesigns.endless.world.effects.EngineEffect;
+import org.snoopdesigns.endless.world.steering.ChaseSteering;
+import org.snoopdesigns.endless.world.steering.Steering;
+import org.snoopdesigns.endless.world.steering.SteeringApplicator;
public class SteerableEnemyShip extends SteerablePhysicalBody implements Renderable {
private Sprite sprite;
- private Sprite targetSprite; //target position
- private Sprite farAttackPointSprite; //farAttackPoint
- private Sprite faceSprite; //face position
- private final SteeringAcceleration<Vector2> steeringOutput = new SteeringAcceleration<>(new Vector2());
- private BlendedSteering<Vector2> steeringCombination;
-
- private Location<Vector2> positionTarget;
- private Location<Vector2> faceTarget;
- private float targetDirection;
-
- private final Vector2 lastVelocity = new Vector2(0f, 0f);
-
private EngineEffect engineEffect;
+ private Steering steering;
@Override
public BodyType getBodyType() {
@@ -55,21 +37,6 @@ public class SteerableEnemyShip extends SteerablePhysicalBody implements Rendera
}
@Override
- public float getMass() {
- return 10000;
- }
-
- @Override
- public float getLinearDamping() {
- return 1.5f;
- }
-
- @Override
- public float getMaxVelocity() {
- return 80f;
- }
-
- @Override
public Vector2 getInitialPosition() {
return new Vector2(MathUtils.random(150), MathUtils.random(150));
}
@@ -77,6 +44,7 @@ public class SteerableEnemyShip extends SteerablePhysicalBody implements Rendera
@Override
public void create() {
initBody();
+
final Texture texture = new Texture(Gdx.files.internal("ship.png"));
sprite = new Sprite(texture);
final float expectedSizeInMeters = 15f;
@@ -86,73 +54,40 @@ public class SteerableEnemyShip extends SteerablePhysicalBody implements Rendera
sprite.setScale(scale.x, scale.y);
sprite.setRotation(MathUtils.radDeg * getBody().getAngle());
- final Texture targetTexture = new Texture(Gdx.files.internal("target.png"));
- targetSprite = new Sprite(targetTexture);
- targetSprite.setScale(0.03f);
- farAttackPointSprite = new Sprite(targetTexture);
- farAttackPointSprite.setScale(0.02f);
- faceSprite = new Sprite(new Texture(Gdx.files.internal("face.png")));
- faceSprite.setScale(0.02f);
+ engineEffect = new EngineEffect(this);
+ steering = new ChaseSteering(this, 120f, 90f, new SteeringApplicator() {
- positionTarget = new Box2DLocation();
- faceTarget = new Box2DLocation();
+ private boolean speedUp = false;
- engineEffect = new EngineEffect(this);
+ @Override
+ public void applyAngularVelocity(float angular) {
+ getBody().setAngularVelocity(angular);
+ }
- steeringCombination = new BlendedSteering<>(this);
- getSteeringBehaviours().forEach(steeringBehaviour ->
- steeringCombination.add(steeringBehaviour, 0.5f));
+ @Override
+ public void applyLinearVelocity(Vector2 linear) {
+ speedUp(linear);
+ if (!speedUp) {
+ engineEffect.start();
+ }
+ speedUp = true;
+ }
- targetDirection = MathUtils.random(MathUtils.PI2);
+ @Override
+ public void stopLinearVelocity() {
+ engineEffect.stop();
+ speedUp = false;
+ }
+ });
}
@Override
public void render(SpriteBatch batch) {
- final float maxDistance = 100f;
- final float minDistance = 70f;
- final Vector2 targetDisplacement = new Vector2(maxDistance, 0f).rotateRad(targetDirection);
- final Vector2 farAttackPoint = new Vector2(
- Context.getInstance().getPlayerShip().getBody().getPosition().x + targetDisplacement.x,
- Context.getInstance().getPlayerShip().getBody().getPosition().y + targetDisplacement.y);
- final float distanceToPlayer = new Vector2(
- getBody().getPosition().x - Context.getInstance().getPlayerShip().getBody().getPosition().x,
- getBody().getPosition().y - Context.getInstance().getPlayerShip().getBody().getPosition().y)
- .len();
- if (distanceToPlayer > maxDistance + 10f) {
- // Rotate target rotation point only of player is far away
- targetDirection += Gdx.graphics.getDeltaTime() / 2f;
- }
- final Vector2 displacement = targetDisplacement.limit(Math.max(0, distanceToPlayer - minDistance));
- final Vector2 targetPos = new Vector2(
- Context.getInstance().getPlayerShip().getBody().getPosition().x + displacement.x,
- Context.getInstance().getPlayerShip().getBody().getPosition().y + displacement.y);
-
- positionTarget.getPosition().set(targetPos);
- //positionTarget.setOrientation(Context.getInstance().getPlayerShip().getBody().getAngle());
- faceTarget.getPosition().set(positionTarget.getPosition());
-
- steeringCombination.calculateSteering(steeringOutput);
- if (distanceToPlayer <= minDistance) { // do not move, if close to player, only rotate
- steeringOutput.linear.setZero();
- }
- applySteering();
+ steering.calculate();
sprite.setCenter(getBody().getPosition().x, getBody().getPosition().y);
sprite.setRotation(MathUtils.radDeg * getBody().getAngle());
sprite.draw(batch);
- farAttackPointSprite.setCenter(
- farAttackPoint.x,
- farAttackPoint.y);
- farAttackPointSprite.draw(batch);
- targetSprite.setCenter(
- positionTarget.getPosition().x,
- positionTarget.getPosition().y);
- targetSprite.draw(batch);
- faceSprite.setCenter(
- faceTarget.getPosition().x,
- faceTarget.getPosition().y);
- faceSprite.draw(batch);
-
engineEffect.render(batch);
// TODO
@@ -163,66 +98,30 @@ public class SteerableEnemyShip extends SteerablePhysicalBody implements Rendera
public void dispose() {
}
- private List<SteeringBehavior<Vector2>> getSteeringBehaviours() {
- return List.of(
- new Face<>(this, faceTarget),
- new Arrive<>(this, positionTarget)
- .setTimeToTarget(0.1f)
- .setArrivalTolerance(10f)
- .setDecelerationRadius(100f)
- );
- }
-
- private void applySteering() {
- // Update position and linear velocity.
- if (steeringOutput.angular != 0) {
- // this method internally scales the torque by deltaTime
- getBody().setAngularVelocity(steeringOutput.angular);
- } else {
- // Update orientation and angular velocity
- final Vector2 linearVelocity = getLinearVelocity();
- if (!linearVelocity.isZero(getZeroLinearSpeedThreshold())) {
- float newOrientation = linearVelocity.angleRad();
- getBody().setAngularVelocity(
- getMaxRotationAcceleration() *
- angleDifference(newOrientation, getBody().getAngle()));
- }
- }
-
- if (!steeringOutput.linear.isZero()) {
- if (steeringOutput.linear.len() >= lastVelocity.len() - 10) {
- speedUp(steeringOutput.linear);
- engineEffect.start();
- } else {
- engineEffect.stop();
- }
- lastVelocity.x = steeringOutput.linear.x;
- lastVelocity.y = steeringOutput.linear.y;
- } else {
- engineEffect.stop();
- }
- }
-
private void speedUp(final Vector2 force) {
- /*getBody().applyForceToCenter(
- force.x * 10000,
- force.y * 10000,
- true);*/
-
final float forceToApply = getBody().getMass() * 200; // force 200x times more than self mass
final Vector2 impulse = new Vector2(forceToApply, 0).rotateRad(getBody().getAngle());
getBody().applyForceToCenter(impulse, true);
}
- // TODO common
- private float angleDifference(float angle1, float angle2) {
- float diff = (angle1 - angle2) % (MathUtils.PI * 2);
- return diff < -1 * MathUtils.PI ? diff + 2 * MathUtils.PI : diff;
+ @Override
+ public float getMass() {
+ return 10000;
+ }
+
+ @Override
+ public float getLinearDamping() {
+ return 1.5f;
+ }
+
+ @Override
+ public float getMaxVelocity() {
+ return getMaxSpeed();
}
@Override
public float getMaxSpeed() {
- return 100f;
+ return 90f;
}
@Override
diff --git a/core/src/org/snoopdesigns/endless/world/steering/ChaseSteering.java b/core/src/org/snoopdesigns/endless/world/steering/ChaseSteering.java
new file mode 100644
index 0000000..3ac3ac7
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/world/steering/ChaseSteering.java
@@ -0,0 +1,108 @@
+package org.snoopdesigns.endless.world.steering;
+
+import java.util.List;
+
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.ai.steer.SteeringAcceleration;
+import com.badlogic.gdx.ai.steer.SteeringBehavior;
+import com.badlogic.gdx.ai.steer.behaviors.Arrive;
+import com.badlogic.gdx.ai.steer.behaviors.BlendedSteering;
+import com.badlogic.gdx.ai.steer.behaviors.Face;
+import com.badlogic.gdx.ai.utils.Location;
+import com.badlogic.gdx.math.MathUtils;
+import com.badlogic.gdx.math.Vector2;
+import org.snoopdesigns.endless.context.Context;
+import org.snoopdesigns.endless.physics.Box2DLocation;
+import org.snoopdesigns.endless.physics.SteerablePhysicalBody;
+
+public class ChaseSteering implements Steering {
+
+ private final SteeringAcceleration<Vector2> steeringOutput = new SteeringAcceleration<>(new Vector2());
+ private final BlendedSteering<Vector2> steeringCombination;
+ private final Location<Vector2> positionTarget;
+ private final Location<Vector2> faceTarget;
+ private final SteeringApplicator steeringApplicator;
+ private final SteerablePhysicalBody steerablePhysicalBody;
+ private final Vector2 lastVelocity = new Vector2(0f, 0f);
+ private final float maxDistance;
+ private final float minDistance;
+ private float targetDirection;
+
+ public ChaseSteering(final SteerablePhysicalBody steerablePhysicalBody,
+ final float maxDistance,
+ final float minDistance,
+ final SteeringApplicator steeringApplicator) {
+ this.steerablePhysicalBody = steerablePhysicalBody;
+ this.maxDistance = maxDistance;
+ this.minDistance = minDistance;
+ this.steeringApplicator = steeringApplicator;
+
+ positionTarget = new Box2DLocation();
+ faceTarget = new Box2DLocation();
+
+ steeringCombination = new BlendedSteering<>(steerablePhysicalBody);
+ getSteeringBehaviours().forEach(steeringBehaviour ->
+ steeringCombination.add(steeringBehaviour, 0.5f));
+
+ targetDirection = MathUtils.random(MathUtils.PI2);
+ }
+
+ @Override
+ public void calculate() {
+ final Vector2 targetDisplacement = new Vector2(maxDistance, 0f).rotateRad(targetDirection);
+ final float distanceToPlayer = new Vector2(
+ steerablePhysicalBody.getBody().getPosition().x -
+ Context.getInstance().getPlayerShip().getBody().getPosition().x,
+ steerablePhysicalBody.getBody().getPosition().y -
+ Context.getInstance().getPlayerShip().getBody().getPosition().y)
+ .len();
+ if (distanceToPlayer > maxDistance + 10f) {
+ // Rotate target rotation point only of player is far away
+ targetDirection += Gdx.graphics.getDeltaTime() / 1f;
+ }
+ final Vector2 displacement = targetDisplacement.limit(Math.max(0, (distanceToPlayer - minDistance)));
+ final Vector2 targetPos = new Vector2(
+ Context.getInstance().getPlayerShip().getBody().getPosition().x + displacement.x,
+ Context.getInstance().getPlayerShip().getBody().getPosition().y + displacement.y);
+
+ positionTarget.getPosition().set(targetPos);
+ faceTarget.getPosition().set(positionTarget.getPosition());
+
+ steeringCombination.calculateSteering(steeringOutput);
+ if (distanceToPlayer <= minDistance) { // do not move, if close to player, only rotate
+ steeringOutput.linear.setZero();
+ }
+
+ applySteering();
+ }
+
+ private void applySteering() {
+ // Update position and linear velocity.
+ if (steeringOutput.angular != 0) {
+ // this method internally scales the torque by deltaTime
+ steeringApplicator.applyAngularVelocity(steeringOutput.angular);
+ }
+
+ if (!steeringOutput.linear.isZero()) {
+ if (steeringOutput.linear.len() >= lastVelocity.len() - 10) {
+ steeringApplicator.applyLinearVelocity(steeringOutput.linear);
+ } else {
+ steeringApplicator.stopLinearVelocity();
+ }
+ lastVelocity.x = steeringOutput.linear.x;
+ lastVelocity.y = steeringOutput.linear.y;
+ } else {
+ steeringApplicator.stopLinearVelocity();
+ }
+ }
+
+ private List<SteeringBehavior<Vector2>> getSteeringBehaviours() {
+ return List.of(
+ new Face<>(steerablePhysicalBody, faceTarget),
+ new Arrive<>(steerablePhysicalBody, positionTarget)
+ .setTimeToTarget(0.1f)
+ .setArrivalTolerance(10f)
+ .setDecelerationRadius(100f)
+ );
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/world/steering/Steering.java b/core/src/org/snoopdesigns/endless/world/steering/Steering.java
new file mode 100644
index 0000000..c13b575
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/world/steering/Steering.java
@@ -0,0 +1,5 @@
+package org.snoopdesigns.endless.world.steering;
+
+public interface Steering {
+ void calculate();
+}
diff --git a/core/src/org/snoopdesigns/endless/world/steering/SteeringApplicator.java b/core/src/org/snoopdesigns/endless/world/steering/SteeringApplicator.java
new file mode 100644
index 0000000..d683465
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/world/steering/SteeringApplicator.java
@@ -0,0 +1,9 @@
+package org.snoopdesigns.endless.world.steering;
+
+import com.badlogic.gdx.math.Vector2;
+
+public interface SteeringApplicator {
+ void applyAngularVelocity(float angular);
+ void applyLinearVelocity(Vector2 linear);
+ void stopLinearVelocity();
+}