Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411474 Posts in 69369 Topics- by 58423 Members - Latest Member: antkind

April 23, 2024, 12:33:21 PM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)Telekinesis Physics
Pages: [1]
Print
Author Topic: Telekinesis Physics  (Read 7094 times)
Soulliard
Level 10
*****


The artist formerly known as Nightshade


View Profile WWW
« on: January 25, 2008, 06:13:07 PM »

I have plans for an upcoming game that involve a protagonist who uses telekinesis to defeat enemies and solve puzzles. Though I'm not sure what program I'll eventually use to create it, I've tested a few things with Game Maker, using GMPhysics. It's a 2D physics engine which works very well for what I want to do.

What I want it to do is this: The controlled object should accelerate in a direction so that it collides with a target under the mouse pointer, regardless of initial velocity, gravity and other factors.

Here's the problem: While at first it seemed obvious to have the controlled objects accelerate directly towards the mouse, this made the controls very difficult to use. Actually getting the object to hit its target was incredibly difficult, due to the effect of gravity; most of the time, it would sloppily bounce off the wall ten feet away and lose most of its momentum.

So, I created the following (somewhat sloppy) code to overcome the problem:

The code within the repeat() loops approximates the angle which the object would need to accelerate at to account for gravity (gravity was set to 10). This code actually worked very well; gravity no longer made the telekinesis less accurate (though of course, it still had an effect on the speed at which the object accelerated).

Unfortunately, this didn't account for objects which had an initial velocity, or moving the mouse after the controlled object was already in motion. This meant it was still very difficult to lift an object into the air and then slam it down, or grab a projectile and toss it back at your enemy. Obviously, I needed a better formula for determining the angle of acceleration.

Starting with the basic physics equation, x = vt + .5at^2, I tried to determine an equation that the program could use to solve for theta (the angle of acceleration). There are seven constants involved: magnitude of acceleration (a), magnitude of velocity (v), angle of velocity, magnitude of acceleration due to gravity (g), angle of gravity, horizontal distance (x), and vertical distance (y). Time (t) is an unknown value, but I was able to remove it from the equation.

You can see my work here (hopefully you can read it):

