Newer
Older
import asteroids.*;
import java.awt.event.KeyListener;
* <p>
* Aim here is to have a simple battle class
* that enables ships to fish with each other
* <p>
* Might start off with just two ships, each with their own types of missile.
*/
public class SimpleBattle {
// play a time limited game with a strict missile budget for
// each player
static int nMissiles = 100;
static int nTicks = 1000;
static int pointsPerKill = 10;
ArrayList<BattleController> controllers;
ArrayList<GameObject> objects;
ArrayList<PlayerStats> stats;
NeuroShip s1, s2;
BattleController p1, p2;
Joseph Walton-Rivers
committed
this(true);
}
public SimpleBattle(boolean visible) {
this.objects = new ArrayList<>();
this.stats = new ArrayList<>();
Joseph Walton-Rivers
committed
this.visible = visible;
if (visible) {
view = new BattleView(this);
new JEasyFrame(view, "battle");
}
public int getTicks() {
return currentTick;
}
public int playGame(BattleController p1, BattleController p2) {
stats.add(new PlayerStats(0, 0));
stats.add(new PlayerStats(0, 0));
if (p1 instanceof KeyListener) {
view.addKeyListener((KeyListener)p1);
}
if (p2 instanceof KeyListener) {
view.addKeyListener((KeyListener)p2);
}
if (p1 instanceof KeyListener) {
view.removeKeyListener((KeyListener)p1);
}
if (p2 instanceof KeyListener) {
view.removeKeyListener((KeyListener)p2);
}
protected void reset() {
stats.clear();
objects.clear();
s1 = buildShip(250, 250, 0);
s2 = buildShip(300, 300, 1);
protected NeuroShip buildShip(int x, int y, int playerID) {
Vector2d position = new Vector2d(x, y, true);
Vector2d speed = new Vector2d(true);
Vector2d direction = new Vector2d(1, 0, true);
return new NeuroShip(position, speed, direction, playerID );
public void update() {
// get the actions from each player
// apply them to each player's ship, taking actions as necessary
Action a1 = p1.getAction(this.clone(), 0);
Action a2 = p2.getAction(this.clone(), 1);
public void update(Action a1, Action a2) {
// now apply them to the ships
s1.update(a1);
s2.update(a2);
// and fire any missiles as necessary
if (a1.shoot) fireMissile(s1.s, s1.d, 0);
if (a2.shoot) fireMissile(s2.s, s2.d, 1);
java.util.List<GameObject> killList = new ArrayList<GameObject>();
for (GameObject object : objects) {
object.update();
if (object.dead()) {
killList.add(object);
}
}
objects.removeAll(killList);
public SimpleBattle clone() {
Joseph Walton-Rivers
committed
SimpleBattle state = new SimpleBattle(false);
state.objects = copyObjects();
state.stats = copyStats();
state.visible = false; //stop MCTS people having all the games :p
state.s1 = s1.copy();
state.s2 = s2.copy();
return state;
}
protected ArrayList<GameObject> copyObjects() {
ArrayList<GameObject> objectClone = new ArrayList<GameObject>();
for (GameObject object : objects) {
objectClone.add(object.copy());
}
return objectClone;
}
protected ArrayList<PlayerStats> copyStats() {
ArrayList<PlayerStats> statsClone = new ArrayList<PlayerStats>();
for (PlayerStats object : stats) {
statsClone.add(new PlayerStats(object.nMissiles, object.nPoints));
}
return statsClone;
}
protected void checkCollision(GameObject actor) {
// check with all other game objects
// but use a hack to only consider interesting interactions
// e.g. asteroids do not collide with themselves
if (!actor.dead() &&
(actor instanceof BattleMissile
|| actor instanceof NeuroShip)) {
if (actor instanceof BattleMissile) {
// System.out.println("Missile: " + actor);
}
for (GameObject ob : objects) {
if (overlap(actor, ob)) {
// the object is hit, and the actor is also
int playerID = (actor == s1 ? 1 : 0);
PlayerStats stats = this.stats.get(playerID);
return;
}
}
}
}
private boolean overlap(GameObject actor, GameObject ob) {
if (actor.equals(ob)) {
return false;
}
// otherwise do the default check
double dist = actor.s.dist(ob.s);
boolean ret = dist < (actor.r() + ob.r());
return ret;
}
public void sleep() {
try {
Thread.sleep(delay);
} catch (Exception e) {
e.printStackTrace();
}
protected void fireMissile(Vector2d s, Vector2d d, int playerId) {
NeuroShip currentShip = playerId == 0 ? s1 : s2;
PlayerStats stats = this.stats.get(playerId);
if (stats.nMissiles < nMissiles) {
Missile m = new Missile(s, new Vector2d(0, 0, true));
m.v.add(d, releaseVelocity);
// make it clear the ship
m.s.add(m.v, (currentShip.r() + missileRadius) * 1.5 / m.v.mag());
objects.add(m);
// System.out.println("Fired: " + m);
// sounds.fire();
stats.nMissiles++;
}
}
public void draw(Graphics2D g) {
// for (Object ob : objects)
if (s1 == null || s2 == null) {
return;
}
// System.out.println("In draw(): " + n);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(bg);
g.fillRect(0, 0, size.width, size.height);
for (GameObject go : objects) {
go.draw(g);
}
if (p1 instanceof RenderableBattleController) {
RenderableBattleController rbc = (RenderableBattleController)p1;
rbc.render(g, s1.copy());
}
if (p2 instanceof RenderableBattleController) {
RenderableBattleController rbc = (RenderableBattleController)p2;
rbc.render(g, s2.copy());
}
public NeuroShip getShip(int playerID) {
assert playerID < 2;
assert playerID >= 0;
if (playerID == 0) {
return s1.copy();
} else {
return s2.copy();
}
}
public ArrayList<GameObject> getObjects()
{
return new ArrayList<>(objects);
assert playerID < 2;
assert playerID >= 0;
return stats.get(playerID).nPoints;
}
public int getMissilesLeft(int playerID) {
assert playerID < 2;
assert playerID >= 0;
return stats.get(playerID).nMissiles - nMissiles;
}
private void wrap(GameObject ob) {
// only wrap objects which are wrappable
if (ob.wrappable()) {
ob.s.x = (ob.s.x + width) % width;
ob.s.y = (ob.s.y + height) % height;
}
}
if (getMissilesLeft(0) >= 0 && getMissilesLeft(1) >= 0) {
//ensure that there are no bullets left in play
if (objects.isEmpty()) {
return true;
}
}
static class PlayerStats {
int nMissiles;
int nPoints;
public PlayerStats(int nMissiles, int nPoints) {
this.nMissiles = nMissiles;
this.nPoints = nPoints;
}
public int getMissilesFired() {
return nMissiles;
}
public int getPoints() {
return nPoints;
}
public String toString() {
return nMissiles + " : " + nPoints;
}
}
}