how to let a ball fly like a ball

Started by Miori, Tue 17/05/2011 22:38:09

Previous topic - Next topic

Miori

I try to program a golf game and everything works fine until now. But the way the ball flies looks really... straight. I just used the walk function, with a waypoint. The ball is player character, so the screen is following it automaticaly. How far the ball flies is calculated with a hitbar. So there is a variable that says where the ball should land. It should fly with a curve. But I don't know how to do that. Could anybody help me? I'm using 3.2.1 Version of AGS.

Thanks for every helpful answer  :)

Khris

Could you post a screenshot or mockup so we can get a clearer picture of how the ball is supposed to fly?

Sephiroth

#2
One solution would be to use a function to move the ball, then you could use basic curves maths, I'm not that good with maths, but I think parabolla function would look like this: y = ax²

So you'd need to update the coords with something like this, assuming the ball moves from left to right on the screen.

Code: ags

function parabolla_movement()
{
  cBall.x = start_x;
  while(cBall.x < final_x)
  { 
    cBall.x++;
    cBall.y = 2 * FloatToInt(Maths.RaiseToPower(IntToFloat(cBall.x),  2.0)); 
    Wait(1);
  }
}


This is just a basic example, you'd need to set the ball's starting point coords, the ending point coords, and then create the appropriate curve function.

Snarky

#3
For this, what you want to do is not have the ball "walk", but move it by setting the x and y coordinates of its position according to a function that describes how it flies.

Appropriately enough, the science of how things fly when you throw them (or in this case hit them) is called ballistics. The simple answer is that a flying projectile follows a parabolic path, or in other words the curve described by -X^2.

If your starting point and ending points are at the same height and you know the distance to the ending point, you just need to decide how high up the top point of your curve should be. With that decided, you can define a function that gives you the Y coordinate for every X coordinate.

Then you can just do something like:

Code: ags

int ball_x = 0;
int ball_y = 0;
while(x<=target_dist)
{
  ball_y = calculateHeight(x, target_dist, max_height);

  ball.X = start_X + ball_x;
  ball.Y = start_y - ball_y;

  Wait(1);

  x++;
}


Off the top of my head, I think you would define the calculateHeight function something like this:

Code: ags

function calculateHeight(int x, int target_dist, int max_height)
{
  return max_height - (x-target_dist/2)*(x-target_dist/2)*max_height/(target_dist/2)/(target_dist/2);
}


(That expression can definitely be simplified, and may not be 100% correct. But I can't be bothered to do algebra at this hour.)

Khris

I think maybe it's better here not to use a fixed endpoint.
After all, golf is basically choosing direction and force, and aiming for the hole is the whole point.

I'll wait for the screenshot.

Wyz

Don't you need something like friction then? Well I don't know what the view it uses so a picture would certainly help.
Life is like an adventure without the pixel hunts.

Sephiroth

Don't you need a fixed end_point? I mean you calculate the impact point according to whatever(wind, force accuracy etc) then make the ball go to that point with a curve? Or did you mean it should rather have an impact on a random point inside a restricted area?

Khris

No, what you'd usually do is use a movement vector for the ball and add that to its position every frame.
The initial vector is determined by direction and force (= length), and during the flight, wind and gravity change the vector. Gravity for instance will add a constant value to the y component every frame.

The only downside of this physically accurate method is predetermining the flight path is a bit harder.
On the other hand, calculating ground collisions and bouncing is a piece of cake (at least on even ground).

Miori

Thanks for the answers  :).

@ Snarky
I tried your script, but maybe I am to stupid to implement it XD. The ball just flies high, and falls down again. But it doesnt move on the x-scale. When I try to just + the cBall.x while its under the distance, it doesnt work anymore.


The Golf Scenes of the game will just be simple sideview. Here is a screenshot:



Uploaded with ImageShack.us

Don't wonder about the simple graphics, it's just for testing. It works following:

1. Mouseclick
Make the black bar move on the grey one, to the max and back.

2. Mouseclick
Marks the sport hitted on the bar and shows the distance in the upper label in yards and the bottom label in pixel.

3. Mouseclick
Stop the bar moving and hit the ball. If you hit the white bar, it adds distance.

If you don't click after the first Click the black bar will move to the beginning and you can try again.

The distance will also be caused on which racket you choose, wind, equip and character stats.


Khris

So is the ball supposed to hit arbitrarily sloped ground? With bouncing and rolling?

Miori

Yeah it should bounce and roll after it landed somewhere  :) but for now it is even not flying, so not able to land somewhere  ;D

Snarky

#11
Quote from: Miori on Wed 18/05/2011 01:07:11
Thanks for the answers  :).

@ Snarky
I tried your script, but maybe I am to stupid to implement it XD. The ball just flies high, and falls down again. But it doesnt move on the x-scale. When I try to just + the cBall.x while its under the distance, it doesnt work anymore.

Ah, that's because I forgot what I had called the x variable. Try this:

Code: ags

int ball_x = 0;
int ball_y = 0;
while(ball_x<=target_dist)
{
  ball_y = calculateHeight(ball_x, target_dist, max_height);

  ball.X = start_X + ball_x;
  ball.Y = start_y - ball_y;

  Wait(1);

  ball_x++;
}


QuoteThe Golf Scenes of the game will just be simple sideview. Here is a screenshot:



Uploaded with ImageShack.us

