Added better camera transforms and whatnot.
This commit is contained in:
parent
300a62e621
commit
27f61f67bc
|
@ -2,8 +2,6 @@ package nl.andrewl.starship_arena;
|
||||||
|
|
||||||
import nl.andrewl.starship_arena.model.Arena;
|
import nl.andrewl.starship_arena.model.Arena;
|
||||||
import nl.andrewl.starship_arena.model.Ship;
|
import nl.andrewl.starship_arena.model.Ship;
|
||||||
import nl.andrewl.starship_arena.model.ShipModel;
|
|
||||||
import nl.andrewl.starship_arena.util.ResourceUtils;
|
|
||||||
import nl.andrewl.starship_arena.view.ArenaWindow;
|
import nl.andrewl.starship_arena.view.ArenaWindow;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -11,10 +9,17 @@ import nl.andrewl.starship_arena.view.ArenaWindow;
|
||||||
*/
|
*/
|
||||||
public class StarshipArena {
|
public class StarshipArena {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
ShipModel corvette = ShipModel.load(ResourceUtils.getString("/ships/corvette.json"));
|
Ship s1 = new Ship("/ships/corvette.json");
|
||||||
Ship s = new Ship(corvette);
|
s1.setVelocity(0, -0.5f);
|
||||||
|
s1.setRotationSpeed(0.5f);
|
||||||
Arena arena = new Arena();
|
Arena arena = new Arena();
|
||||||
arena.getShips().add(s);
|
arena.getShips().add(s1);
|
||||||
|
Ship s2 = new Ship("/ships/corvette.json");
|
||||||
|
s2.setRotation((float) (Math.PI / 6));
|
||||||
|
s2.getPosition().x = 3;
|
||||||
|
s2.getPosition().y = -5;
|
||||||
|
arena.getShips().add(s2);
|
||||||
|
arena.getCamera().setFocus(s1);
|
||||||
var window = new ArenaWindow(arena);
|
var window = new ArenaWindow(arena);
|
||||||
window.setVisible(true);
|
window.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
package nl.andrewl.starship_arena.control;
|
||||||
|
|
||||||
|
import nl.andrewl.starship_arena.model.Camera;
|
||||||
|
import nl.andrewl.starship_arena.model.PhysicsObject;
|
||||||
|
|
||||||
|
import java.awt.event.KeyEvent;
|
||||||
|
import java.awt.event.KeyListener;
|
||||||
|
import java.awt.event.MouseWheelEvent;
|
||||||
|
import java.awt.event.MouseWheelListener;
|
||||||
|
|
||||||
|
public class CameraController implements MouseWheelListener, KeyListener {
|
||||||
|
private final Camera camera;
|
||||||
|
|
||||||
|
public CameraController(Camera camera) {
|
||||||
|
this.camera = camera;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseWheelMoved(MouseWheelEvent e) {
|
||||||
|
if (e.getWheelRotation() > 0) {
|
||||||
|
camera.zoomOut();
|
||||||
|
} else {
|
||||||
|
camera.zoomIn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void keyTyped(KeyEvent e) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void keyPressed(KeyEvent e) {
|
||||||
|
// Reset view.
|
||||||
|
if (e.getKeyCode() == KeyEvent.VK_SPACE && e.isControlDown()) {
|
||||||
|
System.out.println("Resetting view");
|
||||||
|
camera.setRotation(0);
|
||||||
|
camera.setPosition(0, 0);
|
||||||
|
camera.resetScale();
|
||||||
|
}
|
||||||
|
if (e.getKeyCode() == KeyEvent.VK_ESCAPE && camera.getFocus() != null) {
|
||||||
|
System.out.println("Leaving focus!");
|
||||||
|
PhysicsObject f = camera.getFocus();
|
||||||
|
camera.setRotation(0);
|
||||||
|
camera.setPosition(f.getPosition().x, f.getPosition().y);
|
||||||
|
camera.setFocus(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void keyReleased(KeyEvent e) {}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package nl.andrewl.starship_arena.control;
|
||||||
|
|
||||||
|
import nl.andrewl.starship_arena.model.Arena;
|
||||||
|
import nl.andrewl.starship_arena.view.ArenaPanel;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
|
||||||
|
public class GameUpdater extends Thread {
|
||||||
|
public static final double PHYSICS_FPS = 60.0;
|
||||||
|
public static final double MILLISECONDS_PER_PHYSICS_TICK = 1000.0 / PHYSICS_FPS;
|
||||||
|
public static final double PHYSICS_SPEED = 1.0;
|
||||||
|
|
||||||
|
public static final double DISPLAY_FPS = 60.0;
|
||||||
|
public static final double MILLISECONDS_PER_DISPLAY_FRAME = 1000.0 / DISPLAY_FPS;
|
||||||
|
|
||||||
|
private final Arena arena;
|
||||||
|
private final ArenaPanel arenaPanel;
|
||||||
|
private volatile boolean running = true;
|
||||||
|
|
||||||
|
public GameUpdater(Arena arena, ArenaPanel arenaPanel) {
|
||||||
|
this.arena = arena;
|
||||||
|
this.arenaPanel = arenaPanel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRunning(boolean running) {
|
||||||
|
this.running = running;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
long lastPhysicsUpdate = System.currentTimeMillis();
|
||||||
|
long lastDisplayUpdate = System.currentTimeMillis();
|
||||||
|
while (running) {
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
long timeSinceLastPhysicsUpdate = currentTime - lastPhysicsUpdate;
|
||||||
|
long timeSinceLastDisplayUpdate = currentTime - lastDisplayUpdate;
|
||||||
|
if (timeSinceLastPhysicsUpdate >= MILLISECONDS_PER_PHYSICS_TICK) {
|
||||||
|
double elapsedSeconds = timeSinceLastPhysicsUpdate / 1000.0;
|
||||||
|
updateArena(elapsedSeconds * PHYSICS_SPEED);
|
||||||
|
lastPhysicsUpdate = currentTime;
|
||||||
|
timeSinceLastPhysicsUpdate = 0L;
|
||||||
|
}
|
||||||
|
if (timeSinceLastDisplayUpdate >= MILLISECONDS_PER_DISPLAY_FRAME) {
|
||||||
|
SwingUtilities.invokeLater(arenaPanel::repaint);
|
||||||
|
lastDisplayUpdate = currentTime;
|
||||||
|
timeSinceLastDisplayUpdate = 0L;
|
||||||
|
}
|
||||||
|
long timeUntilNextPhysicsUpdate = (long) (MILLISECONDS_PER_PHYSICS_TICK - timeSinceLastPhysicsUpdate);
|
||||||
|
long timeUntilNextDisplayUpdate = (long) (MILLISECONDS_PER_DISPLAY_FRAME - timeSinceLastDisplayUpdate);
|
||||||
|
|
||||||
|
// Sleep to reduce CPU usage.
|
||||||
|
try {
|
||||||
|
Thread.sleep(Math.min(timeUntilNextPhysicsUpdate, timeUntilNextDisplayUpdate));
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateArena(double t) {
|
||||||
|
for (var s : arena.getShips()) {
|
||||||
|
s.update(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,19 +3,19 @@ package nl.andrewl.starship_arena.model;
|
||||||
import java.awt.geom.Point2D;
|
import java.awt.geom.Point2D;
|
||||||
|
|
||||||
public class Camera {
|
public class Camera {
|
||||||
public static final double SCALE_INTERVAL = 50.0;
|
private static final float[] SCALE_FACTORS = {500, 200, 100, 50, 25, 10, 5, 1, 0.5f, 0.25f, 0.1f, 0.05f, 0.01f};
|
||||||
|
public static final byte DEFAULT_SCALE_FACTOR_INDEX = 5;
|
||||||
|
|
||||||
private Object focus;
|
private PhysicsObject focus;
|
||||||
|
private final Point2D.Float position = new Point2D.Float();
|
||||||
|
private float rotation;
|
||||||
|
private byte scaleIndex = DEFAULT_SCALE_FACTOR_INDEX;
|
||||||
|
|
||||||
private Point2D.Float position = new Point2D.Float();
|
public PhysicsObject getFocus() {
|
||||||
|
|
||||||
private int scaleIncrement = 1;
|
|
||||||
|
|
||||||
public Object getFocus() {
|
|
||||||
return focus;
|
return focus;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFocus(Object focus) {
|
public void setFocus(PhysicsObject focus) {
|
||||||
this.focus = focus;
|
this.focus = focus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,15 +23,32 @@ public class Camera {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPosition(Point2D.Float position) {
|
public void setPosition(float x, float y) {
|
||||||
this.position = position;
|
this.position.x = x;
|
||||||
|
this.position.y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getScaleIncrement() {
|
public float getRotation() {
|
||||||
return scaleIncrement;
|
return rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setScaleIncrement(int scaleIncrement) {
|
public void setRotation(float rotation) {
|
||||||
this.scaleIncrement = scaleIncrement;
|
this.rotation = rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getScaleFactor() {
|
||||||
|
return SCALE_FACTORS[scaleIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void zoomOut() {
|
||||||
|
if (scaleIndex < SCALE_FACTORS.length - 1) scaleIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void zoomIn() {
|
||||||
|
if (scaleIndex > 0) scaleIndex--;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetScale() {
|
||||||
|
scaleIndex = DEFAULT_SCALE_FACTOR_INDEX;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ package nl.andrewl.starship_arena.model;
|
||||||
|
|
||||||
import java.awt.geom.Point2D;
|
import java.awt.geom.Point2D;
|
||||||
|
|
||||||
public class PhysicsObject {
|
public abstract class PhysicsObject {
|
||||||
/**
|
/**
|
||||||
* The position of this object in the scene, in meters from the origin.
|
* The position of this object in the scene, in meters from the origin.
|
||||||
* Positive x-axis goes to the right, and positive y-axis goes down.
|
* Positive x-axis goes to the right, and positive y-axis goes down.
|
||||||
|
@ -28,6 +28,11 @@ public class PhysicsObject {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPosition(float x, float y) {
|
||||||
|
this.position.x = x;
|
||||||
|
this.position.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
public float getRotation() {
|
public float getRotation() {
|
||||||
return rotation;
|
return rotation;
|
||||||
}
|
}
|
||||||
|
@ -42,6 +47,11 @@ public class PhysicsObject {
|
||||||
return velocity;
|
return velocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setVelocity(float x, float y) {
|
||||||
|
this.velocity.x = x;
|
||||||
|
this.velocity.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
public float getRotationSpeed() {
|
public float getRotationSpeed() {
|
||||||
return rotationSpeed;
|
return rotationSpeed;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package nl.andrewl.starship_arena.model;
|
package nl.andrewl.starship_arena.model;
|
||||||
|
|
||||||
|
import nl.andrewl.starship_arena.model.ship.Cockpit;
|
||||||
import nl.andrewl.starship_arena.model.ship.Gun;
|
import nl.andrewl.starship_arena.model.ship.Gun;
|
||||||
import nl.andrewl.starship_arena.model.ship.Panel;
|
import nl.andrewl.starship_arena.model.ship.Panel;
|
||||||
import nl.andrewl.starship_arena.model.ship.ShipComponent;
|
import nl.andrewl.starship_arena.model.ship.ShipComponent;
|
||||||
|
@ -15,18 +16,21 @@ public class Ship extends PhysicsObject {
|
||||||
|
|
||||||
private final Collection<Panel> panels;
|
private final Collection<Panel> panels;
|
||||||
private final Collection<Gun> guns;
|
private final Collection<Gun> guns;
|
||||||
|
private final Collection<Cockpit> cockpits;
|
||||||
|
|
||||||
private Color primaryColor = Color.GRAY;
|
private Color primaryColor = Color.GRAY;
|
||||||
|
|
||||||
public Ship(ShipModel model) {
|
private Ship(ShipModel model) {
|
||||||
this.modelName = model.getName();
|
this.modelName = model.getName();
|
||||||
this.components = model.getComponents();
|
this.components = model.getComponents();
|
||||||
this.panels = new ArrayList<>();
|
this.panels = new ArrayList<>();
|
||||||
this.guns = new ArrayList<>();
|
this.guns = new ArrayList<>();
|
||||||
|
this.cockpits = new ArrayList<>();
|
||||||
for (var c : components) {
|
for (var c : components) {
|
||||||
c.setShip(this);
|
c.setShip(this);
|
||||||
if (c instanceof Panel p) panels.add(p);
|
if (c instanceof Panel p) panels.add(p);
|
||||||
if (c instanceof Gun g) guns.add(g);
|
if (c instanceof Gun g) guns.add(g);
|
||||||
|
if (c instanceof Cockpit cp) cockpits.add(cp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +46,18 @@ public class Ship extends PhysicsObject {
|
||||||
return components;
|
return components;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Collection<Panel> getPanels() {
|
||||||
|
return panels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Gun> getGuns() {
|
||||||
|
return guns;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Cockpit> getCockpits() {
|
||||||
|
return cockpits;
|
||||||
|
}
|
||||||
|
|
||||||
public Color getPrimaryColor() {
|
public Color getPrimaryColor() {
|
||||||
return primaryColor;
|
return primaryColor;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,7 @@ package nl.andrewl.starship_arena.model;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import nl.andrewl.starship_arena.model.ship.ComponentDeserializer;
|
import nl.andrewl.starship_arena.model.ship.*;
|
||||||
import nl.andrewl.starship_arena.model.ship.GeometricComponent;
|
|
||||||
import nl.andrewl.starship_arena.model.ship.Gun;
|
|
||||||
import nl.andrewl.starship_arena.model.ship.ShipComponent;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
@ -62,6 +59,7 @@ public class ShipModel {
|
||||||
public static ShipModel load(String json) {
|
public static ShipModel load(String json) {
|
||||||
Gson gson = new GsonBuilder()
|
Gson gson = new GsonBuilder()
|
||||||
.registerTypeAdapter(ShipComponent.class, new ComponentDeserializer())
|
.registerTypeAdapter(ShipComponent.class, new ComponentDeserializer())
|
||||||
|
.registerTypeAdapter(Gun.class, new GunDeserializer())
|
||||||
.create();
|
.create();
|
||||||
ShipModel model = gson.fromJson(json, ShipModel.class);
|
ShipModel model = gson.fromJson(json, ShipModel.class);
|
||||||
model.normalizeComponents();
|
model.normalizeComponents();
|
||||||
|
|
|
@ -5,6 +5,23 @@ import java.awt.geom.Point2D;
|
||||||
public class Gun extends ShipComponent {
|
public class Gun extends ShipComponent {
|
||||||
private String name;
|
private String name;
|
||||||
private Point2D.Float location;
|
private Point2D.Float location;
|
||||||
|
private float rotation;
|
||||||
|
private float maxRotation;
|
||||||
|
private float minRotation;
|
||||||
|
private float barrelWidth;
|
||||||
|
private float barrelLength;
|
||||||
|
|
||||||
|
public Gun() {}
|
||||||
|
|
||||||
|
public Gun(String name, Point2D.Float location, float rotation, float maxRotation, float minRotation, float barrelWidth, float barrelLength) {
|
||||||
|
this.name = name;
|
||||||
|
this.location = location;
|
||||||
|
this.rotation = rotation;
|
||||||
|
this.maxRotation = maxRotation;
|
||||||
|
this.minRotation = minRotation;
|
||||||
|
this.barrelWidth = barrelWidth;
|
||||||
|
this.barrelLength = barrelLength;
|
||||||
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
|
@ -13,4 +30,24 @@ public class Gun extends ShipComponent {
|
||||||
public Point2D.Float getLocation() {
|
public Point2D.Float getLocation() {
|
||||||
return location;
|
return location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float getRotation() {
|
||||||
|
return rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getMaxRotation() {
|
||||||
|
return maxRotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getMinRotation() {
|
||||||
|
return minRotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getBarrelWidth() {
|
||||||
|
return barrelWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getBarrelLength() {
|
||||||
|
return barrelLength;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
package nl.andrewl.starship_arena.model.ship;
|
||||||
|
|
||||||
|
import com.google.gson.*;
|
||||||
|
|
||||||
|
import java.awt.geom.Point2D;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
|
public class GunDeserializer implements JsonDeserializer<Gun> {
|
||||||
|
@Override
|
||||||
|
public Gun deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext ctx) throws JsonParseException {
|
||||||
|
JsonObject obj = jsonElement.getAsJsonObject();
|
||||||
|
return new Gun(
|
||||||
|
obj.get("name").getAsString(),
|
||||||
|
ctx.deserialize(obj.get("location"), Point2D.Float.class),
|
||||||
|
(float) Math.toRadians(obj.get("rotation").getAsFloat()),
|
||||||
|
(float) Math.toRadians(obj.get("maxRotation").getAsDouble()),
|
||||||
|
(float) Math.toRadians(obj.get("minRotation").getAsFloat()),
|
||||||
|
obj.get("barrelWidth").getAsFloat(),
|
||||||
|
obj.get("barrelLength").getAsFloat()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,9 @@
|
||||||
package nl.andrewl.starship_arena.view;
|
package nl.andrewl.starship_arena.view;
|
||||||
|
|
||||||
|
import nl.andrewl.starship_arena.control.CameraController;
|
||||||
import nl.andrewl.starship_arena.model.Arena;
|
import nl.andrewl.starship_arena.model.Arena;
|
||||||
import nl.andrewl.starship_arena.model.Camera;
|
import nl.andrewl.starship_arena.model.Camera;
|
||||||
|
import nl.andrewl.starship_arena.model.PhysicsObject;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
@ -9,15 +11,10 @@ import java.awt.geom.AffineTransform;
|
||||||
|
|
||||||
public class ArenaPanel extends JPanel {
|
public class ArenaPanel extends JPanel {
|
||||||
private final Arena arena;
|
private final Arena arena;
|
||||||
|
|
||||||
private final ShipRenderer shipRenderer = new ShipRenderer();
|
private final ShipRenderer shipRenderer = new ShipRenderer();
|
||||||
|
|
||||||
public ArenaPanel(Arena arena) {
|
public ArenaPanel(Arena arena) {
|
||||||
this.arena = arena;
|
this.arena = arena;
|
||||||
this.addMouseWheelListener(e -> {
|
|
||||||
arena.getCamera().setScaleIncrement(arena.getCamera().getScaleIncrement() + e.getWheelRotation());
|
|
||||||
repaint();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -28,37 +25,44 @@ public class ArenaPanel extends JPanel {
|
||||||
g2.fillRect(0, 0, getWidth(), getHeight());
|
g2.fillRect(0, 0, getWidth(), getHeight());
|
||||||
|
|
||||||
AffineTransform originalTx = g2.getTransform();
|
AffineTransform originalTx = g2.getTransform();
|
||||||
AffineTransform tx = new AffineTransform();
|
AffineTransform camTx = getCameraTransform();
|
||||||
|
|
||||||
Camera cam = arena.getCamera();
|
|
||||||
|
|
||||||
double translateX = (double) getWidth() / 2;
|
|
||||||
double translateY = (double) getHeight() / 2;
|
|
||||||
if (cam.getFocus() == null) {
|
|
||||||
translateX += cam.getPosition().x;
|
|
||||||
translateY += cam.getPosition().y;
|
|
||||||
}
|
|
||||||
|
|
||||||
double scale = 1 * Camera.SCALE_INTERVAL;
|
|
||||||
if (cam.getScaleIncrement() > 0) {
|
|
||||||
scale = cam.getScaleIncrement() * Camera.SCALE_INTERVAL;
|
|
||||||
} else if (cam.getScaleIncrement() < 0) {
|
|
||||||
scale = 1.0 / Math.abs(cam.getScaleIncrement() * Camera.SCALE_INTERVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.translate(translateX, translateY);
|
|
||||||
tx.scale(scale, scale);
|
|
||||||
g2.setTransform(tx);
|
|
||||||
|
|
||||||
for (var s : arena.getShips()) {
|
for (var s : arena.getShips()) {
|
||||||
|
AffineTransform shipTx = new AffineTransform(camTx);
|
||||||
|
shipTx.translate(s.getPosition().x, s.getPosition().y);
|
||||||
|
shipTx.rotate(s.getRotation());
|
||||||
|
g2.setTransform(shipTx);
|
||||||
shipRenderer.render(s, g2);
|
shipRenderer.render(s, g2);
|
||||||
}
|
}
|
||||||
|
|
||||||
g2.setTransform(originalTx);
|
g2.setTransform(originalTx);
|
||||||
|
|
||||||
|
// Testing indicators.
|
||||||
g2.setColor(Color.GREEN);
|
g2.setColor(Color.GREEN);
|
||||||
g2.fillRect(0, 0, 20, 20);
|
g2.fillRect(0, 0, 20, 20);
|
||||||
g2.setColor(Color.BLUE);
|
g2.setColor(Color.BLUE);
|
||||||
g2.fillRect(getWidth() - 20, getHeight() - 20, 20, 20);
|
g2.fillRect(getWidth() - 20, getHeight() - 20, 20, 20);
|
||||||
|
g2.setColor(Color.MAGENTA);
|
||||||
|
g2.fillOval(getWidth() / 2 - 5, getHeight() / 2 - 5, 10, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AffineTransform getCameraTransform() {
|
||||||
|
AffineTransform tx = new AffineTransform();
|
||||||
|
Camera cam = arena.getCamera();
|
||||||
|
// Start by translating such that 0, 0 is in the center of the screen instead of top-left.
|
||||||
|
tx.translate((double) getWidth() / 2, (double) getHeight() / 2);
|
||||||
|
tx.scale(cam.getScaleFactor(), cam.getScaleFactor());
|
||||||
|
|
||||||
|
double rotation = -cam.getRotation();
|
||||||
|
double x = -cam.getPosition().x;
|
||||||
|
double y = -cam.getPosition().y;
|
||||||
|
if (cam.getFocus() != null) {
|
||||||
|
PhysicsObject f = cam.getFocus();
|
||||||
|
rotation -= f.getRotation();
|
||||||
|
x -= f.getPosition().x;
|
||||||
|
y -= f.getPosition().y;
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.rotate(rotation);
|
||||||
|
tx.translate(x, y);
|
||||||
|
return tx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package nl.andrewl.starship_arena.view;
|
package nl.andrewl.starship_arena.view;
|
||||||
|
|
||||||
|
import nl.andrewl.starship_arena.control.CameraController;
|
||||||
|
import nl.andrewl.starship_arena.control.GameUpdater;
|
||||||
import nl.andrewl.starship_arena.model.Arena;
|
import nl.andrewl.starship_arena.model.Arena;
|
||||||
import nl.andrewl.starship_arena.util.ResourceUtils;
|
import nl.andrewl.starship_arena.util.ResourceUtils;
|
||||||
|
|
||||||
|
@ -11,6 +13,7 @@ import java.io.InputStream;
|
||||||
|
|
||||||
public class ArenaWindow extends JFrame {
|
public class ArenaWindow extends JFrame {
|
||||||
private final ArenaPanel arenaPanel;
|
private final ArenaPanel arenaPanel;
|
||||||
|
private final GameUpdater updater;
|
||||||
|
|
||||||
public ArenaWindow(Arena arena) {
|
public ArenaWindow(Arena arena) {
|
||||||
super("Starship Arena");
|
super("Starship Arena");
|
||||||
|
@ -33,7 +36,13 @@ public class ArenaWindow extends JFrame {
|
||||||
}
|
}
|
||||||
|
|
||||||
arenaPanel = new ArenaPanel(arena);
|
arenaPanel = new ArenaPanel(arena);
|
||||||
add(arenaPanel);
|
setContentPane(arenaPanel);
|
||||||
pack();
|
pack();
|
||||||
|
|
||||||
|
var camCtl = new CameraController(arena.getCamera());
|
||||||
|
addKeyListener(camCtl);
|
||||||
|
addMouseWheelListener(camCtl);
|
||||||
|
updater = new GameUpdater(arena, arenaPanel);
|
||||||
|
updater.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,29 +3,49 @@ package nl.andrewl.starship_arena.view;
|
||||||
import nl.andrewl.starship_arena.model.Ship;
|
import nl.andrewl.starship_arena.model.Ship;
|
||||||
import nl.andrewl.starship_arena.model.ship.Cockpit;
|
import nl.andrewl.starship_arena.model.ship.Cockpit;
|
||||||
import nl.andrewl.starship_arena.model.ship.GeometricComponent;
|
import nl.andrewl.starship_arena.model.ship.GeometricComponent;
|
||||||
|
import nl.andrewl.starship_arena.model.ship.Gun;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
import java.awt.geom.AffineTransform;
|
||||||
import java.awt.geom.Path2D;
|
import java.awt.geom.Path2D;
|
||||||
|
|
||||||
public class ShipRenderer implements Renderer<Ship> {
|
public class ShipRenderer implements Renderer<Ship> {
|
||||||
@Override
|
@Override
|
||||||
public void render(Ship ship, Graphics2D g) {
|
public void render(Ship ship, Graphics2D g) {
|
||||||
for (var c : ship.getComponents()) {
|
for (var p : ship.getPanels()) renderGeometricComponent(p, g);
|
||||||
if (c instanceof GeometricComponent geo) {
|
for (var c : ship.getCockpits()) renderGeometricComponent(c, g);
|
||||||
Path2D.Float path = new Path2D.Float();
|
for (var gun : ship.getGuns()) renderGun(gun, g);
|
||||||
var first = geo.getPoints().get(0);
|
}
|
||||||
path.moveTo(first.x, first.y);
|
|
||||||
for (int i = 0; i < geo.getPoints().size(); i++) {
|
private void renderGeometricComponent(GeometricComponent geo, Graphics2D g) {
|
||||||
var point = geo.getPoints().get(i);
|
Path2D.Float path = new Path2D.Float();
|
||||||
path.lineTo(point.x, point.y);
|
var first = geo.getPoints().get(0);
|
||||||
}
|
path.moveTo(first.x, first.y);
|
||||||
if (geo instanceof Cockpit) {
|
for (int i = 0; i < geo.getPoints().size(); i++) {
|
||||||
g.setColor(new Color(0f, 0f, 0.5f, 0.5f));
|
var point = geo.getPoints().get(i);
|
||||||
} else {
|
path.lineTo(point.x, point.y);
|
||||||
g.setColor(ship.getPrimaryColor());
|
|
||||||
}
|
|
||||||
g.fill(path);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (geo instanceof Cockpit) {
|
||||||
|
g.setColor(new Color(0f, 0f, 0.5f, 0.5f));
|
||||||
|
} else {
|
||||||
|
g.setColor(geo.getShip().getPrimaryColor());
|
||||||
|
}
|
||||||
|
g.fill(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderGun(Gun gun, Graphics2D g) {
|
||||||
|
AffineTransform originalTx = g.getTransform();
|
||||||
|
AffineTransform tx = new AffineTransform(originalTx);
|
||||||
|
tx.rotate(gun.getRotation() + Math.PI, gun.getLocation().x, gun.getLocation().y);
|
||||||
|
tx.translate(gun.getLocation().x, gun.getLocation().y);
|
||||||
|
g.setTransform(tx);
|
||||||
|
Path2D.Float path = new Path2D.Float();
|
||||||
|
path.moveTo(-gun.getBarrelWidth() / 2, 0);
|
||||||
|
path.lineTo(gun.getBarrelWidth() / 2, 0);
|
||||||
|
path.lineTo(gun.getBarrelWidth() / 2, gun.getBarrelLength());
|
||||||
|
path.lineTo(-gun.getBarrelWidth() / 2, gun.getBarrelLength());
|
||||||
|
g.setColor(Color.DARK_GRAY);
|
||||||
|
g.fill(path);
|
||||||
|
g.setTransform(originalTx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,13 +40,23 @@
|
||||||
"type": "gun",
|
"type": "gun",
|
||||||
"name": "Port-Side Machine Gun",
|
"name": "Port-Side Machine Gun",
|
||||||
"mass": 500,
|
"mass": 500,
|
||||||
"location": {"x": 0.15, "y": 0.4}
|
"location": {"x": 0.15, "y": 0.35},
|
||||||
|
"rotation": 0,
|
||||||
|
"minRotation": -160,
|
||||||
|
"maxRotation": 5,
|
||||||
|
"barrelWidth": 0.02,
|
||||||
|
"barrelLength": 0.2
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "gun",
|
"type": "gun",
|
||||||
"name": "Starboard-Side Machine Gun",
|
"name": "Starboard-Side Machine Gun",
|
||||||
"mass": 500,
|
"mass": 500,
|
||||||
"location": {"x": 0.85, "y": 0.4}
|
"location": {"x": 0.85, "y": 0.35},
|
||||||
|
"rotation": 0,
|
||||||
|
"minRotation": -5,
|
||||||
|
"maxRotation": 160,
|
||||||
|
"barrelWidth": 0.02,
|
||||||
|
"barrelLength": 0.2
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
Loading…
Reference in New Issue