Smooth rotation issue with javascript - javascript

I have searched all over for a solution to my problem on smooth rotation. I can get it 99% working however there is one small issue that keeps messing with me. The rotations works fine except when the target makes a drastic change. The basic idea is I have a ball and a player when the player comes in contact with the ball he changes the balls direction and speed. The player follows the ball correctly however when he comes in contact with the ball or the ball's location is reset thus making the delta between the angles greater than 45 degrees the player instantly jumps to fact the ball. Here is the code that I have partly working. Thank you for any help in advance.
var newFacing = Math.atan2(theBall.y-player.y,theBall.x-player.x);
var diff = (Math.abs(newFacing) - Math.abs(player.facing));
if (diff < Math.PI*0.1 && diff > -Math.PI*0.1){
player.facing = newFacing;
}else if (diff > Math.PI) {
player.facing -= Math.PI*0.1;
} else {
player.facing += Math.PI*0.1;
}
if (player.facing > Math.PI) {
player.facing -= Math.PI*2;
} else if (player.facing < -Math.PI) {
player.facing += Math.PI*2;
}
Updated: Changed the || to && and added a condition to ensure I do not go above or below PI radians. There are still some odd rotational issues at some angles. For example if the ball passes below the player he will rotate clockwise to follow rather than the logical counter clockwise. At times the player will do a full 360 before tracking the ball again. Without tracing it I am not sure what conditions are causing this.

Related

Rotating to point at something in radians without wrapping around zero

Let's say I have a circle with a line sticking out of it.
I want that line to point at the center of the window, no matter where the circle moves to.
But, I want that line to slowly move to that angle. I don't want the rotation to be calculated and set every single frame, but rather calculated and tweened to that direction.
The issue I'm having with this is that if you move to make the line rotate around where the radians meet 0, it will do a full 360 (or 3.14 in rads ;) to get to that point.
I have spent a while trying to think of how to explain this best, here is a codepen that can hopefully help clarify what I'm asking
// CenterX/Y is the center of the screen.
// dotX/Y is the center of the circle.
var angleToCenter=Math.atan2(centerY-dotY,centerX-dotX);
if (angleToCenter<currentAngle) {
currentAngle-=0.05;
} else {
currentAngle+=0.05;
}
if you move to the right of the screen, then go above or below the center, you will see the line move in a full circle to try to get to the calculated direction. How do I avoid this? I want the line to seamlessly rotate to point at the center, via the shortest possible way, not by doing a full circle.
Great question. Very different.
I would have an inverse (-1) relationship defined for any location below the black circle. Such that, if the red circle crosses a horizontal axis - whose boundry is defined by the black circle - the mathematical result to your equation is inversed.
This would make 0 degrees as we typically think of it, now positioned at 180 degrees.
Reasoning: Looking at your CodePen it's obvious that the stem is going "the long way around", but you want it to go the "short way around". The most intuitive way to make that happen would seem to be to inverse the red-circles calculated rotation. The simplest method I can think of would be to inverse the polarity of the circle.
The problem lies in the point where angleToCenter switches from Math.PI to -Math.PI (and vice versa).
Therefore I'd suggest you create an "epsilon angle distance", in which the angles will be hard-coded:
var angleToCenter = Math.atan2(centerY - dotY, centerX - dotX);
var epsilon = 0.05;
if (Math.abs(angleToCenter - Math.PI) <= epsilon / 2 || Math.abs(angleToCenter + Math.PI) <= epsilon / 2) {
if (dotY > centerY) {
currentAngle = -Math.PI;
} else if (dotY < centerY) {
currentAngle = Math.PI;
}
} else if (angleToCenter < currentAngle - epsilon) {
currentAngle -= epsilon;
} else {
currentAngle += epsilon;
}
For the full edit, you can check my fork to your CodePan

2D vertical angular collisions

