inital commit

This commit is contained in:
nora 2020-12-11 19:49:03 +01:00
parent 5b9846011c
commit 0d5397dbe3
35 changed files with 955 additions and 0 deletions

View file

@ -0,0 +1,47 @@
import core.Master;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
class BasicEx extends JFrame {
Master master;
Timer timer;
public BasicEx() {
initUI();
timer = new Timer(1000/60, e -> {
master.refresh();
});
timer.start();
}
private void initUI() {
master = new Master();
add(master);
setTitle("Points");
setSize(1600, 900);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
master.mousePressed();
}
});
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
BasicEx ex = new BasicEx();
ex.setVisible(true);
});
}
}

View file

@ -0,0 +1,123 @@
package core;
import objects.DebugPos;
import objects.ships.BattleShip;
import objects.GameObject;
import objects.world.Grid;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
/**
* The main object that controls everything
*/
public class Master extends JPanel {
/**
* All GameObjects that exist
*/
private final ArrayList<GameObject> objects;
/**
* Stores all GameObjects that were created during a frame
*/
private final ArrayList<GameObject> objectBuffer;
private boolean mousePressed = false;
/**
* Create a new master object
*/
public Master() {
objects = new ArrayList<>();
objectBuffer = new ArrayList<>();
objects.add(new Grid());
BattleShip battleShip = new BattleShip(Color.DARK_GRAY);
BattleShip bs = new BattleShip(70, 10, 5, 80, Color.GREEN);
/*for (int i = 0; i < 10; i++) {
bs.addTurret(new Turret(bs, 25, 10 * i + 1, 50, i % 5));
}*/
objects.add(bs);
objects.add(battleShip);
}
/**
* The mein drawing method, handles everything about drawing
* @param g
*/
private void doDrawing(Graphics g) {
//TODO w/h fields
int w, h;
if (getWidth() * 9 > getHeight() * 16) {
h = getHeight();
w = h / 9 * 16;
} else {
w = getWidth();
h = w / 16 * 9;
}
Graphics2D g2d = (Graphics2D) g.create();
objects.forEach(o -> o.draw(g2d, w, this));
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
doDrawing(g);
}
/**
* Debug a position, creates a green dot at the position
* @param pos
*/
public void debugPos(Vector2D pos){
create(new DebugPos(pos, new Vector2D(10, 10)));
}
/**
* Call this method when the user pressed the left mouse button
*/
public void mousePressed() {
mousePressed = true;
}
/**
* This method is the entry method for each frame. It handles everything about the frame
*/
public void refresh() {
objects.addAll(objectBuffer);
objectBuffer.clear();
objects.forEach(t -> t.update(this));
mousePressed = false;
repaint();
}
/**
* Get the current location of the mouse relative to the frame
* @return The location of the mouse, already normalized
*/
public Point getMouseLocation() {
Point p = MouseInfo.getPointerInfo().getLocation();
SwingUtilities.convertPointFromScreen(p, this);
return p;
}
public boolean isMousePressed() {
return mousePressed;
}
/**
* This method has to be called for every newly created GameObject
* @param obj
*/
public void create(GameObject obj) {
objectBuffer.add(obj);
}
}

View file

