package org.jrenner.fps.move;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Disposable;
import org.jrenner.fps.GameWorld;
import org.jrenner.fps.Log;
import org.jrenner.fps.utils.Pooler;
public abstract class Movement implements Disposable {
public static Array<Movement> list;
private static Vector2 tmpv2 = new Vector2();
static final Vector3 tmp = new Vector3();
Vector3 position = Pooler.v3();
Vector3 destination = Pooler.v3();
boolean hasDest;
Vector3 velocity = Pooler.v3();
Vector3 acceleration = Pooler.v3();
float accelRate = 0.01f;
float maxHorizontalSpeed = 0.1f;
float maxVerticalSpeed = 0.1f;
float braking = 0.98f;
boolean gravity = false;
protected float arrivalThreshold = 5f;
private int entityId;
public static void init() {
list = new Array<>();
}
public Movement(int entityId) {
this.entityId = entityId;
list.add(this);
}
public void update(float timeStep, boolean onGround) {
// cancel downward velocity if touching the ground and moving downwards
if (onGround) {
if (velocity.y < 0f) velocity.y = 0f;
}
if (!hasDest) {
if (onGround) {
// brake while on ground with no destination
velocity.scl(braking);
}
} else {
// accelerate towards the destination
accelerate(timeStep);
}
applyGravity(onGround);
applyVelocity(timeStep, true);
//stayInGameWorld();
}
abstract void accelerate(float timeStep);
void limitVelocity() {
velocity.y = MathUtils.clamp(velocity.y, -maxVerticalSpeed, maxVerticalSpeed);
tmpv2.set(velocity.x, velocity.z);
tmpv2.limit(maxHorizontalSpeed);
velocity.x = tmpv2.x;
velocity.z = tmpv2.y;
}
public void applyVelocity(float timeStep, boolean limit) {
limitVelocity();
tmp.set(velocity).scl(timeStep);
//System.out.println("add to position: " + Tools.fmt(tmp));
position.add(tmp);
}
public void applyGravity(boolean onGround) {
if (!gravity) return;
tmp.set(0f, GameWorld.GRAVITY, 0f);
/*if (onGround) {
Vector3 floorNormal = Physics.inst.getFloorNormal(position);
if (floorNormal.y <= 0.9f) {
// slide down slopes
// combine and average gravity and the floor normal
tmp.nor();
tmp.add(floorNormal).nor();
tmp.scl(-GameWorld.GRAVITY);
}
}*/
if (!onGround) {
velocity.add(tmp);
}
}
public float getBraking() {
return braking;
}
public void setBraking(float braking) {
this.braking = braking;
}
public Vector3 getVelocity() {
return velocity;
}
/** acceleration as applied to velocity */
public Vector3 getAcceleration() {
return acceleration;
}
/** the rate of acceleration */
public float getAccelRate() {
return accelRate;
}
public void setAccelRate(float accelRate) {
this.accelRate = accelRate;
}
public float getMaxHorizontalSpeed() {
return maxHorizontalSpeed;
}
public void setMaxHorizontalSpeed(float maxHorizontalSpeed) {
this.maxHorizontalSpeed = maxHorizontalSpeed;
}
public float getMaxVerticalSpeed() {
return maxVerticalSpeed;
}
public void setMaxVerticalSpeed(float maxVerticalSpeed) {
this.maxVerticalSpeed = maxVerticalSpeed;
}
public Vector3 getDestination() {
return destination;
}
public boolean hasDestination() {
return hasDest;
}
public void setDestination(Vector3 newDest) {
if (newDest == null) {
hasDest = false;
} else {
hasDest = true;
destination.set(newDest);
}
}
public void cancelDestinationAtThreshold(float range) {
if (hasDest) {
if (destination.dst2(position) <= range * range) {
hasDest = false;
}
}
}
public boolean isAffectedByGravity() {
return gravity;
}
public void setAffectedByGravity(boolean gravity) {
this.gravity = gravity;
}
public Vector3 getPosition() {
return position;
}
public void setPosition(Vector3 position) {
this.position.set(position);
}
public void stayInGameWorld() {
boolean out = position.y < -100f || position.x < -20f || position.x > GameWorld.WORLD_WIDTH + 20f ||
position.z < -20f || position.z > GameWorld.WORLD_DEPTH + 20f;
if (out) {
// TODO handle this for real
// drop in to world randomly
position.set(MathUtils.random(50f, 100f), 30f, MathUtils.random(50f, 100f));
Log.debug("Entity was outside of game world, position reset: " + entityId);
}
}
@Override
public void dispose() {
Pooler.free(velocity, acceleration, position, destination);
list.removeValue(this, true);
}
public static void disposeAll() {
for (Movement move : list) {
move.dispose();
}
}
}