I cant seem to be able to solve a math problem related to collision detection.
I got the basic idea. Find the difference between two opposite x and y values. Calculate the distance by multiplying the two results by itself to get the distance and then a check to see if the two balls collide. Then checking if any part of the angles intersect. Honestly it works somewhat but is still broken.
Problem: When starting the game and I let the ball collide with the visible half then the collison works and when the ball enters the non visible area the collision returns false. At the other hand, when restarting and letting it collide with the non visible area the collision returns true, then false when it enters the visible part of the semicircle.
What could it be? I suspect something due to my rotation. This is honestly weird. Here a demo:
http://jsfiddle.net/2rz296tf/17/
Below the essential formula that makes it "kind of" work:
var dx = a - b;
var dy = a - b;
var semi = Math.atan2(dx, dy)
var distance = Math.sqrt(dx * dx + dy * dy);
var hit = (distance < radiusA + radiusB) && (semi >= 0 && semi < angleB);
You're comparing an angle to a length: semi < radiusB. That doesn't make any sense. You should compare semi to the orientation of your shield, not with its radius.
Looking at your code, you should do something like semi >= angle - Math.PI && semi <= angle instead. You'll need to implement a way to deal with the fact that angles run from -pi to pi and then loop around.
Related
I have a circle in my canvas. The mouse position is calculated in relation to the canvas. I want the circle to move when the mouse is at <=100px distance from it. The minimum distance to start moving is 100px, at 0.5px/tick. It goes up to 2px/tick at 20px distance.
Basically, the closer the mouse is to the circle, the faster the circle should move.
What I have so far moves the circle when distance is less or equal to 100 -- (I'm using easeljs library)
function handleTick() {
distance = calculateDistance(circle, mX, mY);
if (distance<=100) {
circle.x += 0.3;
stage.update();
}
}
What I want
function handleTick() {
distance = calculateDistance(circle, mX, mY);
if (distance<=100) {
circleSpeed = // equation that takes distance and outputs velocity px/tick.
circle.x += circleSpeed;
stage.update();
}
}
So I thought this was a mathmatical problem and posted it on math exchange, but so far no answers. I tried googling several topics like: "how to come up with an equation for a relation" since I have the domain (100, 20) and the range (0.5, 2). What function can relate them?
Thing is I'm bad at math, and these numbers might not even have a relation - I'm not sure what I'm looking for here.
Should I write a random algorithm "circleSpeed = 2x + 5x;" and hope it does what I want? Or is it possible to do as I did - "I want these to be the minimum and maximum values, now I need to come up with an equation for it"?
A pointer in the right direction would be great because so far I'm shooting in the dark.
If I understand it correctly, you want circleSpeed to be a function of distance, such that
circleSpeed is 0.5 when distance is 100.
circleSpeed is 2 when distance is 20.
There are infinity functions which fulfill that, so I will assume linearity.
The equation of the line with slope m and which contains the point (x₀,y₀) is
y = m (x-x₀) + y₀
But in this case you have two points, (x₁,y₁) and (x₂,y₂), so you can calculate the slope with
y₂ - y₁
m = ───────
x₂ - x₁
So the equation of the line is
y₂ - y₁
y = ─────── (x - x₁) + y₁
x₂ - x₁
With your data,
0.5 - 2
y = ──────── (x - 20) + 2 = -0.01875 x + 2.375
100 - 20
Therefore,
circleSpeed = -0.01875 * distance + 2.375
I assume you want a linear relation between the distance and speed?
If so, you could do something like circleSpeed = (2.5 - 0.5(distance/20)).
That would, however set the speed linearly from 0 to 2.5 on the range (100 to 0), but by using another if like this if (distance < 20) circleSpeed = 2 you would limit the speed to 2.0 at 20 range.
It's not 100% accurate to what you asked for, but pretty close and it should look ok I guess. It could possibly also be tweaked to get closer.
However if you want to make the circle move away from the mouse, you also need to do something to calculate the correct direction of movement as well, and your problem gets a tiny bit more complex as you need to calculate speed_x and speed_y
Here is a simple snippet to animate the speed linearly, what that means is that is the acceleration of the circle will be constant.
if distance > 100:
print 0
elseif distance < 20:
print 2
else:
print 2 - (distance -20 ) * 0.01875
Yet other relationships are possible, (other easings you might call them) but they will be more complicated, hehe.
EDIT: Whoops, I’d made a mistake.
I've been experimenting with HTML5 canvases lately and came across this 3d example with relatively little code behind it. I was hoping to find a good introduction to 3d rendering, but I'm having more trouble understanding the geometry behind the code than I was expecting to. I set up a JSbin and copied over the code that was used on his website to play with. I'm stuck at understanding the meaning of
deltaX=1/Math.cos(theta);
which is later used in:
if (deltaX>0) {
stepX = 1;
distX = (mapX + 1 - x) * deltaX;
}
else {
stepX = -1;
distX = (x - mapX) * (deltaX*=-1);
}
Source
My best guess is that it's used for the relation cos(x) = adjacent/hypotenuse in a right triangle, but I don't understand where the triangle would fit in, if at all.
If you draw a line from the origin (0, 0) with direction theta (measured from the x-axis), then
deltaX = 1/cos(theta) is the distance on this line until the vertical line x = 1 is met, and
deltaY = 1/sin(theta) is the distance on this line until the horizontal line y = 1 is met.
It is indeed a triangle relation. In the first case, the triangle has the points (0, 0), (1, 0) and the point (1, y) where the line meets the vertical line x=1.
(mapX, mapY) is a grid point with integer coordinates, and (x, y) is a point in the square [mapX, mapX+1) x [mapY, mapY+1).
distX computes the distance of the next vertical grid line in theta-direction, and distY the distance of the next horizontal grid line.
Remark: The computation fails if the direction is a multiple of π/2, i.e. the direction is exactly right, up, left, or down, because sin(theta) = 0 or cos(theta) = 0 in that case. This probably does not happen in your program, because the playerDirection starts with 0.4 and is incremented or decremented by 0.07.
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.
I have a 2D animation in Javascript, and I need a sprite to move from one point (x1, y1) to another point (x2, y2) on a set speed and direction. For example,
function update(speedX, speedY){
x1 += speedX;
y1 += speedY;
if("(x1, y1) reach (x2, y2)"){
// do other stuff
}
}
In most cases, speedX and speedY are not equal, nor do they factor evenly into the distance needed to travel for each axis. I calculate the speedX and speedY values using a tangent function to compute the necessary velocity for a given speed and angle.
My question is, is there an algorithm that can do this? I would prefer something efficient since this has to be done 30 times a second, and it's float addition! Thanks!
Usually (I developed some games in the past, nothing special btw) I used to see my sprites as rectangles and then I check for the overlapping of the two sprites using a very simple formula (look at this very good explanation).
Let's suppose you have to check collision between a point and a rectangle. You can apply the same formula, simplified, to check if the point stays between the rectangle area. In the case, read here.
SOLUTION:
Okay, with some work I figured it out. First, I defined a function
function getSign(val) { ... }
that simply returns -1, 0, or 1 depending on whether the number passed in is negative, 0, or positive, respectively. Then, I did the following at the beginning (before any updates happened):
var xSign = getSign(x1-x2);
var ySign = getSign(y1-y2);
Finally, to check whether or not the point is currently at or just past the target (x2, y2), just check with this code:
function update(speedX, speedY){
x1 += speedX;
x2 += speedY;
var curXsign = getSign(x1-x2);
var curYsign = getSign(y1-y2);
if( curXsign != xSign || curYsign != ySign ||
(curXsign == 0 && curYsign == 0)){
// do other stuff
}
}
Basically, if either sign of the relative vector distance between X or Y changes sign, that means that axis went past the point. If both curXsign and curYsign are 0, that means it's right on the target point. Either of these three cases mean that you are on or just went past the target point. Tested and works.
Another possible solution would be to test the distance between the start point and the current location (curDist), and compare it to the distance between the start point and the target point (dist). Once curDist >= dist, you know you are at or past the target point.
It is in the $1F port of the VIC-II:
PRINT PEEK(53279)
:-)
I wrote a very simple collision detection demo:
http://jsfiddle.net/colintoh/UzPg2/5/
As you can see, the objects sometimes doesn't connect at all but yet the collision is being triggered. The radius for the balls are 10px so the algo triggered the collision whenever the distance between two balls center is less than 20px. I reduced it to 18px for a better visual but the empty collision still happens randomly. Am I doing something wrong?
It looks like you are not using the right formula for distance between two points. See http://www.purplemath.com/modules/distform.htm for a full explanation.
You are doing this:
this.ballCollide = function(balli) {
if (Math.abs((this.x) - (balli.x)) < (2*radius - buffer)) {
if (Math.abs((this.y) - (balli.y)) < (2*radius - buffer)) {
// Do collision
}
}
};
That's a square bounding box, not a circular one. To get a circular bounding box, you can do something like this, based on the formula in the referenced web page:
this.ballCollide = function(balli) {
var deltax = this.x - balli.x;
var deltay = this.y - balli.y;
if (Math.sqrt(deltax * deltax + deltay * deltay) < 2 * radius - buffer) {
// Do collision
}
};
See http://jsfiddle.net/UzPg2/14/ for a working example.
Note that a perfect circular bounding box is a much slower algorithm than a square bounding box approximation.
Following Jarrod Roberson's point (a perfect circle is always inside a perfect square), you'd do that by basically combining your original code with the code I posted, like this (and you could combine them both into one conditional switch if you wanted to):
var deltax = this.x - balli.x;
var deltay = this.y - balli.y;
var dist = 2 * radius - buffer;
if (Math.abs(deltax) < dist && Math.abs(deltay) < dist) {
if (Math.sqrt(deltax * deltax + deltay * deltay) < dist) {
// Do collision
}
}
See http://jsfiddle.net/UzPg2/21/ for a working example (I've left the buffer as your variable is called at 2, but I personally think it looks better with a value of 1).
There are also many other ways you can optimize this for speed if you need to, but Jarrod's suggestion gives you the biggest immediate speed boost.
You're only checking for collisions on two axis, x and y. You need to use Pythagoras' theorem to detect on all axis at the cost of efficiency. For example.
Your algorithm will detect a collision around the point where these two balls are, since if you draw a tangent line along the x or y axis from one ball it goes through the other ball: http://jsfiddle.net/XpXzW/1/
Here you can see where they should actually collide:
http://jsfiddle.net/wdVmQ/1/
If you change your collision detection algorithm to check for perfect collisions (it will be less efficient) you can get rid of your buffer too:
http://jsfiddle.net/ucxER/
(Using Pythagoras' theorem the formula for a collision is:
Math.sqrt((this.x - balli.x)*(this.x - balli.x)
+ (this.y - balli.y)*(this.y - balli.y)) < 2*radius
Also what Jarrod commented is very smart. You can speed it up by using a technique like that. Since the square root is only calculated when the balls are close to each other:
http://jsfiddle.net/bKDXs/