The three circled equations near the bottom are as far as I could go before I got stuck. I had no idea how to solve for theta in an equation so complicated. So, I used my TI-89. This was the result (notice that theta still wasn't cancelled entirely):

And that was just the first of four results (it assumed that both square routes were positive).

I'm not sure how to proceed from this point, but here are a few possibilities:
1. Perhaps those equations can somehow be solved for theta (though I doubt this, since the calculator couldn't solve it).
2. I might be able to use the "solution" I found with the calculator to approximate theta- though that might slow the game down considerably.
3. Maybe I could solve the initial physics equation for theta instead of time- though this is a long shot, considering time is an unknown, and probably couldn't be cancelled.
4. I could create a loop that plugs theta values into one of the final equations on the yellow sheet (in increments of 10, for example) and finds the one with the closest result. This may be the only plausible option at this point. I'm testing it as we speak.
5. The equations above (on the yellow sheet) assume that acceleration is in a constant direction (theta is static), as long as the destination doesn't move. A constantly changing theta value might give me the results I need, but unfortunately, I have no idea how I would program this.
6. Give up (Never!)
7. Something I haven't thought of...

If anyone has any suggestions or input, I'd love to hear it. If I can just get over this one hurtle, I shouldn't have too much difficulty making the rest of the game.
« Last Edit: January 25, 2008, 06:22:49 PM by Nightshade » Logged

pkt-zer0
Level 0
**



View Profile
« Reply #1 on: January 25, 2008, 06:33:47 PM »

I'm not sure I completely follow, so... why exactly wouldn't a simple spring-based system, possibly using friction as well, work in this case? I'd believe the parameters could be fine-tuned for sufficient accuracy. If not, how about using some variation of a Bezier curve to interpolate between the current and end positions?
Logged
Soulliard
Level 10
*****


The artist formerly known as Nightshade


View Profile WWW
« Reply #2 on: January 25, 2008, 06:53:25 PM »

I'm not sure I completely follow, so...
I hope my post isn't too confusing. To clarify, here's a description of how I want the system to work in game:

The player clicks on an object to select it, then moves the mouse over a nearby enemy. The object begins accelerating straight towards the enemy and hits it directly, dealing damage based off the object's momentum. When the player releases the mouse button, the object stops accelerating and falls to the ground.
Quote
why exactly wouldn't a simple spring-based system, possibly using friction as well, work in this case? I'd believe the parameters could be fine-tuned for sufficient accuracy.
This will be my first game involving realistic physics, so I'm not exactly sure what you're suggesting (but I can guess). I still think it might feel more natural if a force was applied to the object, however.
Quote
If not, how about using some variation of a Bezier curve to interpolate between the current and end positions?
Again, I'm not exactly sure how this would work (like I said before, I don't have much experience in this area). It sounds like a good suggestion, though, as long as it could realistically account for all the constants involved.
Logged

pkt-zer0
Level 0
**



View Profile
« Reply #3 on: January 25, 2008, 07:19:05 PM »

Quote
why exactly wouldn't a simple spring-based system, possibly using friction as well, work in this case? I'd believe the parameters could be fine-tuned for sufficient accuracy.
This will be my first game involving realistic physics, so I'm not exactly sure what you're suggesting (but I can guess). I still think it might feel more natural if a force was applied to the object, however.
Well, that's also what my suggestion would accomplish - apply a force to the moved object as if it was attached to the target point with some sort of spring. That is, the force exerted pointing in the direction of the target, its size proportional to the distance (or its square, square-root, whatever works). It should be simpler than solving for an exact solution.

Quote
Again, I'm not exactly sure how this would work (like I said before, I don't have much experience in this area). It sounds like a good suggestion, though, as long as it could realistically account for all the constants involved.
Well, you've got two points, and the curve's first (velocity) and second (acceleration) derivatives in the starting point - I figure you should be able to fit a spline on 'em. Not sure how well it'd work in practice, though.
Logged
Soulliard
Level 10
*****


The artist formerly known as Nightshade


View Profile WWW
« Reply #4 on: January 25, 2008, 07:34:36 PM »

Well, that's also what my suggestion would accomplish - apply a force to the moved object as if it was attached to the target point with some sort of spring. That is, the force exerted pointing in the direction of the target, its size proportional to the distance (or its square, square-root, whatever works). It should be simpler than solving for an exact solution.
That's what I figured you were suggesting. The problem is, with this method, the force would be lower as the object approached the cursor, and I want the object to have as much momentum as possible when it approaches the target.

It's certainly still worth a try, though. It probably won't produce exactly the result I want, but if I fooled around with it, it might work.
Quote
Well, you've got two points, and the curve's first (velocity) and second (acceleration) derivatives in the starting point - I figure you should be able to fit a spline on 'em. Not sure how well it'd work in practice, though.
I'm worried this won't mesh well with the physics engine, or might seem unnatural to the player. Plus, it could end up being just as complicated as the equations above, if not more so.
Logged

pkt-zer0
Level 0
**



View Profile
« Reply #5 on: January 26, 2008, 03:22:28 AM »

That's what I figured you were suggesting. The problem is, with this method, the force would be lower as the object approached the cursor, and I want the object to have as much momentum as possible when it approaches the target.
Well, nothing says you have to make the forces work like a real spring does. You could make it constant or even increased on short distances. Simulating springs somewhat accurately would make for more natural movement, though. Not to mention that you'll probably end up overshooting the target as it is, so increased forces would likely make your object even less controllable, if you ever wanted to change its course.

I'm worried this won't mesh well with the physics engine, or might seem unnatural to the player. Plus, it could end up being just as complicated as the equations above, if not more so.
Complicated? Not really. Unnatural? Pretty likely.
Logged
raigan
Level 5
*****


View Profile
« Reply #6 on: January 26, 2008, 04:19:45 PM »

A crazy idea: just temporarily disable gravity on the "thrown" object, and use your original idea of applying a constant acceleration each frame (or whatever). When the object collides with something, or the mouse is released, or whatever, start applying gravity as usual.

