Mandelbrot
Senior Newbie


«
Posted
20121023 11:20:55 » 

Hi everybody, I'm working on a tiled based game, In this game there are a player and a bot. Actually the player can shot the target with a straight shot The shots properties looks like something like that: 1 2 3 4
 dx = target.x  player.x ; dy = target.y  player.y ; x = player.x + velocity * dx; y = player.y + velocity * dy; 
But now, i wish the player shot a grenade on the target. Something like that : My problem is that i don't know how to make a parabola between two points when the Y are differents. If someone have an idea, i 'll be happy. Thank.

 I am French, be indulgent with my written words please



Phased


«
Reply #1  Posted
20121023 11:24:11 » 

Best might be some projectile motion physics equations may help, I'm not to sure.




alesky
Junior Member Medals: 2
mmm....


«
Reply #2  Posted
20121023 11:39:11 » 

may be you can use this bspline algorith that i designed this is the link you will need only to define 3 point and it will create the curve for you your will need only to draw the sprite for the point the te algorithm will give you until the end of the path you can use 1) start point (same coordinate of first sprite) 2) intermediant point bertween the two sprite 3) end point (same coordinate of target sprite) this could be nice also becouse the speed is not costant during the path and will create something like 3d effect http://www.javagaming.org/topics/staticpathbuilderobjectfor2d/27600/view.html




Games published by our own members! Check 'em out!


alesky
Junior Member Medals: 2
mmm....


«
Reply #3  Posted
20121023 12:01:09 » 

i created a test to verify if the desing was good with my implemention
with Bspline your only question is to find a common way to determine the intermediant point i found this equation
T= targer P=Plyaer I= intermediant point
case if T.y < P.y Ix = P.x + 2/3 (T.xP.x) Iy = T.y+(1/3 (T.yP.y))
case if T.y > P.y Ix = P.x + 1/3 (T.xP.x) Iy = P.y+(1/3 (P.yT.y))
case if T.y = P.y Ix = P.x + 1/2 (T.xP.x) Iy = P.y + 1/2 (T.xP.x)




Orangy Tang


«
Reply #4  Posted
20121023 14:24:12 » 

This isn't too hard once you realise the way to do it is to split the movement into it's horizontal and vertical components. For simplicity we'll assume 3d, and you can translate that into your 2d perspective however you like.
Your inputs will be your start and end positions, and gravity. Your output you're trying to find will be the launch velocity you need to give to the projectile. Once you've got that, you can simulate it's movement under gravity the normal way and it'll hit the target.
First, you need to solve horizontally:
Ye olde movement equation: s = ut + 0.5at^2
Horizontally we have no acceleration, so eliminate 0.5at^2
We can calculate distance s by finding the vector between the start and end points, then calculating it's length.
Then we pick an arbitrary speed that we want it to move along the ground, substitute in and we can work out t, the time it will take to go from start point to end point.
Vertically: s = ut + 0.5at^2
We want to start and end at the same height, so distance s is zero. Acceleration is just gravity (careful of the sign). Time we know from the horizontal calculation.
That simply gives us an equation with just unknown vertical speed u: u = (0.5 * gravity * time)^2) / time
You calculate that u, and that's your vertical speed. So now your launch velocity is just the horizontal speed and the vertical speed. Done!




RobinB


«
Reply #5  Posted
20121023 14:42:25 » 

Your code makes the granade go fast at the beginning, goig slower and slower at the end, this is not how an thrown object behaves. First load the degrees and speed (at the initialisation, these stay the same). 1 2 3 4
 float degrees = (float)Math.atan2(target.y  player.y, target.x  player.x);
xspeed = (float)(velocity*(Math.cos(rotation)  Math.sin(rotation))); yspeed = (float)(velocity*(Math.sin(rotation) + Math.cos(rotation))); 
Now the throwing speed is constant, so no delays at the beginning or end. Now you just have to calculate an halve circle (z) depending on where the granade is between the enemy and the player. Add the value of z to the y position whe drawing the granade and done.




theagentd


«
Reply #6  Posted
20121023 15:53:37 » 

Your code makes the granade go fast at the beginning, goig slower and slower at the end, this is not how an thrown object behaves. First load the degrees and speed (at the initialisation, these stay the same). 1 2 3 4
 float degrees = (float)Math.atan2(target.y  player.y, target.x  player.x);
