Jump to content
  • Advertisement
Sign in to follow this  
xxDAFFOxx

More help needed with SDL Pong.

This topic is 3030 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Yet again i am stuck. Here is the code so far that i have wrote:

#include<iostream>
#include<SDL/SDL.h>
#include<SDL/SDL_image.h>
#include<SDL/SDL_ttf.h>
#include<string>
#include<vector>
#include<cmath>

using namespace std;

float Player_One_Bat_Speed=2.5
float Player_Two_Bat_Speed=2.5
float Cpu_Bat_Speed=2.5
int Ball_Speed=3
int Player_One_Points,Cpu_Points,Player_Two_Points=0
const int FRAMES_PER_SECOND=20

//The Screens Attributes
const int SCREEN_WIDTH=640
const int SCREEN_HEIGHT=440
const intSCREEN_BPP=32

class Ball

{
public:
int x,y;
int xVel,yVel;
Ball();
void Ball_Collision();
void move();
void show();
};

Ball::Ball()
{
x=630;
y=430;

xVel=0;
yVel=0;
}
Ball::Ball_Collision()




After this i am just stumped with what to write the ball collision part is supposed to be when the ball hits the bat. i have a formula i am using which is:
if the bat is moving up add to the upwards y-velocity and likewise.
if the bat is not moving add or subtract a small random value and add it to the y-velocity.

also is my code set out right i am using lazy foos game loop article to help me out.

furthermore how would i get it to update the screen after a point is scored (cpu or player)so the ball is reset in the middle of the screen also how would i update it after a buton on the main screen ( One Player, Two Player) is clicked on.

Share this post


Link to post
Share on other sites
Advertisement
The collision mechanics you described seem to have the premise established correctly. For the ball being reset, all you would have to do is move the it's x/y coordinates to the middle of the screen and perhaps call SDL_Delay() to pause the screen for a bit so it wouldn't move and maybe give the player a chance to get ready. You'd probably want to make this a sort of reset function for the Ball class.

Ideally, you'd want to be keeping track of the ball during each frame to decide if a point has been scored. I usually make this a function of an object if I need to know where it is on the screen and if certain conditions must be executed if it's in a certain place. The conditions in your case would be either of the off-screen sides of the window. Such a tracking function would allow you to tell who scored and then call on the reset function to replace the ball. The basic structure would probably look something like this; some of the commented sections have been covered with the Lazy Foo' tutorials so I won't put them here.



int main(int argc, char* args[])
{

// Initialize SDL, SDL Surfaces, SDL Events, and misc variables
bool quit = false;

while(quit == false)
{
// Handle Game Logic e.g move player or cpu, track ball, calculate score
// Draw objects

while(SDL_PollEvent(&some_event_variable))
{
//Handle Input
}

// Screen Flip with SDL_Flip to update screen
}

// Clean Up SDL_Surfaces, free misc memory, etc...
return 0;
}







The tracking function I suggested for the Ball class would be called as part of handling the game logic, so it wouldn't be too hard to integrate it into how Lazy Foo' sets up its code.

Lazy Foo' has a tutorial on handling mouse input. If you've seen it, it should describe how to detect when a mouse click is within a certain space of the screen, hence you could determine if it was within the boundaries of a box-like area that corresponds to a button. Getting to update the screen and setting up the Pong game is another story. You could do something with a boolean variable where you have the game only draw the main screen while it's set to false. Once the player clicks on the button, the boolean is reversed and the game draws the rest of the Pong materials when that boolean is set to true. That's perhaps the simplest method for achieving what you want.

Share this post


Link to post
Share on other sites
Thanks for the help. But could i ask a few more questions.

Firstly what are these object everybody talks about and how do you declare/inialize all i know about is classes and stuff.

Also you said about" keeping track of the ball during each frame to decide if a point has been scored" how would i do this.

Finally what you say about the main menu so would i just display the the ping pong table with the text to click on top of it, then after the buttons have been clicked just diplay the bats and ball.

Share this post


Link to post
Share on other sites
C++ allows for the use of the Object Oriented Programming (OOP) paradigm which basically means one can design their program and logic to work around objects, data structures that contain variables as well as functions. In C++, an object is merely an instance of a class. You would initialize it just like any other variable by calling the type (e.g. the class name) and then defining a unique name for it. In your case, any instance of the Ball class would be an object. When you create an object, the default constructor is called. Your Ball class would make the Ball object with the values defined in your constructor, however, you can overload the default constructor and give it additional parameters to take in say if you wanted to make different x,y coordinates when you created it. For now though, your code will only set the predetermined x,y coordinates and x,y velocities. Here's how you go about making an instance of the Ball class.


Ball game_ball; //Initialize Ball class instance. game_ball is an object of the type Ball.
game_ball.move(); //Do whatever the Ball class' move() method does.
game_ball.show(); //Do whatever the Ball class' show() method does.






