How would I direct/drive an object to the position of my cursor? The seek function should have the values for the x and y of the target and then steer the object to the values
class obj {
constructor(x, y) {
this.x = x
this.y = y
this.ysp = 0
this.xsp = 0
}
draw() {
ctx.fillStyle = "#fff"
ctx.beginPath()
ctx.rect(this.x, this.y, 10, 10)
ctx.fill()
}
seek(tx, ty) {
d = distance(this.x, this.y, tx, ty)
}
update() {
this.y = this.ysp
this.x = this.xsp
}
}
CodePudding user response:
To do this, you have to reduce the distance between the object and the target using their positions, if the target is to the left then move to the left, if it's on the right move to the right. Same goes for up and down.
You will probably want to update your position multiple time to move your object at a given speed, and draw again on the cavenas after each movement so that you can see the movement on screen.
class obj {
constructor(x, y) {
this.x = x
this.y = y
this.ysp = 0
this.xsp = 0
}
draw() {
ctx.fillStyle = "#fff"
ctx.beginPath()
ctx.rect(this.x, this.y, 10, 10)
ctx.fill()
}
seek(tx, ty) {
d = distance(this.x, this.y, tx, ty)
speed = 5 //Note it could be better to use something that adjust itself with the distance depending of the goal
this.x = this.x > tx ? this.x - speed : this.x speed
this.x = this.y > ty ? this.y - speed : this.y speed
}
update() {
this.y = this.ysp
this.x = this.xsp
}
}
CodePudding user response:
There's multiple steps to making something like this work well. I have created a snippet with explanations for ease of understanding. I assume you want the missile to take the shortest path to the target and rotate in the direction of the target. You can also change the rotation speed and flight speed in the code. Keep in mind if you make the rotation too fast it could break without more code to prevent this.
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
canvas.width = 400;
canvas.height = 400;
let mouse = { x: 20, y: 20 };
let canvasBounds = canvas.getBoundingClientRect();
let target;
canvas.addEventListener("mousemove", (e) => {
mouse.x = e.x - canvasBounds.x;
mouse.y = e.y - canvasBounds.y;
target = new Target();
});
class Ship {
constructor() {
this.x = 20;
this.y = 20;
this.ptA = { x: 15, y: 0 };
this.ptB = { x: -15, y: 10 };
this.ptC = { x: -15, y: -10 };
this.color = "red";
this.angle1 = 0;
this.angle2 = 0;
this.dir = 1;
}
draw() {
ctx.save();
//use translate to move the ship
ctx.translate(this.x, this.y);
//angle1 is the angle from the ship to the target point
//angle2 is the ships current rotation angle. Once they equal each other then the rotation stops. When you click somewhere else they are no longer equal and the ship will rotate again.
if (!this.direction(this.angle1, this.angle2)) {
//see direction() method for more info on this
if (this.dir == 1) {
this.angle2 = 0.05; //change rotation speed here
} else if (this.dir == 0) {
this.angle2 -= 0.05; //change rotation speed here
}
} else {
this.angle2 = this.angle1;
}
ctx.rotate(this.angle2);
ctx.beginPath();
ctx.strokeStyle = this.color;
ctx.moveTo(this.ptA.x, this.ptA.y);
ctx.lineTo(this.ptB.x, this.ptB.y);
ctx.lineTo(this.ptC.x, this.ptC.y);
ctx.closePath();
ctx.stroke();
ctx.restore();
}
driveToTarget() {
//get angle to mouse click
this.angle1 = Math.atan2(mouse.y - this.y, mouse.x - this.x);
//normalize vector
let vecX = mouse.x - this.x;
let vecY = mouse.y - this.y;
let dist = Math.hypot(vecX, vecY);
vecX /= dist;
vecY /= dist;
//Prevent continuous x and y increment by checking if either vec == 0
if (vecX != 0 || vecY != 0) {
//then also give the ship a little buffer incase it passes the given point it doesn't turn back around. This allows time for it to stop if you increase the speed.
if (
this.x >= mouse.x 3 ||
this.x <= mouse.x - 3 ||
this.y >= mouse.y 3 ||
this.y <= mouse.y - 3
) {
this.x = vecX; //multiple VecX by n to increase speed (vecX*2)
this.y = vecY; //multiple VecY by n to increase speed (vecY*2)
}
}
}
direction(ang1, ang2) {
//converts rads to degrees and ensures we get numbers from 0-359
let a1 = ang1 * (180 / Math.PI);
if (a1 < 0) {
a1 = 360;
}
let a2 = ang2 * (180 / Math.PI);
if (a2 < 0) {
a2 = 360;
}
//checks whether the target is on the right or left side of the ship.
//We use then to ensure it turns in the shortest direction
if ((360 a1 - a2) % 360 > 180) {
this.dir = 0;
} else {
this.dir = 1;
}
//Because of animation timeframes there is a chance the ship could turn past the target if rotating too fast. This gives the ship a 1 degree buffer to either side of the target to determine if it is pointed in the right direction.
//We then correct it to the exact degrees in the draw() method above once the if statment defaults to 'else'
if (
Math.trunc(a2) <= Math.trunc(a1) 1 &&
Math.trunc(a2) >= Math.trunc(a1) - 1
) {
return true;
}
return false;
}
}
let ship = new Ship();
class Target {
constructor() {
this.x = mouse.x;
this.y = mouse.y;
this.r = 3;
this.color = "red";
}
draw() {
ctx.strokeStyle = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2, false);
ctx.stroke();
}
}
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillRect(0, 0, canvas.width, canvas.height);
ship.draw();
ship.driveToTarget();
if (target) {
target.draw();
}
requestAnimationFrame(animate);
}
animate();
<canvas id="canvas"></canvas>