Ping Pong - ball movement. Completely random, smooth, not 'locked' movement. How to?

This is a discussion on Ping Pong - ball movement. Completely random, smooth, not 'locked' movement. How to? within the Game Programming forums, part of the General Programming Boards category; Hi everyone. I took different library, which is much more advanced, and completely in C++ - SFML now, so i'm ...

  1. #1
    Novice programmer newn's Avatar
    Join Date
    Aug 2010
    Posts
    59

    Ping Pong - ball movement. Completely random, smooth, not 'locked' movement. How to?

    Hi everyone. I took different library, which is much more advanced, and completely in C++ - SFML now, so i'm remaking Ping Pong game. Now i would like to do a smooth, nice movement, random movement...

    I used to write the movement like that:

    Code:
    	if (dir == 1 && y > 0)
    	{
    		for(velocity_x = 0;velocity_x > -3; velocity_x --)
    		{
    			for(velocity_y = 0;velocity_y > -3; velocity_y --)
    			{
    			velocity_x --;
    			velocity_y --;
    			}
    		}
    		x -= vel_x - velocity_x;
    		y -= vel_y - velocity_y;
    	}
    Which 'lags', and is not very smooth, looks crappy. I think about something like that, but i'm unable to make it work:

    Before the hit to the wall or the stick, leave it constant. On hit generate a random number, for the direction, to which the ball would move. But how to make the direction work - i don't know. x++ and y-- ain't gonna work here.

  2. #2
    Programming Wraith GReaper's Avatar
    Join Date
    Apr 2009
    Location
    Greece
    Posts
    1,625
    I can't see why you do the above, end i can also see some potential errors to come!
    Devoted my life to programming...

  3. #3
    Novice programmer newn's Avatar
    Join Date
    Aug 2010
    Posts
    59
    Well, i did the above, because i don't know how else i can do it, that's what i've asked here.

    As for errors, well, there are 4 directions, everything works fine. But yea, Error's possible on different resolutions - as offscreen stuff. That was my Allegro code for Ping Pong's ball. Now i'm learning SFML, and rewriting the game for that.

  4. #4
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,304
    What you posted is exactly equivalent to:
    Code:
    	if (dir == 1 && y > 0)
    	{
    		velocity_x = -4;
    		velocity_y = -4;
    		x -= vel_x - velocity_x;
    		y -= vel_y - velocity_y;
    	}
    What effect were you expecting those loops to have?
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  5. #5
    Novice programmer newn's Avatar
    Join Date
    Aug 2010
    Posts
    59
    Well, it's a little bit of acceleration effect.
    Anyway, i'm not using the code i provided anymore, as i said in the first post - it's unrealistic, and have almost no randomness.
    Is there any better way (maybe like i said here after the code) way to make the ball do more random movements, and don't come back, where it's been a sec ago?
    Last edited by newn; 08-21-2010 at 03:08 PM.

  6. #6
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,304
    You mean you want to do something other than exactly reflect its direction in any walls it encounters. Sure, you can vary the angle a few degrees.
    However your first change must be switching from integer coordinates to floating or fixed-point coordinates.
    Floating point coordinates means that your acceleration, velocity, position etc is all of type float or double.
    Fixed-point means you still use integer math but the position needs to be bit-shifted before being drawn on screen. 16.16 fixed-point format would be a good choice.
    Once you've made that switch then we can start discussing how to make it smoother, more realistic, or less predictable.
    I see you've posted on other forums also.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  7. #7
    Novice programmer newn's Avatar
    Join Date
    Aug 2010
    Posts
    59
    Yes, i did.

    Okay, so, floats sounds a little bit easier to me.
    As you can see, i've got an answer there, but still - i don't get how it should work, it calculatesthe movement speed, not the angle...
    Okay, here's some of my 6AM top logic, while i still haven't fallen on my keyboard (going to bed after this post):
    So, i should make the angle randomize in a real small amounts - as you said - floats, maybe 3.60 value would be the max? Also, i should check, that the ball wouldn't fly directly towards the side wall, i mean just straith line, so i should exclude some degrees (i'm not perfect at math, hopefully, i'll get better this year.), then also on collision to a wall, or a paddle, i should randomize the value again, by excluding particular number of the degrees.
    BUT i guess there's a much better way to do this, since as i think of this, this would be unnecesary code, which wouldn't work perfectly, and would be hard to maintain, also the program could take more resources, and i forgot one more thing i just had in mind a sec ago, can't remember... One more fact, that says "Go to bed already!".
    So anyway, maybe i'll find a reply, when i wake up, which would give me a better tip, than i just gave myself.

    Thanks, hopefully, you've understood, what i was talking about, lol.

  8. #8
    Super Moderator VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,596
    For ball movement:

    Code:
    ball.x += cosf(ball.angle) * ball.speed;
    ball.y += sinf(ball.angle) * ball.speed;
    As for hitting the walls there are several ways to do this. As long as your walls are all orthogonal to each other and you detect when a collision happens the response is simple. You can either reflect the velocity on x and y or you can compute the reflected angle. To compute the reflected angle you will need a triangle and some trig. To create the triangle:

    • Subtract the point of collision from the initial point of the ball to get the hypotenuse
    • Extend the y component of a vector from the point of collision towards the direction of the initial point of the ball to form a side.
    • Extend the x component of a vector from the initial point of the ball towards the point of collision.
    • sin = o / h cos = a / h tan = o / a
    • Remember the entire formula is: sin(theta) = o / h, cos(theta) = a / h, and tan(theta) = o / a


    You can also do this with vectors and can reflect the vector about the y or x axis depending on the point of collision. However this is much the same as simply reflecting x or y when you hit the wall.
    If you want to get really fancy then you can use the normals of the walls and the velocity vector of the ball to compute the reflection vector. However in 2D the cross product is undefined so your normals will have to be pseduo-normals - IE: they are unit vectors that are orthogonal to the line or wall.
    Last edited by VirtualAce; 08-22-2010 at 12:12 AM.

  9. #9
    Novice programmer newn's Avatar
    Join Date
    Aug 2010
    Posts
    59
    Thanks, i made it work. although, i not completely understand how it works. But i made it work, collision stuff works alright too, but i made it my way, by converting from Allegro's and adding some additional stuff to it from some example or something like that.

    I would ask someone to explain me a few things, but i BET, that this wouldn't happen, because it would be like tutoring me maths and c++, and that stuff costs...

    Anyway, thanks.

  10. #10
    Super Moderator VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,596
    Then share with us how you did it.

  11. #11
    Novice programmer newn's Avatar
    Join Date
    Aug 2010
    Posts
    59
    Okay, here's how i did it (p.s. soon, i'll be asking for code optimization, so i will post the full source code.):

    Code:
    // Collision stuff.
    			if(SpriteBall.GetPosition().x < SpritePong1.GetPosition().x + SpritePong1.GetSize().x &&
    			   SpriteBall.GetPosition().x > SpritePong1.GetPosition().x + (SpritePong1.GetSize().x / 2.0f) &&
    			   SpriteBall.GetPosition().y + SpriteBall.GetSize().y >= SpritePong1.GetPosition().y &&
    			   SpriteBall.GetPosition().y <= SpritePong1.GetPosition().y + SpritePong1.GetSize().y)
    			{
    				BallAngle = PI - BallAngle;
    				SpriteBall.SetX(SpritePong1.GetPosition().x + SpritePong1.GetSize().x + 0.1f);
    			}
    
    			if(SpriteBall.GetPosition().x + SpriteBall.GetSize().x > SpritePong2.GetPosition().x &&
    			   SpriteBall.GetPosition().x + SpriteBall.GetSize().x < SpritePong2.GetPosition().x + (SpritePong2.GetSize().x / 2.0f) &&
    			   SpriteBall.GetPosition().y + SpriteBall.GetSize().y >= SpritePong2.GetPosition().y &&
    			   SpriteBall.GetPosition().y <= SpritePong2.GetPosition().y + SpritePong2.GetSize().y)
    			{
    				BallAngle = PI - BallAngle;
    				SpriteBall.SetX(SpritePong2.GetPosition().x - SpriteBall.GetSize().x - 0.1f);
    			}
    
    			if(SpriteBall.GetPosition().y < 0.f)
    			{
    				BallAngle = -BallAngle;
    				SpriteBall.SetY(0.1f);
    			}
    
    			if(SpriteBall.GetPosition().y + SpriteBall.GetSize().y > 480.f)
    			{
    				BallAngle = -BallAngle;
    				SpriteBall.SetY(480 - SpriteBall.GetSize().y - 0.1f);
    			}
    
    			if(SpriteBall.GetPosition().x < 0.f)
    			{
    				GameRunning = false;
    				EndGame.SetText("Player 2 wins, congratulations!");
    			}
    			if(SpriteBall.GetPosition().x + SpriteBall.GetSize().x > App.GetView().GetRect().GetWidth())
    			{
    				GameRunning = false;
    				EndGame.SetText("Player 1 wins, congratulations!");
    			}
    		}
    That's simple and understandable for me, not much maths required either. Easiest way... Usually, i take advanced ways, but I'm not quite good enough yet. I'll be optimizing and adding more functions to my game's code anyway, so maybe I'll be able to rewrite the code somehow later on...

    Since I'm sharing this code, I'll share this other code too, from your example:

    x = std::cos(BallAngle) * Factor, y = std::sin(BallAngle) * Factor; // This' little longer, as it's in a library, but i wrote the point, the logic of it. It's just requires different definition, in that library, that's all.

    Hmmm, this i don't understand. But i made it working.

    Well, maybe i understand how it works, but i wouldn't be able to make such thing myself working, nor do i understand WHY it is so. Here's how i think it works:

    It gets the cos and sin of ball's angle, then it multiplies it by ball's speed. Well... Is it supposed to get the value, and multiply it by speed, so it actually moves? Or it goes to that position? It looks like it's setting the position, where to move, not angle or stuff like that. Like clicking with a mouse on the screen, in a strategy game, then fetches the position and moves there.

    I would really appreciate, if you could explain me this thing a little bit more, so i could understand it completely. Programming without understanding - is not programming. It's copying or being lucky. In my opinion

  12. #12
    Super Moderator VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,596
    All those calculations fall apart when:

    • Screen resolution changes
    • Pong paddle size changes
    • Ball speed changes


    Resolution should not be hard-coded. Query your system to grab the current screen or viewport width. For a D3D app the viewport info will always be the most accurate for both windowed and full screen mode.

    Code:
    x += std::cos(BallAngle) * Factor, 
    y += std::sin(BallAngle) * Factor
    Sinf() and cosf() from the CRT should suffice just fine. They are the floating point versions of sin and cos. Sin() and cos() are the double versions.

    I don't quite understand your sentence concerning this code. This is essentially the parametric form of a line. I would advise you do some research on mathematical vectors.

    The formula is essentially:
    Final = Origin + Direction * Distance;

    or

    Code:
    x = x + cosf(angle) * speed;
    which is

    Code:
    x += cosf(angle) * speed;
    Last edited by VirtualAce; 08-22-2010 at 12:34 PM.

  13. #13
    Novice programmer newn's Avatar
    Join Date
    Aug 2010
    Posts
    59
    This one:

    Code:
    			if(SpriteBall.GetPosition().y + SpriteBall.GetSize().y > 480.f)
    			{
    				BallAngle = -BallAngle;
    				SpriteBall.SetY(480 - SpriteBall.GetSize().y - 0.1f);
    			}
    i can understand why, yes, for resolution. But other two things... Not quite getting why they should break, especially paddle's size. Could you explain this a little bit further?

  14. #14
    Super Moderator VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,596
    Code:
    if(SpriteBall.GetPosition().x < SpritePong1.GetPosition().x + SpritePong1.GetSize().x &&
    			   SpriteBall.GetPosition().x > SpritePong1.GetPosition().x + (SpritePong1.GetSize().x / 2.0f) &&
    			   SpriteBall.GetPosition().y + SpriteBall.GetSize().y >= SpritePong1.GetPosition().y &&
    			   SpriteBall.GetPosition().y <= SpritePong1.GetPosition().y + SpritePong1.GetSize().y)
    			{
    				BallAngle = PI - BallAngle;
    				SpriteBall.SetX(SpritePong1.GetPosition().x + SpritePong1.GetSize().x + 0.1f);
    			}
    
    			if(SpriteBall.GetPosition().x + SpriteBall.GetSize().x > SpritePong2.GetPosition().x &&
    			   SpriteBall.GetPosition().x + SpriteBall.GetSize().x < SpritePong2.GetPosition().x + (SpritePong2.GetSize().x / 2.0f) &&
    			   SpriteBall.GetPosition().y + SpriteBall.GetSize().y >= SpritePong2.GetPosition().y &&
    			   SpriteBall.GetPosition().y <= SpritePong2.GetPosition().y + SpritePong2.GetSize().y)
    			{
    				BallAngle = PI - BallAngle;
    				SpriteBall.SetX(SpritePong2.GetPosition().x - SpriteBall.GetSize().x - 0.1f);
    			}
    I did not see the GetSize(). This should work for paddle size changes. But none of this code will work for ball speed changes. Your algorithm suffers from tunneling where the ball moves from point A to point B in time T but never actually collides with an object between A and B because of the time interval.

    I would invite you to look at these articles/sites:
    http://www.gamasutra.com/view/featur..._for_games.php
    http://www.gamasutra.com/view/featur...s_collide_.php
    http://www.three14.demon.nl/sweptell...tEllipsoid.pdf
    http://www.realtimerendering.com/intersections.html

    Moving the thread to Game Programming.
    Last edited by VirtualAce; 08-22-2010 at 12:54 PM.

  15. #15
    Novice programmer newn's Avatar
    Join Date
    Aug 2010
    Posts
    59
    Thanks. Those are quite hard though. I never've thought, that there's so many ways of detecting collision, and every one of them requires a lot of maths knowledge, and IS hard. At least for me it is... I've not that much knowledge of mathematics, i've no resources to buy books, so learning's pretty hard too. Anyway, the good thing is, that i can do something, and i'm learning how to do, what i cannot do, hehe.

    What about this lil code up on my file:

    Code:
    const float PI = 3.14159f;
    float BallSpeed = 400.f;
    float BallAngle;
    do
    {
    BallAngle = sf::Randomizer::Random(0.f, 2 * PI);
    }
    while(std::abs(std::cos(BallAngle)) < 0.7f);
    
    float Factor = BallSpeed * App.GetFrameTime();
    SpriteBall.Move(std::cos(BallAngle) * Factor, std::sin(BallAngle) * Factor);
    It calculates the factor pretty well, and multiplies the angle by the factor (move speed). I could add acceleration, it would calculate it, and recalculate these calculations on every loop. Am i wrong about this? Have no chance to try it yet, i've started doing work sounds for the pong game, have some problems with that.
    Last edited by newn; 08-24-2010 at 04:15 AM.

Popular pages Recent additions subscribe to a feed

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21