diff --git a/core/src/logic/Creature.java b/core/src/logic/Creature.java index b86064b..0d314f0 100644 --- a/core/src/logic/Creature.java +++ b/core/src/logic/Creature.java @@ -14,18 +14,19 @@ import logic.neural.Brain; */ public class Creature extends Element { - public static final int default_radius = 20; - public static final float max_speed = 3; + public static final int default_radius = 20, maxHp = 100; + public static final float max_speed = 3, max_beak = default_radius / 4; 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; public Creature(float x, float y) { super(x, y, default_radius); dir = (float) (Math.random() * 2 * Math.PI); - hp = 100; + hp = maxHp; + prevHp = hp; speed = 0;//(float) Math.random() * 3; rotSpeed = 0;//(float) Math.random() - 0.5f; sightRange = 100; @@ -38,6 +39,7 @@ public class Creature extends Element { public void update() { // apply hunger hp -= 0.5f; + prevHp = hp; if (hp < 0) { // Dead Game.get().getWorld().getGraveyard().add(this); Vegetable carcass = new Vegetable(getX(), getY()); @@ -68,8 +70,6 @@ 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; @@ -77,7 +77,8 @@ public class Creature extends Element { if (dir < 0) { dir += 2 * Math.PI; } - sight = lookAndHit(); // take a look + // read from sensors and interact with world + sight = interactWithWorld(); // feed data to brain float[] values = new float[brain.getNeurons()[0].length]; // 0: sight: see food? @@ -104,7 +105,7 @@ public class Creature extends Element { } else { values[0] = 0f; values[1] = 1f; - values[4] = 100 - ((Creature) sight.getElement()).getHp() / 100; + values[4] = maxHp - ((Creature) sight.getElement()).getHp() / maxHp; } } values[5] = eating ? 1 : 0; @@ -119,9 +120,9 @@ public class Creature extends Element { 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; + beak = actions[3] * max_beak; + if (beak > max_beak) { + beak = max_beak; } else if (beak < 0) { beak = 0; } @@ -130,42 +131,53 @@ public class Creature extends Element { @Override public void render(ShapeRenderer s) { // Body - s.setColor(1 - (hp / 100), hp / 100, 0, 1); + s.setColor(1 - (hp / maxHp), hp / maxHp, 0, 1); s.circle(getX(), getY(), getSize()); - // Eye + // Vision double relX = Math.cos(dir), relY = Math.sin(dir); - s.setColor(1, 1, 1, 1); + float c = 0; if (sight != null) { - float c = sight.getDistance() / sightRange * 2 + sightRange; + c = sight.getDistance() / sightRange * 2 + sightRange; + } else { + s.setColor(1, 1, 1, 1); + } + float eyeX = (float) (relX * getSize() * 0.6f), eyeY = (float) (relY * getSize() * 0.6f); + if (sight != null) { + s.line(eyeX + getX(), getY() + eyeY, sight.getElement().getX(), sight.getElement().getY()); if (sight.getElement() instanceof Creature) { s.setColor(c, 0, 0, 1); } else if (sight.getElement() instanceof Vegetable) { s.setColor(0, c, 0, 1); } } - // Eye - 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.circle(getX() + eyeX, getY() + eyeY, 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 * getSize() + getX(), (float) relY * getSize() + getY(), sightRange, orient, degrees); + s.arc((float) eyeX + getX(), (float) eyeY + getY(), sightRange, orient, degrees); + if (hp < prevHp) { + // Damage mark + s.set(ShapeRenderer.ShapeType.Filled); + s.setColor(1, 0, 0, 1); + s.circle(getX(), getY(), 5); + } else if (killing || eating) { + // Heal mark + s.set(ShapeRenderer.ShapeType.Filled); + s.setColor(0, 1, 0, 1); + s.circle(getX(), getY(), 5); + } + s.set(ShapeRenderer.ShapeType.Line); + // Beak + s.setColor(beak / max_beak, 1 - beak / max_beak, 0, 1); + s.line((float) (relX * getSize() * 0.8f + getX()), (float) (relY * getSize() * 0.8f + getY()), (float) (relX * getSize() * (1.5f + beak / max_beak) + getX()), (float) (relY * getSize() * (1.5f + beak / max_beak) + getY())); } - public Sight lookAndHit() { + public Sight interactWithWorld() { Element seen = null; float dist = 0, angle = 0, ndir = dir - (float) Math.PI; killing = false; + eating = false; for (Element e : Game.get().getWorld().getElements()) { if (e == this) { continue; @@ -186,13 +198,27 @@ public class Creature extends Element { } //Log.log(Log.DEBUG,"RelAngle "+relAngle+" Dir "+ndir); } + // Check if eatable + if (e instanceof Vegetable && tempDist < 0) { + // Eat + eating = true; + e.setSize(e.getSize() - 0.1f); + if (e.getSize() == 0) { + e.setSize(0); + } + hp++; + fitness++; + if (hp > maxHp) { + hp = maxHp; + } + } // Check if attackable if (e instanceof Creature && beak > 5 && tempDist < beak * 1.5f && Math.abs(relAngle - ndir) < (float) Math.PI / 10f) { // Attacking! hp++; fitness++; - if (hp > 100) { - hp = 100; + if (hp > maxHp) { + hp = maxHp; } killing = true; Creature c = (Creature) e; @@ -218,8 +244,8 @@ public class Creature extends Element { } hp++; fitness++; - if (hp > 100) { - hp = 100; + if (hp > maxHp) { + hp = maxHp; } } } @@ -239,7 +265,7 @@ public class Creature extends Element { public void reset() { fitness = 0; - hp = 100; + hp = maxHp; } public float getHp() {