1
0
mirror of https://github.com/fazo96/AIrium.git synced 2025-01-10 09:34:20 +01:00

fixed bugs, implemented brain rendering and creature selection (broken for now)

This commit is contained in:
Enrico Fasoli 2015-07-06 16:40:23 +02:00
parent 75146638bf
commit 124087d381
6 changed files with 980 additions and 858 deletions

View File

@ -7,13 +7,14 @@ import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import java.util.ConcurrentModificationException;
import logic.Creature;
import logic.Element;
import logic.World;
public class Game extends ApplicationAdapter {
private static Game game;
ShapeRenderer shaper;
ShapeRenderer renderer, overlayRenderer;
private World world;
private float cameraSpeed = 15;
private BitmapFont font;
@ -22,8 +23,10 @@ public class Game extends ApplicationAdapter {
@Override
public void create() {
game = this;
shaper = new ShapeRenderer();
shaper.setAutoShapeType(true);
renderer = new ShapeRenderer();
renderer.setAutoShapeType(true);
overlayRenderer = new ShapeRenderer();
overlayRenderer.setAutoShapeType(true);
font = new BitmapFont();
Thread worldThread = new Thread(world);
worldThread.setName("Worker");
@ -42,22 +45,22 @@ public class Game extends ApplicationAdapter {
world.newGen(false);
}
if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) {
shaper.translate(-cameraSpeed, 0, 0);
renderer.translate(-cameraSpeed, 0, 0);
}
if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) {
shaper.translate(cameraSpeed, 0, 0);
renderer.translate(cameraSpeed, 0, 0);
}
if (Gdx.input.isKeyPressed(Input.Keys.UP)) {
shaper.translate(0, -cameraSpeed, 0);
renderer.translate(0, -cameraSpeed, 0);
}
if (Gdx.input.isKeyPressed(Input.Keys.DOWN)) {
shaper.translate(0, cameraSpeed, 0);
renderer.translate(0, cameraSpeed, 0);
}
if (Gdx.input.isKeyJustPressed(Input.Keys.PLUS)) {
shaper.scale(0.5f, 0.5f, 1);
renderer.scale(0.5f, 0.5f, 1);
}
if (Gdx.input.isKeyJustPressed(Input.Keys.MINUS)) {
shaper.scale(1.5f, 1.5f, 1);
renderer.scale(1.5f, 1.5f, 1);
}
if (Gdx.input.isKeyJustPressed(Input.Keys.P)) {
paused = !paused;
@ -69,15 +72,23 @@ public class Game extends ApplicationAdapter {
world.setFpsLimit(60);
}
}
if (Gdx.input.isButtonPressed(Input.Buttons.RIGHT)) {
renderer.translate(Gdx.input.getDeltaX(), Gdx.input.getDeltaY() * -1, 0);
}
/*
// Broken for now
if(Gdx.input.isButtonPressed(Input.Buttons.LEFT)){
// TODO: project coordinates to world
world.selectCreatureAt(Gdx.input.getX(), Gdx.input.getY());
}*/
// Draw
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
shaper.setColor(1, 1, 1, 1);
shaper.begin(ShapeRenderer.ShapeType.Line);
renderer.begin(ShapeRenderer.ShapeType.Line);
try {
for (Element e : world.getElements()) {
try {
e.render(shaper);
e.render(renderer);
} catch (ArrayIndexOutOfBoundsException ex) {
// No idea why it happens, but it's rendering so meh
//Log.log(Log.ERROR, ex+"");
@ -85,10 +96,21 @@ public class Game extends ApplicationAdapter {
}
} catch (ConcurrentModificationException ex) {
}
shaper.setColor(0.3f, 0.3f, 0.3f, 1);
if (world.getSelectedCreature() != null) {
// There is a selection
Creature c = world.getSelectedCreature();
renderer.setColor(1, 1, 1, 1);
// Draw selection rectangle
renderer.rect(c.getX() - c.getSize() / 2, c.getY() - c.getSize() / 2, c.getX() + c.getSize() / 2, c.getY() + c.getSize() / 2);
// Draw brain
overlayRenderer.begin();
c.getBrain().render(overlayRenderer);
overlayRenderer.end();
}
renderer.setColor(0.3f, 0.3f, 0.3f, 1);
// draw borders
shaper.rect(0, 0, world.getWidth(), world.getHeight());
shaper.end();
renderer.rect(0, 0, world.getWidth(), world.getHeight());
renderer.end();
}
public World getWorld() {

View File

@ -24,7 +24,7 @@ public class Vegetable extends Element {
@Override
public void update() {
setSize(getSize()-decayRate);
if (getSize() <= 0) {
if (getSize() <= 2) {
Game.get().getWorld().getDeadPlants().add(this);
}
}

View File

@ -9,6 +9,7 @@ import com.mygdx.game.Game;
import com.mygdx.game.Log;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.ConcurrentModificationException;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -22,6 +23,7 @@ public class World implements Runnable {
private final int width, height, nPlants, creatPerGen;
private int generation = 1;
private int fpsLimit = 60, fps = 0;
private Creature selected;
private final ArrayList<Element> elements;
private final ArrayList<Element> toAdd;
private final ArrayList<Creature> creatures;
@ -42,6 +44,7 @@ public class World implements Runnable {
deadPlants = new ArrayList();
graveyard = new ArrayList();
fpsListeners = new ArrayList();
selected = null;
newGen(true);
}
@ -96,6 +99,10 @@ public class World implements Runnable {
}
toAdd.clear();
elements.removeAll(graveyard);
if (selected != null && graveyard.contains(selected)) {
selected = null;
Log.log(Log.INFO, "Cleared selection");
}
elements.removeAll(deadPlants);
plants.removeAll(deadPlants);
deadPlants.clear();
@ -116,6 +123,10 @@ public class World implements Runnable {
elements.removeAll(creatures);
graveyard.addAll(creatures);
creatures.clear();
if (selected != null) {
selected = null;
Log.log(Log.INFO, "Cleared selection");
}
Comparator creatureComp = new Comparator<Creature>() {
@Override
@ -212,6 +223,19 @@ public class World implements Runnable {
public abstract void fpsChanged(int newValue);
}
public void selectCreatureAt(int x, int y) {
selected = null; // Clear selection
try {
for (Creature c : creatures) {
if (c.overlaps(x, y)) {
selected = c;
Log.log(Log.INFO, "Selected a creature");
}
}
} catch (ConcurrentModificationException ex) {
}
}
private void spawnVegetable() {
spawn(false, null);
}
@ -276,4 +300,12 @@ public class World implements Runnable {
return fps;
}
public Creature getSelectedCreature() {
return selected;
}
public void selectCreature(Creature selected) {
this.selected = selected;
}
}

View File

@ -1,5 +1,6 @@
package logic.neural;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.mygdx.game.Log;
/**
@ -81,6 +82,39 @@ public class Brain {
}
}
/**
* Draw this brain's status.
*
* @param s the ShapeRenderer to use for the drawing
*/
public void render(ShapeRenderer s) {
s.set(ShapeRenderer.ShapeType.Filled);
int neuronHeight = 0;
for (Neuron[] ns : neurons) {
if (ns.length > neuronHeight) {
neuronHeight = ns.length;
}
}
s.rect(0, 0, neurons.length * 50, neuronHeight * 30);
for (int i = 0; i < neurons.length; i++) {
//s.set(ShapeRenderer.ShapeType.Line);
for (int j = 0; j < neurons[i].length; j++) {
// get neuron result first so cache system can kick in and save some calculations
float nr = neurons[i][j].compute();
// Draw neuron links
float[] links = neurons[i][j].getInputs();
for (int f = 0; f < links.length; f++) {
s.setColor(links[f], links[f], links[f], 1);
s.line(i * 50, j * 30, (i - 1) * 50, f * 30);
}
// Draw neuron
s.setColor(1 - nr, nr, 0, 1);
s.set(ShapeRenderer.ShapeType.Filled);
s.circle(i * 50, j * 30, 15);
}
}
}
/**
* Give some input to the brain
*

View File

@ -55,11 +55,12 @@ public class Neuron {
if (isInputNeuron) {
return output;
}
if(cache.hasCachedOutput()) return cache.getCachedOutput();
float a = bias * -1; // activation
for (int i = 0; i < weights.length; i++) {
if (cache.has(i)) {
try {
return cache.get(i);
a += cache.get(i);
} catch (Exception ex) {
// This should never happen
Logger.getLogger(Neuron.class.getName()).log(Level.SEVERE, null, ex);
@ -82,6 +83,23 @@ public class Neuron {
return mutatedWeights;
}
public float[] getInputs() {
float inputs[] = new float[weights.length];
for (int i = 0; i < inputs.length; i++) {
if (cache.has(i)) {
try {
inputs[i] = cache.get(i);
} catch (Exception ex) {
// Shouldnt happen
Logger.getLogger(Neuron.class.getName()).log(Level.SEVERE, null, ex);
}
} else {
inputs[i] = 0;
}
}
return inputs;
}
public void setOutput(float output) {
isInputNeuron = true;
this.output = output;

View File

@ -8,6 +8,8 @@ package logic.neural;
public class NeuronCache {
private float[] cache;
private float cachedOutput;
private boolean cachedOutputValid;
private boolean[] validity;
/**
@ -57,6 +59,18 @@ public class NeuronCache {
return validity[index];
}
public float getCachedOutput() {
return cachedOutput;
}
public boolean hasCachedOutput() {
return cachedOutputValid;
}
public void setCachedOutput(float cachedOutput) {
this.cachedOutput = cachedOutput;
}
/**
* Clears cache.
*/
@ -64,5 +78,7 @@ public class NeuronCache {
for (int i = 0; i < cache.length; i++) {
validity[i] = false;
}
cachedOutputValid = false;
cachedOutput = 0;
}
}