xxxxxxxxxx
136
// Shooter class to make it easy to add new shooters without having to enter everything manually
class shooter{
constructor(cs,x,y,z,h,v,a){
this.cs=cs // Call-sign
this.x=x // Map W-E-coordinate
this.y=y // Map N-S-coordinate
this.z=z // Shooter height
this.h=h // Target height
this.v=v // Speed
this.a=a // Angle
}
// Ballistic animation, shows the projectile path from the side
ball(t){
strokeWeight(5)
stroke('black')
point((5500-vej.dist(this.x,this.y))/10,884-(this.z-115)*10)
stroke('red')
strokeWeight(2)
point(550,884-(this.h-115)*10)
strokeWeight(1)
text(this.cs,550-textWidth(this.cs),884-(this.h-115)*10+15)
stroke('black')
text(this.cs,(5500-vej.dist(this.x,this.y))/10-textWidth(this.cs),884-(this.z-115)*10+15)
noFill()
// Here I draw the parametric function r(t)=(x0+v*t,g/2*t^2-v*t+y0), where the x-coordinate is linear and I only take the horizontal speed component, and the y-coordinate is a quadratic with the vertical speed component. 5500 and 850 are just to place the dots below the map, and each pixel represents 10 meters horizontally and 1 meter vertically, where the whole gray area is 300 meters.
circle((5500-vej.dist(this.x,this.y)+this.v*cos(this.a)*t)/10,5*sq(t)-this.v*sin(this.a)*t+884-(this.z-115)*10,6)
}
// Bird's-eye-view animation, shows the projectile from above
bird(t){
stroke("black")
strokeWeight(5)
point((this.x-O[0])*s,(O[1]-this.y)*s)
strokeWeight(1)
text(this.cs,(this.x-O[0])*s-textWidth(this.cs),(O[1]-this.y)*s+15)
// If the projectile hasn't hit the target yet, i.e. if the time elapsed is lower than the distance to the target divided by the horizontal speed, I find the current position of the projectile.
if(t<vej.dist(this.x,this.y)/this.v/cos(this.a)){
noFill()
// I take the starting position and add a normal unit vector, (n1,n2)/|(n1,n2)|, multiplied by the horizontal speed and the time to find the current position. At the end I have to multiply by a scaling factor to go from "map-coordinates" to the canvas.
circle((this.x+vej.n1*this.v*cos(this.a)*t/vej.length-O[0])*s,(O[1]-(this.y+vej.n2*this.v*cos(this.a)*t/vej.length))*s,6)
}else{ // If the projectile has hit the target I just make a yellow circle there.
fill('yellow')
circle((this.x+vej.n1*vej.dist(this.x,this.y)/vej.length-O[0])*s,(O[1]-(this.y+vej.n2*vej.dist(this.x,this.y)/vej.length))*s,10)
noFill()
}
}
}
// I make a line class that has a method that allows me to calculate the distance from a point to it.
class dLine {
constructor(x1, y1, x2, y2, c, w) {
if (w === undefined) {
w = 1;
}
if (c === undefined) {
c = "black";
}
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.width = w;
this.colour = c;
this.n1 = y1 - y2; // Normal x-coordinate
this.n2 = x2 - x1; // Normal y-coordinate
this.c = -this.n1 * x1 - this.n2 * y1; // Line equation constant
this.length = sqrt(sq(this.n1) + sq(this.n2)); // Length of the line/normal vector.
}
draw() {
stroke(this.colour);
strokeWeight(this.width);
line((this.x1-O[0])*s, (O[1]-this.y1)*s, (this.x2-O[0])*s, (O[1]-this.y2)*s);
stroke("black");
strokeWeight(1);
}
// This method measures the distance from a point with coordinates (x,y) to the line
dist(x, y) {
// If the shortest path to the line is to one of the end points, I take the shortest of these distances
if (
max(dist(x, y, this.x1, this.y1), dist(x, y, this.x2, this.y2)) >
this.length
) {
return min(dist(x, y, this.x1, this.y1), dist(x, y, this.x2, this.y2));
} else {
// else I use the distance formula
return abs(this.n1 * x + this.n2 * y + this.c) / this.length;
}
}
}
let A
let T
let B
let G
let img
let t=[]
let i=0
let O=[59906,60576] // May coordinates of the top-left corner
let w=73723-O[0] // Absolute width of the map segment
let s=584/w // Scale factor from map coordinates to the canvas
let shot=0 // Keeps track of whether I've fired yet
let shooters=[]
function setup() {
createCanvas(584, 884);
// These are shooters that students from my class came up with
BL=new shooter('Bobby Lee',68408,58037,125,122,308,6.85*PI/180)
BC=new shooter('Big Chungus', 66479,59803,122,124,310,14*PI/180)
BS=new shooter('BS',69008,58016,124,122,853,0.65*PI/180)
BG=new shooter('B.I.G',67652,47329,118,119,255,3.5*PI/180)
shooters=[BL,BC,BS,BG]
img = loadImage('Baghold.png')
vej = new dLine(70845,58756,67898,44925) // I define the target road
}
// Clicking the mouse resets the time and starts the firing sequence
function mouseClicked(){
t=[0]
shot=1
}
function draw() {
background(220);
image(img,0,0)
strokeWeight(5)
vej.draw()
if(shot==1){
t.push(t[i]+1/60)
i++
}
for(i=0;i<t.length;i++){
BL.ball(t[i])
BL.bird(t[i])
BC.ball(t[i])
BC.bird(t[i])
BS.ball(t[i])
BS.bird(t[i])
BG.ball(t[i])
BG.bird(t[i])
}
}