Hello :] I went back to an old Pong game I had written several months ago the other day and finished it up.... well, almost. It was working fairly well, with the title screen, losing screen, winning screen, etc. functioning normally. However, it had no sound effects, so I added a sound effect for when the paddles hit the ball. It took me some trial and error in figuring out how to compile the program once I created a buffer and a Sound object (and I had forgotten to link the audio framework, but I took care of that to seal the compilation deal ;]). However, it's compiled now.... the only problem is, it just shows me the very familiar white screen of infinite loop death. I am compiling this under Xcode 3.1.4 on my MacBook, but I don't think that has anything to do with it. Rather, I think something had to have gotten messed up when I added in the sounds. Here, I'll post the source code... it's a bit lengthy, but I commented a bit. Note: I have learned how to code better than this and I know I should have built classes for it, but this was before I learned anything about OOP. I just wanted to clean this project up and finish it so I could be done with it forever :p Here goes:
/* This game is basically a simple remake of Pong. It will be for two players. */
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <SFML/System.hpp>
#include <SFML/Audio.hpp>
// Function prototypes
int distance(int, int, int, int);
void getInput(int&, int&, int&, int&, sf::Clock&, sf::Clock&);
void calculateBall(int&, int&, sf::Clock&, int&, int&, int&, double&, sf::Sound&);
void drawScore(sf::RenderWindow&, int&, int, int);
void screen(sf::RenderWindow&, sf::Sprite&, sf::View&);
// ENUMS
enum BallDirection // Different directions/velocities
{
UpRight, DownRight, UpLeft, DownLeft
};
enum PaddleDirection // Different directions/velocities
{
Up, Down, Still
};
// ************ //
// Paddle structure declaration
struct Paddle
{
int x, y; // Paddle coordinates, upper left
int botx, boty; // Paddle coordinates, bottom right
int direction; // Paddle going up or down?
sf::Clock PaddleTimer; // Movement timer
Paddle(int xcoord, int ycoord, int bottomx, int bottomy, PaddleDirection direc) // Constructor
{
x = xcoord;
y = ycoord;
botx = bottomx;
boty = bottomy;
direction = direc;
}
};
// Ball structure declaration
struct Ball
{
int x, y; // Ball's position in the field
int size; // Ball's size
int direction; // Ball's current direction/velocity
double speed; // Speed (less is more)
sf::Clock BallTimer; // Movement timer
Ball(int xcoord, int ycoord, int ballSize, double ballSpeed = 0.7)
{
x = xcoord;
y = ycoord;
size = ballSize;
}
};
// Render window declaration
sf::RenderWindow App(sf::VideoMode(800, 600), "T4 Pong");
// View declaration -- Atari resolution
sf::View View(sf::FloatRect(0, 0, 192, 160));
// Event Receiver
sf::Event Event;
// Input Receiver
const sf::Input& Input = App.GetInput();
// Images for screens
sf::Image titleImage;
sf::Image winningImage;
sf::Image losingImage;
// Sprites for screens
sf::Sprite titleSprite;
sf::Sprite winningSprite;
sf::Sprite losingSprite;
// Audio variables
sf::SoundBuffer paddleBuffer;
sf::Sound paddleSound;
// Player and ball declarations
// **PLAYER 1**
Paddle Player1(5, 60, 7, 70, Still);
// **PLAYER 2**
Paddle Player2(184, 60, 186, 70, Still);
// **BALL**
Ball Ball(80, 80, 2);
int main()
{
// Game start variable
bool gameStart = true;
// Score variable
int score1 = 0, score2 = 0;
// Ball's speed
double ballSpeed = 0.03;
// Load buffer
paddleBuffer.LoadFromFile("paddle_hit.wav");
// Set sound
paddleSound.SetBuffer(paddleBuffer);
// Load images
titleImage.LoadFromFile("pong_title.png");
winningImage.LoadFromFile("you_win.png");
losingImage.LoadFromFile("you_lose.png");
// Set smoothness off
titleImage.SetSmooth(false);
winningImage.SetSmooth(false);
losingImage.SetSmooth(false);
// Initialize sprites
titleSprite.SetImage(titleImage);
winningSprite.SetImage(winningImage);
losingSprite.SetImage(losingImage);
titleSprite.SetPosition(0,0);
winningSprite.SetPosition(0,0);
losingSprite.SetPosition(0,0);
// Start initialization / escape sequences (events)
while (App.IsOpened())
{
while (App.GetEvent(Event))
{
if (Event.Type == sf::Event::Closed)
App.Close();
if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Escape))
App.Close();
}
// Opening screen
if (gameStart)
{
screen(App, titleSprite, View);
gameStart = false;
}
// Game loop activities
// Process input
getInput(Player1.y, Player1.boty, Player2.y, Player2.boty, Player1.PaddleTimer, Player2.PaddleTimer);
// Calculate ball
calculateBall(Ball.x, Ball.y, Ball.BallTimer, Ball.direction, score1, score2, ballSpeed, paddleSound);
// Clear previous screen
App.Clear();
// Draw the paddles and the ball
App.Draw(sf::Shape::Rectangle(Player1.x, Player1.y, Player1.botx, Player1.boty, sf::Color::White));
App.Draw(sf::Shape::Rectangle(Player2.x, Player2.y, Player2.botx, Player2.boty, sf::Color::White));
App.Draw(sf::Shape::Circle(Ball.x, Ball.y, Ball.size, sf::Color::Blue));
// Draw scores
drawScore(App, score1, 30, 5);
drawScore(App, score2, 160, 5);
// Set the View
App.SetView(View);
// Lose or Win?
if (score1 == 10)
{
screen(App, winningSprite, View);
score1 = 0;
score2 = 0;
}
if (score2 == 10)
{
screen(App, losingSprite, View);
score1 = 0;
score2 = 0;
}
// Display final image
App.Display();
} // End loop
return EXIT_SUCCESS;
} // end main
// Functions and their declarations
// Distance formula
int distance(int x1, int y1, int x2, int y2)
{
int temp = pow((x2 - x1), 2) + pow((y2 - y1), 2);
return sqrt(temp);
}
// Process inputs and move players accordingly
void getInput(int &y1, int &boty1, int &y2, int &boty2, sf::Clock &Pad1, sf::Clock &Pad2)
{
App.GetInput();
if ((Input.IsKeyDown(sf::Key::Up)) && (Pad1.GetElapsedTime() >= 0.01))
{
if (y1 > 0)
{
y1--;
boty1--;
}
Pad1.Reset();
}
else if ((Input.IsKeyDown(sf::Key::Down)) && (Pad1.GetElapsedTime() >= 0.01))
{
if (y1 < 150)
{
y1++;
boty1++;
}
Pad1.Reset();
}
if ((Input.IsKeyDown(sf::Key::Q)) && (Pad2.GetElapsedTime() >= 0.01))
{
if (y2 > 0)
{
y2--;
boty2--;
}
Pad2.Reset();
}
else if ((Input.IsKeyDown(sf::Key::A)) && (Pad2.GetElapsedTime() >= 0.01))
{
if (y2 < 150)
{
y2++;
boty2++;
}
Pad2.Reset();
}
}
// Calculate ball and its movement
void calculateBall(int &x, int &y, sf::Clock& ballTime, int &direc, int &score1, int &score2, double &ballSpeed, sf::Sound &paddle)
{
if (ballTime.GetElapsedTime() >= ballSpeed)
{
if (direc == UpRight) // Ball traveling up and to the right?
{
if (x >= 192)
{
score1++;
x = y = 80;
ballTime.Reset();
direc = UpLeft;
ballSpeed = 0.03;
}
else if (y <= 3)
{
direc = DownRight;
ballTime.Reset();
}
else if ((x >= 184 && x <= 186) && (y >= Player2.y && y <= Player2.boty))
{
direc = UpLeft;
ballTime.Reset();
ballSpeed -= 0.002;
paddle.Play();
}
else
{
y--;
x++;
ballTime.Reset();
}
return;
}
if (direc == DownRight) // Ball traveling down and to the right?
{
if (x >= 192)
{
score1++;
x = y = 80;
ballTime.Reset();
direc = UpLeft;
ballSpeed = 0.03;
}
else if (y >= 158)
{
direc = UpRight;
ballTime.Reset();
}
else if ((x >= 184 && x <= 186) && (y >= Player2.y && y <= Player2.boty))
{
direc = DownLeft;
ballTime.Reset();
ballSpeed -= 0.002;
paddle.Play();
}
else
{
y++;
x++;
ballTime.Reset();
}
return;
}
if (direc == UpLeft) // Ball traveling up and to the left?
{
if (x <= 0)
{
score2++;
x = y = 80;
ballTime.Reset();
direc = UpRight;
ballSpeed = 0.03;
}
else if (y <= 3)
{
direc = DownLeft;
ballTime.Reset();
}
else if ((x >= 5 && x <= 7) && (y >= Player1.y && y <= Player1.boty))
{
direc = UpRight;
ballTime.Reset();
ballSpeed -= 0.002;
paddle.Play();
}
else
{
x--;
y--;
ballTime.Reset();
}
return;
}
if (direc == DownLeft) // Ball traveling down and to the left?
{
if (x <= 0)
{
score2++;
x = y = 80;
ballTime.Reset();
direc = UpRight;
ballSpeed = 0.03;
}
else if (y >= 158)
{
direc = UpLeft;
ballTime.Reset();
}
else if ((x >= 5 && x <= 7) && (y >= Player1.y && y <= Player1.boty))
{
direc = DownRight;
ballTime.Reset();
ballSpeed -= 0.002;
paddle.Play();
}
else
{
y++;
x--;
ballTime.Reset();
}
return;
}
else
return;
}
}
// Draw the number of the score for either player
void drawScore(sf::RenderWindow &myApp, int &score, int x, int y)
{
switch (score)
{
case 0:
myApp.Draw(sf::Shape::Line(x, y, x + 5, y, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x, y, x, y + 8, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x, y + 8, x + 5, y + 8, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x + 5, y, x + 5, y + 8, 1, sf::Color::White));
break;
case 1:
myApp.Draw(sf::Shape::Line(x + 5, y, x + 5, y + 8, 1, sf::Color::White));
break;
case 2:
myApp.Draw(sf::Shape::Line(x, y, x + 5, y, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x + 5, y, x + 5, y + 4, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x, y + 4, x + 5, y + 4, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x, y + 4, x, y + 8, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x, y + 8, x + 5, y + 8, 1, sf::Color::White));
break;
case 3:
myApp.Draw(sf::Shape::Line(x, y, x + 5, y, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x + 5, y, x + 5, y + 8, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x, y + 8, x + 5, y + 8, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x, y + 4, x + 5, y + 4, 1, sf::Color::White));
break;
case 4:
myApp.Draw(sf::Shape::Line(x + 5, y, x + 5, y + 8, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x, y, x, y + 4, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x, y + 4, x + 5, y + 4, 1, sf::Color::White));
break;
case 5:
myApp.Draw(sf::Shape::Line(x, y, x + 5, y, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x, y, x, y + 4, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x, y + 4, x + 5, y + 4, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x + 5, y + 4, x + 5, y + 8, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x, y + 8, x + 5, y + 8, 1, sf::Color::White));
break;
case 6:
myApp.Draw(sf::Shape::Line(x, y, x + 5, y, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x, y, x, y + 8, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x, y + 4, x + 5, y + 4, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x, y + 8, x + 5, y + 8, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x + 5, y + 4, x + 5, y + 8, 1, sf::Color::White));
break;
case 7:
myApp.Draw(sf::Shape::Line(x, y, x + 5, y, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x + 5, y, x + 5, y + 8, 1, sf::Color::White));
break;
case 8:
myApp.Draw(sf::Shape::Line(x, y, x + 5, y, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x, y, x, y + 8, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x + 5, y, x + 5, y + 8, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x, y + 8, x + 5, y + 8, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x, y + 4, x + 5, y + 4, 1, sf::Color::White));
break;
case 9:
myApp.Draw(sf::Shape::Line(x, y, x + 5, y, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x, y, x, y + 4, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x, y + 4, x + 5, y + 4, 1, sf::Color::White));
myApp.Draw(sf::Shape::Line(x + 5, y, x + 5, y + 8, 1, sf::Color::White));
break;
}
}
// Function to display a static screen that waits for the user to press return (or enter)
void screen(sf::RenderWindow &myApp, sf::Sprite &screenshot, sf::View &myView)
{
bool proceed = false;
sf::Event myEvent;
const sf::Input& myInput = App.GetInput();
while (!proceed)
{
myApp.Clear();
myApp.Draw(screenshot);
myApp.SetView(myView);
myApp.Display();
myApp.GetEvent(myEvent);
myApp.GetInput();
if (myInput.IsKeyDown(sf::Key::Return))
{
proceed = true;
}
}
}
Perhaps one of you awesome people can figure out what I must have done wrong..... I've tried to avoid infinite loops as best I can (which usually causes this problem for me), but I may have missed something. All the images and the .wav file are in the right directory (where the program target is). All of the frameworks are linked properly, as well. As always, any help is greatly appreciated and will further my quest to game program and lead me to post more interesting game example questions than Pong in this forum to spice it up ;] Haha, thanks everybody.
Colton