Now for that tracking function. Take a look at the source code from my previous post. That roughly sketches the outline of an SDL program (according to Lazy Foo'). You want to keep tabs on the ball each an every frame. One frame should be one whole run of the primary while loop (while quit == false). I suggest making a tracking function to tell if the ball goes offscreen to the left or right to determine if the player or cpu has scored a point. This isn't necessary, but it would be more logical to make such a tracking function part of the Ball class. Once for each run of the primary while loop, you would call this function to test where the Ball object is and determine if any points were scored. If any points were scored, then the Ball object needs to be reset. Again, it would be logical to have such a reset function part of the Ball class. The tracking function would look something like this when you define it as part of the Ball class.


//Track Ball objects position
void Ball::track()
{

//If Ball's x,y coordinates are past right edge of screen
if(...)
{
//Score One Point For Player & Reset Ball Position
}

//If Ball's x,y coordinates are past left edge of screen
else if(...)
{
//Score One Point For Player & Reset Ball Position
}

}






Referring back to the program outline, you'd call this function thereabouts where the comments says, with the rest of your game logic.

Lastly, for the main screen, you pretty much understood what I was trying to tell you. Just display the title screen and until some button has been clicked. Once it has been, you merely go on with the rest of your program. Think of something like this.


int main(int argc, char* args[])
{

// Initialize SDL, SDL Surfaces, SDL Events, and misc variables
bool quit = false;
bool button_click = false;

while(quit == false)
{
// Handle Game Logic e.g move player or cpu, track ball, calculate score


//If button has not been pressed, display main screen
if(button_click == false)
{
//Draw Main Screen
}

//If button has been pressed, display Pong game e.g. bats and ball
else
{
//Draw Game Objects
}

while(SDL_PollEvent(&some_event_variable))
{

//Handle different mouse input until button is pressed
if(button_click == false)
{
//Main Screen Input
}

//Handle different input for main game
else
{
//Pong Game Input
}

}

// Screen Flip with SDL_Flip to update screen
}

// Clean Up SDL_Surfaces, free misc memory, etc...
return 0;
}






You'll notice that I did two separate actions when I drew things to the screen, one based on if the main menu button was clicked, and one if the user hasn't done it yet. The same goes for the input. For the input, you might be collecting input from the mouse or the keyboard, but it's necessary to tell the program if the button has been pressed or not. This is simply because we want very separate things to happen depending on that button.

Share this post


Link to post
Share on other sites
Just one more question and i think i will know what to do.

Because i have two buttons on the main menu how would this affect the game loop you wrote.

e.g one button ( One Player ) makes the player play against the computer where as the other button ( Two Player ) makes the player play against a friend. i cant have it if One Player was clicked and it displays the players bat and a friends, or likewise. how would i sort this problem out.

Thanks for the help so far!

Share this post


Link to post
Share on other sites
Well, as you noticed correctly, booleans only get you two possible results, but since you're going to have more than that, you might as well go for another variable to keep track of the game state, e.g. what's the current mode of the game supposed to be. It could be anything, a string, a double, or whatever, so long as it limits what actions can be taken by your program given the current state. Here, I'm going to give you an example with integers because its relatively easy to work with whole numbers when talking about game states that aren't too complex. Imagine that Game State 0 refers to the Title Screen, Game State 1 refers to Single Player vs. CPU, and finally Game State 2 refers to Player vs. Player.


int main(int argc, char* args[])
{

// Initialize SDL, SDL Surfaces, SDL Events, and misc variables
bool quit = false;
int game_state = 0;

while(quit == false)
{

//Game State 0 - If any button has not been pressed, display main screen
if(game_state == 0)
{
//Draw Main Screen
}

//Game State 1 - Handle Game Logic, e.g. ball movement, ball tracking, scoring, etc, SPECIFIC to Single Player vs. CPU
else if(game_state == 1)
{
//Do Single Player Game Logic
//Draw Game Objects For Single Player vs. CPU
}

//Game State 2 - Handle Game Logic, e.g. ball movement, ball tracking, scoring, etc, SPECIFIC to Player vs. Player
else
{
//Do Player vs. Player Game Logic
//Draw Game Objects For Player vs. Player
}

while(SDL_PollEvent(&some_event_variable))
{

//Handle different mouse input until button is pressed
if(game_state == 0)
{
//Main Screen Input
//Depending on which button is pressed, set game_state to 1 or 2
}

//Handle Single Player vs. CPU input
else if(game_state == 1)
{
//Single Player vs. CPU Input
}

//Handle Player vs. Player input
else
{
//Player vs. Player Input
}

}

// Screen Flip with SDL_Flip to update screen
}

// Clean Up SDL_Surfaces, free misc. memory, etc...
return 0;
}





This is a primitive way of working with game states, but it works just fine. The variable game_state is rigidly defined and the program expects values between 0 and 2. It's initially set to 0 so it won't draw any of the Pong game materials for either Single Player vs. CPU or Player vs. Player. The game_state variable is only changed when the correct input follows in the SDL event loop. If the Single Player option selected, the game_state variable would be set to 1. If the mouse clicks on the other button, it would be set to 2. From there, the game will only do what the game_state dictates. The game logic for Single Player is going to be different from Player vs. Player, and the game_state variable allows the program to choose the right one. The same goes for the drawing and input.

The nice thing about simple game states like these is that you can easily jump from one to another by merely changing a value. Say if the player pressed a key, something like the M key, during the Pong game. Upon taking that input, you could instantly quit the current game, reset any necessary variables, change game_state and go back to the main screen. Then the player could choose to start a new game in the same mode or in a different mode, all without having to quit the actual application.

Share this post


Link to post
Share on other sites
OK so what you mean by
"//Game State 1 - Handle Game Logic, e.g. ball movement, ball tracking, scoring, etc, SPECIFIC to Single Player vs. CPU
else if(game_state == 1)
{
//Do Single Player Game Logic
//Draw Game Objects For Single Player vs. CPU
}

//Game State 2 - Handle Game Logic, e.g. ball movement, ball tracking, scoring, etc, SPECIFIC to Player vs. Player
else
{
//Do Player vs. Player Game Logic
//Draw Game Objects For Player vs. Player
}

while(SDL_PollEvent(&some_event_variable))
{

//Handle different mouse input until button is pressed
if(game_state == 0)
{
//Main Screen Input
//Depending on which button is pressed, set game_state to 1 or 2
}"
is would i put the game logic before or after the else statement.

Also would i only have to write if(game_state == 1) for it to recognise a gamestate or do i have to specify one if so how.


Also how do i detect if the ball goes too far to the left or right of the screen. would it be like this:
if(ball x,y > SCREEN_WIDTH)
{ //Reset the ball
if not how?

sorry if these questions are really newbie questions but once i understand how it works in the terms of Pong then i can use that knowledge on other games.

Share this post


Link to post
Share on other sites
Questions are always part of the process of learning. If you're new and not asking them, you're either some sort of super-programming-deity, or you're doing it wrong. ;)

Sorry, I should have clarified my example. The example shows two different sets of game logic programming in the if and else statements that I gave you. I'm assuming that your game logic is going to change depending on if the Pong game is set up for Player vs. CPU or Player vs Player. In that case, the two parts are separate and distinct.

The example I gave you doesn't have the game logic take place before or after the else statement. If the game_state variable is equal to 1, indicating that the player wants to play a Pong game where it's Player vs CPU, then the program goes into that if statement and performs all of the game logic that must be done in order to play such a game. If the game_state variable is equal to 2, then we have to perform the game logic necessary in order to make a Pong game where it is Player vs. Player. These are two pieces of game logic, each conditionally executed. To fully answer your question, the game logic goes inside these two conditional statements, not before or after.

Sometimes you might find that some of the game logic, e.g. moving the ball across the screen, is going to be called even if the game is set up for Player vs. CPU or Player vs. Player, thus you might have some duplicate code only because the two game states have something in common.

What is very important to know is how SDL handles its graphics by default, especially in the Lazy Foo' tutorials. The x coordinate of an SDL_Surface graphic is usually the leftmost part of the sprite. If you want to get the boundaries of the sprite, you'll have to know its width and height. Scoring in Pong only occurs on the horizontal, e.g. far left or far right of a screen, so for this example, you'll only need to know the width of the ball. For and example, lets just say the ball is 20 pixels by 20 pixels. Something like this would probably be written for that tracking function I explained earlier (see my 2nd post), so imagine this as an example featuring more detailed code. Assume that the game only scores and resets the ball when it has completely disappeared from the screen's view.


//If Ball's leftmost part is beyond the right side of the screen
if(x > SCREEN_WIDTH)
{
//Add to Player points, reset ball in the middle of the screen
Player_One_Points += 1;
x = 310;
y = 210;

//Set x, y velocities, probably should be random values
}

//If Ball's rightmost part is beyond the left side of the screen
else if((x + 20) < 0)
{
//Add to CPU points, reset ball in the middle of the screen
Cpu_Points += 1;
x = 310;
y = 210;

//Set x, y velocities, probably should be random values
}





The first conditional statement looks to see if the leftmost part of the ball, is beyond the right of the screen. If so, we know then that there's no possible way to see the ball anymore and so a point must be scored. I'm just imagining that the CPU is on the right and the Player is on the left, you can set it up any other way you want to. The second conditional statement occurs when the rightmost part of the ball is beyond the left side of the screen. The rightmost part is calculated by adding 20 (the sprite width) to the leftmost coordinate, which by default is the x value. Again, there's no way that the sprite can be seen, so we know a point must have been scored.

The resetting is basically changing the ball's x,y coordinates and velocities. If you haven't learned how to make random variable values in C++, you should check it out as it's quite easy to do. It'd be ideal to have the ball moving in a different direction every time the ball is reset. Notice, however, that the game would instantly continue after a point was scored. Just to be nice to the player, perhaps you might want to call SDL_Delay() for a second or two after the reset to get the player ready for the next point. Just my game design suggestion.

Share this post


Link to post
Share on other sites
Sorry but i am still stuck and confused with this if statement, the one at hand is "else if(game_state == 1)" and the other ones featuring the gamestate part.
I just don't understand how it works or how to feature it in the code, as in does it work on its own or do i have to write some specific code for it to work.
Furthermore is it related to Lazy Foo's State Machines article

P.S what is the PM for at the bottom of a user reply on this website.

Edit: One more thing how do i get the gamestate thing to tie in with clicking on the buttons i mentioned.

Share this post


Link to post
Share on other sites
Let me step you through the program outline in its entirety (refer to my 3rd post). Before the program enters into the main game loop, the while(quit == false) bit, we set a basic integer value called game_state to zero. The game_state variable tells us what mode we need to choose from when doing actions in the main game loop. Sometimes we only want the main screen to show. Sometimes we want to play a Player vs. CPU game or a Player vs. Player game. The game_state variable makes sure we run the proper one.

game_state is set to 0, which has been predetermined by us as programmers to represent the state relating to the main screen. In reality it could be any value in the world, -1, 202, 1337, anything, so long as you choose it to be the value that represents your main screen and it remains consistent throughout the program. As the game_state variable is set to 0, we go to the first set of if, else if, and else conditions. Here since it is equal to 0, we draw only the object necessary to give the player the main screen. We don't do anything else related to playing a Player vs. CPU game or a Player vs. Player game.

The game_state variable is only ever going to be a 0, 1, or 2, simply because the program does not give it any other values. When it starts off at 0, it's not going to be a 1 or a 2 unless it gets changed during the SDL input while loop. In that same while loop, we check the game_state to see if its equal to 0, meaning the current mode of the game is still where we display the main screen to the user. In that conditional statement, the mouse input needs to be obtained so it can be determined if the player wants a Player vs. Player game or Player vs. CPU game. You would have to write the code for determining this, but once you know which one the player wants, you can set the game_state variable to a 1 or a 2 depending on whatever one was chosen. The input while loop exits with our changed game_state and we return to the main game while loop, flip the screen and start the whole main game while loop over.

The game_state variable, by now, has changed its value, so when we come to the if, else if, and else statements again, its not going to draw the main screen anymore, because it is no longer equal to 0. Since it is a 1 or a 2 now, it will either handle all of the game logic for the Player vs CPU mode and draw the objects, or it will handle all of the game logic for the Player vs. Player mode and draw the objects. In essence, the game "begins" because all code that actually drives the game is allowed to run.

Then of course we hit the input while loop again. The program no longer needs to take mouse input related to choosing a game mode of Player vs. CPU or Player vs. Player. Instead we now need to take input that allows for the bats and stuff to be moved because now the actual game is being played. Since game_state is no longer equal to 0, it is either going to be a 1 or a 2, and thus the section with the mouse input is totally ignored. Now, the program needs to have the necessary input specific to a Player vs. CPU game mode (indicated by game_state == 1) or Player vs. Player game mode (indicated by game_state == 2). Since the game_state variable was changed when we first got the mouse input while the main screen was displayed, the game_state variable essentially tells the program which input it should be looking for, and what to do with it. The loop exits, the program runs and does whatever it needs to do until the boolean quit variable is equal to true and then everything exits.

To tie in the button clicking all you have to do is check if a mouse click is over one of the buttons. You'd need one conditional statement per button you want to check. When you've detected that one of the buttons was pressed, all you have to do it set the game_state variable equal to a 1 or a 2 depending on which button corresponds to Player vs. CPU or Player vs. Player.

This method is a bit different from actual State Machines. I feel it's a little overboard to implement a full state machine, e.g. an entire class dedicated to handling the game state, for something that can easily be handled with a single variable, and for such a simple game as Pong. Your game only has three states, maybe four if you wanted to make the game pause. In later, more complex games it'd be advisable to make a fully functioning State Machine, but before you even get to grips with that, you ought to learn the basics behind them. This method is a bit altered from the Lazy Foo' State Machine article's example with the switch statement.

Lastly, the PM button means Private Message, it basically acts like a mini-email system specific to members of GameDev.net forums. Click it, and you can compose a message to that user.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!