From e3935fe4b6ecfbe161001fc95d295f53e8520c52 Mon Sep 17 00:00:00 2001 From: Dmitri Morozov Date: Fri, 2 Feb 2024 18:58:12 +0100 Subject: Initial commit --- core/src/org/snoopdesigns/endless/EndlessGame.java | 66 +++++++++ .../org/snoopdesigns/endless/config/Config.java | 17 +++ .../org/snoopdesigns/endless/context/Context.java | 37 +++++ .../org/snoopdesigns/endless/context/OnInit.java | 5 + .../endless/input/DefaultInputProcessor.java | 51 +++++++ .../endless/physics/Box2DDebugRenderer.java | 28 ++++ .../endless/physics/Box2DLocation.java | 46 ++++++ .../endless/physics/Box2DRenderer.java | 22 +++ .../snoopdesigns/endless/physics/PhysicalBody.java | 32 ++++ .../endless/physics/SteerablePhysicalBody.java | 115 +++++++++++++++ .../snoopdesigns/endless/physics/WorldContext.java | 17 +++ .../endless/physics/camera/CameraContext.java | 48 ++++++ .../endless/physics/camera/CameraRenderer.java | 55 +++++++ .../endless/renderer/CursorRenderer.java | 29 ++++ .../endless/renderer/DebugRenderer.java | 54 +++++++ .../snoopdesigns/endless/renderer/Renderer.java | 11 ++ .../endless/utils/ExitControllable.java | 17 +++ .../snoopdesigns/endless/world/Controllable.java | 7 + .../endless/world/ObjectsRenderer.java | 41 ++++++ .../org/snoopdesigns/endless/world/Renderable.java | 9 ++ .../endless/world/bg/BackgroundRenderer.java | 35 +++++ .../endless/world/player/PlayerShip.java | 150 +++++++++++++++++++ .../endless/world/ship/SteerableEnemyShip.java | 163 +++++++++++++++++++++ 23 files changed, 1055 insertions(+) create mode 100644 core/src/org/snoopdesigns/endless/EndlessGame.java create mode 100644 core/src/org/snoopdesigns/endless/config/Config.java create mode 100644 core/src/org/snoopdesigns/endless/context/Context.java create mode 100644 core/src/org/snoopdesigns/endless/context/OnInit.java create mode 100644 core/src/org/snoopdesigns/endless/input/DefaultInputProcessor.java create mode 100644 core/src/org/snoopdesigns/endless/physics/Box2DDebugRenderer.java create mode 100644 core/src/org/snoopdesigns/endless/physics/Box2DLocation.java create mode 100644 core/src/org/snoopdesigns/endless/physics/Box2DRenderer.java create mode 100644 core/src/org/snoopdesigns/endless/physics/PhysicalBody.java create mode 100644 core/src/org/snoopdesigns/endless/physics/SteerablePhysicalBody.java create mode 100644 core/src/org/snoopdesigns/endless/physics/WorldContext.java create mode 100644 core/src/org/snoopdesigns/endless/physics/camera/CameraContext.java create mode 100644 core/src/org/snoopdesigns/endless/physics/camera/CameraRenderer.java create mode 100644 core/src/org/snoopdesigns/endless/renderer/CursorRenderer.java create mode 100644 core/src/org/snoopdesigns/endless/renderer/DebugRenderer.java create mode 100644 core/src/org/snoopdesigns/endless/renderer/Renderer.java create mode 100644 core/src/org/snoopdesigns/endless/utils/ExitControllable.java create mode 100644 core/src/org/snoopdesigns/endless/world/Controllable.java create mode 100644 core/src/org/snoopdesigns/endless/world/ObjectsRenderer.java create mode 100644 core/src/org/snoopdesigns/endless/world/Renderable.java create mode 100644 core/src/org/snoopdesigns/endless/world/bg/BackgroundRenderer.java create mode 100644 core/src/org/snoopdesigns/endless/world/player/PlayerShip.java create mode 100644 core/src/org/snoopdesigns/endless/world/ship/SteerableEnemyShip.java (limited to 'core/src/org') 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 renderers = List.of( + new BackgroundRenderer(), + new Box2DRenderer(), + new CameraRenderer(), + new Box2DDebugRenderer(), + new ObjectsRenderer(), + new CursorRenderer(), + new DebugRenderer() + ); + + private final List 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 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 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 { + + 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 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 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 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 steeringOutput = new SteeringAcceleration<>(new Vector2()); + private BlendedSteering steeringCombination; + + private Location 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> 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; + } +} -- cgit v1.2.3