Skip to content
Snippets Groups Projects
SimpleBattle.java 8.9 KiB
Newer Older
Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed
package battle;

Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed
import math.Vector2d;
import utilities.JEasyFrame;
Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed

import java.awt.event.KeyListener;
Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed
import java.util.ArrayList;
Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed
import java.awt.*;

import static asteroids.Constants.*;
Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed

/**
 * Created by simon lucas on 10/06/15.
 * <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.
Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed
 */

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;
    static int releaseVelocity = 5;

    boolean visible = true;
Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed

    ArrayList<BattleController> controllers;

    ArrayList<GameObject> objects;
    ArrayList<PlayerStats> stats;

    NeuroShip s1, s2;
    BattleController p1, p2;
    BattleView view;
    int currentTick;
    public SimpleBattle() {
        this(true);
    }

    public SimpleBattle(boolean visible) {
Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed
        this.objects = new ArrayList<>();
        this.stats = new ArrayList<>();

        if (visible) {
            view = new BattleView(this);
            new JEasyFrame(view, "battle");
        }
    public int getTicks() {
        return currentTick;
    }

Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed
    public int playGame(BattleController p1, BattleController p2) {
Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed
        this.p1 = p1;
        this.p2 = p2;
Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed

        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);
        }

        while (!isGameOver()) {
        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);
        this.currentTick = 0;
    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 );
Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed
    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);
        update(a1, a2);
    }
    public void update(Action a1, Action a2) {
Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed
        // now apply them to the ships
        s1.update(a1);
        s2.update(a2);

Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed
        checkCollision(s1);
        checkCollision(s2);

Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed
        // and fire any missiles as necessary
        if (a1.shoot) fireMissile(s1.s, s1.d, 0);
        if (a2.shoot) fireMissile(s2.s, s2.d, 1);

        wrap(s1);
        wrap(s2);

Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed
        // here need to add the game objects ...
Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed
        java.util.List<GameObject> killList = new ArrayList<GameObject>();
        for (GameObject object : objects) {
            object.update();
            wrap(object);
Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed
            if (object.dead()) {
                killList.add(object);
            }
        }

        objects.removeAll(killList);
        currentTick++;
Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed
        if (visible) {
        SimpleBattle state = new SimpleBattle(false);
        state.objects = copyObjects();
        state.stats = copyStats();
        state.currentTick = currentTick;
        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) {
Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed
        // 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);
                    stats.nPoints += pointsPerKill;
Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed
                    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;
    }

Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed
    public void sleep() {
        try {
            Thread.sleep(delay);
        } catch (Exception e) {
            e.printStackTrace();
        }
    protected void fireMissile(Vector2d s, Vector2d d, int playerId) {
Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed
        // need all the usual missile firing code here
        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++;
        }
Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed
    }

    public void draw(Graphics2D g) {
        // for (Object ob : objects)
        if (s1 == null || s2 == null) {
            return;
        }
Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed

        // 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);
Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed
        for (GameObject go : objects) {
            go.draw(g);
        }
        if (p1 instanceof RenderableBattleController) {
            RenderableBattleController rbc = (RenderableBattleController)p1;
            rbc.render(g, s1.copy());
        }

        s2.draw(g);
        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);
    public int getPoints(int playerID) {
        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;
        }
    }

    public boolean isGameOver() {
        if (getMissilesLeft(0) >= 0 && getMissilesLeft(1) >= 0) {
            //ensure that there are no bullets left in play
            if (objects.isEmpty()) {
                return true;
            }
        }

        return currentTick >= nTicks;
Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed
    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;
        }

Joseph Walton-Rivers's avatar
Joseph Walton-Rivers committed
        public String toString() {
            return nMissiles + " : " + nPoints;
        }
    }

}