xspeed = (float)(velocity*(Math.cos(rotation)  Math.sin(rotation))); yspeed = (float)(velocity*(Math.sin(rotation) + Math.cos(rotation))); 
Now the throwing speed is constant, so no delays at the beginning or end. Now you just have to calculate an halve circle (z) depending on where the granade is between the enemy and the player. Add the value of z to the y position whe drawing the granade and done. It's better to at least reuse sin and cos between the two, but it's even better to just calculate the direction vector instead. One sqrt is better than an atan2 + sin + cos. 1 2 3 4 5
 float dx = target.x  player.x, dy = target.y  player.y; float multiplier = velocity / (float)sqrt(dx*dx + dy*dy);
xspeed = dx * multiplier; yspeed = dy * multiplier; 

Myomyomyo.



RobinB


«
Reply #7  Posted
20121023 18:29:03 » 

Yeah math isnt my best, i understand your code is faster then mine. But i was just giving a simple example.




theagentd


«
Reply #8  Posted
20121023 19:53:40 » 

Yeah math isnt my best, i understand your code is faster then mine. But i was just giving a simple example.
I know. I did it your way in the beginning too, so don't take it personally!

Myomyomyo.



RobinB


«
Reply #9  Posted
20121023 20:02:03 » 

Your version is good for some calculations, but in most cases i need the rotation for the images anyways. I just copied the code from the gun rotation of my game




Games published by our own members! Check 'em out!


theagentd


«
Reply #10  Posted
20121023 20:20:19 » 

In that case I still think it's faster to do a separate atan2() to get the angle and still use the vector approach, since I'm fairly sure sqrt() is faster than sin() + cos().

Myomyomyo.



RobinB


«
Reply #11  Posted
20121023 21:01:02 » 

I see, i thought creating new variables would be costly, but im wrong. Your function would make each call 20 times faster than my function, even with only one sin + cos. Awsome, learned a new trick haha




Mandelbrot
Senior Newbie


«
Reply #12  Posted
20121023 21:29:37 » 

Ok guys =) First i wish to thank you really much. Thanks for your answers. Great forum, Great people ! Ok, so, i saw yours answers, but Itâ€™s not yet absolutely good for me. I note Iâ€™m in the good to topic : Newbie and debugging ^^ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 My constructor : public ShotPlayer(Game _game, Point _player, Point _target) { px = (_player.getX() * Configuration.CASE_WIDTH) + (Configuration.CASE_WIDTH / 2); py = (_player.getY() * Configuration.CASE_HEIGHT) + (Configuration.CASE_HEIGHT / 2); tx = (_target.getX() * Configuration.CASE_WIDTH) + (Configuration.CASE_WIDTH / 2); ty = (_target.getY()* Configuration.CASE_HEIGHT) + (Configuration.CASE_HEIGHT / 2); dx = tx px; dy = ty  py; x = px; y = py; } 
1 2 3 4 5 6 7 8 9 10 11 12 13
 public void update() { if (x > Configuration.WINDOW_WIDTH  y > Configuration.WINDOW_HEIGHT  y < 0  x < 0 ) game.removeShotsPlayerEntity(this); else { } } 
If you could still help me...

 I am French, be indulgent with my written words please



theagentd


«
Reply #13  Posted
20121023 22:29:16 » 

I haven't read this whole thread but here goes. You have x and y, and you know the direction to the target, the distance (break out sqrt(dx*dx + dy*dy) into a variable) and the (2D) velocity. From this you can calculate the time it takes from it to get from the thrower to the target (time = distance / velocity). Since what you're trying to do is throw a grenade in 3D, you have to do the calculations in 3D. We just add a third coordinate Z which represent the height the grenade is above ground. We then do the calculations that Orangy Tang posted to calculate the start velocity U (u = (0.5 * gravity * time)^2) / time). With this we can use the original formula (s = ut + 0.5at^2) to calculate at what height the grenade is at at a certain time t. The whole thing looks something like this (untested): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 float dx = target.x  player.x, dy = target.y  player.y; float distance (float)sqrt(dx*dx + dy*dy); float multiplier = velocity / distance;
float xSpeed = dx * multiplier; float ySpeed = dy * multiplier;
float totalAirTime = distance / velocity;
float temp = 0.5 * GRAVITY * totalAirTime; float upSpeed = (temp * temp) / totalAirTime;
x = player.x + xSpeed * time; y = player.y + ySpeed * time; z = upSpeed * time + 0.5 * GRAVITY * time * time;
drawGrenade(x, yz);

