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.Ship;
|
||||
import nl.andrewl.starship_arena.model.ShipModel;
|
||||
import nl.andrewl.starship_arena.util.ResourceUtils;
|
||||
import nl.andrewl.starship_arena.view.ArenaWindow;
|
||||
|
||||
/**
|
||||
|
@ -11,10 +9,17 @@ import nl.andrewl.starship_arena.view.ArenaWindow;
|
|||
*/
|
||||
public class StarshipArena {
|
||||
public static void main(String[] args) {
|
||||
ShipModel corvette = ShipModel.load(ResourceUtils.getString("/ships/corvette.json"));
|
||||
Ship s = new Ship(corvette);
|
||||
Ship s1 = new Ship("/ships/corvette.json");
|
||||
s1.setVelocity(0, -0.5f);
|
||||
s1.setRotationSpeed(0.5f);
|
||||
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);
|
||||
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;
|
||||
|
||||
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();
|
||||
|
||||
private int scaleIncrement = 1;
|
||||
|
||||
public Object getFocus() {
|
||||
public PhysicsObject getFocus() {
|
||||
return focus;
|
||||
}
|
||||
|
||||
public void setFocus(Object focus) {
|
||||
public void setFocus(PhysicsObject focus) {
|
||||
this.focus = focus;
|
||||
}
|
||||
|
||||
|
@ -23,15 +23,32 @@ public class Camera {
|
|||
return position;
|
||||
}
|
||||
|
||||
public void setPosition(Point2D.Float position) {
|
||||
this.position = position;
|
||||
public void setPosition(float x, float y) {
|
||||
this.position.x = x;
|
||||
this.position.y = y;
|
||||
}
|
||||
|
||||
public int getScaleIncrement() {
|
||||
return scaleIncrement;
|
||||
public float getRotation() {
|
||||
return rotation;
|
||||
}
|
||||
|
||||
public void setScaleIncrement(int scaleIncrement) {
|
||||
this.scaleIncrement = scaleIncrement;
|
||||
public void setRotation(float rotation) {
|
||||
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;
|
||||
|
||||
public class PhysicsObject {
|
||||
public abstract class PhysicsObject {
|
||||
/**
|
||||
* 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.
|
||||
|
@ -28,6 +28,11 @@ public class PhysicsObject {
|
|||
return position;
|
||||
}
|
||||
|
||||
public void setPosition(float x, float y) {
|
||||
this.position.x = x;
|
||||
this.position.y = y;
|
||||
}
|
||||
|
||||
public float getRotation() {
|
||||
return rotation;
|
||||
}
|
||||
|
@ -42,6 +47,11 @@ public class PhysicsObject {
|
|||
return velocity;
|
||||
}
|
||||
|
||||
public void setVelocity(float x, float y) {
|
||||
this.velocity.x = x;
|
||||
this.velocity.y = y;
|
||||
}
|
||||
|
||||
public float getRotationSpeed() {
|
||||
return rotationSpeed;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
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.Panel;
|
||||
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<Gun> guns;
|
||||
private final Collection<Cockpit> cockpits;
|
||||
|
||||
private Color primaryColor = Color.GRAY;
|
||||
|
||||
public Ship(ShipModel model) {
|
||||
private Ship(ShipModel model) {
|
||||
this.modelName = model.getName();
|
||||
this.components = model.getComponents();
|
||||
this.panels = new ArrayList<>();
|
||||
this.guns = new ArrayList<>();
|
||||
this.cockpits = new ArrayList<>();
|
||||
for (var c : components) {
|
||||
c.setShip(this);
|
||||
if (c instanceof Panel p) panels.add(p);
|
||||
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;
|
||||
}
|
||||
|
||||
public Collection<Panel> getPanels() {
|
||||
return panels;
|
||||
}
|
||||
|
||||
public Collection<Gun> getGuns() {
|
||||
return guns;
|
||||
}
|
||||
|
||||
public Collection<Cockpit> getCockpits() {
|
||||
return cockpits;
|
||||
}
|
||||
|
||||
public Color getPrimaryColor() {
|
||||
return primaryColor;
|
||||
}
|
||||
|
|
|
@ -2,10 +2,7 @@ package nl.andrewl.starship_arena.model;
|
|||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import nl.andrewl.starship_arena.model.ship.ComponentDeserializer;
|
||||
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 nl.andrewl.starship_arena.model.ship.*;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
|
@ -62,6 +59,7 @@ public class ShipModel {
|
|||
public static ShipModel load(String json) {
|
||||
Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapter(ShipComponent.class, new ComponentDeserializer())
|
||||
.registerTypeAdapter(Gun.class, new GunDeserializer())
|
||||
.create();
|
||||
ShipModel model = gson.fromJson(json, ShipModel.class);
|
||||
model.normalizeComponents();
|
||||
|
|
|
@ -5,6 +5,23 @@ import java.awt.geom.Point2D;
|
|||
public class Gun extends ShipComponent {
|
||||
private String name;
|
||||
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() {
|
||||
return name;
|
||||
|
@ -13,4 +30,24 @@ public class Gun extends ShipComponent {
|
|||
public Point2D.Float getLocation() {
|
||||
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;
|
||||
|
||||
import nl.andrewl.starship_arena.control.CameraController;
|
||||
import nl.andrewl.starship_arena.model.Arena;
|
||||
import nl.andrewl.starship_arena.model.Camera;
|
||||
import nl.andrewl.starship_arena.model.PhysicsObject;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
@ -9,15 +11,10 @@ import java.awt.geom.AffineTransform;
|
|||
|
||||
public class ArenaPanel extends JPanel {
|
||||
private final Arena arena;
|
||||
|
||||
private final ShipRenderer shipRenderer = new ShipRenderer();
|
||||
|
||||
public ArenaPanel(Arena arena) {
|
||||
this.arena = arena;
|
||||
this.addMouseWheelListener(e -> {
|
||||
arena.getCamera().setScaleIncrement(arena.getCamera().getScaleIncrement() + e.getWheelRotation());
|
||||
repaint();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -28,37 +25,44 @@ public class ArenaPanel extends JPanel {
|
|||
g2.fillRect(0, 0, getWidth(), getHeight());
|
||||
|
||||
AffineTransform originalTx = g2.getTransform();
|
||||
AffineTransform tx = new AffineTransform();
|
||||
|
||||
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);
|
||||
|
||||
AffineTransform camTx = getCameraTransform();
|
||||
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);
|
||||
}
|
||||
|
||||
g2.setTransform(originalTx);
|
||||
|
||||
// Testing indicators.
|
||||
g2.setColor(Color.GREEN);
|
||||
g2.fillRect(0, 0, 20, 20);
|
||||
g2.setColor(Color.BLUE);
|
||||
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;
|
||||
|
||||
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.util.ResourceUtils;
|
||||
|
||||
|
@ -11,6 +13,7 @@ import java.io.InputStream;
|
|||
|
||||
public class ArenaWindow extends JFrame {
|
||||
private final ArenaPanel arenaPanel;
|
||||
private final GameUpdater updater;
|
||||
|
||||
public ArenaWindow(Arena arena) {
|
||||
super("Starship Arena");
|
||||
|
@ -33,7 +36,13 @@ public class ArenaWindow extends JFrame {
|
|||
}
|
||||
|
||||
arenaPanel = new ArenaPanel(arena);
|
||||
add(arenaPanel);
|
||||
setContentPane(arenaPanel);
|
||||
pack();
|
||||
|
||||
var camCtl = new CameraController(arena.getCamera());
|
||||
addKeyListener(camCtl);
|
||||
addMouseWheelListener(camCtl);
|
||||
updater = new GameUpdater(arena, arenaPanel);
|
||||
updater.start();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,15 +3,21 @@ package nl.andrewl.starship_arena.view;
|
|||
import nl.andrewl.starship_arena.model.Ship;
|
||||
import nl.andrewl.starship_arena.model.ship.Cockpit;
|
||||
import nl.andrewl.starship_arena.model.ship.GeometricComponent;
|
||||
import nl.andrewl.starship_arena.model.ship.Gun;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Path2D;
|
||||
|
||||
public class ShipRenderer implements Renderer<Ship> {
|
||||
@Override
|
||||
public void render(Ship ship, Graphics2D g) {
|
||||
for (var c : ship.getComponents()) {
|
||||
if (c instanceof GeometricComponent geo) {
|
||||
for (var p : ship.getPanels()) renderGeometricComponent(p, g);
|
||||
for (var c : ship.getCockpits()) renderGeometricComponent(c, g);
|
||||
for (var gun : ship.getGuns()) renderGun(gun, g);
|
||||
}
|
||||
|
||||
private void renderGeometricComponent(GeometricComponent geo, Graphics2D g) {
|
||||
Path2D.Float path = new Path2D.Float();
|
||||
var first = geo.getPoints().get(0);
|
||||
path.moveTo(first.x, first.y);
|
||||
|
@ -22,10 +28,24 @@ public class ShipRenderer implements Renderer<Ship> {
|
|||
if (geo instanceof Cockpit) {
|
||||
g.setColor(new Color(0f, 0f, 0.5f, 0.5f));
|
||||
} else {
|
||||
g.setColor(ship.getPrimaryColor());
|
||||
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",
|
||||
"name": "Port-Side Machine Gun",
|
||||
"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",
|
||||
"name": "Starboard-Side Machine Gun",
|
||||
"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