I've been working on some studies with animation and with the help of some jquery I've created an animation where when a square that is moved by the users mouse through a mousemove jquery event collides with another square on the screen (square2) thats been hit will move a certain length and if the hitbox is struck near its edges than the object is expected to rotate. The problem ive been running into is that when the object rotates it creates a pseudo afterimage of the outline of the square. At first I thought that I could remove the afterImage by using a clearRect() method to encompass a larger area around square2, but doing this not only leaves my problem unresolved, but also makes a part of my first square invisible which is undesired. If anybody could hep me figure out where ive gone wrong in this code, would definitely appreciate it fellas.
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
canvas.width = 1000;
canvas.height = 400;
var width = canvas.width;
var height = canvas.height;
var particles = [];
var mouseSize = 50;
var isColliding = false;
var mouseX;
var mouseY;
var animationForward = false;
function particle() {
var particle = {
originX: width / 2,
originY: height / 2,
x: width / 2,
y: height / 2,
size: 30,
centerPointX: this.x + this.size / 2,
centerPointY: this.y + this.size / 2,
decay: .98,
vx: 0,
vy: 0,
rotate: 0,
vr: 0,
draw: function() {
ctx.fillStyle = "white";
ctx.fillRect(this.x, this.y, this.size, this.size)
// rotation logic
// method found at http://stackoverflow.com/questions/2677671/how-do-i-rotate-a-single-object-on-an-html-5-canvas
function drawImageRot(x, y, width, height, deg) {
ctx.clearRect(x, y, width, height);
//Convert degrees to radian
var rad = deg * Math.PI / 180;
//Set the origin to the center of the image
ctx.translate(x + width / 2, y + height / 2);
//Rotate the canvas around the origin
ctx.rotate(rad);
//draw the image
ctx.fillRect(width / 2 * (-1), height / 2 * (-1), width, height);
//reset the canvas
ctx.rotate(rad * (-1));
ctx.translate((x + width / 2) * (-1), (y + height / 2) * (-1));
}
//check for collision
if (mouseX < particles[0].x + particles[0].size &&
mouseX + mouseSize > particles[0].x &&
mouseY < particles[0].y + particles[0].size &&
mouseSize + mouseY > particles[0].y) {
isColliding = true;
} else {
isColliding = false;
}
//controlling velocity dependending on location of collision.
if (isColliding) {
//x axis
animationForward = true;
// checking below to see if mouseRect is hitting near the center of particleRect.
// if it hits near center the vy or vx will not be as high depending on direction and if it //does not than we will make square rotate
if (mouseX < this.x) {
this.vr = 3 + Math.random() * 10
if (mouseX + mouseSize / 2 > this.x) {
this.vx = 0 + Math.random() * 2;
} else {
this.vx = 3 + Math.random() * 3;
}
} else {
this.vr = -3 - Math.random() * 10
if (mouseX + mouseSize / 2 < this.x + this.size) {
this.vx = 0 - Math.random() * 2;
} else {
this.vx = -3 - Math.random() * 3;
}
}
//y axis checking
if (mouseY < this.y) {
if (mouseY + mouseSize / 2 > this.y) {
this.vy = 0 + Math.random() * 2;
} else {
this.vy = 3 + Math.random() * 3;
}
} else {
if (mouseY + mouseSize / 2 < this.y + this.size) {
this.vy = 0 - Math.random() * 2;
} else {
this.vy = -3 - Math.random() * 3;
}
}
}
//decay all motions each frame while animation is forward
if (animationForward) {
this.vx *= this.decay;
this.vy *= this.decay;
this.vr *= this.decay;
}
//when animation is done, set all velocities to 0
if (this.x != this.originX && Math.abs(this.vx) < .1 && this.y != this.originY && Math.abs(this.vy) < .1) {
animationForward = false;
this.vx = 0;
this.vy = 0;
this.vr = 0
}
//x check to see if animation over. if it is slowly put square back to original location
if (this.x != this.originX && !animationForward) {
if (this.x > this.originX) {
this.vx = -1;
}
if (this.x < this.originX) {
this.vx = 1;
}
if (this.x > this.originX && this.x - this.originX < 1) {
this.vx = 0;
this.x = this.originX;
}
if (this.x < this.originX && this.originX - this.x < 1) {
this.vx = 0;
this.x = this.originX;
}
}
// end x collison
// y check to see if animation over
if (this.y != this.originX && !animationForward) {
if (this.y > this.originY) {
this.vy = -1;
}
if (this.y < this.originY) {
this.vy = 1;
}
if (this.y > this.originY && this.y - this.originY < 1) {
this.vy = 0;
this.y = this.originY;
}
if (this.y < this.originY && this.originY - this.y < 1) {
this.vy = 0;
this.y = this.originY;
}
}
// end y collison
//check rotation
if (this.rotate != 0 && !animationForward) {
this.rotate = Math.round(this.rotate);
if (this.rotate < 0) {
if (this.rotate < -300) {
this.rotate += 10
} else if (this.rotate < -200) {
this.rotate += 7
} else if (this.rotate < -125) {
this.rotate += 5
} else if (this.rotate < -50) {
this.rotate += 3
} else {
this.rotate++;
}
} else {
if (this.rotate > 300) {
this.rotate -= 10;
} else if (this.rotate > 200) {
this.rotate -= 7
} else if (this.rotate > 125) {
this.rotate -= 5
} else if (this.rotate > 50) {
this.rotate -= 3
} else {
this.rotate--;
}
}
}
// move the rect based off of previous set conditions and make square rotate if edges hit
this.x += this.vx;
this.y += this.vy;
this.rotate += this.vr;
drawImageRot(this.x, this.y, this.size, this.size, this.rotate);
// boundary control
if (this.x + this.size > width || this.x < 0) {
this.vx = -this.vx * 2
}
if (this.y + this.size > height || this.y < 0) {
this.vy = -this.vy * 2
}
}
}
return particle;
}
function createParticles() {
particles.push(particle())
//wouldnt be too hard to put more particles. would have to go back and change the isColliding and animationForward global variable and make each object have their own to check. also would have to go back and implement for loops wherever i mention an element in my array
}
createParticles();
function draw() {
console.log(particles[0].rotate);
ctx.clearRect(0, 0, width, height);
ctx.fillStyle = 'white';
ctx.fillRect(mouseX, mouseY, mouseSize, mouseSize);
particles[0].draw();
requestAnimationFrame(draw);
}
$("#canvas").mousemove(function(event) {
mouseX = event.pageX;
mouseY = event.pageY;
})
window.onload = draw();
I think your problem is right here:
draw: function() {
ctx.fillStyle = "white";
ctx.fillRect(this.x, this.y, this.size, this.size)
....
You are drawing 2nd shape here. Comment this lines and pseudo image should be gone.
Related
I am trying to make a simple breakout game with p5js. I got the balls to work fine, but when I try to make them interact with the brick class, I run into some problems. I can't seem to figure ourI don't have a ton of experience with classes in javascript, so this is a little confusing to me. Here is the code:
`
//Variables
let scene = 0;
let paddlex = 250;
let paddlespeed = 10;
let allBalls = [];
class Brick {
constructor(brickX, brickY, brickW, brickH) {
this.brickX = brickX
this.brickY = brickY
this.brickW = brickW
this.brickH = brickH
this.brickAlive = true
}
display(){
push()
if(this.brickAlive){
fill("red")
rect(this.brickX, this.brickY, this.brickW, this.brickH)
}
pop()
}
}
class Ball {
constructor(x, y, w, xdir, ydir) {
this.x = x;
this.y = y;
this.w = w;
this.xdir = xdir;
this.ydir = ydir;
this.alive = true;
allBalls.push(this);
}
move() {
this.x += this.xdir;
this.y += this.ydir;
//Bounce off walls
if (this.x >= 600 - this.w / 2) {
this.xdir = this.xdir * -1;
}
if (this.x <= 0 + this.w / 2) {
this.xdir = this.xdir * -1;
}
if (this.y <= 0 + this.w / 2) {
this.ydir = this.ydir * -1;
}
if (this.y >= 400 + this.w / 2) {
this.alive = false;
}
if (
this.y >= 360 - this.w / 2 &&
this.y <= 380 &&
this.x >= paddlex &&
this.x <= paddlex + 100
) {
this.ydir = this.ydir * -1;
}
}
show() {
if (this.alive) {
push();
fill(0);
ellipse(this.x, this.y, this.w, this.w);
pop();
}
}
//I believe this part is causing the error
collide(brick){
if(this.x >= brick.brickX && this.x <= brick.brickX + brick.brickW && this.y <= brick.brickY + brick.brickH){
console.log("HI")
brick.brickAlive = false
}
}
}
`
I recieved an error that said "TypeError: Cannot read properties of undefined (reading 'brickX')"
After a few hours of work and research (I just started learning p5js and javascript) I have about 50 lines of code that creates a grid of circles and begins to move them across the canvas. Before I get into my issue, I will share the code.
var circles = [];
function setup() {
createCanvas(500, 500);
for (var a = 50; a < width - 300; a += 20) {
for (var b = 50; b < height - 300; b += 20) {
circles.push(new Circle(a, b));
}
}
}
function draw() {
background(50);
for (var b = 0; b < circles.length; b++) {
circles[b].show();
}
}
function Circle(x, y) {
this.x = x;
this.y = y;
this.show = function() {
fill(255);
noStroke();
ellipse(this.x, this.y, 10, 10);
if (this.x < 51) {
this.x += 1
this.y += 1
}
if (this.x < 430) {
this.x += 1
this.y += 1
}
if (this.x > 430) {
this.x -= 1
this.y -= 1
}
if (this.x < 51) {
this.x += 1
this.y += 1
}
}
}
What I would like to do is move this grid of circles starting at (50,50) to the bottom right corner. Once it hits (width-50,height-50) I'd like the movement to reverse back to the starting point, and then back the other way. This code moves the circles to the bottom right corner successfully, them something goes wrong. The circles don't reverse their movement, rather, they get messed up. I thought the if statements would handle this but I must be missing something. I trouble shooted for about an hour and now I thought I'd ask SO. Thanks!
Add a moving direction to the object. Change the direction when the object goes out of bounds:
var circles = [];
function setup() {
createCanvas(500, 500);
for (var a = 50; a < width - 300; a += 20) {
for (var b = 50; b < height - 300; b += 20) {
circles.push(new Circle(a, b));
}
}
}
function draw() {
background(50);
for (var b = 0; b < circles.length; b++) {
circles[b].show();
}
}
function Circle(x, y) {
this.x = x;
this.y = y;
this.dx = 1;
this.dy = 1
this.show = function() {
fill(255);
noStroke();
ellipse(this.x, this.y, 10, 10);
this.x += this.dx
this.y += this.dy
if (this.x < 51 || this.y < 51) {
this.dx = 1
this.dy = 1
}
if (this.x > 430 || this.y > 430) {
this.dx = -1
this.dy = -1
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>
If you do not want to move the objects individually, you must use 1 direction of movement for all objects:
var circles = [];
function setup() {
createCanvas(500, 500);
for (var a = 50; a < width - 300; a += 20) {
for (var b = 50; b < height - 300; b += 20) {
circles.push(new Circle(a, b));
}
}
}
var dx = 1
var dy = 1
function draw() {
background(50);
mx = dx
my = dy
for (var b = 0; b < circles.length; b++) {
circles[b].show(mx, my);
}
}
function Circle(x, y) {
this.x = x;
this.y = y;
this.show = function(mx, my) {
fill(255);
noStroke();
ellipse(this.x, this.y, 10, 10);
this.x += mx
this.y += my
if (this.x < 51) {
dx = 1
dy = 1
}
if (this.x > 430) {
dx = -1
dy = -1
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>
Following the collision between a ball from an array and an object (rectangle), the ball doesn't seem to have the same bounce affect as it has when it hits the ground.
When coming into contact with the object, it seems to pick up speed and suddenly glitches through and comes to rest on the ground.
Questions:
Why does it seem to want to rest on the ground and not on the object itself?
How can I make the ball have the same bounce affect when coming into contact with the object as it has when coming into contact with the ground?
Code:
var balls = [];
var obstacle;
function setup() {
createCanvas(400, 400);
obstacle = new Obstacle();
}
function draw() {
background(75);
obstacle.display();
for (var i = 0; i < balls.length; i++) {
balls[i].display();
balls[i].update();
balls[i].edges();
RectCircleColliding(balls[i], obstacle);
//console.log(RectCircleColliding(balls[i], obstacle));
}
}
function mousePressed() {
balls.push(new Ball(mouseX, mouseY));
}
function Ball(x, y) {
this.x = x;
this.y = y;
this.r = 15;
this.gravity = 0.5;
this.velocity = 0;
this.display = function() {
fill(255, 0, 100);
stroke(255);
ellipse(this.x, this.y, this.r * 2);
}
this.update = function() {
this.velocity += this.gravity;
this.y += this.velocity;
}
this.edges = function() {
if (this.y >= height - this.r) {
this.y = height - this.r;
this.velocity = this.velocity * -1;
this.gravity = this.gravity * 1.1;
}
}
}
function Obstacle() {
this.x = width - width;
this.y = height / 2;
this.w = 200;
this.h = 25;
this.display = function() {
fill(0);
stroke(255);
rect(this.x, this.y, this.w, this.h);
}
}
function RectCircleColliding(Ball, Obstacle) {
// define obstacle borders
var oRight = Obstacle.x + Obstacle.w;
var oLeft = Obstacle.x;
var oTop = Obstacle.y;
var oBottom = Obstacle.y + Obstacle.h;
//compare ball's position (acounting for radius) with the obstacle's border
if (Ball.x + Ball.r > oLeft) {
if (Ball.x - Ball.r < oRight) {
if (Ball.y + Ball.r > oTop) {
if (Ball.y - Ball.r < oBottom) {
Ball.y = Obstacle.y - Ball.r * 2;
Ball.velocity = Ball.velocity * -1;
Ball.gravity = Ball.gravity * 1.1;
Ball.velocity += Ball.gravity;
Ball.y += Ball.velocity;
return (true);
}
}
}
}
return false;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.min.js"></script>
The main issue with this question's code is that we need to check for collisions and only allow updates when the ball is not colliding. Another issue was that when collisions occur we must cap the gravity to prevent the ball from plunging all the way to the ground.
Here is the corrected code:
var balls = [];
var obstacle;
function setup() {
createCanvas(400, 400);
obstacle = new Obstacle();
}
function draw() {
background(75);
obstacle.display();
for (var i = 0; i < balls.length; i++) {
balls[i].display();
if (!RectCircleColliding(balls[i], obstacle)){
balls[i].update();
balls[i].edges();
}
//console.log(RectCircleColliding(balls[i], obstacle));
}
}
function mousePressed() {
balls.push(new Ball(mouseX, mouseY));
}
function Ball(x, y) {
this.x = x;
this.y = y;
this.r = 15;
this.gravity = 0.5;
this.velocity = 0;
this.display = function() {
fill(255, 0, 100);
stroke(255);
ellipse(this.x, this.y, this.r * 2);
}
this.update = function() {
this.velocity += this.gravity;
this.y += this.velocity;
}
this.edges = function() {
if (this.y >= height - this.r) {
this.y = height - this.r;
this.velocity = this.velocity * -1;
this.gravity = this.gravity * 1.1;
}
}
}
function Obstacle() {
this.x = width - width;
this.y = height / 2;
this.w = 200;
this.h = 25;
this.display = function() {
fill(0);
stroke(255);
rect(this.x, this.y, this.w, this.h);
}
}
function RectCircleColliding(Ball, Obstacle) {
// define obstacle borders
var oRight = Obstacle.x + Obstacle.w;
var oLeft = Obstacle.x;
var oTop = Obstacle.y;
var oBottom = Obstacle.y + Obstacle.h;
//compare ball's position (acounting for radius) with the obstacle's border
if (Ball.x + Ball.r > oLeft) {
if (Ball.x - Ball.r < oRight) {
if (Ball.y + Ball.r > oTop) {
if (Ball.y - Ball.r < oBottom) {
let oldY = Ball.y;
Ball.y = oTop - Ball.r;
Ball.velocity = Ball.velocity * -1;
if (Ball.gravity < 2.0){
Ball.gravity = Ball.gravity * 1.1;
} else {
Ball.velocity = 0;
Ball.y = oldY;
}
return (true);
}
}
}
}
return false;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.min.js"></script>
I made a little game where there are 3 objects
Player: Can move using WASD
Bullet: Moved by an event listener of click
Enemy: Follows the player like a zombie.
How do I make it so the angle of the zombie is the direction he is moving, Rather than always facing the player object?
Fiddle
tick: function() {
enemy.angle = Math.atan2(player.y - enemy.y, player.x - enemy.x);// * (180 / Math.PI);
},
above is the code I use to make the enemy face the player
I understand what you're trying to ask, but really, right now the zombie is always going directly to player, so it would actually be weird if it looked some other way. What you need to do is to actually make zombie slowly turn and walk on it's own, rather than just reducing euclidean distance between it and the player.
First stem, one that I'll do for you is calculating the rotation. Instead of just getting to the correct angle instantly, we have to slowly turn every tick:
tick: function() {
// 1 degree per tick
const rotationSpeed = (1/180)*Math.PI;
// the angle we want - facing the player
const desiredAngle = Math.atan2(player.y - enemy.y, player.x - enemy.x)
// transition angle will be explained below
enemy.angle = transitionAngle(enemy.angle, desiredAngle,rotationSpeed );
},
This is not as easy as it sounds, because you need to calculate whether it's faster to turn left or right to face the player again. Fortunately this is easy to google once you know what you need. I based my function on this answer:
function transitionAngle(fromAngle, toAngle, speed) {
// normalize the angles to 0-360 range
const rad360 = 2*Math.PI;
fromAngle = fromAngle % rad360;
toAngle = toAngle % rad360;
if (fromAngle < toAngle) {
if (Math.abs(fromAngle - toAngle) < Math.PI)
fromAngle += speed;
else fromAngle -= speed;
}
else {
if (Math.abs(fromAngle - toAngle) < Math.PI)
fromAngle -= speed;
else fromAngle += speed;
}
return fromAngle;
}
With that, the zombie slows slowly, and it already looks a little better.
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var bounds = canvas.getBoundingClientRect();
var mouseX = 0.0;
var mouseY = 0.0;
var pressingDown = false;
var pressingUp = false;
var pressingLeft = false;
var pressingRight = false;
var player = {
x: 210,
y: 250,
radius: 17.5,
angle: 0.0,
tick: function() {
this.angle = Math.atan2(mouseY - this.y, mouseX - this.x);
},
draw: function() {
context.fillStyle = "darkred";
context.strokeStyle = "black";
context.translate(this.x, this.y);
context.rotate(this.angle);
context.beginPath();
context.moveTo(this.radius, 0.0);
context.lineTo(-0.5 * this.radius, 0.5 * this.radius);
context.lineTo(-0.5 * this.radius, -0.5 * this.radius);
context.lineTo(this.radius, 0.0);
context.fill();
context.stroke();
context.rotate(-this.angle);
context.translate(-this.x, -this.y);
},
updatePlayerPosition: function() {
if (pressingRight)
player.x += 1;
if (pressingLeft)
player.x -= 1;
if (pressingDown)
player.y += 1;
if (pressingUp)
player.y -= 1;
}
}
var bullet = {
x: player.x,
y: player.y,
dx: 0.0,
dy: 0.0,
radius: 5.0,
tick: function() {
this.x += this.dx;
this.y += this.dy;
if (this.x + this.radius < 0.0 || this.x - this.radius > canvas.width || this.y + this.radius < 0.0 || this.y - this.radius > canvas.height) {
this.dx = 0.0;
this.dy = 0.0;
}
},
render: function() {
context.fillStyle = "darkcyan";
context.strokeStyle = "white";
context.beginPath();
context.arc(this.x, this.y, this.radius, 0.0, 2.0 * Math.PI, false);
context.fill();
context.stroke();
}
};
var enemy = {
x: 200,
y: 300,
radius: 17.5,
angle: 0.0,
tick: function() {
// 1 degree per tick
const rotationSpeed = (1/180)*Math.PI;
const desiredAngle = Math.atan2(player.y - enemy.y, player.x - enemy.x)
enemy.angle = transitionAngle(enemy.angle, desiredAngle,rotationSpeed );
},
draw: function() {
context.fillStyle = "Green";
context.strokeStyle = "darkgreen";
context.translate(this.x, this.y);
context.rotate(this.angle);
context.beginPath();
context.moveTo(this.radius, 0.0);
context.lineTo(-0.5 * this.radius, 0.5 * this.radius);
context.lineTo(-0.5 * this.radius, -0.5 * this.radius);
context.lineTo(this.radius, 0.0);
context.fill();
context.stroke();
context.rotate(-this.angle);
context.translate(-this.x, -this.y);
},
drawEnemy: function(something){
var diffX = player.x - something.x;
var diffY = player.y - something.y
if (diffX > 0)
something.x += .3
else
something.x -= .3;
if (diffY > 0)
something.y += .3
else
something.y -= .3;
}
}
function Refresh() {
context.clearRect(0, 0, canvas.width, canvas.height);
bullet.render();
bullet.tick();
player.draw();
player.tick();
player.updatePlayerPosition();
enemy.draw();
enemy.tick();
enemy.drawEnemy(enemy);
}
setInterval(Refresh, 0)
window.onmousemove = function(e) {
mouseX = e.clientX - bounds.left;
mouseY = e.clientY - bounds.top;
}
document.onkeydown = function(event) {
if (event.keyCode === 83) //s
pressingDown = true;
else if (event.keyCode === 87) //w
pressingUp = true;
else if (event.keyCode === 65) //a
pressingLeft = true;
else if (event.keyCode === 68) //d
pressingRight = true;
}
document.onkeyup = function(event) {
if (event.keyCode === 83) //s
pressingDown = false;
else if (event.keyCode === 87) //w
pressingUp = false;
else if (event.keyCode === 65) //a
pressingLeft = false;
else if (event.keyCode === 68) //d
pressingRight = false;
}
window.onmousedown = function(e) {
// The mouse pos - the player pos gives a vector
// that points from the player toward the mouse
var x = mouseX - player.x;
var y = mouseY - player.y;
// Using pythagoras' theorm to find the distance (the length of the vector)
var l = Math.sqrt(x * x + y * y);
// Dividing by the distance gives a normalized vector whose length is 1
x = x / l;
y = y / l;
// Reset bullet position
bullet.x = player.x;
bullet.y = player.y;
// Get the bullet to travel towards the mouse pos with a new speed of 10.0 (you can change this)
bullet.dx = x * 10.0;
bullet.dy = y * 10.0;
}
function transitionAngle(fromAngle, toAngle, speed) {
// normalize the angles to 0-360 range
const rad360 = 2*Math.PI;
fromAngle = fromAngle % rad360;
toAngle = toAngle % rad360;
if (fromAngle < toAngle) {
if (Math.abs(fromAngle - toAngle) < Math.PI)
fromAngle += speed;
else fromAngle -= speed;
}
else {
if (Math.abs(fromAngle - toAngle) < Math.PI)
fromAngle -= speed;
else fromAngle += speed;
}
return fromAngle;
}
<canvas id="canvas" style="border:2px solid darkred" width="700" height="500"></canvas>
The second part of the job - and I'm leaving that to you - is to make zombie actually walk in the direction it's facing. To do that, assign it a walking speed and then use sin and cos of the zombie's angle multiplied with the speed to get X and Y offsets. Again, google is your friend, just type "move by speed and angle javascript".
How make Santa follow to mouse with rotation and own speed, not mouse speed?
Where mouse now - it's destination, where go santa with own speed.
Santa rotate with speed.
How can I do this?
Demo code
game.js
var canvas, ctx, player
function init() {
canvas = document.getElementById("canvas")
ctx = canvas.getContext( "2d" )
resizeCanvas()
player = new Player(
ctx,
canvas.width / 2,
canvas.height / 2 + 100
)
window.onresize = resizeCanvas
canvas.onmousemove = mousemove
}
function mousemove( e ) {
player.x = e.clientX * devicePixelRatio
player.y = e.clientY * devicePixelRatio
}
function render() {
ctx.clearRect( 0, 0, canvas.width, canvas.height )
player.draw()
}
function step() {
render()
requestAnimationFrame( step )
}
init()
step()
It's not trivial task with rotation.
Modified version with some magic: demo
For distance used Pythagorean theorem.
Player moving to forward (by current rotation).
class Player {
constructor(ctx, x, y) {
this.x = x
this.y = y
this.dest = {
x: 0,
y: 0
}
this.width = 200
this.height = 200
this.velocity = 12
this.angularVelocity = 7
this.rotation = 0
this.ctx = ctx
this.image = new Image()
this.image.src = "//habrastorage.org/files/447/9b4/6d3/4479b46d397e439a9613ce122a66a506.png"
}
draw() {
this.ctx.translate(this.x, this.y)
this.ctx.rotate(this.rotation + 4.7)
this.ctx.drawImage(
this.image,
-this.width / 2, -this.height / 2,
this.width, this.height
)
this.ctx.rotate(-this.rotation - 4.7)
this.ctx.translate(-this.x, -this.y)
}
distance(target) {
let data = {
x: target.x - this.x,
y: target.y - this.y
}
data.len = Math.sqrt(data.x * data.x + data.y * data.y)
return data
}
rotate(dt) {
let path = this.distance(this.dest)
let target = Math.atan2(path.y, path.x)
let delta = this.rotation - target
if (delta > 0.1 || delta < -0.1) {
var _delta = delta
if (_delta < 0) {
_delta += Math.PI * 2
}
if (delta < -Math.PI || (delta > 0 && delta < Math.PI)) {
this.rotation -= _delta / this.angularVelocity
} else {
this.rotation -= (_delta - Math.PI * 2) / this.angularVelocity
}
// Reduce character rotation into the -PI thru PI range
this.rotation = (this.rotation + 3 * Math.PI) % (2 * Math.PI) - Math.PI
}
}
step() {
let distance = this.distance(this.dest).len
if (distance < this.width / 1.5) {
this.draw()
return
}
let vel = distance / 15
if (vel > this.velocity) {
vel = this.velocity
}
this.rotate()
this.x += vel * Math.cos(this.rotation)
this.y += vel * Math.sin(this.rotation)
this.draw()
}
}