This should look _identical_ to the object being driven by a feedback controller which is compensating for the effects of gravity, except it's wayyyyyy simpler to implement.

Also, you almost never need to resort to trig for this sort of thing -- you should be able to do pretty much any game-physics-related task using linear algebra/vectors/etc.. stick with geometry, it's simpler!
Logged
Soulliard
Level 10
*****


The artist formerly known as Nightshade


View Profile WWW
« Reply #7 on: January 26, 2008, 08:42:27 PM »

A crazy idea: just temporarily disable gravity on the "thrown" object, and use your original idea of applying a constant acceleration each frame (or whatever). When the object collides with something, or the mouse is released, or whatever, start applying gravity as usual.

This should look _identical_ to the object being driven by a feedback controller which is compensating for the effects of gravity, except it's wayyyyyy simpler to implement.

Also, you almost never need to resort to trig for this sort of thing -- you should be able to do pretty much any game-physics-related task using linear algebra/vectors/etc.. stick with geometry, it's simpler!
Unfortunately, using a system like this, it's possible to lift any object, no matter how massive it is. Ideally, raising an object should be more difficult than lowering it.

Besides, gravity is easily accounted for. The code at the top handled that pretty well. What's difficult to handle are objects which were previously moving (possibly because you had already lifted them and then changed directions).

I tried using strings to represent the telekinesis. So far, I haven't had much luck, but this might have to do with the fact that the physics engine isn't really suited to handle this sort of thing.

I tried implementing possibility number 4 (substituting values for theta), but so far that hasn't worked well. The following code just caused the object to accelerate to the right:
Code:
{
if(select=1){
if(get_body_mass(h)<1){a=20;}
else{a=20/get_body_mass(h);}

gy = 10*sin(3*pi/2);
gx = 10*cos(3*pi/2);
vy = get_body_speed(h)*sin(degtorad(get_body_direction(h)));
vx = get_body_speed(h)*cos(degtorad(get_body_direction(h)));
xy = -get_body_y(h) + mouse_y;
xx = -get_body_x(h) + mouse_x;

diff = abs((a*sin(pi)+gy)*(-vx+sqrt(vx^2+2*xx*(a*cos(pi)+gx))) - (a*cos(pi)+gx)*(-vy+sqrt(vy^2+2*xy*(a*sin(pi)+gy))));
bestdiff = diff;
best = pi;

for(i = pi/18; i < 2*pi+.1; i += pi/18)
{
    diff = abs((a*sin(i)+gy)*(-vx+sqrt(vx^2+2*xx*(a*cos(i)+gx))) - (a*cos(i)+gx)*(-vy+sqrt(vy^2+2*xy*(a*sin(i)+gy))));
    if(diff < bestdiff)
    {
        bestdiff = diff;
        best = i;
    }
}
for(i = pi/18; i < 2*pi+.1; i += pi/18)
{
    diff = abs((a*sin(i)+gy)*(-vx+sqrt(vx^2+2*xx*(a*cos(i)+gx))) - (a*cos(i)+gx)*(-vy-sqrt(vy^2+2*xy*(a*sin(i)+gy))));
    if(diff < bestdiff)
    {
        bestdiff = diff;
        best = i;
    }
}
for(i = pi/18; i < 2*pi+.1; i += pi/18)
{
    diff = abs((a*sin(i)+gy)*(-vx-sqrt(vx^2+2*xx*(a*cos(i)+gx))) - (a*cos(i)+gx)*(-vy+sqrt(vy^2+2*xy*(a*sin(i)+gy))));
    if(diff < bestdiff)
    {
        bestdiff = diff;
        best = i;
    }
}
for(i = pi/18; i < 2*pi+.1; i += pi/18)
{
    diff = abs((a*sin(i)+gy)*(-vx-sqrt(vx^2+2*xx*(a*cos(i)+gx))) - (a*cos(i)+gx)*(-vy-sqrt(vy^2+2*xy*(a*sin(i)+gy))));
    if(diff < bestdiff)
    {
        bestdiff = diff;
        best = i;
    }
}

add_force_direction(h,a,best*180/pi);
}
}
Logged

