Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified Assets/Scene/neural.unity
Binary file not shown.
94 changes: 47 additions & 47 deletions Assets/Scripts/Boomerang.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@
using UnityEngine;

public class Boomerang : MonoBehaviour {
private bool initilized = false;
private bool _initialized = false;
private Transform hex;

//public float Angle2Hex0 = 0f;
//public float Angle2Hex1 = 0f;
//public float Distance2Hex = 0f;
//public float BoomHead = 0f;
//public Vector2 DVector2 = Vector2.up;

private NeuralNetwork net;
private Rigidbody2D rBody;
private Material[] mats;
Expand All @@ -20,67 +26,61 @@ void Start()

void FixedUpdate ()
{
if (initilized == true)
if (_initialized)
{
float distance = Vector2.Distance(transform.position, hex.position);
if (distance > 20f)
distance = 20f;
for (int i = 0; i < mats.Length; i++)
mats[i].color = new Color(distance / 20f, (1f-(distance / 20f)), (1f - (distance / 20f)));

float[] inputs = new float[1];


float angle = transform.eulerAngles.z % 360f;
if (angle < 0f)
angle += 360f;
float distance = Vector2.Distance(transform.position, hex.position); //distance to the HEX

Vector2 deltaVector = (hex.position - transform.position).normalized;

//Distance2Hex = distance;
if (distance > 20f) distance = 20f; //max out distance to 20
foreach (Material t in mats)
t.color = new Color((1f - (distance / 20f)), 0, distance / 20f); //close is red, far is blue

float rad = Mathf.Atan2(deltaVector.y, deltaVector.x);
rad *= Mathf.Rad2Deg;

rad = rad % 360;
if (rad < 0)
{
rad = 360 + rad;
}

rad = 90f - rad;
if (rad < 0f)
{
rad += 360f;
}
rad = 360 - rad;
rad -= angle;
if (rad < 0)
rad = 360 + rad;
if (rad >= 180f)
{
rad = 360 - rad;
rad *= -1f;
}
rad *= Mathf.Deg2Rad;

inputs[0] = rad / (Mathf.PI);
float[] inputs = new float[1];

inputs[0] = BearingToHex()/180; //-1 to +1

float[] output = net.FeedForward(inputs);

rBody.velocity = 2.5f * transform.up;
rBody.angularVelocity = 500f * output[0];

net.AddFitness((1f-Mathf.Abs(inputs[0])));
//net.AddFitness((1f-Mathf.Abs(inputs[0]))); //the smaller the angle to the HEX the Fitter
net.AddFitness((1f - Vector2.Distance(transform.position, hex.position))); //the closer to the HEX the Fitter

}
}
}

public void Init(NeuralNetwork net, Transform hex)
{
this.hex = hex;
this.net = net;
initilized = true;
_initialized = true;
}


}
/// <summary>
/// Returns the deg to turn towards the HEX <br/>
/// CCW is + , CW is -
/// </summary>
/// <returns>Degrees heading towards HEX</returns>
private float BearingToHex()
{
float heading = (transform.eulerAngles.z+90f) % 360f; // Current boomerang heading ccw from x-axis
if (heading < 0f) heading += 360f; //turn acute negative angles into positive obtuse angles

Vector2 deltaVector = (hex.position - transform.position);
var ang2Hex = Mathf.Atan2(deltaVector.y, deltaVector.x)*Mathf.Rad2Deg; //angle of Hex ccw from X-axis
if (ang2Hex < 0f) ang2Hex += 360f; //turn acute negative angles into positive obtuse angles

//DVector2 = deltaVector;
//Angle2Hex0 = ang2Hex;

ang2Hex -= heading;
if (ang2Hex >= 180f) // do we need to turn CW-or CCW+ ?
ang2Hex = (360 - ang2Hex)*-1f;

//BoomHead = heading;
//Angle2Hex1 = ang2Hex;

return ang2Hex;
}
}
35 changes: 19 additions & 16 deletions Assets/Scripts/HexagonAnimator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using UnityEngine;