Currently I am working on a 2D particle simulator. I have each particle moving on a unique angle. I found a basic formula to change x and y velocity, but I currently have a set velocity that moves according to the angle.
particles[a][3] += particles[a][1] * cos(radians(particles[a][5]));//move X
particles[a][4] += particles[a][1] * sin(radians(particles[a][5]));//move Y
I have a basic collision for collisions on walls, but can't find the best way to sort the collisions out. Currently I just multiply the rotation by -1, but that only works on the top and bottom. Note: The particle will always move after running the collision (its not getting stuck in the collision boxes and bugging out).
if(particles[a][3] < 0 || particles[a][3] > windowWidth/2 || particles[a][4] < 0 || particles[a][4] > windowHeight/2) {
/*windowWidth and windowHeight are divided by 2 to find the canvas size. In the setup() I have the canvas set to that value).*/
particles[a][5] *= -1;
}
Array values:
particles[a][1] = speed
particles[a][3] = x position
particles[a][4] = y position
particles[a][5] = rotation
My question is what is the best way to run these collision tests. I understand that collisions bounce at 90 degrees, but I'd like to use as few if statements as possible (simpler the better) instead of a tedious bunch.
Merry Christmas, and thanks in advance!
Figured it out!
Final code:
if(particles[a][4] < 0 || particles[a][4] > windowHeight/2) {
particles[a][5] *= -1;
} else if(particles[a][3] < 0 || particles[a][3] > windowWidth/2) {
particles[a][5] = 180 - particles[a][5];
}
Try googling "javascript reflect angle" and you'll find formulas for reflecting around both the X and Y axis. You do one when you collide with the top or bottom, and you do the other when you collide with the left or right.
Also, you probably shouldn't be using an array to hold your data. Create a class that holds your values, and then create instances of that class. Using magic array indexes is a recipe for headaches.
If you still can't get it working, then please post an MCVE and we'll go from there. Good luck.

How to detect collision

I am doing a small game based on this tutorial http://code.tutsplus.com/tutorials/learn-createjs-by-building-an-html5-pong-game--active-11845
I made my changes but this line is buggy
if(ball.x <= player.x + 22 && ball.x > player.x && ball.y >= player.y && ball.y < player.y + 75)
whenever the user hit it fast from the left or the right the ball keep bouncing even in the tutorial, the bug is there, can anybody help me with this ?
Thanks
I think the easiest solution would be to add a direction variable to the ball and test it. If it's towards the player do the check you've coded, else ignore. If the check passes, change the direction when the player intercepts it. Then when it bounces back, change the direction again. This will also simplify your code a lot and reduce the number of checks going on.
I have found right solution for your problum
you should add one more condition that is xSpeed<0 so that your if statement changes to as shown bellow
if(xSpeed<0 && ball.x <= player.x + 22 && ball.x > player.x && ball.y >= player.y && ball.y < player.y + 75 )
{
xSpeed *= -1;
SoundJS.play('hit');
}
I have given you this solution after testing the code.
I think this is because ball goes in too far for some reason and it does multiple *= -1; run.
so you should measure distance and bring it back and then *= -1
code would be like this:
if(ball.x <= player.x + 22 && ball.x > player.x && ball.y >= player.y && ball.y < player.y + 75)
{
ball.x += ball.x-player.x;
xSpeed *= -1;
SoundJS.play('hit');
}
so then we can make sure ball is out whenever it is inside bar.
** edited code from the link you posted.
There are two main methods of detecting collisions in 2D:
Pixel by pixel. You should use this method only if you have complex shapes, because this algorithm has O(Height*Width) complexity where Height and Width are sizes of smaller sprite in pixels.
By formulas. You should always use this method when possible. This will usually result in O(1) complexity.
In your case ball is circle(obviously) and player is rectangle, I think.
Answer to question "How to check by formulas if rectangle and circle intersect?" was answered here.
Umm If the problem is that the "too fast" ball will go inside paddles, you have three options:
make collision tests with mathematics ie. calculate if the ball will draw a line through the paddle during the current timestep.
make the timestep smaller , ie move the ball in smaller increments and collision check each step.
make the timestep adaptable , so it gets smaller when stuff gets faster and the ball will move approximately the same amount per timestep, regardless of it's speed.

Create smooth rotation in given time interval (+- x%)

