AI Demo Canon Shooting - ML5js
I created a canon shooting demo to make the AI Canon tries to aim and shoot at a target. Basically, the neural network will receive the target’s location and will try to predict the angle and the force for the canon.
Code explanation notes
Neural Network Settings
I used the ML5js library to create a simple neural network with only 2 input neurons (x, y) , and 2 output neurons (angle, force).
Import the library:
<script src="https://unpkg.com/ml5@0.12.2/dist/ml5.min.js"></script>
Setup the network:
// Setup neural network
function setupNN() {
let options = {
inputs: 2, // Target (x, y)
outputs: 2, // Angle and Force
task: 'regression',
debug: true
};
model = ml5.neuralNetwork(options);
// Add data to the model
trainingData.forEach(data => {
model.addData(data.input, data.output);
});
model.normalizeData();
}
Data Preparation
Base on the network structure, I will create a dataset by randomly picking a location in the area and calculate the accurate force and angle of the canon. Then I will feed to the network.
Given \((x,y)\), we must calculate the \((\theta, f)\) by solving the system of equations:
Having:
$$\begin{cases} x = f\cos\theta t \\ y = f \sin \theta t - \frac 1 2 g t^2\end{cases} \iff \begin{cases} f\cos\theta = \frac x t \\ f \sin \theta = \frac y t + \frac 1 2 g t\end{cases}$$
With \(t\) is the time of the projectile. Now, I have 2 equations and 3 unknowns. I fix the time \(t=30\) to make the system of equations solvable. Then the right hand sides of the equations becomes constants. Call them \(A\) and \(B\), and to simplify the equation, let \(a = \cos\theta \implies \sin\theta = \sqrt{1 - a^2}\). The equations become:
$$\begin{cases} fa = \frac x t = A \\ f \sqrt{1 - a^2} = \frac y t + \frac 1 2 g t = B \end{cases} \iff \begin{cases} f = \frac A a \\ f \sqrt{1 - a^2} = B \end{cases} \iff \begin{cases} f = \frac A a \\ f^2 (\sqrt{1 - a^2})^2 = B^2 \end{cases}$$
Replacing \(f\) with \(\frac A a\):
$$\begin{cases} f = \frac A a \\ \frac {A^2}{a^2} (\sqrt{1 - a^2})^2 = B^2 \end{cases} \iff \begin{cases} f = \frac A a \\ a^2 = \frac {A^2} {A^2+B^2} \iff a = \frac A {\sqrt{A^2+B^2}} \end{cases}$$
Now, put them into the code:
// given target (x,y), calculate the angle and force required to hit the target
function simulateProjectile(x, y) {
// calculate time of flight
const T = 30;
// calculate angle theta and force f
// knowing x = f * cos(theta) * t and y = f * sin(theta) * t - 0.5 * g * t^2
// we can solve for f and theta
const A = x / T;
const B = y / T + 0.5 * g * T;
const cosTheta = A / Math.sqrt(A**2 + B**2);
const angle = Math.acos(cosTheta) * 180 / Math.PI;
const force = A / cosTheta;
// test the prediction
// testSimulateProjectile(x, y, T, angle, force);
return [T, angle, force];
}
And generate the training Data:
// Generate training data
function generateTrainingData() {
for (let i = 0; i < sampleSize; i++) {
let [x, y] = [random(0, width), random(0, height)];
let [_, angle, force] = simulateProjectile(x, y);
console.log(`Generating... Target: ${x}, ${y}, Angle: ${angle}, Force: ${force}`);
trainingData.push({ input: [x, y], output: [angle, force] });
}
}
The rest of the code is simple, you can understand easily.
Demo
Link: https://quangnle.github.io/legos-writing-demos/ml-ann-canon/
Train first
Click to change the target’s location
The more you train, the more accurate
Subscribe to my newsletter
Read articles from Legos Light directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by