From 54e5dbb30f961f36bda2f1d80022a74751701db3 Mon Sep 17 00:00:00 2001 From: Enrico Fasoli Date: Thu, 2 Jul 2015 13:51:44 +0200 Subject: [PATCH] added stuffffff and genetic algo --- core/src/com/mygdx/game/Camera.java | 51 +++++++++++++++++++ core/src/com/mygdx/game/Game.java | 40 +++++++++------ core/src/logic/Creature.java | 77 ++++++++++++++++++----------- core/src/logic/Vegetable.java | 4 +- core/src/logic/World.java | 20 +++++--- core/src/logic/neural/Brain.java | 45 ++++++++++------- 6 files changed, 166 insertions(+), 71 deletions(-) create mode 100644 core/src/com/mygdx/game/Camera.java diff --git a/core/src/com/mygdx/game/Camera.java b/core/src/com/mygdx/game/Camera.java new file mode 100644 index 0000000..fd8d753 --- /dev/null +++ b/core/src/com/mygdx/game/Camera.java @@ -0,0 +1,51 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.mygdx.game; + +/** + * + * @author fazo + */ +public class Camera { + + private int x, y, speed; + + public Camera() { + x = 0; + y = 0; + speed = 5; + } + + public void translate(int deltaX, int deltaY) { + x += deltaX; + y += deltaY; + } + + public int getX() { + return x; + } + + public void setX(int x) { + this.x = x; + } + + public int getY() { + return y; + } + + public void setY(int y) { + this.y = y; + } + + public int getSpeed() { + return speed; + } + + public void setSpeed(int speed) { + this.speed = speed; + } + +} diff --git a/core/src/com/mygdx/game/Game.java b/core/src/com/mygdx/game/Game.java index b4b5ae5..6d4eec8 100644 --- a/core/src/com/mygdx/game/Game.java +++ b/core/src/com/mygdx/game/Game.java @@ -4,8 +4,6 @@ import com.badlogic.gdx.ApplicationAdapter; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; import com.badlogic.gdx.graphics.GL20; -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.glutils.ShapeRenderer; import logic.Element; import logic.World; @@ -13,39 +11,49 @@ import logic.World; public class Game extends ApplicationAdapter { private static Game game; - SpriteBatch batch; ShapeRenderer shaper; - Texture img; + private Camera camera; private World world; @Override public void create() { game = this; - batch = new SpriteBatch(); - img = new Texture("badlogic.jpg"); - world = new World(640, 480); + world = new World(1920, 1080); shaper = new ShapeRenderer(); + camera = new Camera(); //shaper.setAutoShapeType(true); } @Override public void render() { - // Input - if(Gdx.input.isKeyJustPressed(Input.Keys.SPACE)){ + // Controls + if (Gdx.input.isKeyJustPressed(Input.Keys.SPACE)) { world.newGen(false); } + if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) { + camera.translate(-camera.getSpeed(), 0); + } + if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) { + camera.translate(1+camera.getSpeed(), 0); + } + if (Gdx.input.isKeyPressed(Input.Keys.UP)) { + camera.translate(0, -camera.getSpeed()); + } + if (Gdx.input.isKeyPressed(Input.Keys.DOWN)) { + camera.translate(0, camera.getSpeed()); + } // Update world.update(); // Draw Gdx.gl.glClearColor(0, 0, 0, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); - /*batch.begin(); - batch.draw(img, 0, 0); - batch.end();*/ shaper.setColor(1, 1, 1, 1); shaper.begin(ShapeRenderer.ShapeType.Line); - //shaper.circle(640, 480, 100); - for(Element e: world.getElements()) e.render(shaper); + for (Element e : world.getElements()) { + e.render(shaper); + } + shaper.setColor(0.3f, 0.3f, 0.3f, 1); + shaper.rect(camera.getX(), camera.getY(), world.getWidth(), world.getHeight()); shaper.end(); } @@ -53,6 +61,10 @@ public class Game extends ApplicationAdapter { return world; } + public Camera getCamera() { + return camera; + } + public static Game get() { return game; } diff --git a/core/src/logic/Creature.java b/core/src/logic/Creature.java index a53e52d..ee54bcd 100644 --- a/core/src/logic/Creature.java +++ b/core/src/logic/Creature.java @@ -3,6 +3,8 @@ package logic; import com.badlogic.gdx.graphics.glutils.ShapeRenderer; import com.mygdx.game.Game; import com.mygdx.game.Log; +import java.util.logging.Level; +import java.util.logging.Logger; import logic.neural.Brain; /** @@ -16,8 +18,8 @@ public class Creature extends Element { public static final float max_speed = 3; private Brain brain; - private float dir, speed, sightRange, fov, fitness, rotSpeed; - private float hp; + private float dir, hp, speed, sightRange, fov, fitness, rotSpeed; + private boolean eating = false; private Sight sight; public Creature(float x, float y) { @@ -29,7 +31,7 @@ public class Creature extends Element { sightRange = 60; fov = (float) Math.PI / 1.5f; fitness = 0; - brain = new Brain(3, 2, 2, 8); + brain = new Brain(4, 3, 1, 6); } @Override @@ -48,12 +50,18 @@ public class Creature extends Element { // apply speed float xMul = (float) Math.cos(dir), yMul = (float) Math.sin(dir); move(xMul * speed, yMul * speed); - if(getX() < 0) setX(0); - if(getY() < 0) setX(0); - if(getX() > Game.get().getWorld().getWidth()) - setX(Game.get().getWorld().getWidth()); - if(getY() > Game.get().getWorld().getHeight()) - setY(Game.get().getWorld().getHeight()); + if (getX() < 0) { + setX(Game.get().getWorld().getWidth()+getX()); + } + if (getY() < 0) { + setX(Game.get().getWorld().getHeight()+getY()); + } + if (getX() > Game.get().getWorld().getWidth()) { + setX(getX()-Game.get().getWorld().getWidth()); + } + if (getY() > Game.get().getWorld().getHeight()) { + setY(getY()-Game.get().getWorld().getHeight()); + } dir += rotSpeed; // try eating eat(); @@ -66,29 +74,36 @@ public class Creature extends Element { } sight = look(); // take a look // feed data to brain - float[] values = new float[3]; - // 0: type of sight + float[] values = new float[4]; + // 0: see food // 1: distance // 2: angle - if (sight == null) { + // 3: food sensor + if (sight == null || sight.getElement() == null) { values[0] = 0; - values[1] = 1; + values[1] = 0; values[2] = 0; - } else if (sight.getElement() instanceof Creature) { - values[0] = 1; + } else if (sight.getElement() instanceof Vegetable) { + values[1] = 1; values[1] = sight.getDistance() / sightRange; values[2] = sight.getAngle(); } else { - values[0] = 0.5f; + values[0] = 0f; values[1] = sight.getDistance() / sightRange; values[2] = sight.getAngle(); } - brain.input(values); + values[3] = eating ? 1 : 0; + try { + brain.input(values); + } catch (Exception ex) { + // Should not happen + Logger.getLogger(Creature.class.getName()).log(Level.SEVERE, null, ex); + } // compute behavior float[] actions = brain.compute(); - Log.log(Log.DEBUG,"Accel: " + actions[0] + " Rot: " + actions[1]); - speed = actions[0]*max_speed; - rotSpeed = actions[1]/10; + Log.log(Log.DEBUG, "Accel: " + actions[0] + " RotClock: " + actions[1] + " RotAntiClock: " + actions[2]); + speed = actions[0] * max_speed; + rotSpeed = actions[1] - actions[2]; } public void setHp(float hp) { @@ -99,25 +114,24 @@ public class Creature extends Element { public void render(ShapeRenderer s) { // Body s.setColor(1 - (hp / 100), hp / 100, 0, 1); - s.circle(getX(), getY(), getSize()); + s.circle(getX() + Game.get().getCamera().getX(), getY() + Game.get().getCamera().getY(), getSize()); // Eye double relX = Math.cos(dir) * getSize(), relY = Math.sin(dir) * getSize(); + s.setColor(1, 1, 1, 1); if (sight != null) { - float c = sight.getDistance() / sightRange*2 + sightRange; + float c = sight.getDistance() / sightRange * 2 + sightRange; if (sight.getElement() instanceof Creature) { s.setColor(c, 0, 0, 1); } else if (sight.getElement() instanceof Vegetable) { s.setColor(0, c, 0, 1); - } else { - s.setColor(1, 1, 1, 1); } } - s.circle((float) relX + getX(), (float) relY + getY(), 3); + s.circle((float) relX + getX() + Game.get().getCamera().getX(), (float) relY + getY() + Game.get().getCamera().getY(), 3); //FOV float degrees = fov * 180f / (float) Math.PI; float orient = dir * 180f / (float) Math.PI - degrees / 2; s.setColor(0.3f, 0.3f, 0.3f, 1); - s.arc((float) relX + getX(), (float) relY + getY(), sightRange, orient, degrees); + s.arc((float) relX + getX() + Game.get().getCamera().getX(), (float) relY + getY() + Game.get().getCamera().getY(), sightRange, orient, degrees); } public Sight look() { @@ -153,9 +167,12 @@ public class Creature extends Element { } public void eat() { - for (Element e : Game.get().getWorld().getElements()) { - if (e instanceof Vegetable && overlaps(e)) { + eating = false; + for (Element e : Game.get().getWorld().getPlants()) { + if (overlaps(e)) { + eating = true; e.setSize(e.getSize() - 0.1f); + if(e.getSize() == 0) e.setSize(0); hp++; fitness++; if (hp > 100) { @@ -177,9 +194,9 @@ public class Creature extends Element { return fitness; } - public void reset(){ + public void reset() { fitness = 0; hp = 100; } - + } diff --git a/core/src/logic/Vegetable.java b/core/src/logic/Vegetable.java index 38c3044..5f58312 100644 --- a/core/src/logic/Vegetable.java +++ b/core/src/logic/Vegetable.java @@ -23,7 +23,7 @@ public class Vegetable extends Element { @Override public void update() { - if(getSize() < 0){ + if (getSize() <= 0) { Game.get().getWorld().getDeadPlants().add(this); } } @@ -31,6 +31,6 @@ public class Vegetable extends Element { @Override public void render(ShapeRenderer s) { s.setColor(1, 1, 1, 1); - s.circle(getX(), getY(), getSize()); + s.circle(getX() + Game.get().getCamera().getX(), getY() + Game.get().getCamera().getY(), getSize()); } } diff --git a/core/src/logic/World.java b/core/src/logic/World.java index 0ad7cbf..87c0251 100644 --- a/core/src/logic/World.java +++ b/core/src/logic/World.java @@ -41,16 +41,16 @@ public class World { elements.removeAll(graveyard); elements.removeAll(deadPlants); plants.removeAll(deadPlants); - creatures.removeAll(graveyard); deadPlants.clear(); + creatures.removeAll(graveyard); if (creatures.isEmpty()) { // All dead, next gen newGen(false); } - while (plants.size() < 50) { + while (plants.size() < (width*height)/5000) { spawnVegetable(); } - for (Creature e : creatures) { + for (Element e : elements) { e.update(); } } @@ -63,7 +63,7 @@ public class World { @Override public int compare(Creature t, Creature t1) { // put the highest fitness first (sort in reverse) - return (int) (t1.getFitness() - t.getFitness() ); + return (int) (t1.getFitness() - t.getFitness()); /*if (t.getFitness() < t1.getFitness()) { return -1; } else if (t.getFitness() > t1.getFitness()) { @@ -132,7 +132,7 @@ public class World { } } while (overlaps); if (isCreature) { - Log.log(Log.INFO, "New Creat: " + x + " " + y); + Log.log(Log.DEBUG, "New Creat: " + x + " " + y); Creature c = new Creature(x, y); if (brainMap != null) { c.getBrain().remap(brainMap); @@ -140,7 +140,7 @@ public class World { elements.add(c); creatures.add(c); } else { - Log.log(Log.INFO, "New Veg: " + x + " " + y); + Log.log(Log.DEBUG, "New Veg: " + x + " " + y); Vegetable v = new Vegetable(x, y); elements.add(v); plants.add(v); @@ -179,4 +179,12 @@ public class World { return deadPlants; } + public ArrayList getCreatures() { + return creatures; + } + + public ArrayList getPlants() { + return plants; + } + } diff --git a/core/src/logic/neural/Brain.java b/core/src/logic/neural/Brain.java index 1cbffd2..43e08cc 100644 --- a/core/src/logic/neural/Brain.java +++ b/core/src/logic/neural/Brain.java @@ -57,10 +57,10 @@ public class Brain { for (int i = 0; i < brainMap.length; i++) { // for each layer for (int j = 0; j < brainMap[i].length; j++) { // for each neuron // skip input layer - if (neurons[i+1][j] == null) { - neurons[i+1][j] = new Neuron(j, bias, this, brainMap[i][j]); + if (neurons[i + 1][j] == null) { + neurons[i + 1][j] = new Neuron(j, bias, this, brainMap[i][j]); } else { - neurons[i+1][j].setWeights(brainMap[i][j]); + neurons[i + 1][j].setWeights(brainMap[i][j]); } } } @@ -86,8 +86,13 @@ public class Brain { * * @param values the array of input. Its length must match the number of * input neurons of this brain + * @throws Exception if the number of inputs given differs from the number + * of input neurons of this brain */ - public void input(float[] values) { + public void input(float[] values) throws Exception { + if (values.length != neurons[0].length) { + throw new Exception("Not enough or too many inputs"); + } for (int i = 0; i < values.length; i++) { neurons[0][i].setOutput(values[i]); } @@ -114,8 +119,10 @@ public class Brain { * * @param values * @return the results of the neural network + * @throws Exception if the number of inputs given differs from the number + * of input neurons of this brain */ - public float[] compute(float[] values) { + public float[] compute(float[] values) throws Exception { input(values); return compute(); } @@ -127,13 +134,13 @@ public class Brain { * mind */ public float[][][] getMap() { - float[][][] res = new float[neurons.length-1][][]; + float[][][] res = new float[neurons.length - 1][][]; for (int i = 1; i < neurons.length; i++) // layers (skip input layer) { - res[i-1] = new float[neurons[i].length][]; + res[i - 1] = new float[neurons[i].length][]; for (int j = 0; j < neurons[i].length; j++) // neurons per layer { - res[i-1][j] = neurons[i][j].getWeights(); + res[i - 1][j] = neurons[i][j].getWeights(); } } return res; @@ -146,27 +153,27 @@ public class Brain { * @return a mutated brain map of this brain's mind */ public float[][][] getMutatedMap(float mutationFactor) { - float[][][] res = new float[neurons.length-1][][]; + float[][][] res = new float[neurons.length - 1][][]; for (int i = 1; i < neurons.length; i++) // layers (skip input layer) { - res[i-1] = new float[neurons[i].length][]; + res[i - 1] = new float[neurons[i].length][]; for (int j = 0; j < neurons[i].length; j++) // neurons per layer { - res[i-1][j] = neurons[i][j].mutate(mutationFactor); + res[i - 1][j] = neurons[i][j].mutate(mutationFactor); } } return res; } public float[][][] breed(float[][][] map) throws Exception { - float[][][] res = new float[neurons.length-1][][]; - if (map.length != neurons.length-1) { + float[][][] res = new float[neurons.length - 1][][]; + if (map.length != neurons.length - 1) { throw new Exception("incompatible brains"); } for (int i = 1; i < neurons.length; i++) // layers (skip input layer) { - res[i-1] = new float[neurons[i].length][]; - if (map[i-1].length != neurons[i].length) { + res[i - 1] = new float[neurons[i].length][]; + if (map[i - 1].length != neurons[i].length) { throw new Exception("incompatible brains"); } for (int j = 0; j < neurons[i].length; j++) // neurons per layer @@ -174,17 +181,17 @@ public class Brain { // j = 8 not valid for neurons[i][j]. investigate why. //System.out.println(i+" "+j+" | "+neurons[i].length+" "+res[i-1].length+" "+neurons[i][j].getWeights().length); //System.out.println(neurons[i].length +" has to be > "+j); - res[i-1][j] = new float[neurons[i][j].getWeights().length]; - if (map[i-1][j].length != neurons[i][j].getWeights().length) { + res[i - 1][j] = new float[neurons[i][j].getWeights().length]; + if (map[i - 1][j].length != neurons[i][j].getWeights().length) { throw new Exception("incompatible brains"); } for (int z = 0; z < neurons[i][j].getWeights().length; z++) // each weight { // Combine the two weights if (Math.random() < 0.5) { - res[i-1][j][z] = map[i-1][j][z]; + res[i - 1][j][z] = map[i - 1][j][z]; } else { - res[i-1][j][z] = neurons[i][j].getWeights()[z]; + res[i - 1][j][z] = neurons[i][j].getWeights()[z]; } } }