Chris Whitman
Sepia Toned
Level 10
*****


A master of karate and friendship for everyone.


View Profile
« Reply #8 on: January 28, 2008, 01:55:47 AM »

I think you might be going about this in a really weird way.

What is it, specifically, that you would like? You'd like to determine a direction to apply an acceleration to cause a body which is in motion and has other forces on it to move directly from where it is to the destination?

As an example, if you apply the acceleration on a vector from the object to its destination, but it is already traveling orthogonally to the acceleration, it will make a wide arc, and this is the sort of behavior you'd like to avoid?

I'm not really sure which theta it is that you are solving for. Is it the angle at which the object is currently traveling, or the angle at which it is accelerating (i.e., the vector sum of forces applied to the object) or is it the angle that it *should* accelerate at to achieve some behavior?
Logged

Formerly "I Like Cake."
Soulliard
Level 10
*****


The artist formerly known as Nightshade


View Profile WWW
« Reply #9 on: January 28, 2008, 05:18:52 PM »

I think you might be going about this in a really weird way.
I think I might be, too. That's why I'm asking for your thoughts.

Quote
What is it, specifically, that you would like? You'd like to determine a direction to apply an acceleration to cause a body which is in motion and has other forces on it to move directly from where it is to the destination?
Sounds right.

Quote
As an example, if you apply the acceleration on a vector from the object to its destination, but it is already traveling orthogonally to the acceleration, it will make a wide arc, and this is the sort of behavior you'd like to avoid?
Exactly. That sort of behavior makes it very difficult to move the object with any accuracy.

Quote
I'm not really sure which theta it is that you are solving for. Is it the angle at which the object is currently traveling, or the angle at which it is accelerating (i.e., the vector sum of forces applied to the object) or is it the angle that it *should* accelerate at to achieve some behavior?
It's the angle that it should accelerate to hit its target.
Logged

Zaphos
Guest
« Reply #10 on: January 28, 2008, 11:31:31 PM »

Why are you representing acceleration as an angle and magnitude instead of a vector?

Unfortunately, using a system like this, it's possible to lift any object, no matter how massive it is. Ideally, raising an object should be more difficult than lowering it.

Besides, gravity is easily accounted for. The code at the top handled that pretty well. What's difficult to handle are objects which were previously moving (possibly because you had already lifted them and then changed directions).
Can't you can use the same basic idea for objects which were previously moving -- just kill their velocity (or at least the component of their velocity which is orthogonal to the desired direction of motion)
Logged
Chris Whitman
Sepia Toned
Level 10
*****


A master of karate and friendship for everyone.


View Profile
« Reply #11 on: January 29, 2008, 12:42:20 AM »

Okay, solving this directly the way you have been trying to do is probably not a good idea. You're looking at the equation p=p_0+v_0t+(1/2)at^2 and trying to solve for the vector a (this is actually three equations, one for x, y and z).

You already have vectors p_0 and v_0, and you're trying to calculate a such that the components of p are equal to some value. Basically, you're looking for a vector a such that p_0-p+v_0t+(1/2)at^2=0 has solutions. Since t is a variable and there are no constraints on t, there are probably an infinite number of choices for a.

The other problem is you're assuming a constant acceleration, meaning no outside forces are acting on the object for the entire time. Otherwise, the above equation is invalid, and you'll need to integrate.

I've been giving this some thought, though, and I think I've come up with something which might be a viable solution as an approximation. You'll probably have to fiddle with constants to get it to work properly, but I ran over it a few times in the ol' noggin (the original simulator) and it looks pretty sound to me. Your basic issue is not the initial velocity, but only the component of it which is orthogonal to the vector from the object to its destination.

Under this model, you apply two forces which are summed when the object is under influence from telekinesis. Taking u as the vector from the object to its destination and v as the object's current velocity, the force f = f_t + f_d, where f_t is equal to c_1*u (c_1 is some constant controlling the strength of the telekinesis) and f_d is equal to some constant c_2 (a damping constant, negative) times the orthogonal projection of v on to u.

Therefore, the force applied each frame is equal to (c_1 * u) + (c_2 * v-(proj_u(v)))

