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.
Related
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.
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.
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'm developing an HTML5 3D fps-like engine that already looks quite nice, but as this might be one of the worst language choices to make 3D there's noticeable lag sometimes.
I programmed movements (WASD) to be independent of rendering speed, so sometimes it's quite jerky, but other times is working at an acceptable 30+ fps (depending on CPU of course).
The only thing I can't wrap my mind around is jumping: currently the jumping is done by adding a positive constant to the falling variable (gravity is always negative and then corrected by collision detection) and then subtracting a constant, this is called every time a new frame is rendered, the thing is that when fps go low I feel like I'm on the moon. I prefer jerkiness to slow-mo effect.
If I use the same method like I do for moving (calculate time between current and last frame) the deducted variable gets too big sometimes and the jumping apex changes (to half of the value compared to high fps) - this is unacceptable as jumping height must be always the same.
Here's some pseudo-code to help understanding the problem (called during one rendering routine):
// when clicked on spacebar:
if(spacebar)
{
// this defines jumping apex
jump = 0.5
}
// constant added to y (vertical position) later in the code
cy += jump;
// terminal velocity = -2
if(jump > -2)
{
// gravity (apex multiple to get maximum height)
jump -= 0.05;
}
if(collision_with_floor)
{
// stop falling
cy = 0;
if(jump < 0)
{
jump = 0;
}
}
player.position.y += cy;
Now with time dependent jumping (replace in the code above):
// terminal velocity = -2
if(jump > -2)
{
// gravity, 0.4 is an arbitrary constant
jump -= (now - last_frame)*0.4;
last_frame = now;
}
To illustrate even better here's an image of what's going on:
Blue dots indicate frame renders.
I'm not even sure of this is the right way to program jumping routine. Basically jerkiness and constant jumping height is better than smoothness and slow-mo effect.
If the frame updates are coming too slowly to get accurate physics, then maybe you can hack in the jump apex so that the player always hits it. The cue here might be when the y velocity changes from positive to negative. If I'm reading your pseudocode right, then it looks like:
old_cy = cy;
cy += jump;
if(old_cy > 0 && cy <= 0)
player.position.y = jump_apex_height;
In terms of your graph, the idea is that you want to identify the blue dot that reaches the orange line, then bump it up to the dotted line.
And now that I'm thinking about it, if the player really has to reach the jump apex every time, then this might help even for high-rate updates.
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/