From ac475b18c4927b0c87995bdd80dad8b0da3aeae2 Mon Sep 17 00:00:00 2001 From: Enrico Fasoli Date: Fri, 3 Jul 2015 00:14:40 +0200 Subject: [PATCH] many changes related to carnivores --- core/src/logic/Creature.java | 268 ++++++++++++++++++++--------------- core/src/logic/World.java | 2 +- 2 files changed, 157 insertions(+), 113 deletions(-) diff --git a/core/src/logic/Creature.java b/core/src/logic/Creature.java index b86064b..b252c6d 100644 --- a/core/src/logic/Creature.java +++ b/core/src/logic/Creature.java @@ -12,47 +12,121 @@ import logic.neural.Brain; * * @author fazo */ -public class Creature extends Element { +public class Creature extends Element implements Runnable { public static final int default_radius = 20; - public static final float max_speed = 3; + public static final float max_speed = 3, max_rot_speed = 0.05f; private Brain brain; - private float dir, hp, speed, sightRange, fov, fitness, rotSpeed, beak; + private float dir, hp, prevHp, speed, sightRange, fov, fitness, rotSpeed, beak; private boolean eating = false, killing = false; - private Sight sight; + private Sight[] sights; public Creature(float x, float y) { super(x, y, default_radius); dir = (float) (Math.random() * 2 * Math.PI); hp = 100; - speed = 0;//(float) Math.random() * 3; - rotSpeed = 0;//(float) Math.random() - 0.5f; - sightRange = 100; - fov = (float) Math.PI / 2.5f; + prevHp = 100; + speed = 0; + rotSpeed = 0; + sightRange = 350; + fov = (float) Math.PI / 2f; fitness = 0; - brain = new Brain(6, 5, 2, 10); + brain = new Brain(10, 5, 2, 10); + } + + @Override + public void run() { + update(); } @Override public void update() { // apply hunger - hp -= 0.5f; + hp -= 0.3f; + prevHp = hp; if (hp < 0) { // Dead Game.get().getWorld().getGraveyard().add(this); - Vegetable carcass = new Vegetable(getX(), getY()); - carcass.setSize(getSize()); - //carcass.setDecayRate(0.01f); - Game.get().getWorld().add(carcass); + /*Vegetable carcass = new Vegetable(getX(), getY()); + carcass.setSize(getSize()); + carcass.setDecayRate(0.01f); + Game.get().getWorld().add(carcass);*/ return; } + // take a look + sights = interactWithWorld(); + // FEED DATA TO BRAIN + // Input Neurons: + // 0: sight: see food? + // 1: sight(veg): distance + // 2: sight(veg): angle + // 3: sight(veg): size + // 4: sight(creat): see creat? + // 5: sight(creat): distance + // 6: sight(creat): angle + // 7: sight(creat): hunger + // 8: food sensor + // 9: pain sensor + float[] values = new float[brain.getNeurons()[0].length]; + for (int i = 0; i < 2; i++) { + if (sights[i] == null || sights[i].getElement() == null) { + // See nothing + values[0 + 4 * i] = 0; + values[1 + 4 * i] = 0; + values[2 + 4 * i] = 0; + values[3 + 4 * i] = 0; + values[4 + 4 * i] = 0; + } else { + // See something + values[2 + 4 * i] = sights[i].getDistance() / sightRange; + values[3 + 4 * i] = sights[i].getAngle(); + if (sights[i].getElement() instanceof Vegetable) { + values[0 + 4 * i] = 1f; + values[1 + 4 * i] = 0; + values[4 + 4 * i] = sights[i].getElement().getSize() / default_radius; + } else { + values[0 + 4 * i] = 0f; + values[1 + 4 * i] = 1f; + values[4 + 4 * i] = 100 - ((Creature) sights[i].getElement()).getHp() / 100; + } + } + } + values[8] = eating || killing ? 1 : 0; + values[9] = prevHp > hp ? 1 : 0; + // Compute brain + float[] actions = null; + try { + actions = brain.compute(values); + } catch (Exception ex) { + // Should not happen + Logger.getLogger(Creature.class.getName()).log(Level.SEVERE, null, ex); + } + 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]) / 3; + /*if (rotSpeed > max_rot_speed) { + rotSpeed = max_rot_speed; + } + if (rotSpeed < -max_rot_speed) { + rotSpeed = -max_rot_speed; + }*/ + beak = actions[3]; + if (beak > default_radius * 3) { + beak = default_radius * 3; + } else if (beak < 0) { + beak = 0; + } + applyToWorld(); + } + + public void applyToWorld() { if (speed > max_speed) { speed = max_speed; } if (speed < -max_speed) { speed = -max_speed; } - // apply speed + // apply speed and rot speed float xMul = (float) Math.cos(dir), yMul = (float) Math.sin(dir); move(xMul * speed, yMul * speed); if (getX() < 0) { @@ -68,93 +142,35 @@ public class Creature extends Element { setY(getY() - Game.get().getWorld().getHeight()); } dir += rotSpeed; - // try eating - eat(); - //fitness -= 0.1; if (dir > 2 * Math.PI) { dir -= 2 * Math.PI; } if (dir < 0) { dir += 2 * Math.PI; } - sight = lookAndHit(); // take a look - // feed data to brain - float[] values = new float[brain.getNeurons()[0].length]; - // 0: sight: see food? - // 1: sight: see creat? - // 2: sight: distance - // 3: sight: angle - // 4: sight: size for vegetables, hunger for creatures - // 5: food sensor - if (sight == null || sight.getElement() == null) { - // See nothing - values[0] = 0; - values[1] = 0; - values[2] = 0; - values[3] = 0; - values[4] = 0; - } else { - // See something - values[2] = sight.getDistance() / sightRange; - values[3] = sight.getAngle(); - if (sight.getElement() instanceof Vegetable) { - values[0] = 1f; - values[1] = 0; - values[4] = sight.getElement().getSize() / default_radius; - } else { - values[0] = 0f; - values[1] = 1f; - values[4] = 100 - ((Creature) sight.getElement()).getHp() / 100; - } - } - values[5] = eating ? 1 : 0; - // compute behavior - float[] actions = null; - try { - actions = brain.compute(values); - } catch (Exception ex) { - // Should not happen - Logger.getLogger(Creature.class.getName()).log(Level.SEVERE, null, ex); - } - 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]; - beak = actions[3]; - if (beak > 20) { - beak = 20; - } else if (beak < 0) { - beak = 0; - } } @Override public void render(ShapeRenderer s) { + if (prevHp > hp || killing) { + // Kill/BeKilled mark + s.set(ShapeRenderer.ShapeType.Filled); + s.setColor(prevHp > hp ? 1 : 0, killing ? 1 : 0, 0, 1); + s.circle(getX(), getY(), default_radius); + s.set(ShapeRenderer.ShapeType.Line); + } // Body s.setColor(1 - (hp / 100), hp / 100, 0, 1); s.circle(getX(), getY(), getSize()); // Eye double relX = Math.cos(dir), relY = Math.sin(dir); - s.setColor(1, 1, 1, 1); - if (sight != null) { - 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); - } - } - // Eye + float c0 = sights[0] != null ? sights[0].getDistance() / sightRange * 2 + sightRange : 1; + float c1 = sights[1] != null ? sights[1].getDistance() / sightRange * 2 + sightRange : 1; + s.setColor(c0, c1, sights[0] == null && sights[1] == null ? 1 : 0, 1); s.circle((float) relX * getSize() * 0.6f + getX(), (float) relY * getSize() * 0.6f + getY(), 3); - if (killing) { - // Evil mark - s.set(ShapeRenderer.ShapeType.Filled); - s.setColor(1, 0, 0, 1); - s.circle(getX(), getY(), 5); - } - s.set(ShapeRenderer.ShapeType.Line); // Beak - s.setColor(1, 1, 0, beak / 20); - s.line((float) (relX * getSize() * 0.8f + getX()), (float) (relY * getSize() * 0.8f + getY()), (float) (relX * getSize() * (1.5f + beak / 20) + getX()), (float) (relY * getSize() * (1.5f + beak / 20) + getY())); + s.setColor(beak / default_radius * 3, 1 - beak / default_radius * 3, 0, 1); + s.line((float) (relX * getSize() * 0.8f + getX()), (float) (relY * getSize() * 0.8f + getY()), (float) (relX * getSize() * (1.5f + beak / default_radius * 3) + getX()), (float) (relY * getSize() * (1.5f + beak / default_radius * 3) + getY())); //FOV float degrees = fov * 180f / (float) Math.PI; float orient = dir * 180f / (float) Math.PI - degrees / 2; @@ -162,11 +178,57 @@ public class Creature extends Element { s.arc((float) relX * getSize() + getX(), (float) relY * getSize() + getY(), sightRange, orient, degrees); } - public Sight lookAndHit() { + public Sight[] interactWithWorld() { + eating = false; + Sight[] sights = new Sight[2]; + // Vegetables Element seen = null; float dist = 0, angle = 0, ndir = dir - (float) Math.PI; + for (Vegetable 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 can eat + if (overlaps(e)) { + eating = true; + if (hp < 100) { + e.setSize(e.getSize() - 0.5f); + } + if (e.getSize() <= 0) { + e.setSize(0); + } + hp++; + fitness++; + if (hp > 100) { + hp = 100; + } + } + } + if (seen != null) { + sights[0] = new Sight(seen, dist, angle); + } else { + sights[0] = null; + } + // Creatures + seen = null; + dist = 0; + angle = 0; + ndir = dir - (float) Math.PI; killing = false; - for (Element e : Game.get().getWorld().getElements()) { + for (Creature e : Game.get().getWorld().getCreatures()) { if (e == this) { continue; } @@ -187,42 +249,24 @@ public class Creature extends Element { //Log.log(Log.DEBUG,"RelAngle "+relAngle+" Dir "+ndir); } // Check if attackable - if (e instanceof Creature && beak > 5 && tempDist < beak * 1.5f && Math.abs(relAngle - ndir) < (float) Math.PI / 10f) { + if (tempDist < beak && Math.abs(relAngle - ndir) < fov / 4) { // Attacking! - hp++; - fitness++; + hp += beak / default_radius * 3; + fitness += 10; if (hp > 100) { hp = 100; } killing = true; - Creature c = (Creature) e; - c.setHp(c.getHp() - 0.2f); + e.setHp(e.getHp() - beak / default_radius * 3); } } if (seen != null) { - return new Sight(seen, dist, angle); + sights[1] = new Sight(seen, dist, angle); } else { - return null; - } - } - - public void eat() { - 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) { - hp = 100; - } - } + sights[1] = null; } + return sights; } public Brain getBrain() { diff --git a/core/src/logic/World.java b/core/src/logic/World.java index 514ee09..db69618 100644 --- a/core/src/logic/World.java +++ b/core/src/logic/World.java @@ -32,7 +32,7 @@ public class World { elements = new ArrayList(); creatures = new ArrayList(); toAdd = new ArrayList(); - creatPerGen = Math.min(Math.round(width * height / 20000), 50); + creatPerGen = 50; nPlants = Math.round(width * height / 5500); plants = new ArrayList(); deadPlants = new ArrayList();