GRAVITY should be a constant for the gravity applied to all grenades. It controls the force the grenade is thrown at upwards (higher gravity must be countered by a higher throwing force). You'll have to experiment. You can even try with 0 gravity or negative gravity. =S Good luck!

Myomyomyo.



Best Username Ever


«
Reply #14  Posted
20121023 23:27:03 » 

You need to work in three dimensions. Use parametric projectile physics to get a simple and accurate projectile path. Your overhead view probably emulates an angled view instead of a direct overhead view. (If you were using a direct overhead view, then you would basically only see the tops of characters' heads and you could throw grenades on straight line paths instead of parabolas. You're probably using an angled view, of course, judging by the sign.) Use theagentd's code. You may need to change the coefficients of y  z part depending on the view angle and other projectionrelated stuff.




Mandelbrot
Senior Newbie


«
Reply #15  Posted
20121024 06:47:18 » 

Thanks a lot, i'll try to finish it today (after work) thanks you for yours answers =) It was great help for me. I'll say you when it'll be good.

 I am French, be indulgent with my written words please



SHC


«
Reply #16  Posted
20121024 10:39:48 » 

Try this 1. Calculate the horizontal distance. 2. Calculate the no. of frames to reach the destination. 1
 int nframes = h_dist/velocity; 
3. For half the frames move up along with horizontal dist and go down for the next half frames.




Mandelbrot
Senior Newbie


«
Reply #17  Posted
20121024 13:50:10 » 

Hi, SHC your solution is simple, but how i tried it. The result is too straight. The agent D, i like your solution, but i do not understand all of it. I can not define the velocity and le gravity and the temp. I'll stop to annoy you with my grenade throwing. I'll continu and when i 'll have the solution, i'll post it here =) To be continue... If someone want to shoot a target whith a define duration, i do that : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
 in constructor(Point _player, Point _target) { px = _player.getX(); py = _player.getY();
x = px; y = py;
tx = _target.getX(); ty = _target.getY();
dx = (tx  px); dy = (ty  py);
duration = 2000; step = (duration / Configuration.FRAMES_PER_SECOND);
vx = dx / step; vy = dy / step; }
in update() { x += vx; y += vy; } 
that's all I can do for now =)

 I am French, be indulgent with my written words please



theagentd


«
Reply #18  Posted
20121024 14:07:58 » 

@Mandelbrot 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
 private static final float GRAVITY = 0.1f; in constructor(Point _player, Point _target) { px = _player.getX(); py = _player.getY();
x = px; y = py;
tx = _target.getX(); ty = _target.getY();
dx = (tx  px); dy = (ty  py);
duration = 2000; step = (duration / Configuration.FRAMES_PER_SECOND);
vx = dx / step; vy = dy / step; float temp = 0.5 * GRAVITY * step; vz = (temp * temp) / step; }
int ticks = 0;
in update() { ticks++; x = px + vx * ticks; y = py + vy * ticks; z = vz * ticks + 0.5 * GRAVITY * ticks * ticks; }
in draw() { } 
Does that help? Just add a z variable and a vz variable, and change your draw code to draw the grenade at (x, yz). (There was a bug concerning how I calculated the x and y positions in the original code which has been edited and fixed.)

Myomyomyo.



Mandelbrot
Senior Newbie


«
Reply #19  Posted
20121024 18:13:38 » 

Hello, I understand the principle.
Bravo, nice explanation. The result is not yet perfect. But it now looks like something. As you pointed out, the grenade flies. I finish studying the issue.
Thank you for your help. I hope it could help other people

 I am French, be indulgent with my written words please



theagentd


«
Reply #20  Posted
20121025 01:35:39 » 

Try to adjust the gravity, that should do the trick. =S

Myomyomyo.



SHC


«
Reply #21  Posted
20121026 04:48:33 » 

Here's a code example. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
 int curr_x, curr_y; int target_x, target_y;
int h_distance, velocity;
int frames;
int currframe = 0;
boolean calculated = false; public void update(){ if (!calculated){ h_distance = Math.abs(target_x  curr_x); frames = h_distance/velocity; calculated = true; } currframe++; curr_x += velocity; if (currframe<(frames/2)){ curr_y = 2; } else { curr_y += 2; } } 
This had worked for me.




