forked from ArztSamuel/Applying_EANNs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCarController.cs
173 lines (146 loc) · 3.96 KB
/
CarController.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/// Author: Samuel Arzt
/// Date: March 2017
#region Includes
using UnityEngine;
#endregion
/// <summary>
/// Class representing a controlling container for a 2D physical simulation
/// of a car with 5 front facing sensors, detecting the distance to obstacles.
/// </summary>
public class CarController : MonoBehaviour
{
#region Members
#region IDGenerator
// Used for unique ID generation
private static int idGenerator = 0;
/// <summary>
/// Returns the next unique id in the sequence.
/// </summary>
private static int NextID
{
get { return idGenerator++; }
}
#endregion
// Maximum delay in seconds between the collection of two checkpoints until this car dies.
public float MAX_CHECKPOINT_DELAY = 2.98f;
/// <summary>
/// The underlying AI agent of this car.
/// </summary>
public Agent Agent
{
get;
set;
}
public float CurrentCompletionReward
{
get { return Agent.Genotype.Evaluation; }
set { Agent.Genotype.Evaluation = value; }
}
/// <summary>
/// Whether this car is controllable by user input (keyboard).
/// </summary>
public bool UseUserInput = false;
/// <summary>
/// The movement component of this car.
/// </summary>
public CarMovement Movement
{
get;
private set;
}
/// <summary>
/// The current inputs for controlling the CarMovement component.
/// </summary>
public double[] CurrentControlInputs
{
get { return Movement.CurrentInputs; }
}
/// <summary>
/// The cached SpriteRenderer of this car.
/// </summary>
public SpriteRenderer SpriteRenderer
{
get;
private set;
}
/// <summary>
/// The cached TrailRenderer of this car.
/// </summary>
public TrailRenderer TrailRenderer
{
get;
private set;
}
private Sensor[] sensors;
private float timeSinceLastCheckpoint;
#endregion
#region Constructors
void Awake()
{
//Cache components
Movement = GetComponent<CarMovement>();
SpriteRenderer = GetComponent<SpriteRenderer>();
sensors = GetComponentsInChildren<Sensor>();
TrailRenderer = GetComponentInChildren<TrailRenderer>();
}
void Start()
{
Movement.HitWall += Die;
//Set name to be unique
this.name = "Car (" + NextID + ")";
Debug.Log("Created car with ID " + NextID);
}
#endregion
#region Methods
/// <summary>
/// Restarts this car, making it movable again.
/// </summary>
public void Restart()
{
Movement.enabled = true;
timeSinceLastCheckpoint = 0;
foreach (Sensor s in sensors)
s.Show();
Agent.Reset();
this.enabled = true;
}
// Unity method for normal update
void Update()
{
timeSinceLastCheckpoint += Time.deltaTime;
}
// Unity method for physics update
void FixedUpdate()
{
//Get control inputs from Agent
if (!UseUserInput)
{
//Get readings from sensors
double[] sensorOutput = new double[sensors.Length];
for (int i = 0; i < sensors.Length; i++)
sensorOutput[i] = sensors[i].Output;
double[] controlInputs = Agent.FNN.ProcessInputs(sensorOutput);
Movement.SetInputs(controlInputs);
}
if (timeSinceLastCheckpoint > MAX_CHECKPOINT_DELAY)
{
Die();
}
}
// Makes this car die (making it unmovable and stops the Agent from calculating the controls for the car).
private void Die()
{
this.enabled = false;
Movement.Stop();
Movement.enabled = false;
foreach (Sensor s in sensors)
s.Hide();
Agent.Kill();
Debug.Log("Killed car with ID " + NextID);
}
public void CheckpointCaptured()
{
timeSinceLastCheckpoint = 0;
}
#endregion
}