Im trying to make an particle move towards where on canvas was clicked however the formula returns NaN. Why is this and how can I fix this?
step 1: Particle gets placed at player.x, player.y properly.
step 2: At first tick the particle goes to the upper left point of the canvas without x,y position.
Screenie of particle props
example at jsfiddle
Particle Object
function Shuriken(mouseX, mouseY) {
this.rot = 0;
this.vel = 2;
this.angle = 0;
this.x = player.x || WIDTH / 2;
this.y = player.y || HEIGHT / 2;
this.mouseX = mouseX || WIDTH /2;
this.mouseY = mouseY || HEIGHT /2
this.width = shurikenImg.width;
this.height = shurikenImg.height;
}
update on tick
Shuriken.prototype.move = function() {
this.angle = Math.atan2(this.mouseY, this.x) * (180 / Math.PI);
this.x += this.vel * Math.cos(this.angle);
this.y += this.vel * Math.sin(this.angle);
}
You convert angle from radians into degrees. Nicer to debug (because degrees are still taught in school) but alas, the sin and cos in the next lines expect their arguments to be in radians again. Granted, the functions ought still to work; but the values you get are no longer what you expect.
this.vel is undefined in the jsfiddle. This is most likely what lead to the observed NaN.
This is a wrong calculation:
this.x = this.vel * Math.cos(this.angle);
this.y = this.vel * Math.sin(this.angle);
You don't want the x and y positions calculated this way. Add or subtract the (adjusted) velocity from the x/y coordinates.
Related
I'm drawing out sine curves using the following formula,
this.x += this.speed
this.y = this.amp * Math.sin( this.x * this.cycles ) + this.center
I'm dotting out points by drawing tiny circles every frame. What this achieves is a nice looking sine curve that draws from left to right. But if I want to rotate this curve so that it draws in a random 360 degree, how should I modify the code? Aka, sometimes I want the curve to be the same drawing from left to right, other times I want it drawing at a 45 degree downwards, sometimes, backwards, etc...
One option is to calculate the point in Cartesian coordinates, convert to polar, add your angle offset, and convert back to Cartesian again.
this.x += this.speed
this.y = this.amp * Math.sin( this.x * this.cycles ) + this.center
this.r = Math.sqrt(this.x * this.x + this.y * this.y);
this.a = Math.atan2(this.y, this.x);
this.a += rotation_angle;
this.x = this.r * Math.cos(this.a);
this.y = this.r * Math.sin(this.a);
This increases the number of Math library calls from one to five, so I would expect it to be about one fifth as fast as your original calculation. This may or may not be acceptable. We can actually do a little better using the trigonometric identities sin(a+b) = sin(a)cos(b) + cos(a)sin(b) and cos(a+b) = cos(a)cos(b) - sin(a)sin(b) identities.
For the rotated X-coordinate:
this.r * cos(this.a)
= this.r * cos(atan2(this.y, this.x) + rotation)
= this.r * (cos(atan2(this.y, this.x))cos(rotation) - sin(atan2(this.y, this.x))sin(rotation))
= this.r * ((this.x / this.r)cos(rotation) - (this.y / this.r)sin(rotation))
= this.x * cos(rotation) - this.y * sin(rotation)
For the rotated Y-coordinate:
this.r * sin(this.a)
= this.r * sin(atan2(this.y, this.x) + rotation)
= this.r * (sin(atan2(this.y, this.x))cos(rotation) + cos(atan2(this.y, this.x))sin(rotation))
= this.r * ((this.y / this.r)cos(rotation) + (this.x / this.r)sin(rotation))
= this.y * cos(rotation) + this.x * sin(rotation)
Our new code looks like this:
x = this.x + this.speed
y = this.amp * Math.sin( x * this.cycles ) + this.center
this.x = x * cos(rotation_angle) - y * sin(rotation_angle);
this.y = y * cos(rotation_angle) + x * sin(rotation_angle);
We introduced variables x and y since we need each in its original form to calculate each of this.x and this.y. We no longer need to work in polar coordinates because our identities allowed us to eliminate those intermediate steps. Also, if rotation_angle is constant, it can be pre-computed; otherwise, you can leave the calls in the calculation of each point and get spiral-type effects.
If you prefer not to work with angles at all, you can work in terms of arbitrary functions by using parametric definitions x = f(t) and y = g(t) to define a curve, determining the perpendicular at each point t - either by analytically finding and encoding f'(t) and g'(t) - or by approximating these numerically around points of interest. Then, you simply plot a point at a displacement along that directed normal line equal to the value you are currently calculating for this.y. So, if you wanted to plot a sine curve along a parabola, you could do this:
t += speed;
r = this.amp * Math.sin(t * this.cycles) + this.center;
x = t;
y = t * t;
dxdt = 1;
dydt = 2t;
dydx = dydt / dxdt;
if (-epsilon <= dydt && dydt <= epsilon) {
this.x = x;
this.y = y + r;
} else {
normal = -1.0 / dydx;
this.x = x + r * ( 1.0 / Math.sqrt(1 + dydx * dydx));
this.y = y + r * (dydx / Math.sqrt(1 + dydx * dydx));
}
I haven't tried running that, so it might have some errors, but in theory those errors should be fixable so that you get the intended effect: a sine curve wrapped around the (directed!) parabola y = x^2 oriented to from negative to positive x.
So I built some time ago a little Breakout clone, and I wanted to upgrade it a little bit, mostly for the collisions. When I first made it I had a basic "collision" detection between my ball and my brick, which in fact considered the ball as another rectangle. But this created an issue with the edge collisions, so I thought I would change it. The thing is, I found some answers to my problem:
for example this image
and the last comment of this thread : circle/rect collision reaction but i could not find how to compute the final velocity vector.
So far I have :
- Found the closest point on the rectangle,
- created the normal and tangent vectors,
And now what I need is to somehow "divide the velocity vector into a normal component and a tangent component; negate the normal component and add the normal and tangent components to get the new Velocity vector" I'm sorry if this seems terribly easy but I could not get my mind around that ...
code :
function collision(rect, circle){
var NearestX = Max(rect.x, Min(circle.pos.x, rect.x + rect.w));
var NearestY = Max(rect.y, Min(circle.pos.y, rect.y + rect.w));
var dist = createVector(circle.pos.x - NearestX, circle.pos.y - NearestY);
var dnormal = createVector(- dist.y, dist.x);
//change current circle vel according to the collision response
}
Thanks !
EDIT: Also found this but I didn't know if it is applicable at all points of the rectangle or only the corners.
Best explained with a couple of diagrams:
Have angle of incidence = angle of reflection. Call this value θ.
Have θ = normal angle - incoming angle.
atan2 is the function for computing the angle of a vector from the positive x-axis.
Then the code below immediately follows:
function collision(rect, circle){
var NearestX = Max(rect.x, Min(circle.pos.x, rect.x + rect.w));
var NearestY = Max(rect.y, Min(circle.pos.y, rect.y + rect.h));
var dist = createVector(circle.pos.x - NearestX, circle.pos.y - NearestY);
var dnormal = createVector(- dist.y, dist.x);
var normal_angle = atan2(dnormal.y, dnormal.x);
var incoming_angle = atan2(circle.vel.y, circle.vel.x);
var theta = normal_angle - incoming_angle;
circle.vel = circle.vel.rotate(2*theta);
}
Another way of doing it is to get the velocity along the tangent and then subtracting twice this value from the circle velocity.
Then the code becomes
function collision(rect, circle){
var NearestX = Max(rect.x, Min(circle.pos.x, rect.x + rect.w));
var NearestY = Max(rect.y, Min(circle.pos.y, rect.y + rect.h));
var dist = createVector(circle.pos.x - NearestX, circle.pos.y - NearestY);
var tangent_vel = dist.normalize().dot(circle.vel);
circle.vel = circle.vel.sub(tangent_vel.mult(2));
}
Both of the code snippets above do basically the same thing in about the same time (probably). Just pick whichever one you best understand.
Also, as #arbuthnott pointed out, there's a copy-paste error in that NearestY should use rect.h instead of rect.w.
Edit: I forgot the positional resolution. This is the process of moving two physics objects apart so that they're no longer intersecting. In this case, since the block is static, we only need to move the ball.
function collision(rect, circle){
var NearestX = Max(rect.x, Min(circle.pos.x, rect.x + rect.w));
var NearestY = Max(rect.y, Min(circle.pos.y, rect.y + rect.h));
var dist = createVector(circle.pos.x - NearestX, circle.pos.y - NearestY);
if (circle.vel.dot(dist) < 0) { //if circle is moving toward the rect
//update circle.vel using one of the above methods
}
var penetrationDepth = circle.r - dist.mag();
var penetrationVector = dist.normalise().mult(penetrationDepth);
circle.pos = circle.pos.sub(penetrationVector);
}
Bat and Ball collision
The best way to handle ball and rectangle collision is to exploit the symmetry of the system.
Ball as a point.
First the ball, it has a radius r that defines all the points r distance from the center. But we can turn the ball into a point and add to the rectangle the radius. The ball is now just a single point moving over time, which is a line.
The rectangle has grown on all sides by radius. The diagram shows how this works.
The green rectangle is the original rectangle. The balls A,B are not touching the rectangle, while the balls C,D are touching. The balls A,D represent a special case, but is easy to solve as you will see.
All motion as a line.
So now we have a larger rectangle and a ball as a point moving over time (a line), but the rectangle is also moving, which means over time the edges will sweep out areas which is too complicated for my brain, so once again we can use symmetry, this time in relative movement.
From the bat's point of view it is stationary while the ball is moving, and from the ball, it is still while the bat is moving. They both see each other move in the opposite directions.
As the ball is now a point, making changes to its movement will only change the line it travels along. So we can now fix the bat in space and subtract its movement from the ball. And as the bat is now fixed we can move its center point to the origin, (0,0) and move the ball in the opposite direction.
At this point we make an important assumption. The ball and bat are always in a state that they are not touching, when we move the ball and/or bat then they may touch. If they do make contact we calculate a new trajectory so that they are not touching.
Two possible collisions
There are now two possible collision cases, one where the ball hits the side of the bat, and one where the ball hits the corner of the bat.
The next images show the bat at the origin and the ball relative to the bat in both motion and position. It is travelling along the red line from A to B then bounces off to C
Ball hits edge
Ball hits corner
As there is symmetry here as well which side or corner is hit does not make any difference. In fact we can mirror the whole problem depending on which size the ball is from the center of the bat. So if the ball is left of the bat then mirror its position and motion in the x direction, and the same for the y direction (you must keep track of this mirror via a semaphore so you can reverse it once the solution is found).
Code
The example does what is described above in the function doBatBall(bat, ball) The ball has some gravity and will bounce off of the sides of the canvas. The bat is moved via the mouse. The bats movement will be transferred to the ball, but the bat will not feel any force from the ball.
const ctx = canvas.getContext("2d");
const mouse = {x : 0, y : 0, button : false}
function mouseEvents(e){
mouse.x = e.pageX;
mouse.y = e.pageY;
mouse.button = e.type === "mousedown" ? true : e.type === "mouseup" ? false : mouse.button;
}
["down","up","move"].forEach(name => document.addEventListener("mouse" + name, mouseEvents));
// short cut vars
var w = canvas.width;
var h = canvas.height;
var cw = w / 2; // center
var ch = h / 2;
const gravity = 1;
// constants and helpers
const PI2 = Math.PI * 2;
const setStyle = (ctx,style) => { Object.keys(style).forEach(key=> ctx[key] = style[key] ) };
// the ball
const ball = {
r : 50,
x : 50,
y : 50,
dx : 0.2,
dy : 0.2,
maxSpeed : 8,
style : {
lineWidth : 12,
strokeStyle : "green",
},
draw(ctx){
setStyle(ctx,this.style);
ctx.beginPath();
ctx.arc(this.x,this.y,this.r-this.style.lineWidth * 0.45,0,PI2);
ctx.stroke();
},
update(){
this.dy += gravity;
var speed = Math.sqrt(this.dx * this.dx + this.dy * this.dy);
var x = this.x + this.dx;
var y = this.y + this.dy;
if(y > canvas.height - this.r){
y = (canvas.height - this.r) - (y - (canvas.height - this.r));
this.dy = -this.dy;
}
if(y < this.r){
y = this.r - (y - this.r);
this.dy = -this.dy;
}
if(x > canvas.width - this.r){
x = (canvas.width - this.r) - (x - (canvas.width - this.r));
this.dx = -this.dx;
}
if(x < this.r){
x = this.r - (x - this.r);
this.dx = -this.dx;
}
this.x = x;
this.y = y;
if(speed > this.maxSpeed){ // if over speed then slow the ball down gradualy
var reduceSpeed = this.maxSpeed + (speed-this.maxSpeed) * 0.9; // reduce speed if over max speed
this.dx = (this.dx / speed) * reduceSpeed;
this.dy = (this.dy / speed) * reduceSpeed;
}
}
}
const ballShadow = { // this is used to do calcs that may be dumped
r : 50,
x : 50,
y : 50,
dx : 0.2,
dy : 0.2,
}
// Creates the bat
const bat = {
x : 100,
y : 250,
dx : 0,
dy : 0,
width : 140,
height : 10,
style : {
lineWidth : 2,
strokeStyle : "black",
},
draw(ctx){
setStyle(ctx,this.style);
ctx.strokeRect(this.x - this.width / 2,this.y - this.height / 2, this.width, this.height);
},
update(){
this.dx = mouse.x - this.x;
this.dy = mouse.y - this.y;
var x = this.x + this.dx;
var y = this.y + this.dy;
x < this.width / 2 && (x = this.width / 2);
y < this.height / 2 && (y = this.height / 2);
x > canvas.width - this.width / 2 && (x = canvas.width - this.width / 2);
y > canvas.height - this.height / 2 && (y = canvas.height - this.height / 2);
this.dx = x - this.x;
this.dy = y - this.y;
this.x = x;
this.y = y;
}
}
//=============================================================================
// THE FUNCTION THAT DOES THE BALL BAT sim.
// the ball and bat are at new position
function doBatBall(bat,ball){
var mirrorX = 1;
var mirrorY = 1;
const s = ballShadow; // alias
s.x = ball.x;
s.y = ball.y;
s.dx = ball.dx;
s.dy = ball.dy;
s.x -= s.dx;
s.y -= s.dy;
// get the bat half width height
const batW2 = bat.width / 2;
const batH2 = bat.height / 2;
// and bat size plus radius of ball
var batH = batH2 + ball.r;
var batW = batW2 + ball.r;
// set ball position relative to bats last pos
s.x -= bat.x;
s.y -= bat.y;
// set ball delta relative to bat
s.dx -= bat.dx;
s.dy -= bat.dy;
// mirror x and or y if needed
if(s.x < 0){
mirrorX = -1;
s.x = -s.x;
s.dx = -s.dx;
}
if(s.y < 0){
mirrorY = -1;
s.y = -s.y;
s.dy = -s.dy;
}
// bat now only has a bottom, right sides and bottom right corner
var distY = (batH - s.y); // distance from bottom
var distX = (batW - s.x); // distance from right
if(s.dx > 0 && s.dy > 0){ return }// ball moving away so no hit
var ballSpeed = Math.sqrt(s.dx * s.dx + s.dy * s.dy); // get ball speed relative to bat
// get x location of intercept for bottom of bat
var bottomX = s.x +(s.dx / s.dy) * distY;
// get y location of intercept for right of bat
var rightY = s.y +(s.dy / s.dx) * distX;
// get distance to bottom and right intercepts
var distB = Math.hypot(bottomX - s.x, batH - s.y);
var distR = Math.hypot(batW - s.x, rightY - s.y);
var hit = false;
if(s.dy < 0 && bottomX <= batW2 && distB <= ballSpeed && distB < distR){ // if hit is on bottom and bottom hit is closest
hit = true;
s.y = batH - s.dy * ((ballSpeed - distB) / ballSpeed);
s.dy = -s.dy;
}
if(! hit && s.dx < 0 && rightY <= batH2 && distR <= ballSpeed && distR <= distB){ // if hit is on right and right hit is closest
hit = true;
s.x = batW - s.dx * ((ballSpeed - distR) / ballSpeed);;
s.dx = -s.dx;
}
if(!hit){ // if no hit may have intercepted the corner.
// find the distance that the corner is from the line segment from the balls pos to the next pos
const u = ((batW2 - s.x) * s.dx + (batH2 - s.y) * s.dy)/(ballSpeed * ballSpeed);
// get the closest point on the line to the corner
var cpx = s.x + s.dx * u;
var cpy = s.y + s.dy * u;
// get ball radius squared
const radSqr = ball.r * ball.r;
// get the distance of that point from the corner squared
const dist = (cpx - batW2) * (cpx - batW2) + (cpy - batH2) * (cpy - batH2);
// is that distance greater than ball radius
if(dist > radSqr){ return } // no hit
// solves the triangle from center to closest point on balls trajectory
var d = Math.sqrt(radSqr - dist) / ballSpeed;
// intercept point is closest to line start
cpx -= s.dx * d;
cpy -= s.dy * d;
// get the distance from the ball current pos to the intercept point
d = Math.hypot(cpx - s.x,cpy - s.y);
// is the distance greater than the ball speed then its a miss
if(d > ballSpeed){ return } // no hit return
s.x = cpx; // position of contact
s.y = cpy;
// find the normalised tangent at intercept point
const ty = (cpx - batW2) / ball.r;
const tx = -(cpy - batH2) / ball.r;
// calculate the reflection vector
const bsx = s.dx / ballSpeed; // normalise ball speed
const bsy = s.dy / ballSpeed;
const dot = (bsx * tx + bsy * ty) * 2;
// get the distance the ball travels past the intercept
d = ballSpeed - d;
// the reflected vector is the balls new delta (this delta is normalised)
s.dx = (tx * dot - bsx);
s.dy = (ty * dot - bsy);
// move the ball the remaining distance away from corner
s.x += s.dx * d;
s.y += s.dy * d;
// set the ball delta to the balls speed
s.dx *= ballSpeed;
s.dy *= ballSpeed;
hit = true;
}
// if the ball hit the bat restore absolute position
if(hit){
// reverse mirror
s.x *= mirrorX;
s.dx *= mirrorX;
s.y *= mirrorY;
s.dy *= mirrorY;
// remove bat relative position
s.x += bat.x;
s.y += bat.y;
// remove bat relative delta
s.dx += bat.dx;
s.dy += bat.dy;
// set the balls new position and delta
ball.x = s.x;
ball.y = s.y;
ball.dx = s.dx;
ball.dy = s.dy;
}
}
// main update function
function update(timer){
if(w !== innerWidth || h !== innerHeight){
cw = (w = canvas.width = innerWidth) / 2;
ch = (h = canvas.height = innerHeight) / 2;
}
ctx.setTransform(1,0,0,1,0,0); // reset transform
ctx.globalAlpha = 1; // reset alpha
ctx.clearRect(0,0,w,h);
// move bat and ball
bat.update();
ball.update();
// check for bal bat contact and change ball position and trajectory if needed
doBatBall(bat,ball);
// draw ball and bat
bat.draw(ctx);
ball.draw(ctx);
requestAnimationFrame(update);
}
requestAnimationFrame(update);
canvas { position : absolute; top : 0px; left : 0px; }
body {font-family : arial; }
Use the mouse to move the bat and hit the ball.
<canvas id="canvas"></canvas>
Flaws with this method.
It is possible to trap the ball with the bat such that there is no valid solution, such as pressing the ball down onto the bottom of the screen. At some point the balls diameter is greater than the space between the wall and the bat. When this happens the solution will fail and the ball will pass through the bat.
In the demo there is every effort made to not loss energy, but over time floating point errors will accumulate, this can lead to a loss of energy if the sim is run without some input.
As the bat has infinite momentum it is easy to transfer a lot of energy to the ball, to prevent the ball accumulating to much momentum I have added a max speed to the ball. if the ball moves quicker than the max speed it is gradually slowed down until at or under the max speed.
On occasion if you move the bat away from the ball at the same speed, the extra acceleration due to gravity can result in the ball not being pushed away from the bat correctly.
Correction of an idea shared above, with adjusting velocity after collision using tangental velocity.
bounciness - constant defined to represent lost force after collision
nv = vector # normalized vector from center of cricle to collision point (normal)
pv = [-vector[1], vector[0]] # normalized vector perpendicular to nv (tangental)
n = dot_product(nv, circle.vel) # normal vector length
t = dot_product(pv, circle.vel) # tangental_vector length
new_v = sum_vectors(multiply_vector(t*bounciness, pv), multiply_vector(-n*self.bounciness, nv)) # new velocity vector
circle.velocity = new_v
i need to zoom to a particular coordinate(X,Y) on the canvas in fabrics js.
I know that there will be 2 functions being called
1. Scaled (x times)
2. Move the image to some x,y location so that the image appears to be at that coordinate.
Also i need that once zoomed in , i specify some other coordinate and it should zoom to that new coordinate. Any tips
You can define yourself a camera.
You have some absolute coordinate system and you want to project things from that system to the screen. That is done by the camera object.
The camera has a position somewhere in your absolute coordinate system and it has a zoom factor and a rotation angle. The toScreen function takes absolute coordinates and translates them into coordinates on the screen. fromScreen does the opposite. moveBy is a relative move i.e. it moves in screen coordinates not absolute coordinates. That is useful for example if you have an image and you want it to follow your mouse pointer since the mouse pointer coordinates are screen coordinates. So you just calculate by how much the pointer moved and then call moveBy on the camera with the negative of those numbers. (negative because if a camera is moved left the image it produces moves right on the screen)
Or lets say you click on a point on the screen and you then want the camera to zoom onto that point. Then you just say camera.moveBy(pointX, pointY) (where pointX/Y is the mouse position relative to the center of the screen i.e. the position of the camera since in screen coordinates the camera is always at position (0, 0)) and change the zoom factor if needed. btw. the "screen" here is of course your canvas. And pos (0,0) in screen coordinates should be the center of the canvas. So just to emphasize, the canvas is not your absolute coordinate system but the screen onto which the camera projects its image.
function Camera() {
this.x = 0;
this.y = 0;
this.zoom = 1;
this.angle = 0;
}
Camera.prototype.moveTo = function(x, y) {
this.x = x; this.y = y;
};
Camera.prototype.moveBy = function(x, y) {
var xy = this.fromScreen(x, y);
this.moveTo(xy.x, xy.y);
};
Camera.prototype.rotateTo = function(angle) {
while(angle < 0) angle += 360;
angle %= 360;
this.angle = angle;
};
Camera.prototype.rotateBy = function(angle) {
this.rotateTo(this.angle + angle);
};
Camera.prototype.zoomTo = function(zoom) {
this.zoom = zoom;
};
Camera.prototype.zoomBy = function(zoom) {
this.zoom *= zoom;
};
Camera.prototype.toScreen = function(x, y) {
x -= this.x; y -= this.y;
if(this.angle !== 0) {
var rad = Math.PI * this.angle / 180;
rad = 2 * Math.PI - rad;
var _x = x * Math.cos(rad) - y * Math.sin(rad),
_y = x * Math.sin(rad) + y * Math.cos(rad);
x = _x; y = _y;
}
return {x: x * this.zoom,
y: y * this.zoom}
};
Camera.prototype.fromScreen = function(x, y) {
x /= this.zoom;
y /= this.zoom;
if(this.angle !== 0) {
var rad = Math.PI * this.angle / 180;
var _x = x * Math.cos(rad) - y * Math.sin(rad),
_y = x * Math.sin(rad) + y * Math.cos(rad);
x = _x; y = _y;
}
x += this.x; y += this.y;
return {x: x,
y: y};
};
I have a point drawn in an canvas (html5). Then I want this point to animate in a circular path.
I saw an example using time differences to set the x and y variables, in respect to time. Some of the variables and formulas used are quite vague, I have forgotten my physics, d*mn. But I have researched quite a bit on circular motion, so I can understand some of it. Here is my codepen on how it was done.
Basically here are the parts I have identified so far:
this.orbit = 100; // this is the radius of the circular orbit
this.radius = 5; // orbiting object's radius
this.velocity = 50; // yeah velocity but without direction, should be speed (agree?)
var angle = 0; starting angle of the point in the orbit inside the canvas's quadrant,
set x and y coordinates with respect to the coordinates of the canvas
first get the center of the canvas by dividing the width and the height by 2
then adding to the product of the orbit's radius and the position of x and y
with respect to the initial position in the orbit(angle), and since Math trigonometric
functions uses radians, we should multiply it to the quotient of PI and 180.
this.x = _width / 2 + this.orbit * Math.cos(angle * Math.PI / 180)
this.y = _height / 2 + this.orbit * Math.sin(angle * Math.PI / 180)
// by doing the above, we now get the initial position of x and y in the orbit.
What is quite trivial to me are the next variables _dx and _dy and also the _magnitude.
Here is how the point is animated:
Point.prototype.update = function(dt) {
var dps = this.orbit * 2 * Math.PI / this.velocity;
var angle = (360 / dps) * dt / 1000 * -1;
this.vx = this.vx * Math.cos(angle * Math.PI / 180) - this.vy*Math.sin(angle * Math.PI / 180);
this.vy = this.vx * Math.sin(angle * Math.PI / 180) + this.vy*Math.cos(angle * Math.PI / 180);
var _magnitude = Math.sqrt( this.vx * this.vx + this.vy * this.vy);
this.vx = this.vx / _magnitude * this.velocity;
this.vy = this.vy / _magnitude * this.velocity;
this.x += this.vx * dt / 1000;
this.y += this.vy * dt / 1000;
}
And here is the execution of the script:
function animate () {
dt = new Date() - ldt;
if (dt < 500) {
// context.clearRect(0, 0, canvas.width, canvas.height);
point.update(dt);
point.draw(context);
};
ldt = new Date();
setTimeout(function() {
window.requestAnimationFrame(animate);
}, 1000 / 30)
}
ldt = new Date();
animate();
With the unclear variables, like _dx _dy _magnitude I cannot understand how it works and how the computation of variables, vx vy which I assume the velocity with respect to x and y respectively.
I wanted to use greensock tweenlite for the animation and it is done like so:
Point.prototype.update = function(p){
var _to = {
x: , // change the value of x
y: , // change the value of y
ease: Cubic.easeInOut,
onComplete: function () { this.update(p) }
}
TweenLite.to(point, 2, _to)
}
As you can see the first parameter is the current object (point), then the second parameter is the time, I assume this to be the velocity and the the third parameter is the change in the object's properties, x and y.
Question
I made the codepen, now How do I use gsap tweenlite to animate the circle like what I did, I suppose using tweenlite will make it a little simple.
In your case you are trying to use TweenLite to animate point as the crow flies, and you trigger TweenLite.to() function for each new position of point. This method of using TweenLite.to() function has no sense and performance, because distance between 2 position of point is too short. So, this method will only slow down your animation because instead of just draw point in new position you want to animate it.
The best solution in this case is trying to use TweenLite's methods to animate whole circle.
Take a look on this article: Tween around circle
Especially on these examples:
1) http://codepen.io/GreenSock/pen/jCdbq (not canvas, but it displays the main idea)
TweenMax.to("#logo", 4, {rotation:360, transformOrigin:"40px -100px", repeat:10, ease:Linear.easeNone});
2) and http://codepen.io/rhernando/pen/kjmDo
Okay, so I want to make a javascript/html canvas game where the player is being followed by some enemies, and after a little bit of 'research' her is the most important part of my Monster (enemy) class:
this.UpdateAngle = function() {
this.dx = this.x - player.x;
this.dy = this.y - player.y;
this.angle = Math.atan2(this.dy, this.dx) * 180 / Math.PI;
if (this.angle < 0) {
this.angle += 2 * Math.PI;
}
}
this.UpdateSpeed = function() {
this.speedX = this.speed * Math.cos(this.angle);
this.speedY = this.speed * Math.sin(this.angle);
}
this.Move = function() {
this.UpdateAngle();
this.UpdateSpeed();
this.x += this.speedX;
this.y += this.speedY;
}
So what I meant to do here, was to calculate the angle from the enemy to the player with atan2() and then calculate how much I should move in the x and y axis by using cos() and sin(), the speed and the angle I calculated, and then just moved the calculated pixels.
This all seems to work well, until I move the player, then the enemies start to move in weird directions. I have no idea whats wrong, it would be awesome if someone could learn me how this is meant to be done. :D
You can see it in action here. *I have updated the code with PremierBromanov's suggestion.
It may have something to do with this block
this.angle = Math.atan2(this.dy,this.dx) * 180 / Math.PI;
if (this.angle < 0) {
this.angle += 2 * Math.PI;
You are using Math.atan2 which outputs the angle in radians, then you are converting to degrees with * 180 / Math.PI; After that, you're checking to see if it's less than zero and adding 2Pi to the angle to make sure it's correctly calculating it's actual angle of a full circle minus the angle. BUT, you are using radians here instead of degrees. So when your code is negative, you're adding 2Pi to the degree, which isn't very much, but sometimes causes it to go positive. This is why your dots are spinning when you move. If you notice, the dots spin slower when you are farther away, meaning the negative angle is larger than 2Pi and so doesn't circle around right away.
in short, try changing it to this
if (this.angle < 0) {
this.angle += 360;
}
Ok, so it was actually Premier Bromanov who answered this, thanks, but I can't accept a comment, which it was, so I will just do this to make it more clear, if anyone should come by and want the answer too.
The math i did was a bit wrong, and here is how my code ended up looking like:
this.UpdateAngle = function() {
this.dx = player.x - this.x;
this.dy = player.y - this.y;
this.distance = Math.sqrt((this.dx*this.dx) + (this.dy*this.dy));
this.angle = Math.atan2(this.dy,this.dx) * 180 / Math.PI;
}
this.UpdateSpeed = function() {
this.speedX = this.speed * (this.dx/this.distance);
this.speedY = this.speed * (this.dy/this.distance);
}
this.Move = function() {
this.UpdateAngle();
this.UpdateSpeed();
this.x += this.speedX;
this.y += this.speedY;
}
Thanks again to Premier Bromanov, this is his answer, and also to everyone else, this was my first post and i am glad how fast i got a response! (I was the slowest one here) :D