@ -0,0 +1,158 @@
package core;
/**
* A 2-dimensional Vector that can be used to store position or velocity
*/
public class Vector2D {
public static final int CLOCKWISE = -1;
public static final int COUNTERCLOCKWISE = 1;
/**
* The x and y values of the vector
*/
public double x, y;
/**
* Create a new Vector2D object
*
* @param x the x value
* @param y the y value
*/
public Vector2D(double x, double y) {
this.x = x;
this.y = y;
}
/**
* Create a new empty Vector2D object
*/
public Vector2D() {
x = 0;
y = 0;
}
/**
* Add another Vector to this vector, modifies this object
*
* @param a The other Vector2D
* @return this after the addition
*/
public Vector2D add(Vector2D a) {
x += a.x;
y += a.y;
return this;
}
/**
* Mulitply this vector with a simple scalar, modifies this object
*
* @param a The scalar
* @return this after the multiplication
*/
public Vector2D multiply(double a) {
x *= a;
y *= a;
return this;
}
/**
* Get the magnitude of the vector
*
* @return The magnitude of this vector
*/
public double magnitude() {
return Math.sqrt(x * x + y * y);
}
/**
* Get the normalized value of this vector, with magnitude 1, does not modify this object
*
* @return The normalized value
*/
public Vector2D normalized() {
double mag = magnitude();
if (mag == 0) {
return new Vector2D();
} else {
return new Vector2D(x / mag, y / mag);
}
}
/**
* Get the negative value of this vector, does not modify this object
*
* @return The negative value
*/
public Vector2D negative() {
return new Vector2D(-x, -y);
}
/**
* Add two Vectors
* @param a Vector a
* @param b Vector b
* @return The result
*/
public static Vector2D add(Vector2D a, Vector2D b) {
return new Vector2D(a.x + b.x, a.y + b.y);
}
/**
* Subtract two Vectors
* @param a Vector a
* @param b Vector b
* @return The result
*/
public static Vector2D subtract(Vector2D a, Vector2D b) {
return new Vector2D(a.x - b.x, a.y - b.y);
}
/**
* Rotate a point around another point
* @param center The center of the rotation
* @param value The point to be rotated, absolut to the center
* @param rotation The rotation angle in radians
* @param rotationDirection The direction, -1 for clockwise, 1 for counterclockwise
* @return The rotated point
*/
public static Vector2D rotateAround(Vector2D center, Vector2D value, double rotation, int rotationDirection){
Vector2D dif = Vector2D.subtract(value, center);
double rotatedX = Math.cos(rotation * rotationDirection) * dif.x;
double rotatedY = Math.sin(rotation * rotationDirection) * dif.x;
return new Vector2D(rotatedX + center.x, rotatedY + center.y);
}
public Vector2D copy(){
return new Vector2D(x, y);
}
@Override
public String toString() {
return "Vector2D{" +
"x=" + x +
", y=" + y +
'}';
}
/**
* Overrides the equals method. True when the x and y values match
*
* @param o The other Vector
* @return True if both x and values are the same
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Vector2D vector2D = (Vector2D) o;
if (Double.compare(vector2D.x, x) != 0) return false;
return Double.compare(vector2D.y, y) == 0;
}
}

View file

@ -0,0 +1,26 @@
package objects;
import core.Master;
import core.Vector2D;
import java.awt.*;
/**
* A GameObject used for debugging
*/
public class DebugPos extends GameObject {
public DebugPos(Vector2D position, Vector2D size) {
super(position.copy(), size);
this.velocity = new Vector2D();
}
@Override
public void draw(Graphics2D g2d, int w, Master master) {
g2d.setPaint(Color.green);
g2d.drawOval((int) (position.x + size.x / 2), (int) (position.y + size.y / 2), (int) size.x, (int) size.y);
}
@Override
public void update(Master master) {
}
}

View file

@ -0,0 +1,67 @@
package objects;
import core.Master;
import core.Vector2D;
import java.awt.*;
/**
* The GameObject class is the superclass of every GameObject that can be displayed on screen. It has the 2
* {@link #update(Master)} and {@link #draw(Graphics2D, int, Master)} methods that have to be
*/
public abstract class GameObject {
protected int w;
protected int h;
protected Vector2D position;
protected Vector2D size;
protected Vector2D velocity;
public GameObject(double x, double y, double xSize, double ySize) {
this(new Vector2D(x, y), new Vector2D(xSize, ySize));
}
public GameObject(Vector2D position, Vector2D size) {
this.position = position;
this.size = size;
this.velocity = new Vector2D();
}
public abstract void draw(Graphics2D g2d, int w, Master master);
public abstract void update(Master master);
public double getMapCoords(double value, boolean isX){
if (isX){
return (position.x + value / 100 * size.x);
} else {
return (position.y + value / 100 * size.y);
}
}
public double getMapCoordsSize(double value, boolean useX){
if (useX){
return (value / 100 * size.x);
} else {
return (value / 100 * size.y);
}
}
public double getWorldCoords(double value, boolean isX){
if (isX){
return (value / 100 * w);
} else {
return (value / 100 * h);
}
}
public int getWorldCoordsFromLocal(double value, boolean isX){
return (int) getWorldCoords(getMapCoords(value, isX), isX);
}
public int getWorldCoordsFromLocalSize(double value, boolean useX){
return (int) getWorldCoords(getMapCoordsSize(value, useX), useX);
}
}

View file

@ -0,0 +1,54 @@
package objects.ships;
import core.Master;
import objects.GameObject;
import java.awt.*;
import java.util.ArrayList;
/**
* A Battleship that can have several turrets
*/
public class BattleShip extends GameObject {
private Color mainColor;
private ArrayList<Turret> turrets;
public BattleShip(Color mainColor) {
super(20, 20, 5, 40);
turrets = new ArrayList<>();
turrets.add(new Turret(this, 25, 25, 50, 1));
//turrets.add(new Turret(this, 25, 10, 50, 2));
//turrets.add(new Turret(this, 25, 70, 50, 2));
this.mainColor = mainColor;
}
public BattleShip(double x, double y, double xSize, double ySize, Color mainColor) {
super(x, y, xSize, ySize);
turrets = new ArrayList<>();
this.mainColor = mainColor;
}
@Override
public void draw(Graphics2D g2d, int w, Master master) {
this.w = w;
h = w/16*9;
g2d.setPaint(mainColor);
int xAbs = (int) getWorldCoords(position.x, true);
int yAbs = (int) getWorldCoords(position.y, false);
int sizeXAbs = (int) getWorldCoords(size.x, true);
int sizeYAbs = (int) getWorldCoords(size.y, false);
g2d.fillRoundRect(xAbs, yAbs, sizeXAbs, sizeYAbs, w/10, w/10);
turrets.forEach((turret -> turret.draw(g2d, w, master)));
}
@Override
public void update(Master master) {
turrets.forEach((turret -> turret.update(master)));
}
public void addTurret(Turret turret){
turrets.add(turret);
}
}

View file

@ -0,0 +1,27 @@
package objects.ships;
import core.Master;
import core.Vector2D;
import objects.GameObject;
import java.awt.*;
public class Shell extends GameObject {
public Shell(Vector2D position, Vector2D size, Vector2D velocity) {
super(position, size);
this.velocity = velocity;
}
@Override
public void draw(Graphics2D g2d, int w, Master master) {
g2d.setPaint(Color.orange);
g2d.fillOval((int) position.x, (int) position.y, (int) size.x, (int) size.y);
}
@Override
public void update(Master master) {
position.add(velocity);
}
}

View file

@ -0,0 +1,103 @@
package objects.ships;
import core.Master;
import core.Vector2D;
import objects.GameObject;
import java.awt.*;
/**
* A Turret that can shoot projectiles
*/
public class Turret extends GameObject {
BattleShip battleShip;
private int barrelAmount = 3;
private Color mainColor;
private long lastShot = 0;
private static int SHOT_EFFECT_TIME = 300;
private static int SHELL_SPEED = 10;
private double rotation;
public Turret(BattleShip battleShip, double x, double y, double size, int barrelAmount) {
super(x, y, size, size);
this.battleShip = battleShip;
this.barrelAmount = barrelAmount;
mainColor = Color.GRAY;
}
public Turret(BattleShip battleShip) {
super(25, 50, 50, 50);
this.battleShip = battleShip;
mainColor = Color.GRAY;
}
@Override
public void draw(Graphics2D g2d, int w, Master master) {
//TODO draw should be draw only for better everything
h = w / 16 * 9;
g2d.setPaint(mainColor);
int xAbs = battleShip.getWorldCoordsFromLocal(position.x, true);
int yAbs = battleShip.getWorldCoordsFromLocal(position.y, false);
int sizeAbs = battleShip.getWorldCoordsFromLocalSize(size.x, true);
int xCenterAbs = xAbs + sizeAbs / 2;
int yCenterAbs = yAbs + sizeAbs / 2;
g2d.fillOval(xAbs, yAbs, sizeAbs, sizeAbs);
g2d.setStroke(new BasicStroke(battleShip.getWorldCoordsFromLocalSize(10, true), BasicStroke.CAP_BUTT,
BasicStroke.JOIN_BEVEL));
//BARRELS---------------------------------------
g2d.setPaint(Color.BLACK);
int barrelSpacing = sizeAbs / (barrelAmount + 1);
g2d.rotate(rotation, xCenterAbs, yCenterAbs);
for (int i = 0; i < barrelAmount; i++) {
int barrelX = xAbs + (i + 1) * barrelSpacing;
int frontPosY = yAbs - sizeAbs / 2;
g2d.drawLine(barrelX, yCenterAbs, barrelX, frontPosY);
if (lastShot + SHOT_EFFECT_TIME > System.currentTimeMillis()) {
g2d.setPaint(Color.YELLOW);
g2d.fillOval(barrelX - 5, frontPosY - 5, 10, 10);
g2d.setPaint(Color.BLACK);
}
}
g2d.rotate(-rotation, xCenterAbs, yCenterAbs);
}
@Override
public void update(Master master) {
int xAbs = battleShip.getWorldCoordsFromLocal(position.x, true);
int yAbs = battleShip.getWorldCoordsFromLocal(position.y, false);
int sizeAbs = battleShip.getWorldCoordsFromLocalSize(size.x, true);
int xCenterAbs = xAbs + sizeAbs / 2;
int yCenterAbs = yAbs + sizeAbs / 2;
Point msLoc = master.getMouseLocation();
rotation = -Math.atan2(xCenterAbs - msLoc.x, yCenterAbs - msLoc.y);
int barrelSpacing = sizeAbs / (barrelAmount + 1);
for (int i = 0; i < barrelAmount; i++) {
int barrelX = xAbs + (i + 1) * barrelSpacing;
int frontPosY = yAbs - sizeAbs / 2;
if (master.isMousePressed()) {
lastShot = System.currentTimeMillis();
Vector2D shellVel = new Vector2D(xCenterAbs - msLoc.x, yCenterAbs - msLoc.y).normalized().negative().multiply(SHELL_SPEED);
Vector2D pos = Vector2D.rotateAround(new Vector2D(xCenterAbs, yCenterAbs), new Vector2D(barrelX, frontPosY), rotation, Vector2D.CLOCKWISE);
master.debugPos(pos);
master.create(new Shell(pos, new Vector2D(10, 10), shellVel));
}
}
}
}

View file

@ -0,0 +1,47 @@
package objects.world;
import core.Master;
import objects.GameObject;
import java.awt.*;
/**
* A basic background grid
*/
public class Grid extends GameObject {
private int gridSpacing = 50;
public Grid() {
super(0, 0, 0, 0);
}
@Override
public void draw(Graphics2D g2d, int w, Master master) {
g2d.setPaint(Color.LIGHT_GRAY);
this.w = w;
h = w/16*9;
g2d.drawRect(0, 0, w, h);
int verticalLines = w / gridSpacing;
int horizontalLines = h / gridSpacing;
for (int i = 0; i < horizontalLines; i++) {
int y = i * h / horizontalLines;
g2d.drawLine(0, y, w, y);
}
for (int i = 0; i < verticalLines; i++) {
int x = i * w / verticalLines;
g2d.drawLine(x, 0, x, h);
}
}
@Override
public void update(Master master) {
}
}

View file

@ -0,0 +1,60 @@
package core;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class Vector2DTest {
@Test
void addOK() {
Vector2D a = new Vector2D(1, 2);
Vector2D b = new Vector2D(1, 2);
Vector2D c = new Vector2D(-1 ,-1);
Vector2D d = new Vector2D(0, 1);
assertEquals(new Vector2D(2, 4), Vector2D.add(a, b));
assertEquals(new Vector2D(0, 1), Vector2D.add(a, c));
assertEquals(new Vector2D(-1, 0), Vector2D.add(c, d));
}
@Test
void normalized() {
Vector2D a = new Vector2D(1, 1);
Vector2D b = new Vector2D(1, 0);
assertEquals(new Vector2D(1 / Math.sqrt(2), 1 / Math.sqrt(2)), a.normalized());
assertEquals(new Vector2D(1,0), b.normalized());
}
@Test
void subtractOK() {
Vector2D a = new Vector2D(1, 2);
Vector2D b = new Vector2D(1, 2);
Vector2D c = new Vector2D(-1 ,-1);
Vector2D d = new Vector2D(0, 1);
assertEquals(new Vector2D(0, 0), Vector2D.subtract(a, b));
assertEquals(new Vector2D(2, 3), Vector2D.subtract(a, c));
assertEquals(new Vector2D(-1, -2), Vector2D.subtract(c, d));
}
@Test
void rotateAroundTest(){
Vector2D cent = new Vector2D(0, 0);
Vector2D a = new Vector2D(1, 0);
Vector2D exceptedA = new Vector2D(6.123233995736766E-17 ,-1); //floating point precision probably
Vector2D centB = new Vector2D(1, 1);
Vector2D b = new Vector2D(2, 1);
Vector2D exceptedB = new Vector2D(1 ,2);
Vector2D rotated = Vector2D.rotateAround(cent, a, Math.toRadians(90), Vector2D.CLOCKWISE);
Vector2D rotatedb = Vector2D.rotateAround(centB, b, Math.toRadians(90), Vector2D.COUNTERCLOCKWISE);
assertEquals(exceptedA, rotated);
assertEquals(exceptedB, rotatedb);
}
}