public class HexagonAnimator : MonoBehaviour {
bool increasingSize = true;
bool _increasingSize = true;
Material mat;
// Use this for initialization
void Start () {
Expand All @@ -12,28 +12,31 @@ void Start () {
}

// Update is called once per frame

void Update () {
float delta = Time.deltaTime;
Vector3 angles = transform.eulerAngles;
angles.z += delta * 50f;
transform.eulerAngles = angles;
transform.eulerAngles = angles; //rotate the HEX

// make the HEX "breathe"
Vector3 localScale = transform.localScale;
if (increasingSize == true)
switch (_increasingSize)
{
localScale += new Vector3(delta, delta ,0f);
if (localScale.x >= 2f)
{
increasingSize = false;
}
}
else if (increasingSize == false)
{
localScale -= new Vector3(delta, delta, 0f);
if (localScale.x <=1f)
{
increasingSize = true;
}
case true:
localScale += new Vector3(delta, delta ,0f);
if (localScale.x >= 2f)
{
_increasingSize = false;
}
break;
case false:
localScale -= new Vector3(delta, delta, 0f);
if (localScale.x <=1f)
{
_increasingSize = true;
}
break;
}

transform.localScale = localScale;
Expand Down
109 changes: 58 additions & 51 deletions Assets/Scripts/Manager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,110 +7,117 @@ public class Manager : MonoBehaviour {
public GameObject boomerPrefab;
public GameObject hex;

private bool isTraning = false;
private int populationSize = 50;
private int generationNumber = 0;
private int[] layers = new int[] { 1, 10, 10, 1 }; //1 input and 1 output
private List<NeuralNetwork> nets;
private bool leftMouseDown = false;
private List<Boomerang> boomerangList = null;
// these allow for tweaking from Unity frontend
public int PopulationSize = 4;
public float TrainTime = 15f;
[Space(10)]
public int[] Layers = new int[] { 1, 10, 10, 1 };
// --

private List<Boomerang> boomerangList = null;
private List<NeuralNetwork> boomerBrainz;
private bool _leftMouseDown = false;
private int _generationNumber = 0;
private bool _isTraning = false;

void Timer()
{
isTraning = false;
_isTraning = false;
}


void Update ()
{
if (isTraning == false)
if (!_isTraning) // if not training
{
if (generationNumber == 0)
if (_generationNumber == 0)
{
InitBoomerangNeuralNetworks();
}
else
{
nets.Sort();
for (int i = 0; i < populationSize / 2; i++)
{
nets[i] = new NeuralNetwork(nets[i+(populationSize / 2)]);
nets[i].Mutate();
boomerBrainz.Sort(); //sort by fit worst to best

nets[i + (populationSize / 2)] = new NeuralNetwork(nets[i + (populationSize / 2)]); //too lazy to write a reset neuron matrix values method....so just going to make a deepcopy lol
}

for (int i = 0; i < populationSize; i++)
for (int badHalf = 0; badHalf < PopulationSize / 2; badHalf++)
{
nets[i].SetFitness(0f);
var goodHalf = badHalf + (PopulationSize/2);
//was this the other way around on purpose? yeah a fit of 1 is perfect -1 is horrible
//copy the good half over the bad half and mutate it
boomerBrainz[badHalf] = new NeuralNetwork(boomerBrainz[goodHalf]);
boomerBrainz[badHalf].Mutate();
//swapped. keep the good half
boomerBrainz[goodHalf] = new NeuralNetwork(boomerBrainz[goodHalf]); //todo: matrix reset vs this ? why would it be better?
if (_generationNumber < 5) boomerBrainz[goodHalf].Mutate(); //increase early mutations
//reset all their fitnesses to 0f
boomerBrainz[badHalf].SetFitness(0f);
boomerBrainz[goodHalf].SetFitness(0f);
}
}


generationNumber++;
_generationNumber++;

isTraning = true;
Invoke("Timer",15f);
_isTraning = true;
Invoke("Timer",TrainTime); //train for trainTime sec
CreateBoomerangBodies();
}


if (Input.GetMouseButtonDown(0))
{
leftMouseDown = true;
_leftMouseDown = true;
}
else if (Input.GetMouseButtonUp(0))
{
leftMouseDown = false;
_leftMouseDown = false;
}

if(leftMouseDown == true)
{
Vector2 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
hex.transform.position = mousePosition;
}
if (_leftMouseDown != true) return;
Vector2 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
hex.transform.position = mousePosition;
}


/// <summary>
/// Destroys the current Boomerangs, if any
/// Creates _populationSize new ones
/// </summary>
private void CreateBoomerangBodies()
{
// if we have any, kill em!
if (boomerangList != null)
{
for (int i = 0; i < boomerangList.Count; i++)
foreach (var t in boomerangList)
{
GameObject.Destroy(boomerangList[i].gameObject);
GameObject.Destroy(t.gameObject);
}

}

// Rise my babies!
boomerangList = new List<Boomerang>();

for (int i = 0; i < populationSize; i++)
for (int i = 0; i < PopulationSize; i++)
{
Boomerang boomer = ((GameObject)Instantiate(boomerPrefab)).GetComponent<Boomerang>();
boomer.Init(nets[i],hex.transform);
var boomer = ((GameObject)Instantiate(boomerPrefab)).GetComponent<Boomerang>();
boomer.Init(boomerBrainz[i],hex.transform);
boomerangList.Add(boomer);
}

}

/// <summary>
/// Initializes the Boomerangs' "brains" <br/>
///
/// </summary>
void InitBoomerangNeuralNetworks()
{
//population must be even, just setting it to 20 incase it's not
if (populationSize % 2 != 0)
{
populationSize = 20;
}
//population must be even
if (PopulationSize % 2 != 0) PopulationSize++;

nets = new List<NeuralNetwork>();

boomerBrainz = new List<NeuralNetwork>();

for (int i = 0; i < populationSize; i++)
for (int i = 0; i < PopulationSize; i++)
{
NeuralNetwork net = new NeuralNetwork(layers);
net.Mutate();
nets.Add(net);
//var boomerBrain = new NeuralNetwork(1, 10, 4, 1); //1 input and 1 output
var boomerBrain = new NeuralNetwork(Layers); // this allows for tweaking from Unity frontend
boomerBrain.Mutate();
boomerBrainz.Add(boomerBrain);
}
}
}
Loading