mirror of
https://github.com/fazo96/AIrium.git
synced 2025-01-10 09:34:20 +01:00
improved API and docs
This commit is contained in:
parent
4528f787cb
commit
7650ff44eb
@ -9,9 +9,16 @@ package com.mygdx.game;
|
|||||||
*
|
*
|
||||||
* @author Fazo
|
* @author Fazo
|
||||||
*/
|
*/
|
||||||
public interface Listener {
|
public abstract class Listener {
|
||||||
|
|
||||||
public static int FPS_CHANGED = 0, CREATURE_LIST_CHANGED = 1, PAUSED_OR_RESUMED = 2;
|
public static int FPS_CHANGED = 0, CREATURE_LIST_CHANGED = 1, PAUSED_OR_RESUMED = 2;
|
||||||
|
|
||||||
public void on(int event);
|
public void pollAndHandleEvents() {
|
||||||
|
if(Game.get() == null || Game.get().getWorld() == null) return;
|
||||||
|
while(Game.get().getWorld().getEventQueue().size() > 0) {
|
||||||
|
on(Game.get().getWorld().getEventQueue().poll());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void on(int event);
|
||||||
}
|
}
|
||||||
|
@ -10,9 +10,12 @@ import java.util.Comparator;
|
|||||||
import java.util.ConcurrentModificationException;
|
import java.util.ConcurrentModificationException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Queue;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
import logic.creatures.Beak;
|
||||||
import logic.creatures.Eye;
|
import logic.creatures.Eye;
|
||||||
import logic.creatures.Movement;
|
import logic.creatures.Movement;
|
||||||
import logic.creatures.Torso;
|
import logic.creatures.Torso;
|
||||||
@ -34,6 +37,7 @@ public class World implements Runnable {
|
|||||||
private Map<String, Float> options;
|
private Map<String, Float> options;
|
||||||
private long ticksSinceGenStart = 0, maximumTicksPerGen = 0;
|
private long ticksSinceGenStart = 0, maximumTicksPerGen = 0;
|
||||||
private Creature selected;
|
private Creature selected;
|
||||||
|
private Queue<Integer> events = new LinkedList<>();
|
||||||
private final Comparator creatureComp;
|
private final Comparator creatureComp;
|
||||||
private final ArrayList<Element> elements;
|
private final ArrayList<Element> elements;
|
||||||
private final ArrayList<Element> toAdd;
|
private final ArrayList<Element> toAdd;
|
||||||
@ -41,7 +45,6 @@ public class World implements Runnable {
|
|||||||
private final ArrayList<Creature> graveyard;
|
private final ArrayList<Creature> graveyard;
|
||||||
private final ArrayList<Vegetable> plants;
|
private final ArrayList<Vegetable> plants;
|
||||||
private final ArrayList<Vegetable> deadPlants;
|
private final ArrayList<Vegetable> deadPlants;
|
||||||
private final ArrayList<Listener> listeners;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new World. Can be customized with given options.
|
* Create a new World. Can be customized with given options.
|
||||||
@ -56,13 +59,13 @@ public class World implements Runnable {
|
|||||||
this.options = options;
|
this.options = options;
|
||||||
}
|
}
|
||||||
reloadOptions();
|
reloadOptions();
|
||||||
|
events = new LinkedList<>();
|
||||||
elements = new ArrayList();
|
elements = new ArrayList();
|
||||||
creatures = new ArrayList();
|
creatures = new ArrayList();
|
||||||
toAdd = new ArrayList();
|
toAdd = new ArrayList();
|
||||||
plants = new ArrayList();
|
plants = new ArrayList();
|
||||||
deadPlants = new ArrayList();
|
deadPlants = new ArrayList();
|
||||||
graveyard = new ArrayList();
|
graveyard = new ArrayList();
|
||||||
listeners = new ArrayList();
|
|
||||||
selected = null;
|
selected = null;
|
||||||
creatureComp = new Comparator<Creature>() {
|
creatureComp = new Comparator<Creature>() {
|
||||||
|
|
||||||
@ -333,7 +336,15 @@ public class World implements Runnable {
|
|||||||
} while (overlaps && i++ < 20);
|
} while (overlaps && i++ < 20);
|
||||||
if (isCreature) {
|
if (isCreature) {
|
||||||
Log.log(Log.DEBUG, "New Creat: " + x + " " + y);
|
Log.log(Log.DEBUG, "New Creat: " + x + " " + y);
|
||||||
Creature c = new Creature(x, y);
|
Creature c = new Creature(x, y) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void buildBody() {
|
||||||
|
addBodyPart(new Beak(0, this));
|
||||||
|
addBodyPart(new Eye(5, 0, this));
|
||||||
|
addBodyPart(new Movement(this));
|
||||||
|
}
|
||||||
|
};
|
||||||
if (brainMap != null) {
|
if (brainMap != null) {
|
||||||
c.getBrain().remap(brainMap);
|
c.getBrain().remap(brainMap);
|
||||||
}
|
}
|
||||||
@ -380,9 +391,11 @@ public class World implements Runnable {
|
|||||||
*/
|
*/
|
||||||
public void fire(int eventCode) {
|
public void fire(int eventCode) {
|
||||||
Log.log(Log.DEBUG, "Firing Event. Code: " + eventCode);
|
Log.log(Log.DEBUG, "Firing Event. Code: " + eventCode);
|
||||||
for (Listener f : listeners) {
|
events.add(eventCode);
|
||||||
f.on(eventCode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Queue<Integer> getEventQueue(){
|
||||||
|
return events;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void spawnVegetable() {
|
public void spawnVegetable() {
|
||||||
@ -409,10 +422,6 @@ public class World implements Runnable {
|
|||||||
return generation;
|
return generation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addListener(Listener f) {
|
|
||||||
listeners.add(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add(Element e) {
|
public void add(Element e) {
|
||||||
toAdd.add(e);
|
toAdd.add(e);
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@ import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
|||||||
import logic.Element;
|
import logic.Element;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* A body part. Used in creatures. Extend this class to create custom body
|
||||||
|
* parts.
|
||||||
*
|
*
|
||||||
* @author fazo
|
* @author fazo
|
||||||
*/
|
*/
|
||||||
@ -14,6 +16,16 @@ public abstract class BodyPart {
|
|||||||
protected float outputs[];
|
protected float outputs[];
|
||||||
protected Creature creature;
|
protected Creature creature;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an instance of a Body Part.
|
||||||
|
*
|
||||||
|
* @param inputNeuronsUsed how many input neurons it'll need
|
||||||
|
* @param outputNeuronsUsed how many output neurons it'll need
|
||||||
|
* @param angle the angle relative to the center of the creature
|
||||||
|
* @param distFromCenter how distance from the center of the creature is
|
||||||
|
* this body part
|
||||||
|
* @param creature the creature that owns this body part
|
||||||
|
*/
|
||||||
public BodyPart(int inputNeuronsUsed, int outputNeuronsUsed, float angle, float distFromCenter, Creature creature) {
|
public BodyPart(int inputNeuronsUsed, int outputNeuronsUsed, float angle, float distFromCenter, Creature creature) {
|
||||||
this.inputNeuronsUsed = inputNeuronsUsed;
|
this.inputNeuronsUsed = inputNeuronsUsed;
|
||||||
this.angle = angle;
|
this.angle = angle;
|
||||||
@ -23,14 +35,18 @@ public abstract class BodyPart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare data to be sent to the brain
|
* Prepare data to be sent to the brain. This is called once every frame,
|
||||||
|
* before the interactions with other elements.
|
||||||
*
|
*
|
||||||
* @return the data to send to the brain, must be inputNeuronsUsed long
|
* @return the data to send to the brain, must be inputNeuronsUsed long
|
||||||
*/
|
*/
|
||||||
public abstract float[] act();
|
public abstract float[] act();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interact with another element
|
* Interact with another element. This will be called every time the body
|
||||||
|
* part has a chance to interact with another element. act() will be called
|
||||||
|
* once every frame, before all the interactions. readFromBrain will be
|
||||||
|
* called once every frame, after all the interactions.
|
||||||
*
|
*
|
||||||
* @param e the Element (creature or plant)
|
* @param e the Element (creature or plant)
|
||||||
* @param distance the distance
|
* @param distance the distance
|
||||||
@ -39,29 +55,56 @@ public abstract class BodyPart {
|
|||||||
public abstract void interactWithElement(Element e, float distance, float relAngle);
|
public abstract void interactWithElement(Element e, float distance, float relAngle);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Receive some data from the brain
|
* Receive some data from the brain. This is called once every frame, after
|
||||||
|
* interactions with other elements.
|
||||||
*
|
*
|
||||||
* @param data the data received from the brain, will be outputNeuronsUsed
|
* @param data the data received from the brain, will be outputNeuronsUsed
|
||||||
* long
|
* long
|
||||||
*/
|
*/
|
||||||
public abstract void readFromBrain(float data[]);
|
public abstract void readFromBrain(float data[]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This will be called when the
|
||||||
|
*
|
||||||
|
* @param s the ShapeRenderer used to draw this body part.
|
||||||
|
* @param relX the X position of this bodypart relative to the center its
|
||||||
|
* creature
|
||||||
|
* @param relY the Y position of this bodypart relative to the center its
|
||||||
|
* creature
|
||||||
|
*/
|
||||||
protected abstract void draw(ShapeRenderer s, float relX, float relY);
|
protected abstract void draw(ShapeRenderer s, float relX, float relY);
|
||||||
|
|
||||||
public void render(ShapeRenderer s) {
|
/**
|
||||||
|
* Prepares data and calls draw
|
||||||
|
*
|
||||||
|
* @param s the ShapeRenderer used to draw this body part.
|
||||||
|
*/
|
||||||
|
public final void render(ShapeRenderer s) {
|
||||||
double relX = Math.cos(creature.getDirection() + angle) * creature.getTorso().getRadius() * distFromCenter;
|
double relX = Math.cos(creature.getDirection() + angle) * creature.getTorso().getRadius() * distFromCenter;
|
||||||
double relY = Math.sin(creature.getDirection() + angle) * creature.getTorso().getRadius() * distFromCenter;
|
double relY = Math.sin(creature.getDirection() + angle) * creature.getTorso().getRadius() * distFromCenter;
|
||||||
draw(s, (float) relX, (float) relY);
|
draw(s, (float) relX, (float) relY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return how many input neurons are used by this body part
|
||||||
|
*/
|
||||||
public int getInputNeuronsUsed() {
|
public int getInputNeuronsUsed() {
|
||||||
return inputNeuronsUsed;
|
return inputNeuronsUsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return how many output neurons are used by this body part
|
||||||
|
*/
|
||||||
public int getOutputNeuronsUsed() {
|
public int getOutputNeuronsUsed() {
|
||||||
return outputs.length;
|
return outputs.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return the angle of this bodypart relative to the center of the creature
|
||||||
|
*/
|
||||||
public float getAngle() {
|
public float getAngle() {
|
||||||
return angle;
|
return angle;
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,14 @@ import logic.Vegetable;
|
|||||||
import logic.neural.Brain;
|
import logic.neural.Brain;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A (hopefully) smart biological creature in the simulated world.
|
* A (hopefully) smart biological creature in the simulated world. It is
|
||||||
|
* initialized with a set of body parts. Every creature has a brain which gets
|
||||||
|
* automatically wired to the body parts. Only creatures with matching brain
|
||||||
|
* structures can breed for now.
|
||||||
*
|
*
|
||||||
* @author fazo
|
* @author fazo
|
||||||
*/
|
*/
|
||||||
public class Creature extends Element implements Runnable {
|
public abstract class Creature extends Element implements Runnable {
|
||||||
|
|
||||||
public static int brain_hidden_layers = 2, brain_hidden_neurons = 10;
|
public static int brain_hidden_layers = 2, brain_hidden_neurons = 10;
|
||||||
public static float corpseDecayRate = 0, pointsForEatingPlants = 1f, pointsForAttacking = 2f, hpForAttacking = 1f, hpForEatingPlants = 1f;
|
public static float corpseDecayRate = 0, pointsForEatingPlants = 1f, pointsForAttacking = 2f, hpForAttacking = 1f, hpForEatingPlants = 1f;
|
||||||
@ -25,7 +28,6 @@ public class Creature extends Element implements Runnable {
|
|||||||
private final ArrayList<BodyPart> bodyParts;
|
private final ArrayList<BodyPart> bodyParts;
|
||||||
private float dir, fitness = 0;
|
private float dir, fitness = 0;
|
||||||
private boolean workerDone = false, killWorker = false;
|
private boolean workerDone = false, killWorker = false;
|
||||||
private Sight[] sights;
|
|
||||||
private Thread workerThread;
|
private Thread workerThread;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -39,11 +41,8 @@ public class Creature extends Element implements Runnable {
|
|||||||
dir = (float) (Math.random() * 2 * Math.PI);
|
dir = (float) (Math.random() * 2 * Math.PI);
|
||||||
bodyParts = new ArrayList<BodyPart>();
|
bodyParts = new ArrayList<BodyPart>();
|
||||||
bodyParts.add(torso = new Torso(this));
|
bodyParts.add(torso = new Torso(this));
|
||||||
bodyParts.add(new Beak(0, this));
|
buildBody();
|
||||||
bodyParts.add(new Eye(5, 0, this));
|
|
||||||
bodyParts.add(new Movement(this));
|
|
||||||
brain = new Brain(howManyInputNeurons(), howManyOutputNeurons(), brain_hidden_layers, brain_hidden_neurons);
|
brain = new Brain(howManyInputNeurons(), howManyOutputNeurons(), brain_hidden_layers, brain_hidden_neurons);
|
||||||
sights = new Sight[2];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -196,13 +195,24 @@ public class Creature extends Element implements Runnable {
|
|||||||
for (BodyPart b : bodyParts) {
|
for (BodyPart b : bodyParts) {
|
||||||
if (b instanceof Beak) {
|
if (b instanceof Beak) {
|
||||||
beaks++;
|
beaks++;
|
||||||
danger += (((Beak)b).getLength() - Beak.min_length) / Beak.max_length;
|
danger += (((Beak) b).getLength() - Beak.min_length) / Beak.max_length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(beaks == 0) return 0;
|
if (beaks == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return danger / beaks;
|
return danger / beaks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compose this creature's body using the addBodyPart function.
|
||||||
|
*/
|
||||||
|
public abstract void buildBody();
|
||||||
|
|
||||||
|
public void addBodyPart(BodyPart p) {
|
||||||
|
bodyParts.add(p);
|
||||||
|
}
|
||||||
|
|
||||||
public Brain getBrain() {
|
public Brain getBrain() {
|
||||||
return brain;
|
return brain;
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,9 @@ public class Brain {
|
|||||||
*/
|
*/
|
||||||
public void input(float[] values) throws Exception {
|
public void input(float[] values) throws Exception {
|
||||||
if (values.length != neurons[0].length) {
|
if (values.length != neurons[0].length) {
|
||||||
throw new Exception("Not enough or too many inputs");
|
throw new Exception("Brain has " + neurons[0].length
|
||||||
|
+ " input neurons," + " but was supplied with "
|
||||||
|
+ values.length + " inputs");
|
||||||
}
|
}
|
||||||
for (int i = 0; i < values.length; i++) {
|
for (int i = 0; i < values.length; i++) {
|
||||||
neurons[0][i].setOutput(values[i]);
|
neurons[0][i].setOutput(values[i]);
|
||||||
|
@ -41,13 +41,14 @@ import logic.World;
|
|||||||
*
|
*
|
||||||
* @author fazo
|
* @author fazo
|
||||||
*/
|
*/
|
||||||
public class GUI extends javax.swing.JFrame implements LogListener, Listener {
|
public class GUI extends javax.swing.JFrame implements LogListener {
|
||||||
|
|
||||||
private Game game;
|
private Game game;
|
||||||
private World world;
|
private World world;
|
||||||
private LwjglApplication app;
|
private LwjglApplication app;
|
||||||
private boolean shouldUpdateGUI = false;
|
private boolean shouldUpdateGUI = false;
|
||||||
private final Thread guiUpdater;
|
private final Thread guiUpdater;
|
||||||
|
private final Listener listener;
|
||||||
private Map<String, Float> options;
|
private Map<String, Float> options;
|
||||||
private boolean updatingSliders = false, updatingTable = false;
|
private boolean updatingSliders = false, updatingTable = false;
|
||||||
|
|
||||||
@ -59,6 +60,13 @@ public class GUI extends javax.swing.JFrame implements LogListener, Listener {
|
|||||||
currentFpsLimit.setText("" + fpsLimitSlider.getValue());
|
currentFpsLimit.setText("" + fpsLimitSlider.getValue());
|
||||||
setLocationRelativeTo(null); // Center the window
|
setLocationRelativeTo(null); // Center the window
|
||||||
Log.addListener(this);
|
Log.addListener(this);
|
||||||
|
listener = new Listener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void on(int event) {
|
||||||
|
updateGUI();
|
||||||
|
}
|
||||||
|
};
|
||||||
options = new HashMap<String, Float>();
|
options = new HashMap<String, Float>();
|
||||||
world = new World(options);
|
world = new World(options);
|
||||||
updateSettingsUI();
|
updateSettingsUI();
|
||||||
@ -90,17 +98,13 @@ public class GUI extends javax.swing.JFrame implements LogListener, Listener {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (shouldUpdateGUI) {
|
listener.pollAndHandleEvents();
|
||||||
updateGUI();
|
|
||||||
shouldUpdateGUI = false;
|
|
||||||
} else {
|
|
||||||
try {
|
try {
|
||||||
Thread.sleep(5000);
|
Thread.sleep(100);
|
||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException ex) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
guiUpdater.setPriority(Thread.MAX_PRIORITY);
|
guiUpdater.setPriority(Thread.MAX_PRIORITY);
|
||||||
guiUpdater.start();
|
guiUpdater.start();
|
||||||
@ -885,7 +889,6 @@ public class GUI extends javax.swing.JFrame implements LogListener, Listener {
|
|||||||
app = new LwjglApplication(game = new Game(world), config);
|
app = new LwjglApplication(game = new Game(world), config);
|
||||||
startButton.setText("Restart");
|
startButton.setText("Restart");
|
||||||
pauseButton.setEnabled(true);
|
pauseButton.setEnabled(true);
|
||||||
world.addListener(this);
|
|
||||||
setCreatureList();
|
setCreatureList();
|
||||||
}
|
}
|
||||||
updateGUI();
|
updateGUI();
|
||||||
@ -900,12 +903,6 @@ public class GUI extends javax.swing.JFrame implements LogListener, Listener {
|
|||||||
setScrollBarToTheBottom();
|
setScrollBarToTheBottom();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void on(int event) {
|
|
||||||
shouldUpdateGUI = true;
|
|
||||||
guiUpdater.interrupt();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void enableControlButtons(boolean yn) {
|
public void enableControlButtons(boolean yn) {
|
||||||
pauseButton.setEnabled(yn);
|
pauseButton.setEnabled(yn);
|
||||||
pauseMenuButton.setEnabled(yn);
|
pauseMenuButton.setEnabled(yn);
|
||||||
|
Loading…
Reference in New Issue
Block a user