The distance will also be caused on which racket you choose, wind, equip and character stats.
Quote from: Miori on Wed 18/05/2011 01:47:13
Yeah it should bounce and roll after it landed somewhere  :) but for now it is even not flying, so not able to land somewhere  ;D

Well, the code I showed will work well for the simplest case, but if you want sloped ground and bouncing and rolling balls and stuff like that, I think you're better off with Khris's suggestion. It will be a fair bit more difficult, though (particularly rolling, which is going to take a whole other chunk of programming). If you're not confident in your programming and math skills, I'd suggest scaling back your ambitions slightly.

What we're ultimately looking for here is a 2D physics engine, like Box2D (used in Angry Birds, Fantastic Contraption, Crayon Physics etc.). It would be awesome if there were a module like that for AGS.

Calin Leafshade

I actually half started an interface for Box2D. The format of that library makes it very AGS friendly.

I never finished it though because no one uses plugins  :=

Snarky

Yeah, that's why I suggested a module instead, with a simplified version of the library.

An actual Box2D API would be awesome, though. And it wouldn't even have to be a plugin, now: it could go directly in the engine! (Box2D is at least as portable as AGS, and the license is very flexible.) If only there was more call for it; not too many adventure games use physics-based gameplay.

To come clean, the reason I'm interested in this (apart from the fact that the very first piece of AGS code I wrote back in 2004 was a simple ballistics function to replicate the "rubber tree" scene from Monkey Island) is that I've planned a physics-based puzzle for the game I'm working on. I take it SSH just wrote a simple projectile motion function for Pigeon Pingers?

Khris

This is how far I got a few days ago; I still have to implement rolling though. It's pretty modular but the ball occasionally drops through the lines so I'd rather not publish it yet.
Tap Space to hurl the ball upwards, F9 restarts, Esc quits.

Miori

Quote from: Snarky on Wed 18/05/2011 07:14:15
Well, the code I showed will work well for the simplest case, but if you want sloped ground and bouncing and rolling balls and stuff like that, I think you're better off with Khris's suggestion. It will be a fair bit more difficult, though (particularly rolling, which is going to take a whole other chunk of programming). If you're not confident in your programming and math skills, I'd suggest scaling back your ambitions slightly.

To be honest I would be really happy if it just would fly like it should. I added your change. Now the ball moves on x-scale yay  ;D but not on y-scale anymore  :o It doesn't wanna do both  :P


Snarky

#16
Yeah, I missed another instance of x in the script that should have been ball_x (fixed now). Sorry about that. I'm a sloppy coder; even if I know how to solve a problem, it usually doesn't come out right the first time. It's just a matter of looking at the code, figuring out what's wrong and fixing it until it does what you want.

But let me put this to you: Do you understand the code? Do you see why it works or doesn't work? I mean, if you just copy-paste this stuff without building any understanding yourself, you might get this particular thing to work, but you'll never be able to change and improve on it, and those other things you describe won't be possible.

Miori

Now it works, thank you very much. And I programm my games in the same way, I'm a bit sloppy too.  :P

I understand how it works a bit, but not completely. It says it should calculate y while its moving to the targeted x. But I don't really know, how you calculate the y in the formula

return max_height - (x-target_dist/2)*(x-target_dist/2)*max_height/(target_dist/2)/(target_dist/2);

I don't know what that all means, and why the ball flies slower, when it's higher.

And is it possible to change the speed of the ball, it's flying very slow.

Snarky

OK, good!

The y-calculation is the formula for an upside-down parabola which crosses the x-axis at 0 and target_dist, and reaches max_height in the middle (which it is symmetric around). Since the standard X^2 function is symmetric around x = 0, we subtract target_dist/2 from the x-value so it'll be symmetric around that point instead (essentially shifting the curve to the right). Apart from the first term, the rest of the equation is with a negative sign so that the parabola is upside-down.

*max_height/(target_dist/2)/(target_dist/2) is a way to scale the parabola along the y-axis, because we want the difference in height between the lowest points (x=0 and x=target_dist) and the highest point (x = target_dist/2) to be max_height, not (target_dist/2)^2.  And having (+) max_height at the beginning shifts the curve up so that the top point is at that y-value. Like I said, this isn't the simplest form of this equation, I just wrote it down according to the logic just described.

The ball should move at the same speed along the x-axis (you increment ball.x by one each loop, moving the ball one pixel to the right), but along the y-axis it moves slower when it's higher. Why? Because of course it starts moving up quickly, then more and more slowly until reaches the highest point, and then it turns around and starts falling faster and faster. That's realistic. However, by doing this all with ints, there's likely to be some serious rounding errors, so the y-movement could be off in ways that makes it move even slower. Really the best way is to convert everything to floats, do the calculation, and then round the result to the nearest int.

To make it move faster, instead of doing ball_x++ at the end of the loop, you can increment ball_x by 2 or more. But then you should set the coordinates to the target after the loop finishes, since it might skip the last step otherwise. Again, you can use floats to set fraction-of-a-pixel movements, but you'll need to keep track of error terms and stuff like that, and at that point you might as well go with Khris's vector idea.

Miori

Ah, I think I understand it better now, even if not completely. I'm happy its working now, also that could make it faster. No slow-motion flying ball anymore  ;D

But could I bother you with another question? How can I make the function stop? I mean, you see the hill on my screenshot. A variable has to be true, when the shot begins. I made a collidingwithobject function, that makes this variable false, to stop it and do other things. It works, but not until the ball reached the target.

With other words: Can I abort the while-process, before it reaches the target?

SMF spam blocked by CleanTalk