In effect, this force pushes the object towards its destination while damping velocity in an orthogonal direction which causes the 'swinging' behavior. If you'd like, c_2 can also be multiplied by the mass m for each object to make the damping independent of mass.
Logged

Formerly "I Like Cake."
Chris Whitman
Sepia Toned
Level 10
*****


A master of karate and friendship for everyone.


View Profile
« Reply #12 on: January 29, 2008, 12:46:51 AM »

You'll probably also want to set f_d to zero if its magnitude drops below some very small error constant. Otherwise you might get some up and down 'jittering,' assuming you're integrating using the Euler method (by taking discrete samples each frame).
Logged

Formerly "I Like Cake."
Soulliard
Level 10
*****


The artist formerly known as Nightshade


View Profile WWW
« Reply #13 on: February 01, 2008, 04:05:55 PM »

I've tried your idea, and it seems like it could work. Unfortunately, determining the necessary strength of the damping force is difficult, so I still haven't had much success. Still, it's a good idea, so I'll see what I can do with it.
« Last Edit: February 01, 2008, 04:07:36 PM by Nightshade » Logged

Chris Whitman
Sepia Toned
Level 10
*****


A master of karate and friendship for everyone.


View Profile
« Reply #14 on: February 01, 2008, 11:52:19 PM »

I've tried your idea, and it seems like it could work. Unfortunately, determining the necessary strength of the damping force is difficult, so I still haven't had much success. Still, it's a good idea, so I'll see what I can do with it.

What sorts of problems have you been getting in finding a good coefficient? Do you find it's too small a force for very large velocities, or that it is too strong for small velocities, or that the error is too large and there is a lot of back and forth motion?

The equation can probably be tweaked up a bit, depending on the problem.
Logged

Formerly "I Like Cake."
Soulliard
Level 10
*****


The artist formerly known as Nightshade


View Profile WWW
« Reply #15 on: February 02, 2008, 02:36:03 PM »

If the object is traveling over a very large distance, it works pretty well. However, for short distances, the damping force is often not strong enough to shift the object in time. If I increase the strength of the damping force too much, it causes the object to bounce back and forth and become even more inaccurate.

As long as I keep the strength of the damping force fairly small, it improves the accuracy of the telekinesis noticeably. Unfortunately, it still does not allow for the level of accuracy I would like.
Logged

Chris Whitman
Sepia Toned
Level 10
*****


A master of karate and friendship for everyone.


View Profile
« Reply #16 on: February 02, 2008, 06:04:22 PM »

Hmm...

First of all, note that the damping force a = c_2 * -v (where v is the velocity orthogonal to the telekinesis vector) converges on d^2x/dt^2 = c_2 * -dx/dt (where x is the position at time t) as your evaluation step size becomes infinitely small, and the solution to this is an exponential function x=c_3*e^-(c_2*t) + c_4 (with initial conditions based on the starting position and velocity).

So ideally, velocity should be reduced quite quickly when it is large and more slowly when it is small, as in a physically correct damping model.

The problem in this case is going to be discretization error introduced by the relatively large step size in between each frame. While the damping force should cause the position to reach a stable equilibrium regardless of the initial velocity, discretization error can cause the calculations to repeatedly 'overshoot' the equilibrium, meaning the direction of the acceleration changes and results in oscillation.

One thing you could do is pick an 'up' vector orthogonal to the direction of the telekinesis and take the dot product of that with your velocity vector each frame. When the next frame rolls around, apply the new acceleration and repeat the dot product operation, multiplying the result from last frame. If the result is positive, do nothing. If the result is negative, the acceleration has reversed direction from the previous frame and the velocity in that direction should be set to zero. It's sort of like a root-finding approach (obviously the solution to the differential equation has no roots, but you get the idea).

Alternately, you could try the same root operation, but change the equation to a non-physically correct damping model, perhaps something which causes the velocity orthogonal to the telekinesis vector to linearly or quadratically approach zero. It might look kind of weird, though.
« Last Edit: February 02, 2008, 06:07:14 PM by I Like Cake » Logged

Formerly "I Like Cake."
Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic