diff --git a/core/src/logic/World.java b/core/src/logic/World.java index 1d8e442..356210e 100644 --- a/core/src/logic/World.java +++ b/core/src/logic/World.java @@ -13,6 +13,8 @@ import java.util.HashMap; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; +import logic.creatures.Eye; +import logic.creatures.Movement; import logic.creatures.Torso; import logic.neural.Brain; @@ -283,9 +285,9 @@ public class World implements Runnable { Creature.leaveCorpses = options.get("enable_corpses") > 0; Torso.default_radius = Math.round(options.get("creature_radius")); Torso.max_hp = Math.round(options.get("creature_max_hp")); - Creature.max_speed = options.get("creature_max_speed"); - Creature.fov = options.get("creature_fov"); - Creature.sightRange = options.get("creature_sight_range"); + Movement.max_speed = options.get("creature_max_speed"); + Eye.fov = options.get("creature_fov"); + Eye.sightRange = options.get("creature_sight_range"); Torso.hpDecay = options.get("creature_hp_decay"); Creature.hpForAttacking = options.get("creature_hp_for_attacking"); Creature.hpForEatingPlants = options.get("creature_hp_for_eating_plants"); diff --git a/core/src/logic/creatures/Beak.java b/core/src/logic/creatures/Beak.java index 50b00fa..576090a 100644 --- a/core/src/logic/creatures/Beak.java +++ b/core/src/logic/creatures/Beak.java @@ -6,9 +6,7 @@ package logic.creatures; import com.badlogic.gdx.graphics.glutils.ShapeRenderer; -import static logic.creatures.Creature.fov; -import static logic.creatures.Creature.hpForAttacking; -import static logic.creatures.Creature.pointsForAttacking; +import logic.Element; /** * @@ -17,28 +15,49 @@ import static logic.creatures.Creature.pointsForAttacking; public class Beak extends BodyPart { private float length; + private boolean attacking = false; public static float max_length = Torso.default_radius / 4, min_length = max_length / 4; public Beak(float angle, Creature creature) { - super(1, 1, angle, 1, creature); + super(3, 1, angle, 1, creature); length = min_length; } @Override - public float[] update() { - return new float[]{}; + public float[] act() { + float r[] = new float[]{ + length / max_length, // current beak length + length > max_length / 2 ? 1f : 0f, // wether the beak is doing damage + attacking ? 1f : 0f + }; + attacking = false; + return r; } - + + @Override + public void interactWithElement(Element e, float distance, float relAngle) { + if (e instanceof Creature && distance < length && length > max_length / 2 && Math.abs(relAngle) < 0.3f) { + // Can attack + creature.praise(Creature.pointsForAttacking); + creature.getTorso().heal(length*Creature.hpForAttacking/2); + ((Creature) e).getTorso().heal(-length*Creature.hpForAttacking/2); + attacking = true; + } + } + @Override protected void draw(ShapeRenderer s, float relX, float relY) { s.set(ShapeRenderer.ShapeType.Line); // Draw Beak s.setColor(getLength() / Beak.max_length, 1 - getLength() / Beak.max_length, 0, 1); s.line((float) (relX + creature.getX()), (float) (relY + creature.getY()), (float) (relX * (1.5f + getLength() / Beak.max_length) + creature.getX()), (float) (relY * (1.5f + getLength() / Beak.max_length) + creature.getY())); + if (attacking) { + s.circle((float) (relX * (1.5f + getLength() / Beak.max_length) + creature.getX()), (float) (relY * (1.5f + getLength() / Beak.max_length) + creature.getY()), 0.3f); + } } @Override - protected void useOutputs(float[] outputs) { + public void readFromBrain(float[] outputs) { length = outputs[0] * max_length; if (length > max_length) { length = max_length; diff --git a/core/src/logic/creatures/BodyPart.java b/core/src/logic/creatures/BodyPart.java index 3a9fbe1..3d8d547 100644 --- a/core/src/logic/creatures/BodyPart.java +++ b/core/src/logic/creatures/BodyPart.java @@ -1,7 +1,7 @@ package logic.creatures; import com.badlogic.gdx.graphics.glutils.ShapeRenderer; -import com.mygdx.game.Log; +import logic.Element; /** * @@ -9,7 +9,7 @@ import com.mygdx.game.Log; */ public abstract class BodyPart { - protected int inputNeuronsUsed, outputNeuronsUsed; + protected int inputNeuronsUsed; protected float angle, distFromCenter; protected float outputs[]; protected Creature creature; @@ -22,7 +22,29 @@ public abstract class BodyPart { outputs = new float[outputNeuronsUsed]; } - public abstract float[] update(); + /** + * Prepare data to be sent to the brain + * + * @return the data to send to the brain, must be inputNeuronsUsed long + */ + public abstract float[] act(); + + /** + * Interact with another element + * + * @param e the Element (creature or plant) + * @param distance the distance + * @param relAngle the relative angle + */ + public abstract void interactWithElement(Element e, float distance, float relAngle); + + /** + * Receive some data from the brain + * + * @param data the data received from the brain, will be outputNeuronsUsed + * long + */ + public abstract void readFromBrain(float data[]); protected abstract void draw(ShapeRenderer s, float relX, float relY); @@ -31,15 +53,13 @@ public abstract class BodyPart { double relY = Math.sin(creature.getDirection() + angle) * creature.getTorso().getRadius() * distFromCenter; draw(s, (float) relX, (float) relY); } - - protected abstract void useOutputs(float outputs[]); public int getInputNeuronsUsed() { return inputNeuronsUsed; } public int getOutputNeuronsUsed() { - return outputNeuronsUsed; + return outputs.length; } public float getAngle() { diff --git a/core/src/logic/creatures/Creature.java b/core/src/logic/creatures/Creature.java index a7a0aaa..0a7a86a 100644 --- a/core/src/logic/creatures/Creature.java +++ b/core/src/logic/creatures/Creature.java @@ -2,7 +2,6 @@ package logic.creatures; import com.badlogic.gdx.graphics.glutils.ShapeRenderer; import com.mygdx.game.Game; -import com.mygdx.game.Log; import java.util.ArrayList; import java.util.logging.Level; import java.util.logging.Logger; @@ -18,15 +17,15 @@ import logic.neural.Brain; public class Creature extends Element implements Runnable { public static int brain_hidden_layers = 2, brain_hidden_neurons = 10; - public static float max_speed = 3, fov, sightRange, corpseDecayRate = 0, pointsForEatingPlants = 1f, pointsForAttacking = 2f, hpForAttacking = 1f, hpForEatingPlants = 1f; + public static float corpseDecayRate = 0, pointsForEatingPlants = 1f, pointsForAttacking = 2f, hpForAttacking = 1f, hpForEatingPlants = 1f; public static boolean leaveCorpses = false; private final Brain brain; private final Torso torso; private final Beak beak; private final ArrayList bodyParts; - private float dir, speed, fitness, rotSpeed; - private boolean eating = false, killing = false, workerDone = false, killWorker = false; + private float dir, fitness = 0; + private boolean workerDone = false, killWorker = false; private Sight[] sights; private Thread workerThread; @@ -39,13 +38,12 @@ public class Creature extends Element implements Runnable { public Creature(float x, float y) { super(x, y, Torso.default_radius); dir = (float) (Math.random() * 2 * Math.PI); - speed = 0; - rotSpeed = 0; - fitness = 0; bodyParts = new ArrayList(); bodyParts.add(torso = new Torso(this)); bodyParts.add(beak = new Beak(0, this)); - brain = new Brain(9, 5, brain_hidden_layers, brain_hidden_neurons); + bodyParts.add(new Eye(5, 0, this)); + bodyParts.add(new Movement(this)); + brain = new Brain(howManyInputNeurons(), howManyOutputNeurons(), brain_hidden_layers, brain_hidden_neurons); sights = new Sight[2]; } @@ -80,80 +78,17 @@ public class Creature extends Element implements Runnable { killWorker = true; return; } - if (speed > max_speed) { - speed = max_speed; - } - if (speed < -max_speed) { - speed = -max_speed; - } - // apply speed - float xMul = (float) Math.cos(dir), yMul = (float) Math.sin(dir); - move(xMul * speed, yMul * speed); - if (getX() < 0) { - setX(Game.get().getWorld().getWidth() + getX()); - } else if (getX() > Game.get().getWorld().getWidth()) { - setX(getX() - Game.get().getWorld().getWidth()); - } - if (getY() < 0) { - setY(Game.get().getWorld().getHeight() + getY()); - } else if (getY() > Game.get().getWorld().getHeight()) { - setY(getY() - Game.get().getWorld().getHeight()); - } - dir += rotSpeed; - //fitness -= 0.1; - if (dir > 2 * Math.PI) { - dir -= 2 * Math.PI; - } else if (dir < 0) { - dir += 2 * Math.PI; + // collect inputs + float values[] = new float[howManyInputNeurons()]; + int i = 0; + for (BodyPart b : bodyParts) { + for (float v : b.act()) { + values[i] = v; + i++; + } } // read from sensors and interact with world - sights = interactWithWorld(); - // feed data to brain - float[] values = new float[brain.getNeurons()[0].length]; - int valueCounter = 0; - for (BodyPart b : bodyParts) { - for (float v : b.update()) { - values[valueCounter] = v; - valueCounter++; - } - } - // VIEW: PLANTS - // 0: sight(v): see food? - // 1: sight(v): distance - // 2: sight(v): angle - // 3: sight(v): size - // VIEW: CREATS - // 4: sight(c): see food? - // 5: sight(c): distance - // 6: sight(c): angle - // 8: sight(c): hunger - // 7: sight(c): beak.getLength() - // OTHER: - // 8: food sensor - int viewSensors = 4; - for (int i = 0; i < sights.length; i++) { - int offset = i * viewSensors + valueCounter; - if (sights[i] == null || sights[i].getElement() == null) { - // See nothing - values[0 + offset] = 0; - values[1 + offset] = 0; - values[2 + offset] = 0; - values[3 + offset] = 0; - } else { - // See something - values[1 + offset] = sights[i].getDistance() / sightRange; - values[2 + offset] = sights[i].getAngle(); - if (sights[i].getElement() instanceof Vegetable) { - values[0 + offset] = 1f; - values[3 + offset] = sights[i].getElement().getSize() / torso.getRadius(); - } else { - values[0 + offset] = 1f; - values[3 + offset] = Torso.max_hp - ((Creature) sights[i].getElement()).getTorso().getHp() / Torso.max_hp; - values[3 + offset] = ((Creature) sights[i].getElement()).getBeak() / Beak.max_length; - } - } - } - values[8] = eating || killing ? 1 : 0; + interactWithWorld(); // compute behavior float[] actions = null; try { @@ -162,7 +97,7 @@ public class Creature extends Element implements Runnable { // Should not happen Logger.getLogger(Creature.class.getName()).log(Level.SEVERE, null, ex); } - int i = 0; + i = 0; // Save brain outputs to body parts for (BodyPart b : bodyParts) { int n = 0; @@ -172,11 +107,8 @@ public class Creature extends Element implements Runnable { i++; n++; } - b.useOutputs(data); + b.readFromBrain(data); } - Log.log(Log.DEBUG, "Accel: " + actions[0] + " RotClock: " + actions[1] + " RotAntiClock: " + actions[2] + " Beak: " + actions[3]); - speed = (actions[0] * 2 - actions[4] / 2) * max_speed; - rotSpeed = actions[1] - actions[2]; } @Override @@ -185,124 +117,22 @@ public class Creature extends Element implements Runnable { for (BodyPart b : bodyParts) { b.render(s); } - // Prepare vision stuff - double relX = Math.cos(dir), relY = Math.sin(dir); - float c = 0; - float eyeX = (float) (relX * getSize() * 0.6f), eyeY = (float) (relY * getSize() * 0.6f); - // Draw Sight Lines - s.set(ShapeRenderer.ShapeType.Line); - if (Game.get().getWorld().getOptions().getOrDefault("draw_sight_lines", 0f) > 0) { - for (Sight sight : sights) { - if (sight != null) { - c = sight.getDistance() / sightRange * 2 + sightRange; - } else { - } - if (sight != null) { - if (sight.getElement() instanceof Creature) { - s.setColor(c, 0, 0, 1); - } else if (sight.getElement() instanceof Vegetable) { - s.setColor(0, c, 0, 1); - } - s.line(eyeX + getX(), getY() + eyeY, sight.getElement().getX(), sight.getElement().getY()); - } - } - } - // Draw eye - if (sights[0] == null && sights[1] == null) { - s.setColor(1, 1, 1, 1); - } else { - s.setColor(sights[1] == null ? 0 : 1, sights[0] == null ? 0 : 1, 0, 1); - } - s.circle(getX() + eyeX, getY() + eyeY, 3); - // Draw FOV cone - float degrees = fov * 360f / (float) Math.PI; - float orient = dir * 180f / (float) Math.PI - degrees / 2; - if (Game.get().getWorld().getOptions().getOrDefault("draw_view_cones", 0f) > 0) { - s.setColor(0.3f, 0.3f, 0.3f, 1); - s.arc((float) eyeX + getX(), (float) eyeY + getY(), sightRange, orient, degrees); - } } /** - * Store Sight information (what the creature sees) and eat/attack if - * applicable - * - * @return the sight information retrieved + * Make the body components interact with the world */ - public Sight[] interactWithWorld() { - Sight[] newSights = new Sight[2]; - // Try to see plant - Element seen = null; - float dist = 0, angle = 0, ndir = dir - (float) Math.PI; - eating = false; - for (Element e : Game.get().getWorld().getPlants()) { - float tempDist = distanceFrom(e); - if (tempDist > sightRange) { - continue; - } - //Log.log(Log.DEBUG,"TempDist "+tempDist+" SightRange "+sightRange); - float relAngle = (float) (Math.atan2(getY() - e.getY(), getX() - e.getX())); - if (tempDist < dist || seen == null) { - // Check if Visible - if (Math.abs(relAngle - ndir) < fov) { - // Visible - seen = e; - angle = relAngle - ndir; - dist = tempDist; - } - //Log.log(Log.DEBUG,"RelAngle "+relAngle+" Dir "+ndir); - } - // Check if eatable - if (tempDist < 0) { - // Eat - eating = true; - e.setSize(e.getSize() - 0.1f); - if (e.getSize() == 0) { - e.setSize(0); - } - torso.heal(hpForEatingPlants); - praise(pointsForEatingPlants); + public void interactWithWorld() { + for (Element e : Game.get().getWorld().getElements()) { + float distance = distanceFrom(e); + float angle = (float) (Math.atan2(getY() - e.getY(), getX() - e.getX())) - (dir - (float) Math.PI); + for (BodyPart b : bodyParts) { + b.interactWithElement(e, distance, angle); } } - if (seen != null) { - newSights[0] = new Sight(seen, dist, angle); - } - // Try to see creature - seen = null; - dist = 0; - angle = 0; - ndir = dir - (float) Math.PI; - killing = false; - for (Element e : Game.get().getWorld().getCreatures()) { - if (e == this) { - continue; - } - float tempDist = distanceFrom(e); - if (tempDist > sightRange) { - continue; - } - //Log.log(Log.DEBUG,"TempDist "+tempDist+" SightRange "+sightRange); - float relAngle = (float) (Math.atan2(getY() - e.getY(), getX() - e.getX())); - if (tempDist < dist || seen == null) { - // Check if Visible - float tempAngle = Math.abs(relAngle - ndir); - if (tempAngle < fov) { - // Visible - seen = e; - angle = relAngle - ndir; - dist = tempDist; - - } - //Log.log(Log.DEBUG,"RelAngle "+relAngle+" Dir "+ndir); - } - } - if (seen != null) { - newSights[1] = new Sight(seen, dist, angle); - } - return newSights; } - public int howManyInputNeurons() { + public final int howManyInputNeurons() { int n = 0; for (BodyPart b : bodyParts) { n += b.getInputNeuronsUsed(); @@ -310,7 +140,7 @@ public class Creature extends Element implements Runnable { return n; } - public int howManyOutputNeurons() { + public final int howManyOutputNeurons() { int n = 0; for (BodyPart b : bodyParts) { n += b.getOutputNeuronsUsed(); @@ -318,13 +148,22 @@ public class Creature extends Element implements Runnable { return n; } + public void rotate(float amount) { + dir += amount; + if (dir > 2 * Math.PI) { + dir -= 2 * Math.PI; + } else if (dir < 0) { + dir += 2 * Math.PI; + } + } + /** * Praise this creature by increasing fitness. Can be negative to decrease * fitness * * @param amount how much */ - private void praise(float amount) { + public void praise(float amount) { fitness += amount; } diff --git a/core/src/logic/creatures/Eye.java b/core/src/logic/creatures/Eye.java index 64e9c06..fc9fbbc 100644 --- a/core/src/logic/creatures/Eye.java +++ b/core/src/logic/creatures/Eye.java @@ -5,10 +5,102 @@ */ package logic.creatures; +import com.badlogic.gdx.graphics.glutils.ShapeRenderer; +import com.mygdx.game.Game; +import com.mygdx.game.Log; +import logic.Element; +import logic.Vegetable; + /** * * @author fazo */ -public class Eye { - +public class Eye extends BodyPart { + + private Sight sights[]; + private int seen; + public static float fov = 2, sightRange = 30; + + public Eye(int nSights, float angle, Creature creature) { + super(6 * nSights, 0, angle, 0.8f, creature); + sights = new Sight[nSights]; + seen = 0; + } + + @Override + public float[] act() { + float ret[] = new float[inputNeuronsUsed]; + int j = 0; + for (int i = 0; i < sights.length; i++) { + if (i < seen) { + // Saw something + ret[j] = 1; + ret[j + 1] = sights[i].getElement() instanceof Creature ? 1 : 0; + ret[j + 2] = sights[i].getDistance() / sightRange; + ret[j + 3] = sights[i].getAngle(); + if (sights[i].getElement() instanceof Creature) { + ret[i + 4] = ((Creature) sights[i].getElement()).getBeak() / Beak.max_length; + ret[i + 5] = ((Creature) sights[i].getElement()).getTorso().getHp() / Torso.max_hp; + } else { + ret[i + 4] = ((Vegetable) sights[i].getElement()).getSize() / Vegetable.default_radius; + ret[i + 5] = 0; + } + } else { + // Saw nothing + for (int z = 0; z < 6; z++) { + ret[j + z] = 0; + } + } + j += 6; + } + seen = 0; + sights = new Sight[sights.length]; + return ret; + } + + + @Override + public void interactWithElement(Element e, float distance, float angle) { + if (e != creature && distance < sightRange && Math.abs(angle) < fov / 2) { + if (seen < sights.length) { + sights[seen] = new Sight(e, distance, angle); + Log.log(Log.DEBUG, "Saw " + e.getClass().getName() + " at " + distance + " with relative angle " + angle); + seen++; + } + } + } + + @Override + protected void draw(ShapeRenderer s, float relX, float relY) { + // Draw eye + s.setColor(1, 1, 1, 1); + s.circle(creature.getX() + relX, creature.getY() + relY, 3); + // Draw FOV cone + float degrees = fov * 360f / (float) Math.PI; + float orient = (creature.getDirection() + angle) * 180f / (float) Math.PI - degrees / 2; + if (Game.get().getWorld().getOptions().getOrDefault("draw_view_cones", 0f) > 0) { + s.setColor(0.3f, 0.3f, 0.3f, 1); + s.arc((float) relX + creature.getX(), (float) relY + creature.getY(), sightRange, orient, degrees); + } + // Sight Lines + float c = 0; + if (Game.get().getWorld().getOptions().getOrDefault("draw_sight_lines", 0f) > 0) { + for (Sight sight : sights) { + if (sight != null) { + 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); + } + s.line(relX + creature.getX(), creature.getY() + relY, sight.getElement().getX(), sight.getElement().getY()); + } + } + } + } + + @Override + public void readFromBrain(float[] data) { + } + } diff --git a/core/src/logic/creatures/Movement.java b/core/src/logic/creatures/Movement.java new file mode 100644 index 0000000..c197469 --- /dev/null +++ b/core/src/logic/creatures/Movement.java @@ -0,0 +1,66 @@ +/* + * 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 logic.creatures; + +import com.badlogic.gdx.graphics.glutils.ShapeRenderer; +import com.mygdx.game.Game; +import com.mygdx.game.Log; +import logic.Element; + +/** + * + * @author Fazo + */ +public class Movement extends BodyPart { + + private float speed = 0, rotSpeed = 0; + public static float max_speed = 3; + + public Movement(Creature creature) { + super(0, 4, 0, 0, creature); + } + + @Override + public float[] act() { + if (speed > max_speed) { + speed = max_speed; + } + if (speed < -max_speed) { + speed = -max_speed; + } + // apply speed + float xMul = (float) Math.cos(creature.getDirection()), yMul = (float) Math.sin(creature.getDirection()); + creature.move(xMul * speed, yMul * speed); + if (creature.getX() < 0) { + creature.setX(Game.get().getWorld().getWidth() + creature.getX()); + } else if (creature.getX() > Game.get().getWorld().getWidth()) { + creature.setX(creature.getX() - Game.get().getWorld().getWidth()); + } + if (creature.getY() < 0) { + creature.setY(Game.get().getWorld().getHeight() + creature.getY()); + } else if (creature.getY() > Game.get().getWorld().getHeight()) { + creature.setY(creature.getY() - Game.get().getWorld().getHeight()); + } + creature.rotate(rotSpeed); + return new float[]{}; + } + + @Override + public void interactWithElement(Element e, float distance, float relAngle) { + } + + @Override + protected void draw(ShapeRenderer s, float relX, float relY) { + } + + @Override + public void readFromBrain(float[] data) { + Log.log(Log.DEBUG, "Fowward: " + data[0] + "Back: " + data[1] + " Rot: " + data[2] + " RotAnti: " + data[3]); + speed = (data[0] * 2 - data[1] / 2) * max_speed; + rotSpeed = data[2] - data[3]; + } + +} diff --git a/core/src/logic/creatures/Torso.java b/core/src/logic/creatures/Torso.java index 028030f..701f68a 100644 --- a/core/src/logic/creatures/Torso.java +++ b/core/src/logic/creatures/Torso.java @@ -1,6 +1,8 @@ package logic.creatures; import com.badlogic.gdx.graphics.glutils.ShapeRenderer; +import logic.Element; +import logic.Vegetable; /** * @@ -8,11 +10,12 @@ import com.badlogic.gdx.graphics.glutils.ShapeRenderer; */ public class Torso extends BodyPart { - private float hp, prevHp, radius; - public static float default_radius = 20, max_hp = 100, hpDecay = 0.5f; + private float hp, prevHp, radius, pain = 0; + public static float default_radius = 20, max_hp = 100, hpDecay = 0.5f, eatingSpeed = 0.1f; + private boolean eating = false; public Torso(Creature c) { - super(2, 0, 0, 0, c); + super(3, 0, 0, 0, c); radius = default_radius; hp = max_hp; prevHp = hp; @@ -21,31 +24,58 @@ public class Torso extends BodyPart { @Override public void draw(ShapeRenderer s, float x, float y) { s.setColor(1 - (hp / max_hp), hp / max_hp, 0, 1); - s.circle(x+creature.getX(), y+creature.getY(), radius); + s.circle(x + creature.getX(), y + creature.getY(), radius); // Draw damage/heal marks s.set(ShapeRenderer.ShapeType.Filled); if (getReceivedDamage() > 0) { // Damage mark s.setColor(1, 0, 0, 1); - } else if (getReceivedDamage() < 0) { + } else if (getReceivedDamage() < 0 || eating) { // Heal mark s.setColor(0, 1, 0, 1); } - if (getReceivedDamage() != 0) { - s.circle(x, y, 5); + if (getReceivedDamage() != 0 || eating) { + s.circle(x + creature.getX(), y + creature.getY(), 5); } } @Override - protected void useOutputs(float[] outputs) { + public float[] act() { + // apply hunger + hp -= hpDecay; + float r[] = new float[]{ + hp/max_hp, + eating ? 1f : 0f, + pain + }; + pain = 0; + prevHp = hp; + eating = false; + return r; } @Override - public float[] update() { - // apply hunger - hp -= hpDecay; - prevHp = hp; - return new float[]{}; + public void interactWithElement(Element e, float distance, float relAngle) { + if (e instanceof Vegetable && distance < 0 && hp < max_hp) { + e.setSize(e.getSize() - eatingSpeed); + if (e.getSize() == 0) { + e.setSize(0); + } + heal(Creature.hpForEatingPlants); + creature.praise(Creature.pointsForEatingPlants); + eating = true; + } + } + + @Override + public void readFromBrain(float[] data) { + if (getReceivedDamage() > 0) { + pain = -1; + } else if (getReceivedDamage() < 0) { + pain = 1; + } else { + pain = 0; + } } public boolean isAlive() {