I have got a cube in my scene which I want to rotate at a specific start velocity and in a given time interval.
In addition, the cube's end angle should be the same as the start angle.
Therefore, I thought of allowing +- 5% deviation of the time interval.
Here is my current status: http://jsfiddle.net/5NWab/1/.
Don't wonder that is currently working. The problem occurs if I change the time interval, e.g. by '3000': http://jsfiddle.net/5NWab/2/.
The essential move() method of my cube:
Reel.prototype.move = function (delta) {
if (this.velocity < 0 && this.mesh.rotation.x == 0) {
return false;
}
// Create smooth end rotation
if (this.velocity < 0 && this.mesh.rotation.x != 0) {
this.mesh.rotation.x += Math.abs(delta * this.speedUp * 0.5 * this.timeSpan);
if (Math.abs(this.mesh.rotation.x - 2 * Math.PI) < 0.1) {
this.mesh.rotation.x = 0;
}
}
else {
this.mesh.rotation.x += delta * this.velocity;
this.time -= delta;
this.velocity = this.speedUp * this.time;
}
}
The problem is that I cannot think of a solution or method in order to accomplish my topic.
It would not be so complex if I the variable delta would be constant.
It should be around 60fps = 1000/60 because I'm using requestAnimationFrame().
I have also found this question which could help finding the solution.
I think the code should either
slow down the velocity before the actual end is reached.
That should be the case if the final angle is a little bit greater than the desired (start) angle.
or should speed up the rotation speed after the actual end is reached.
That should be the case if the final angle is a little bit smaller than the desired (start) angle.
But what is when the angle is a hemicycle away from the desired one (i.e. 180° or PI)?
In order to clarify my question, here are my knowns and unknowns:
Known:
Start velocity
Time interval
Start angle (usually 0)
I want the cube to have the same start angle/position at the end of the rotation.
Because the FPS count is not constant, I have to shorten or lengthen the time interval in order to get the cube into the desired position.
If you want the rotation to end at a particular angle at a particular time, then I would suggest that instead of continually decrementing the rotation as your current code (2012-09-27) does, set the target time and rotation when you initialise the animation and calculate the correct rotation for the time of the frame recalculation.
So if you were doing a sine-shaped speed curve (eases in and out, linearish in the middle, nice native functions to calculate it), then (pseudocode not using your variables):
//in init
var targetTime = now + animationTime;
// normalize the length of the sine curve
var timeFactor = pi/animationTime;
var startAngle = ...
var endAngle = ...
var angleChange = endAngle - startAngle;
// inside the animation, at some time t
var remainingT = targetTime - t;
if(remainingT <= 0) {
var angle = endAngle;
} else {
var angle = startAngle + cos(remainingT * timefactor) * angleChange;
}
[Edited to add startAngle into andle calculation]
Because the cos function is odd (i.e. symmetric about the origin), as t approaches targetTime, the remainingT approaches zero and we move backward from pi to 0 on the curve. The curve of the sin shape flattens toward zero (and pi) so it will ease out at the end (and in at the beginning. There is an explicit zeroing of the angle at or past the targetTime, so that any jitter in the framerate doesn't just push it into an endless loop.
Here's one possible method, although it's not quite as good as I'd like: http://jsfiddle.net/5NWab/8/
The idea is to decrease the speed gradually, as you were doing, based on the amount of time left, until you get to a point where the amount of distance that the cube has to rotate to reach it's starting rotation (0) becomes greater than or equal to the amount of rotation that can possibly be made given the current velocity and the current amount of time left. After that point, ignore the time left, and slow down the velocity in proportion to the amount of rotation left.
This works fairly well for certain timeSpans, but for others the ending slowdown animation takes a little long.

Collision detection not detecting

I have an array of objects that are all 'rectangles'. I also have a circle that is the object. The equation I use for gravity is:
newYPos = oldYPos + prevFallingSpeed + gravity
Basically, I am adding the rate of gravity to the number of pixels the circle 'fell' in the previous frame and then adding that to the position of the circle in the last frame.
I am detecting if any part of the ball is inside of any of the objects using this code:
for(var i = 0; i < objects.length; i++){
if(ball.x > objects[i].x - ball.r && ball.y > objects[i].y - ball.r && ball.x < ball.r + objects[i].x + objects[i].w && ball.y < ball.r + objects[i].y + objects[i].h){
alert('test');
gSy = (-1 * gSy);
}
}
The code checks if the circle's coordinates plus or minus the radius is greater than the top/left positions of the walls of the box and less than the right/bottom positions of the walls of the box.
The ball is inside the object at one point, but I never get an alert. I've tried everything I can think of. Hopefully I'm just making some dumb mistake I can't see...
Here is a jsfiddle if you are up for messing with my code or don't understand the variables:
http://jsfiddle.net/JGKx5/
The small problem:
You have four objects.
Two of them (numbers 1 and 3) are tall and thin, and off to the left or right. The ball never goes near them.
One of them (number 2) is short and wide, and at y-coordinates smaller than the ball ever attains.
The other one (number 0) is short and wide, and its y-coordinates are ones that a real physical ball would pass through -- but because your ball moves in discrete steps your script never actually sees it do so. (It goes from y=580.4 to y=601.2.)
The big problem:
In the jsfiddle, all your comparisons in the collision test appear to be exactly the wrong way around :-). (Which is odd since the ones in the code here are the right way around.)
With both of these changed (I made the ball move by 0.1*gSy instead of by gSy, and flipped all the comparison operators), collisions are detected.

Categories