I have a slider, whose velocity I calculate via the difference between positions each tick (this can sometimes be huge due to using it via a touch screen, so maybe I should clamp this at some arbitrary number to avoid some of these issues?)
I have a ball with a 3 dimensional direction vector and a velocity.
When the ball collides with the slider I invert its direction on the Z axis (going away from the slider) and then use the sliders velocity to manipulate its X (left <-> right) direction. so:
ball.direction.x += (slider_friction * slider_velocity)
Now the ball update is carried out as follows:
velocity = ball.velocity * time
ball.direction.normalise()
ball.position = ball.direction * ball.velocity
This seems to work great, except in some cases it seems to be very possible for any of the balls axis to equal zero, resulting in it never returning to the slider in some cases. What would be a good solution to this? And what would be a good way to handle the response with the blocks when it collides with them? Should it return to bouncing at right angles, or should it maintain reflecting with the same bounce modifiers applied by the slider? Also any other physics tips for this kind of projectile simulation would be appreciated.
Hmm, this is a nice problem; the thing is, a good solution (that is, one that looks and feels just like real physics) is by nature one that uses real physics. Luckily, most of the newtonian physics within this problem can be easily simplified. Pardon me if I get overly verbose, but physics tends to do that to you.
So, to define the problem, this is an elastic (as in, no energy is absorbed) collision between an arkanoid ball and a paddle. First of all, since you've obviously got the vertical motion down, I won't concern myself with that. So what follows is all on the horizontal components of the collsions.
The paddle transfers a certain amount of horizontal momentum to the ball (although, since this is Arkanoid physics, the paddle loses no momentum itself :P). This can be recieved in two ways -- by making the ball spin, and by giving the ball some horizontal momentum (obviously, if the ball already has horizontal momentum or spin, the added momentum will be...well, added).
delta momentum + delta angular momentum = momentum paddle gave
Of course, it might be annoying to work with momenta, since you don't really have to. I would asssume that the ball and the paddle have constant mass (that is, the ball does not suddenly become heavier, although you could easily work with that), because then you could factor the mass of each out of your momentum equations. So then,
delta horizontal velocity + delta angular velocity = paddle velocity * mass of paddle / mass of ball
To get an equation you could use out of this, you have to set how much of the momentum from the paddle would go into the spin, and how much would go into ball movement. For example,
mass_factor = 2 # ratio between paddle and ball masses
angular_factor = 0.3 # the amount of the paddle's movement which will go into the ball's spin
# and now for the bouncy-bouncy
ball.hVel += (1 - angular_factor) * paddle.hVel * mass_factor * friction or whatever
ball.spin += angular_factor * paddle.hVel * mass_factor * friction or whatever
ball.vVel = - ball.vVel # of course, its vertical velocity reverses
This will be enough to set up a quasi-realistic bounce, but one nugget remains (which you don't need to adress, but adressing it would make your Arkanoid amazing) -- what happens to all that spin? Can the spin be used somehow for more interesting bounces?
So, to recap, your spin is the speed at which the periphery of the ball is moving relative to the center. Thing is, whenever a spinning ball bounces against something stationary, its spin changes as well as its velocity. If a spinning ball hits a stationary surface, the bal gets a little "kick" in the direction opposite that of its spin (if spin is measured at the point of contact), and the spin will change.
#Upon collision with a surface (assumed horizontal, with the ball above the surface)
ball.hVel += -(ball.Avel * rate) # Where "rate" is the ratio which determines how much angular velocity decays with each bounce
ball.Avel *= 1 - rate # So the angular velocity decays properly
Since angular velocity is rotationally symmetric, you would just treat collisions at different angles (balls on walls, balls on ceilings) as rotations of this.
Phew, that was unintentionally long-winded, and it is nowhere near complete, but it's enough to answer your question IMHO.
Related
I am coding a simulation of a cricket player throwing a ball and I have come to the part where the player throws the ball. I don't think my simulation of the ball is very accurate though and I am not quite sure why (no idea what to be looking for in physics). What I have so far is something similar to this, the arm has a rotation speed and the ball is released at a certain point. So I approached this using a vector from the arm to the ball, I figured the direction the ball should travel in the direction of the right normal. So this is what I have for the direction.
throwSpeedHorz = -1*sin(bowlerArmRotation * (3.14159/180)); // * rotationSpeed
throwSpeedVert = cos(bowlerArmRotation * (3.14159/180)); // * rotationSpeed
The problem I have is how do I use the speed of the arm with this to get the total speed for each. I have tried multiplying it by the speed of rotation which gave a way too high number for the speed.
If someone can point me in the right direction it will be greatly appreciated.
Speed is usually given in rotations per second, so the speed of the tip of bowlers "arm" is given by
speed = rotationSpeed * 2 * PI * bowlerArmLength
(or more exactly the distance of the ball to the rotation axis). You can then extract horizontal and vertical components as described in your question.
So I have a system with colliding balls that generally works, except for when they collide with similar directions, less than 90 degrees apart.
This is because the ball above tries to collide against the yellow line which is supposedly the collision plane, but it sends it off the wrong direction, and it "follows" the other ball. The general algorithm for the collision is:
dot = direction.surface;
parallel = surface * dot;
perpendicular = direction - parallel;
direction = perpendicular - parallel;
Which negates the component of the direction parallel to the surface normal, which is perpendicular to the collision plane, and the part perpendicular to the surface normal is unchanged.
Does anyone know a fix for this? Have I done something wrong?
Edit: So now I added:
average = (ball1.velocity + ball2.velocity) / 2;
ball1.velocity -= average;
ball2.velocity -= average;
Before doing the calculations above, and after that:
ball1.velocity += average;
ball2.velocity += average;
To get in the right reference frame, according to #Beta's answer. The problem now is that the speeds of the balls aren't maintained, since they both have the same speeds and masses, yet after the collisions they're different. I do not think this is supposed to happen, or is it?
Consider the 1D problem of bouncing a ball off a wall. Simple.
Now watch me bounce a ball off the forward bulkhead of a jet plane in flight. The ball is moving north at 252 m/s, the bulkhead is moving north at 250 m/s. The answer is not obvious. But shift into my coordinate frame (by subtracting the velocity of the bulkhead, 250 m/s, from everything) and the problem is trivial. Solve it, then shift the result back into the ground frame (by adding 250 m/s to everything) and you're done.
Now the 2D problem of a ball bouncing off a wall at an angle. Simple. (But verify that your code does it correctly.)
Now two balls colliding with equal and opposite momenta (I'll assume they have the same mass, for now). You can imagine a yellow wall at the collision plane, and the answer comes easily.
Now two balls colliding, but with velocities that do not add up to zero. There's still a yellow wall, but it's moving. Well, shift into the wall's frame by subtracting the average of the balls' velocities (sum/2) from everything, solve the simpler problem, then shift back by adding that same velocity back to everything, and you're done.
So I have a ship, that has thrusters at the bottom and that can only use these to move forward. It can also rotate itself around its center. Its thrusters gives it acceleration, so it doesn't move at a constant velocity. What I want to do is to tell it "move to point B".
I have come up with a solution but it doesn't work very well and it doesn't rotate smoothly, it moves jerkily and it doesn't end up exactly where it should be, so I have to have a big margin of error.
Is this a normal problem, and if so is there a "standard" way of doing it? Is this an easy problem? I want to make it look like the ship is steering itself to that point, using the constraints (thrusters, rotation) the player has. This excludes just lerping it from point A to B. Or does it?
I'd love some help in solving this problem. Positions are stored in vectors, and it's a 2D problem. Just for reference I'm including my solution, which basically is accelerating the ship until and rotating it to point to the point. I think my implementation of this idea is the problem:
Vector diff = vector_sub(to_point, pos);
float angle = vector_getangle(diff);
float current_angle = vector_getangle(dir);
float angle_diff = rightrange(angle) - rightrange(current_angle);
float len = vector_getlength(diff);
// "Margin of error"
float margin = 15.0;
// Adjust direction, only if we're not stopping the next thing we do (len <= margin)
if ( len > margin && fabs(angle_diff) > 2.0 )
{
dir = vector_setangle(dir, current_angle + (angle_diff)*delta*(MY_PI) - MY_PI/2);
}
else if ( len > margin )
{
dir = vector_normalize(diff);
}
// accelerate ship (if needed)
acc.x = acc.y = speed;
acc = vector_setangle(acc, vector_getangle(dir));
if ( len <= margin )
{
// Player is within margin of error
}
If you are not looking for a very general solution that works online, then there is a simple solution. What I mean by online is continuously re-calculating the actions along the complete trajectory.
Assuming the ship is at rest at start, simply rotate it towards your target point (while still at rest). Now, your ship can reach the target by accelerating for t seconds, rotating back while in motion (for 0.5 seconds as per your constraint), and decelerating for another t seconds. If the distance between current point and destination is d, then the equation you need to solve is:
d = 0.5*a*t^2 + 0.5*a*t + 0.5*a*t^2
The first term is distance traveled while accelerating. The second term is distance traveled while rotating (v*t_rot, v=a*t, t_rot=0.5). The final term is the distance traveled while decelerating. Solve the above for t, and you have your trajectory.
If the ship is moving at start, I would first stop it (just rotate in opposite direction of its speed vector, and decelerate until at rest). Now we know how to reach destination.
The problem with offline trajectory calculation is that it is not very accurate. There is a good chance that you will end up in the vicinity of the target, but not exactly on top of it.
Let's make the problem a little more interesting: the ship cannot rotate without acceleration. Let's call this acceleration vector a_r, a vector that is at a certain angle against the ship's direction (somewhat like having a thruster at an angle at the back). Your task now is to rotate the ship and accelerate in such a direction that the speed component perpendicular to the vector connecting the current position to the target is canceled out. Instead of trying to calculate the vectors offline, I would go with an online approach with this.
The easiest thing to do would be to add the following algorithm calculated at every time interval:
Calculate the vector pointing from ship to destination.
Split your current speed vector into two components: towards the destination, and perpendicular to it.
If perpendicular speed is zero, skip 4
Start rotating towards the negative of the perpendicular vector's direction. If already looking away from it (not exact opposite, but just looking away), also fire main thruster.
This will oscillate a bit, I suspect it will also stabilize after a while. I must admit, I don't know how I would make it stop at destination.
And the final approach is to model the ship's dynamics, and try to linearize it. It will be a non-linear system, so the second step will be necessary. Then convert the model to a discrete time system. And finally apply a control rule to make it reach target point. For this, you can change your state-space from position and speed to error in position and (maybe) error in speed, and finally add a regulation control (a control loop that takes the current state, and generates an input such that the state variables will approach zero).
This last one is fairly difficult in the maths compartment, and you'd probably need to study control engineering a bit to do it. However, you'll get much better results than the above simplistic algorithm - which admittedly might not even work. In addition, you can now apply various optimization rules to it: minimize time to reach target, minimize fuel consumption, minimize distance traveled, etc.
I'm trying to make a top-down spaceship game and I want the movement to somewhat realistic. 360 degrees with inertia, gravity, etc.
My problem is I can make the ship move 360° with inertia with no problem, but what I need to do is impose a limit for how fast the engines can go while not limiting other forces pushing/pulling the ship.
So, if the engines speed is a maximum of 500 and the ship is going 1000 from a gravity well, the ship is not going to go 1500 when it's engines are on, but if is pointing away from the angle is going then it could slow down.
For what it's worth, I'm using Construct, and all I need is the math of it.
Thanks for any help, I'm going bald from trying to figure this out.
Take a page from relative physics, where objects cannot exceed the speed of light:
(See below for my working C++ code snippet and running demo [Windows only].)
Set the constant c to the maximum speed an object can reach (the "speed of light" in your game).
If applying a force will increase the speed of the object, divide the acceleration (change in velocity) by the Lorentz factor. The if condition is not realistic in terms of special relativity, but it keeps the ship more "controllable" at high speeds.
Update: Normally, the ship will be hard to maneuver when going at speeds near c because changing direction requires an acceleration that pushes velocity past c (The Lorentz factor will end up scaling acceleration in the new direction to nearly nothing.) To regain maneuverability, use the direction that the velocity vector would have been without Lorentz scaling with the magnitude of the scaled velocity vector.
Explanation:
Definition of Lorentz factor, where v is velocity and c is the speed of light:
This works because the Lorentz factor approaches infinity as velocity increases. Objects would need an infinite amount of force applied to cross the speed of light. At lower velocities, the Lorentz factor is very close to 1, approximating classical Newtonian physics.
Graph of Lorentz factor as velocity increases:
Note: I previously tried to solve a similar problem in my asteroids game by playing with friction settings. I just came up with this solution as I read your question^^
Update: I tried implementing this and found one potential flaw: acceleration in all directions is limited as the speed of light c is approached, including deceleration! (Counter-intuitive, but does this happen with special relativity in the real world?) I guess this algorithm could be modified to account for the directions of the velocity and force vectors... The algorithm has been modified to account for directions of vectors so the ship does not "lose controllability" at high speeds.
Update: Here is a code snippet from my asteroids game, which uses the Lorentz factor to limit the speed of game objects. It works pretty well!
update:* added downloadable demo (Windows only; build from source code for other platforms) of this algorithm in action. I'm not sure if all the dependencies were included in the zip; please let me know if something's missing. And have fun^^
void CObject::applyForces()
{
// acceleration: change in velocity due to force f on object with mass m
vector2f dv = f/m;
// new velocity if acceleration dv applied
vector2f new_v = v + dv;
// only apply Lorentz factor if acceleration increases speed
if (new_v.length() > v.length())
{
// maximum speed objects may reach (the "speed of light")
const float c = 4;
float b = 1 - v.length_squared()/(c*c);
if (b <= 0) b = DBL_MIN;
double lorentz_factor = 1/sqrt(b);
dv /= lorentz_factor;
}
// apply acceleration to object's velocity
v += dv;
// Update:
// Allow acceleration in the forward direction to change the direction
// of v by using the direction of new_v (without the Lorentz factor)
// with the magnitude of v (that applies the Lorentz factor).
if (v.length() > 0)
{
v = new_v.normalized() * v.length();
}
}
Well, lets consider the realistic problem first and see why this doesn't work and how we have to differ from it. In space as long as your engines are firing, you will be accelerating. Your speed is only limited by your fuel (and in fact you can accelerate faster once you've spent some fuel because your moving less mass).
To give this model an effective maximum speed, you can consider particles in space slowing you down and causing friction. The faster you go, the more particles you're hitting and the faster you're hitting them, so eventually at some fast enough speed, you will be hitting enough particles the amount of decelerating they do exactly cancels out the amount of accelerating your engine is doing.
This realistic model does NOT sound like what you want. The reason being: You have to introduce friction. This means if you cut your engines, you will automatically start to slow down. You can probably count this as one of the unintended forces you do not want.
This leaves us with reducing the effective force of your engine to 0 upon reaching a certain speed. Now keep in mind if your going max speed in the north direction, you still want force to be able to push you in the east direction, so your engines shouldn't be cut out by raw velocity alone, but instead based on the velocity your going in the direction your engines are pointing.
So, for the math:
You want to do a cross dot product between your engine pointing vector and your velocity vector to get the effective velocity in the direction your engines are pointing. Once you have this velocity, say, 125 mph (with a max speed of 150) you can then scale back the force of your engines is exerting to (150-125)/150*(Force of Engines).
This will drastically change the velocity graph of how long it will take you to accelerate to full speed. As you approach the full speed your engines become less and less powerful. Test this out and see if it is what you want. Another approach is to just say Force of Engines = 0 if the dot product is >=150, otherwise it is full force. This will allow you to accelerate linearly to your max speed, but no further.
Now that I think about it, this model isn't perfect, because you could accelerate to 150 mph in the north direction, and then turn east and accelerate to 150 mph going in that direction for a total of 212 mph in the north east direction, so not a perfect solution.
I really do like Wongsungi's answer (with the Lorentz factor), but I wanted to note that the code can be simplified to have fewer floating-point operations.
Instead of calculating the Lorentz factor (which itself is a reciprocal) and then dividing by it, like this:
double lorentz_factor = 1/sqrt(b);
dv /= lorentz_factor;
simply multiply by the reciprocal of the Lorentz factor, like this:
double reciprocal_lorentz_factor = sqrt(b);
dv *= reciprocal_lorentz_factor;
This eliminates one floating-point operation from the code, and also eliminates the need to clamp b to DBL_MIN (it can now be clamped to 0 because we're not dividing anymore). Why divide by the reciprocal of x when you can just multiply by x?
Additionally, if you can guarantee that the magnitude of v will never exceed c, then you can eliminate the testing of b being less than zero.
Finally, you can eliminate two additional sqrt() operations by using length_squared() instead of length() in the outer if statement:
if (new_v.length_squared() > v.length_squared())
{
const float c = 4;
float b = 1 - v.length_squared()/(c*c);
if (b < 0) b = 0;
double reciprocal_lorentz_factor = sqrt(b);
dv *= reciprocal_lorentz_factor;
}
This may only make a 0.1% difference in speed, but I think the code is simpler this way.
You need to have three variables for your ship, which you update at each physics time step based on the forces that are acting on it. These will be mass, position, and velocity. (note that position and velocity are single numbers but vectors). At each physics time step you update the position based on the velocity, and the velocity based on the acceleration. you calculate the acceleration based on the forces acting on the ship (gravity, friction, engines)
Newton's equation for force is F = M*A We can rearrange that to A = F/M to get Acceleration. Basically you need to figure out how much the ship should accelerate, and in which direction (vector), then add that acceleration to the ship's velocity, and add the ship's velocity to its position.
Here is the code you should execute each physics time step (I hope you can fill in the blanks) please ask if this is not enough detail
gravity = //calculate force of gravity acting on ship from Newton's law of universal gravitation
friction = //ten percent of the ship's velocity vector, in the opposite direction
engines = 0
if (engines_are_firing)
engines = 500
forces = gravity + friction + engines
acceleration = forces / ship.mass
ship.velocity += acceleration
ship.position += velocity
redraw()
Your question is difficult for me to understand but it seems like you're not using real physics for this game. Have you considered using real physics equations such as velocity, acceleration, force, etc?
Edit:
After your edits, I think I have a better understanding. You are simply keeping track of the current velocity (or something similar) but you don't keep track of the force where that velocity comes from. The ship should not be storing any of that information (other than engine thrust) -- it should come from the environment the ship is in.
For instance, the environment has a gravity vector (directional force) so you would need to take that into account when calculating the directional force provided by the engine.
Your ship should be storing its own engine force, acceleration, and velocity.
I'm having trouble wrapping my mind around how to calculate the normal for a moving circle in a 2d space. I've gotten as far as that I'm suppose to calculate the Normal of the Velocity(Directional Speed) of the object, but that's where my college algebra mind over-heats, any I'm working with to 2d Circles that I have the centerpoint, radius, velocity, and position.
Ultimately I'm wanting to use the Vector2.Reflect Method to get a bit more realistic physics out of this exercise.
thanks ahead of time.
EDIT: Added some code trying out suggestion(with no avail), probably misunderstanding the suggestion. Here I'm using a basketball and a baseball, hence base and basket. I also have Position, and Velocity which is being added to position to create the movement.
if ((Vector2.Distance(baseMid, basketMid)) < baseRadius + basketRadius)
{
Vector2 baseNorm = basketMid - baseMid;
baseNorm.Normalize();
Vector2 basketNorm = baseMid - basketMid;
basketNorm.Normalize();
baseVelocity = Vector2.Reflect(baseVelocity, baseNorm);
basketVelocity = Vector2.Reflect(basketVelocity, basketNorm);
}
basePos.Y += baseVelocity.Y;
basePos.X += baseVelocity.X;
basketPos.Y += basketVelocity.Y;
basketPos.X += basketVelocity.X;
basketMid = new Vector2((basketballTex.Width / 2 + basketPos.X), (basketballTex.Height / 2 + basketPos.Y));
baseMid = new Vector2((baseballTex.Width / 2 + basePos.X), (baseballTex.Height / 2 + basePos.Y));
First the reflection. If I'm reading your code right, the second argument to Vector2.Reflect is a normal to a surface. A level floor has a normal of (0,1), and a ball with velocity (4,-3) hits it and flies away with velocity (4,3). Is that right? If that's not right then we'll have to change the body of the if statement. (Note that you can save some cycles by setting basketNorm = -baseNorm.)
Now the physics. As written, when the two balls collide, each bounces off as if it had hit a glass wall tangent to both spheres, and that's not realistic. Imagine playing pool: a fast red ball hits a stationary blue ball dead center. Does the red ball rebound and leave the blue ball where it was? No, the blue ball gets knocked away and the red ball loses most of its speed (all, in the perfect case). How about a cannonball and a golf ball, both moving at the same speed but in opposite directions, colliding head-on. Will they both bounce equally? No, the cannonball will continue, barely noticing the impact, but the golf ball will reverse direction and fly away faster than it came.
To understand these collisions you have to understand momentum (and if you want collisions that aren't perfectly elastic, like when beanbags collide, you also have to understand energy). A basic physics textbook will cover this in an early chapter. If you just want to be able to simulate these things, use the center-of-mass frame:
Vector2 CMVelocity = (basket.Mass*basket.Velocity + base.Mass*base.Velocity)/(basket.Mass + base.Mass);
baseVelocity -= CMVelocity;
baseVelocity = Vector2.Reflect(baseVelocity, baseNorm);
baseVelocity += CMVelocity;
basketVelocity -= CMVelocity;
basketVelocity = Vector2.Reflect(basketVelocity, basketNorm);
basketVelocity += CMVelocity;
The normal of a circle at a given point on its edge is going to be the direction from its center to that point. Assuming that you're working with collisions of circles here, then one easy "shorthand" way to work this out would be that at the time of collision (when the circles are touching), the following will hold true:
Let A be the center of one circle and B the center of the other. The normal for circle A will be normalize(B-A) and the normal for circle B will be normalize(A-B). This is true because the point where they touch will always be colinear with the centers of the two circles.
Caveat: I'm not going to assume that this is completely correct. Physics are not my specialty.
Movement has no effect on a normal. Typically, a normal is just a normalized (length 1) vector indicating a direction, typically the direction that a poly faces on a 3d object.
What I think you want to do is find the collision normal between two circles, yes? If so, one of the cool properties of spheres is that if you find the distance between the centers of them, you can normalize that to get the normal of the sphere.
What seems correct for 2d physics is that you take the velocity * mass (energy) of a sphere, and multiply that by the normalized vector to the other sphere. Add the result to the destination sphere's energy, subtract it from the original sphere's energy, and divide each, individually, by mass to get the resulting velocity. If the other sphere is moving, do the same in reverse. You can probably simplify the math down from there, of course, but it's late and I don't feel like doing it :)
If both spheres are moving, repeat the process for the other sphere (though you could probably simplify that equation to get some more efficient math).
This is just back-of-the-napkin math, but it seems to give the correct results. And, hey, I once derived Euler angles on my own, so sometimes my back-of-the-napkin math actually works out.
This also assumes perfectly elastic collisions.
If I'm incorrect, I'd be happy to find out where :)