summaryrefslogtreecommitdiff
path: root/core/src/org
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/org')
-rw-r--r--core/src/org/snoopdesigns/endless/EndlessGame.java66
-rw-r--r--core/src/org/snoopdesigns/endless/config/Config.java17
-rw-r--r--core/src/org/snoopdesigns/endless/context/Context.java37
-rw-r--r--core/src/org/snoopdesigns/endless/context/OnInit.java5
-rw-r--r--core/src/org/snoopdesigns/endless/input/DefaultInputProcessor.java51
-rw-r--r--core/src/org/snoopdesigns/endless/physics/Box2DDebugRenderer.java28
-rw-r--r--core/src/org/snoopdesigns/endless/physics/Box2DLocation.java46
-rw-r--r--core/src/org/snoopdesigns/endless/physics/Box2DRenderer.java22
-rw-r--r--core/src/org/snoopdesigns/endless/physics/PhysicalBody.java32
-rw-r--r--core/src/org/snoopdesigns/endless/physics/SteerablePhysicalBody.java115
-rw-r--r--core/src/org/snoopdesigns/endless/physics/WorldContext.java17
-rw-r--r--core/src/org/snoopdesigns/endless/physics/camera/CameraContext.java48
-rw-r--r--core/src/org/snoopdesigns/endless/physics/camera/CameraRenderer.java55
-rw-r--r--core/src/org/snoopdesigns/endless/renderer/CursorRenderer.java29
-rw-r--r--core/src/org/snoopdesigns/endless/renderer/DebugRenderer.java54
-rw-r--r--core/src/org/snoopdesigns/endless/renderer/Renderer.java11
-rw-r--r--core/src/org/snoopdesigns/endless/utils/ExitControllable.java17
-rw-r--r--core/src/org/snoopdesigns/endless/world/Controllable.java7
-rw-r--r--core/src/org/snoopdesigns/endless/world/ObjectsRenderer.java41
-rw-r--r--core/src/org/snoopdesigns/endless/world/Renderable.java9
-rw-r--r--core/src/org/snoopdesigns/endless/world/bg/BackgroundRenderer.java35
-rw-r--r--core/src/org/snoopdesigns/endless/world/player/PlayerShip.java150
-rw-r--r--core/src/org/snoopdesigns/endless/world/ship/SteerableEnemyShip.java163
23 files changed, 1055 insertions, 0 deletions
diff --git a/core/src/org/snoopdesigns/endless/EndlessGame.java b/core/src/org/snoopdesigns/endless/EndlessGame.java
new file mode 100644
index 0000000..fc72c66
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/EndlessGame.java
@@ -0,0 +1,66 @@
+package org.snoopdesigns.endless;
+
+import java.util.List;
+
+import com.badlogic.gdx.ApplicationAdapter;
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.InputMultiplexer;
+import com.badlogic.gdx.utils.ScreenUtils;
+import org.snoopdesigns.endless.context.Context;
+import org.snoopdesigns.endless.context.OnInit;
+import org.snoopdesigns.endless.physics.Box2DDebugRenderer;
+import org.snoopdesigns.endless.physics.Box2DRenderer;
+import org.snoopdesigns.endless.physics.camera.CameraRenderer;
+import org.snoopdesigns.endless.renderer.CursorRenderer;
+import org.snoopdesigns.endless.renderer.DebugRenderer;
+import org.snoopdesigns.endless.renderer.Renderer;
+import org.snoopdesigns.endless.utils.ExitControllable;
+import org.snoopdesigns.endless.world.ObjectsRenderer;
+import org.snoopdesigns.endless.world.bg.BackgroundRenderer;
+
+public class EndlessGame extends ApplicationAdapter {
+
+ private final List<Renderer> renderers = List.of(
+ new BackgroundRenderer(),
+ new Box2DRenderer(),
+ new CameraRenderer(),
+ new Box2DDebugRenderer(),
+ new ObjectsRenderer(),
+ new CursorRenderer(),
+ new DebugRenderer()
+ );
+
+ private final List<OnInit> intializers = List.of(
+ new Context()
+ );
+
+ @Override
+ public void create () {
+ intializers.forEach(OnInit::create);
+
+ final InputMultiplexer inputMultiplexer = new InputMultiplexer();
+ renderers.forEach(inputMultiplexer::addProcessor);
+ inputMultiplexer.addProcessor(Context.getInstance().getPlayerShip());
+ inputMultiplexer.addProcessor(new ExitControllable());
+ Gdx.input.setInputProcessor(inputMultiplexer);
+
+ renderers.forEach(Renderer::create);
+ }
+
+ @Override
+ public void render () {
+ ScreenUtils.clear(0, 0, 0, 1);
+ renderers.forEach(Renderer::render);
+ }
+
+ @Override
+ public void resize(int width, int height) {
+ renderers.forEach(renderer ->
+ renderer.resize(width, height));
+ }
+
+ @Override
+ public void dispose() {
+ renderers.forEach(Renderer::dispose);
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/config/Config.java b/core/src/org/snoopdesigns/endless/config/Config.java
new file mode 100644
index 0000000..34ce45d
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/config/Config.java
@@ -0,0 +1,17 @@
+package org.snoopdesigns.endless.config;
+
+public final class Config {
+ private static int screenWidth = 1280;
+ private static int screenHeight = 720;
+
+ private Config() {
+ }
+
+ public static int getScreenWidth() {
+ return screenWidth;
+ }
+
+ public static int getScreenHeight() {
+ return screenHeight;
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/context/Context.java b/core/src/org/snoopdesigns/endless/context/Context.java
new file mode 100644
index 0000000..4081c87
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/context/Context.java
@@ -0,0 +1,37 @@
+package org.snoopdesigns.endless.context;
+
+import org.snoopdesigns.endless.physics.WorldContext;
+import org.snoopdesigns.endless.physics.camera.CameraContext;
+import org.snoopdesigns.endless.world.player.PlayerShip;
+
+public final class Context implements OnInit {
+ private static Context INSTANCE;
+
+ private CameraContext cameraContext;
+ private WorldContext worldContext;
+ private PlayerShip playerShip;
+
+ @Override
+ public void create() {
+ INSTANCE = new Context();
+ INSTANCE.cameraContext = new CameraContext();
+ INSTANCE.worldContext = new WorldContext();
+ INSTANCE.playerShip = new PlayerShip();
+ }
+
+ public static Context getInstance() {
+ return INSTANCE;
+ }
+
+ public CameraContext getCameraContext() {
+ return cameraContext;
+ }
+
+ public WorldContext getWorldContext() {
+ return worldContext;
+ }
+
+ public PlayerShip getPlayerShip() {
+ return playerShip;
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/context/OnInit.java b/core/src/org/snoopdesigns/endless/context/OnInit.java
new file mode 100644
index 0000000..7b5678a
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/context/OnInit.java
@@ -0,0 +1,5 @@
+package org.snoopdesigns.endless.context;
+
+public interface OnInit {
+ void create();
+}
diff --git a/core/src/org/snoopdesigns/endless/input/DefaultInputProcessor.java b/core/src/org/snoopdesigns/endless/input/DefaultInputProcessor.java
new file mode 100644
index 0000000..ca3f301
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/input/DefaultInputProcessor.java
@@ -0,0 +1,51 @@
+package org.snoopdesigns.endless.input;
+
+import com.badlogic.gdx.InputProcessor;
+
+public interface DefaultInputProcessor extends InputProcessor {
+
+ @Override
+ default boolean keyDown(int keycode) {
+ return false;
+ }
+
+ @Override
+ default boolean keyUp(int keycode) {
+ return false;
+ }
+
+ @Override
+ default boolean keyTyped(char character) {
+ return false;
+ }
+
+ @Override
+ default boolean touchDown(int screenX, int screenY, int pointer, int button) {
+ return false;
+ }
+
+ @Override
+ default boolean touchUp(int screenX, int screenY, int pointer, int button) {
+ return false;
+ }
+
+ @Override
+ default boolean touchCancelled(int screenX, int screenY, int pointer, int button) {
+ return false;
+ }
+
+ @Override
+ default boolean touchDragged(int screenX, int screenY, int pointer) {
+ return false;
+ }
+
+ @Override
+ default boolean mouseMoved(int screenX, int screenY) {
+ return false;
+ }
+
+ @Override
+ default boolean scrolled(float amountX, float amountY) {
+ return false;
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/physics/Box2DDebugRenderer.java b/core/src/org/snoopdesigns/endless/physics/Box2DDebugRenderer.java
new file mode 100644
index 0000000..15f930f
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/physics/Box2DDebugRenderer.java
@@ -0,0 +1,28 @@
+package org.snoopdesigns.endless.physics;
+
+import org.snoopdesigns.endless.context.Context;
+import org.snoopdesigns.endless.renderer.Renderer;
+
+public class Box2DDebugRenderer implements Renderer {
+
+ private com.badlogic.gdx.physics.box2d.Box2DDebugRenderer debugRenderer;
+
+ @Override
+ public void create() {
+ debugRenderer = new com.badlogic.gdx.physics.box2d.Box2DDebugRenderer();
+ debugRenderer.setDrawBodies(true);
+ debugRenderer.setDrawVelocities(true);
+ debugRenderer.setDrawAABBs(true);
+ }
+
+ @Override
+ public void render() {
+ debugRenderer.render(
+ Context.getInstance().getWorldContext().getWorld(),
+ Context.getInstance().getCameraContext().getCameraProjection());
+ }
+
+ @Override
+ public void dispose() {
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/physics/Box2DLocation.java b/core/src/org/snoopdesigns/endless/physics/Box2DLocation.java
new file mode 100644
index 0000000..338b595
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/physics/Box2DLocation.java
@@ -0,0 +1,46 @@
+package org.snoopdesigns.endless.physics;
+
+import com.badlogic.gdx.ai.utils.Location;
+import com.badlogic.gdx.math.Vector2;
+
+public class Box2DLocation implements Location<Vector2> {
+ Vector2 position;
+ float orientation;
+
+ public Box2DLocation () {
+ this.position = new Vector2();
+ this.orientation = 0;
+ }
+
+ @Override
+ public Vector2 getPosition () {
+ return position;
+ }
+
+ @Override
+ public float getOrientation () {
+ return orientation;
+ }
+
+ @Override
+ public void setOrientation (float orientation) {
+ this.orientation = orientation;
+ }
+
+ @Override
+ public Location<Vector2> newLocation () {
+ return new Box2DLocation();
+ }
+
+ @Override
+ public float vectorToAngle (Vector2 vector) {
+ return (float)Math.atan2(-vector.x, vector.y);
+ }
+
+ @Override
+ public Vector2 angleToVector (Vector2 outVector, float angle) {
+ outVector.x = -(float)Math.sin(angle);
+ outVector.y = (float)Math.cos(angle);
+ return outVector;
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/physics/Box2DRenderer.java b/core/src/org/snoopdesigns/endless/physics/Box2DRenderer.java
new file mode 100644
index 0000000..641e397
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/physics/Box2DRenderer.java
@@ -0,0 +1,22 @@
+package org.snoopdesigns.endless.physics;
+
+import com.badlogic.gdx.physics.box2d.Box2D;
+import org.snoopdesigns.endless.context.Context;
+import org.snoopdesigns.endless.renderer.Renderer;
+
+public class Box2DRenderer implements Renderer {
+
+ @Override
+ public void create() {
+ Box2D.init();
+ }
+
+ @Override
+ public void render() {
+ Context.getInstance().getWorldContext().getWorld().step(1/60f, 6, 2);
+ }
+
+ @Override
+ public void dispose() {
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/physics/PhysicalBody.java b/core/src/org/snoopdesigns/endless/physics/PhysicalBody.java
new file mode 100644
index 0000000..23ede8d
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/physics/PhysicalBody.java
@@ -0,0 +1,32 @@
+package org.snoopdesigns.endless.physics;
+
+import com.badlogic.gdx.math.Vector2;
+import com.badlogic.gdx.physics.box2d.Body;
+import com.badlogic.gdx.physics.box2d.BodyDef;
+import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
+import com.badlogic.gdx.physics.box2d.FixtureDef;
+import org.snoopdesigns.endless.context.Context;
+
+public abstract class PhysicalBody {
+
+ Body body;
+
+ public abstract BodyType getBodyType();
+ public abstract FixtureDef getFixture();
+
+ public Vector2 getInitialPosition() {
+ return new Vector2(0, 0);
+ }
+
+ public void initBody() {
+ final BodyDef bodyDef = new BodyDef();
+ bodyDef.type = getBodyType();
+ bodyDef.position.set(getInitialPosition());
+ body = Context.getInstance().getWorldContext().getWorld().createBody(bodyDef);
+ body.createFixture(getFixture());
+ }
+
+ public Body getBody() {
+ return body;
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/physics/SteerablePhysicalBody.java b/core/src/org/snoopdesigns/endless/physics/SteerablePhysicalBody.java
new file mode 100644
index 0000000..9e9a85c
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/physics/SteerablePhysicalBody.java
@@ -0,0 +1,115 @@
+package org.snoopdesigns.endless.physics;
+
+import com.badlogic.gdx.ai.steer.Steerable;
+import com.badlogic.gdx.ai.utils.Location;
+import com.badlogic.gdx.math.Vector2;
+
+public abstract class SteerablePhysicalBody extends PhysicalBody implements Steerable<Vector2> {
+
+ public abstract float getMaxSpeed();
+ public abstract float getMaxAcceleration();
+ public abstract float getMaxRotationSpeed();
+ public abstract float getMaxRotationAcceleration();
+
+ @Override
+ public Vector2 getLinearVelocity() {
+ return getBody().getLinearVelocity();
+ }
+
+ @Override
+ public float getAngularVelocity() {
+ return getBody().getAngularVelocity();
+ }
+
+ @Override
+ public float getBoundingRadius() {
+ return 0.001f;
+ }
+
+ @Override
+ public boolean isTagged() {
+ return false;
+ }
+
+ @Override
+ public void setTagged(boolean tagged) {
+ }
+
+ @Override
+ public float getZeroLinearSpeedThreshold() {
+ return 0.1f;
+ }
+
+ @Override
+ public void setZeroLinearSpeedThreshold(float value) {
+ }
+
+ @Override
+ public float getMaxLinearSpeed() {
+ return getMaxSpeed();
+ }
+
+ @Override
+ public void setMaxLinearSpeed(float maxLinearSpeed) {
+ }
+
+ @Override
+ public float getMaxLinearAcceleration() {
+ return getMaxAcceleration();
+ }
+
+ @Override
+ public void setMaxLinearAcceleration(float maxLinearAcceleration) {
+ }
+
+ @Override
+ public float getMaxAngularSpeed() {
+ return getMaxRotationSpeed();
+ }
+
+ @Override
+ public void setMaxAngularSpeed(float maxAngularSpeed) {
+ }
+
+ @Override
+ public float getMaxAngularAcceleration() {
+ return getMaxRotationAcceleration();
+ }
+
+ @Override
+ public void setMaxAngularAcceleration(float maxAngularAcceleration) {
+ }
+
+ @Override
+ public Vector2 getPosition() {
+ return getBody().getPosition();
+ }
+
+ @Override
+ public float getOrientation() {
+ return getBody().getAngle();
+ }
+
+ @Override
+ public void setOrientation(float orientation) {
+ getBody().setTransform(getPosition(), orientation);
+ }
+
+ @Override
+ public float vectorToAngle(Vector2 vector) {
+ return vector.angleRad();
+ }
+
+ @Override
+ public Vector2 angleToVector(Vector2 outVector, float angle) {
+ final var tmpVector = new Vector2(1, 0).rotateRad(angle);
+ outVector.x = tmpVector.x;
+ outVector.y = tmpVector.y;
+ return outVector;
+ }
+
+ @Override
+ public Location<Vector2> newLocation() {
+ return new Box2DLocation();
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/physics/WorldContext.java b/core/src/org/snoopdesigns/endless/physics/WorldContext.java
new file mode 100644
index 0000000..5f10ba8
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/physics/WorldContext.java
@@ -0,0 +1,17 @@
+package org.snoopdesigns.endless.physics;
+
+import com.badlogic.gdx.math.Vector2;
+import com.badlogic.gdx.physics.box2d.World;
+
+public class WorldContext {
+
+ private final World world;
+
+ public WorldContext() {
+ this.world = new World(new Vector2(0, 0), true);
+ }
+
+ public World getWorld() {
+ return world;
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/physics/camera/CameraContext.java b/core/src/org/snoopdesigns/endless/physics/camera/CameraContext.java
new file mode 100644
index 0000000..635813c
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/physics/camera/CameraContext.java
@@ -0,0 +1,48 @@
+package org.snoopdesigns.endless.physics.camera;
+
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.math.Matrix4;
+import com.badlogic.gdx.math.Vector2;
+
+public final class CameraContext {
+
+ private static final float DEFAULT_WORLD_WIDTH = 300.0f;
+
+ private final Vector2 position;
+ private final Vector2 viewport;
+ private float zoom;
+ private Matrix4 cameraProjection;
+
+ public CameraContext() {
+ final float w = Gdx.graphics.getWidth();
+ final float h = Gdx.graphics.getHeight();
+
+ this.position = new Vector2(0, 0);
+ this.zoom = 1.0f;
+ this.viewport = new Vector2(DEFAULT_WORLD_WIDTH, DEFAULT_WORLD_WIDTH * (h / w));
+ }
+
+ public Matrix4 getCameraProjection() {
+ return cameraProjection;
+ }
+
+ public void setCameraProjection(Matrix4 cameraProjection) {
+ this.cameraProjection = cameraProjection;
+ }
+
+ public Vector2 getPosition() {
+ return position;
+ }
+
+ public float getZoom() {
+ return zoom;
+ }
+
+ public void setZoom(float zoom) {
+ this.zoom = zoom;
+ }
+
+ public Vector2 getViewport() {
+ return viewport;
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/physics/camera/CameraRenderer.java b/core/src/org/snoopdesigns/endless/physics/camera/CameraRenderer.java
new file mode 100644
index 0000000..165240a
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/physics/camera/CameraRenderer.java
@@ -0,0 +1,55 @@
+package org.snoopdesigns.endless.physics.camera;
+
+import com.badlogic.gdx.graphics.OrthographicCamera;
+import com.badlogic.gdx.math.Vector2;
+import com.badlogic.gdx.utils.viewport.ExtendViewport;
+import com.badlogic.gdx.utils.viewport.Viewport;
+import org.snoopdesigns.endless.context.Context;
+import org.snoopdesigns.endless.renderer.Renderer;
+
+public class CameraRenderer implements Renderer {
+
+ private static final float DEFAULT_WORLD_WIDTH = 300.0f;
+ private static final float DEFAULT_WORLD_HEIGHT = 300.0f;
+
+ private OrthographicCamera camera;
+ private Viewport viewport;
+
+ @Override
+ public void create() {
+ camera = new OrthographicCamera();
+ camera.zoom = Context.getInstance().getCameraContext().getZoom();
+ viewport = new ExtendViewport(
+ Context.getInstance().getCameraContext().getViewport().x,
+ Context.getInstance().getCameraContext().getViewport().y,
+ camera);
+ camera.update();
+ Context.getInstance().getCameraContext().setCameraProjection(camera.combined);
+ }
+
+ @Override
+ public void render() {
+ final Vector2 cameraPosition = Context.getInstance().getCameraContext().getPosition();
+ camera.position.set(cameraPosition.x, cameraPosition.y, 0);
+ camera.update();
+ }
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public void resize(int width, int height) {
+ viewport.update(width, height);
+ Context.getInstance().getCameraContext().getViewport().set(
+ camera.viewportWidth,
+ camera.viewportHeight);
+ }
+
+ @Override
+ public boolean scrolled(float amountX, float amountY) {
+ camera.zoom += amountY / 10f;
+ Context.getInstance().getCameraContext().setZoom(camera.zoom);
+ return true;
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/renderer/CursorRenderer.java b/core/src/org/snoopdesigns/endless/renderer/CursorRenderer.java
new file mode 100644
index 0000000..05b12f9
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/renderer/CursorRenderer.java
@@ -0,0 +1,29 @@
+package org.snoopdesigns.endless.renderer;
+
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.graphics.Cursor;
+import com.badlogic.gdx.graphics.Pixmap;
+
+public class CursorRenderer implements Renderer {
+
+ private Pixmap crosshair;
+
+ @Override
+ public void create() {
+ crosshair = new Pixmap(Gdx.files.internal("crosshair.png"));
+ final Cursor cursor = Gdx.graphics.newCursor(crosshair,
+ crosshair.getWidth() / 2,
+ crosshair.getHeight() / 2);
+ Gdx.graphics.setCursor(cursor);
+ }
+
+ @Override
+ public void render() {
+
+ }
+
+ @Override
+ public void dispose() {
+ crosshair.dispose();
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/renderer/DebugRenderer.java b/core/src/org/snoopdesigns/endless/renderer/DebugRenderer.java
new file mode 100644
index 0000000..f31336b
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/renderer/DebugRenderer.java
@@ -0,0 +1,54 @@
+package org.snoopdesigns.endless.renderer;
+
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.graphics.Color;
+import com.badlogic.gdx.graphics.g2d.BitmapFont;
+import com.badlogic.gdx.graphics.g2d.SpriteBatch;
+import org.snoopdesigns.endless.context.Context;
+
+public class DebugRenderer implements Renderer {
+
+ private BitmapFont font;
+ private SpriteBatch batch;
+
+ @Override
+ public void create() {
+ font = new BitmapFont(Gdx.files.internal("calibri.fnt"), false);
+ font.setColor(Color.GREEN);
+ font.getData().setScale(0.7f);
+ batch = new SpriteBatch();
+ }
+
+ @Override
+ public void render() {
+ batch.begin();
+ final String debugText = String.format("""
+ window size %d x %d
+ viewport %f %f
+ zoom %f
+ position %f %f
+ angle %f
+ speed %f
+ velocity %f %f
+ """,
+ Gdx.graphics.getWidth(),
+ Gdx.graphics.getHeight(),
+ Context.getInstance().getCameraContext().getViewport().x,
+ Context.getInstance().getCameraContext().getViewport().y,
+ Context.getInstance().getCameraContext().getZoom(),
+ Context.getInstance().getCameraContext().getPosition().x,
+ Context.getInstance().getCameraContext().getPosition().y,
+ Context.getInstance().getPlayerShip().getBody().getAngle(),
+ Context.getInstance().getPlayerShip().getBody().getLinearVelocity().len(),
+ Context.getInstance().getPlayerShip().getBody().getLinearVelocity().x,
+ Context.getInstance().getPlayerShip().getBody().getLinearVelocity().y);
+ font.draw(batch, debugText, 10f, 190f);
+ batch.end();
+ }
+
+ @Override
+ public void dispose() {
+ font.dispose();
+ batch.dispose();
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/renderer/Renderer.java b/core/src/org/snoopdesigns/endless/renderer/Renderer.java
new file mode 100644
index 0000000..a98e36a
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/renderer/Renderer.java
@@ -0,0 +1,11 @@
+package org.snoopdesigns.endless.renderer;
+
+import org.snoopdesigns.endless.input.DefaultInputProcessor;
+
+public interface Renderer extends DefaultInputProcessor {
+ void create();
+ void render();
+ void dispose();
+ default void resize(int width, int height) {
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/utils/ExitControllable.java b/core/src/org/snoopdesigns/endless/utils/ExitControllable.java
new file mode 100644
index 0000000..12469a6
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/utils/ExitControllable.java
@@ -0,0 +1,17 @@
+package org.snoopdesigns.endless.utils;
+
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.Input.Keys;
+import org.snoopdesigns.endless.world.Controllable;
+
+public class ExitControllable implements Controllable {
+
+ @Override
+ public boolean keyDown(int keycode) {
+ if (keycode == Keys.ESCAPE) {
+ Gdx.app.exit();
+ System.exit(1);
+ }
+ return true;
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/world/Controllable.java b/core/src/org/snoopdesigns/endless/world/Controllable.java
new file mode 100644
index 0000000..77f1181
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/world/Controllable.java
@@ -0,0 +1,7 @@
+package org.snoopdesigns.endless.world;
+
+import org.snoopdesigns.endless.input.DefaultInputProcessor;
+
+public interface Controllable extends DefaultInputProcessor {
+
+}
diff --git a/core/src/org/snoopdesigns/endless/world/ObjectsRenderer.java b/core/src/org/snoopdesigns/endless/world/ObjectsRenderer.java
new file mode 100644
index 0000000..f97f05c
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/world/ObjectsRenderer.java
@@ -0,0 +1,41 @@
+package org.snoopdesigns.endless.world;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.badlogic.gdx.graphics.g2d.SpriteBatch;
+import org.snoopdesigns.endless.context.Context;
+import org.snoopdesigns.endless.renderer.Renderer;
+import org.snoopdesigns.endless.world.ship.SteerableEnemyShip;
+
+public class ObjectsRenderer implements Renderer {
+
+ private final List<Renderable> renderables = new ArrayList<>();
+
+ private SpriteBatch batch;
+
+ @Override
+ public void create() {
+ batch = new SpriteBatch();
+ renderables.add(Context.getInstance().getPlayerShip());
+ renderables.add(new SteerableEnemyShip());
+ renderables.add(new SteerableEnemyShip());
+ renderables.add(new SteerableEnemyShip());
+
+ renderables.forEach(Renderable::create);
+ }
+
+ @Override
+ public void render() {
+ batch.setProjectionMatrix(Context.getInstance().getCameraContext().getCameraProjection());
+ batch.begin();
+ renderables.forEach(renderable -> renderable.render(batch));
+ batch.end();
+ }
+
+ @Override
+ public void dispose() {
+ batch.dispose();
+ renderables.forEach(Renderable::dispose);
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/world/Renderable.java b/core/src/org/snoopdesigns/endless/world/Renderable.java
new file mode 100644
index 0000000..e5ba159
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/world/Renderable.java
@@ -0,0 +1,9 @@
+package org.snoopdesigns.endless.world;
+
+import com.badlogic.gdx.graphics.g2d.SpriteBatch;
+
+public interface Renderable {
+ void create();
+ void render(final SpriteBatch batch);
+ void dispose();
+}
diff --git a/core/src/org/snoopdesigns/endless/world/bg/BackgroundRenderer.java b/core/src/org/snoopdesigns/endless/world/bg/BackgroundRenderer.java
new file mode 100644
index 0000000..094a827
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/world/bg/BackgroundRenderer.java
@@ -0,0 +1,35 @@
+package org.snoopdesigns.endless.world.bg;
+
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.graphics.Texture;
+import com.badlogic.gdx.graphics.g2d.Sprite;
+import com.badlogic.gdx.graphics.g2d.SpriteBatch;
+import org.snoopdesigns.endless.context.Context;
+import org.snoopdesigns.endless.renderer.Renderer;
+
+public class BackgroundRenderer implements Renderer {
+
+ private SpriteBatch batch;
+ private Sprite bgSprite;
+
+ @Override
+ public void create() {
+ batch = new SpriteBatch();
+ bgSprite = new Sprite(new Texture(Gdx.files.internal("bg.png")));
+ bgSprite.setCenter(0, 0);
+ bgSprite.setSize(1000, 1000);
+ }
+
+ @Override
+ public void render() {
+ batch.setProjectionMatrix(Context.getInstance().getCameraContext().getCameraProjection());
+ batch.begin();
+ bgSprite.draw(batch);
+ batch.end();
+ }
+
+ @Override
+ public void dispose() {
+ batch.dispose();
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/world/player/PlayerShip.java b/core/src/org/snoopdesigns/endless/world/player/PlayerShip.java
new file mode 100644
index 0000000..3670d6f
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/world/player/PlayerShip.java
@@ -0,0 +1,150 @@
+package org.snoopdesigns.endless.world.player;
+
+import java.util.LinkedList;
+import java.util.Queue;
+
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.Input.Keys;
+import com.badlogic.gdx.graphics.Texture;
+import com.badlogic.gdx.graphics.g2d.ParticleEffect;
+import com.badlogic.gdx.graphics.g2d.Sprite;
+import com.badlogic.gdx.graphics.g2d.SpriteBatch;
+import com.badlogic.gdx.math.MathUtils;
+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.PhysicalBody;
+import org.snoopdesigns.endless.world.Controllable;
+import org.snoopdesigns.endless.world.Renderable;
+
+public final class PlayerShip extends PhysicalBody implements Controllable, Renderable {
+
+ private final Queue<ParticleEffect> effects = new LinkedList<>();
+ private Sprite sprite;
+
+ @Override
+ public BodyType getBodyType() {
+ return BodyType.DynamicBody;
+ }
+
+ @Override
+ public FixtureDef getFixture() {
+ final CircleShape circle = new CircleShape();
+ circle.setRadius(7f);
+ final FixtureDef fixtureDef = new FixtureDef();
+ fixtureDef.shape = circle;
+ fixtureDef.density = 1f; // weight of body
+ return fixtureDef;
+ }
+
+ @Override
+ public void create() {
+ initBody();
+
+ final Texture texture = new Texture(Gdx.files.internal("ship.png"));
+ sprite = new Sprite(texture);
+ sprite.setScale(0.1f);
+ }
+
+ @Override
+ public void render(SpriteBatch batch) {
+ handleInput();
+ handleMousePosition();
+ final float x = getBody().getPosition().x;
+ final float y = getBody().getPosition().y;
+ Context.getInstance().getCameraContext().getPosition().set(x, y);
+
+ sprite.setCenter(x, y);
+ sprite.setRotation(MathUtils.radDeg * getBody().getAngle());
+
+ effects.removeIf(ParticleEffect::isComplete);
+ effects.forEach(effect -> {
+ final Vector2 effectOffset = new Vector2(-5f, 0f).rotateRad(getBody().getAngle());
+ effect.setPosition(x + effectOffset.x, y + effectOffset.y);
+ effect.getEmitters().forEach(emitter -> {
+ final float effectRotation = MathUtils.radDeg * getBody().getAngle();
+ emitter.getAngle().setLow(effectRotation);
+ emitter.getAngle().setHigh(effectRotation);
+ });
+ });
+
+ sprite.draw(batch);
+ effects.forEach(effect ->
+ effect.draw(batch, Gdx.graphics.getDeltaTime()));
+ }
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public boolean keyDown(int keycode) {
+ if (keycode == Keys.SPACE) {
+ final ParticleEffect effect = new ParticleEffect();
+ effect.load(Gdx.files.internal("particles.p"), Gdx.files.internal(""));
+ effect.setPosition(
+ getBody().getPosition().x,
+ getBody().getPosition().y);
+ effect.start();
+ effects.add(effect);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean keyUp(int keycode) {
+ if (keycode == Keys.SPACE) {
+ effects.forEach(ParticleEffect::allowCompletion);
+ return true;
+ }
+ return false;
+ }
+
+ private void speedUp() {
+ final float force = 100000.0f;
+ final Vector2 impulse = new Vector2(force, 0).rotateRad(getBody().getAngle());
+ getBody().applyForceToCenter(impulse, true);
+ }
+
+ private void slowDown() {
+ getBody().setLinearVelocity(
+ getBody().getLinearVelocity().x * 0.98f,
+ getBody().getLinearVelocity().y * 0.98f);
+ }
+
+ private void handleInput() {
+ if (Gdx.input.isKeyPressed(Keys.SPACE)) {
+ speedUp();
+ } else {
+ slowDown();
+ }
+ }
+
+ private void handleMousePosition() {
+ final float screenX = Gdx.input.getX();
+ final float screenY = Gdx.input.getY();
+ final float screenCenterX = (float) Gdx.graphics.getWidth() / 2;
+ final float screenCenterY = (float) Gdx.graphics.getHeight() / 2;
+ final float effectiveViewportWidth = Context.getInstance().getCameraContext().getViewport().x *
+ Context.getInstance().getCameraContext().getZoom();
+ final float effectiveViewportHeight = Context.getInstance().getCameraContext().getViewport().y *
+ Context.getInstance().getCameraContext().getZoom();
+
+ final float directionX = (screenX - screenCenterX) * (effectiveViewportWidth / Gdx.graphics.getWidth());
+ final float directionY = ((Gdx.graphics.getHeight() - screenY) - screenCenterY) * (effectiveViewportHeight / Gdx.graphics.getHeight());
+
+ final Vector2 direction = new Vector2(directionX, directionY);
+ float rotationRad = direction.angleRad();
+
+ float c = 10; //speed of rotation
+ getBody().setAngularVelocity(c * (angleDifference(rotationRad, getBody().getAngle())));
+ }
+
+ public static float angleDifference(float angle1, float angle2) {
+ float diff = (angle1 - angle2) % (MathUtils.PI * 2);
+ return diff < -1 * MathUtils.PI ? diff + 2 * MathUtils.PI : diff;
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/world/ship/SteerableEnemyShip.java b/core/src/org/snoopdesigns/endless/world/ship/SteerableEnemyShip.java
new file mode 100644
index 0000000..4c24408
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/world/ship/SteerableEnemyShip.java
@@ -0,0 +1,163 @@
+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.BlendedSteering;
+import com.badlogic.gdx.ai.steer.behaviors.Face;
+import com.badlogic.gdx.ai.steer.behaviors.Wander;
+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;
+import com.badlogic.gdx.math.MathUtils;
+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;
+
+public class SteerableEnemyShip extends SteerablePhysicalBody implements Renderable {
+
+ private Sprite sprite;
+ private final SteeringAcceleration<Vector2> steeringOutput = new SteeringAcceleration<>(new Vector2());
+ private BlendedSteering<Vector2> steeringCombination;
+
+ private Location<Vector2> target;
+
+ @Override
+ public BodyType getBodyType() {
+ return BodyType.DynamicBody;
+ }
+
+ @Override
+ public FixtureDef getFixture() {
+ final CircleShape circle = new CircleShape();
+ circle.setRadius(7f);
+ final FixtureDef fixtureDef = new FixtureDef();
+ fixtureDef.shape = circle;
+ fixtureDef.density = 1f;
+ return fixtureDef;
+ }
+
+ @Override
+ public Vector2 getInitialPosition() {
+ return new Vector2(MathUtils.random(50), MathUtils.random(50));
+ }
+
+ @Override
+ public void create() {
+ initBody();
+ final Texture texture = new Texture(Gdx.files.internal("ship.png"));
+ sprite = new Sprite(texture);
+ sprite.setScale(0.1f);
+ sprite.setRotation(MathUtils.radDeg * getBody().getAngle());
+
+ target = new Box2DLocation();
+ target.getPosition().set(
+ Context.getInstance().getPlayerShip().getBody().getPosition().x,
+ Context.getInstance().getPlayerShip().getBody().getPosition().y);
+ target.setOrientation(Context.getInstance().getPlayerShip().getBody().getAngle());
+
+ steeringCombination = new BlendedSteering<>(this);
+ getSteeringBehaviours().forEach(steeringBehaviour ->
+ steeringCombination.add(steeringBehaviour, 0.5f));
+ }
+ @Override
+ public void render(SpriteBatch batch) {
+ target.getPosition().set(
+ Context.getInstance().getPlayerShip().getBody().getPosition().x,
+ Context.getInstance().getPlayerShip().getBody().getPosition().y);
+ target.setOrientation(Context.getInstance().getPlayerShip().getBody().getAngle());
+
+ steeringCombination.calculateSteering(steeringOutput);
+ applySteering();
+
+ sprite.setCenter(getBody().getPosition().x, getBody().getPosition().y);
+ sprite.setRotation(MathUtils.radDeg * getBody().getAngle());
+ sprite.draw(batch);
+ }
+
+ @Override
+ public void dispose() {
+ }
+
+ private List<SteeringBehavior<Vector2>> getSteeringBehaviours() {
+ return List.of(
+ new Face<>(this, target),
+ /*new Arrive<>(this, target)
+ .setTimeToTarget(0.1f)
+ .setArrivalTolerance(1f)
+ .setDecelerationRadius(100f)*/
+ new Wander<>(this)
+ .setTarget(target)
+ .setFaceEnabled(true) // We want to use Face internally (independent facing is on)
+ .setAlignTolerance(0.001f) // Used by Face
+ .setDecelerationRadius(100f) // Used by Face
+ .setTimeToTarget(0.1f) // Used by Face
+ .setWanderOffset(200) //
+ .setWanderOrientation(10) //
+ .setWanderRadius(200f) //
+ .setWanderRate(MathUtils.PI2 * 4)
+ );
+ }
+
+ 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()) {
+ speedUp(steeringOutput.linear);
+ }
+ }
+
+ private void speedUp(final Vector2 force) {
+ getBody().applyForceToCenter(
+ force.x * 100,
+ force.y * 100,
+ 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 getMaxSpeed() {
+ return 70f;
+ }
+
+ @Override
+ public float getMaxAcceleration() {
+ return 50000f;
+ }
+
+ @Override
+ public float getMaxRotationSpeed() {
+ return 5f;
+ }
+
+ @Override
+ public float getMaxRotationAcceleration() {
+ return 5f;
+ }
+}