Double buffering - need help

Started by
15 comments, last by phil05 19 years, 4 months ago
This is my pong code. Three bitmaps (lpad, rpad, and the ball) are continuely flickering. I spent maybe 10 hours on finding the reason. I looked at code examples on some sites, and still, I'm at the same point where I was 9 hours ago. Please help! Thanks :)

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Program: Pong Frenzy
// Author:  Phillip Vaira
// Dates:	December 6, 2004
////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// PREPROCESSOR DIRECTIVES
#include <windows.h>		// Win32 Header
#include <windowsx.h>		// Win32 Macros
#include <iostream>			// C++ Functions 
#include <string>			// Strings
#include "resource.h"		// Resource Header
#include <mmsystem.h>		// Multimedia System
#include "Header.h"			// Main Header File

// MACROS
#define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEYUP(vk_code)   ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)

// GLOBALS
const char g_szClassName[]	= "ParentClassWindow";					// Class Name
const char g_szWinTitle[]	= "Pong Frenzy";						// Window Title
const long int WIDTH = 800, HEIGHT = 600;							// Width & Height Size
char PScoreBuffer[20] = "", CScoreBuffer[20] = "", Buffer[50] = ""; // Score & General Char Buffers 							 
bool Active = false, Multiplayer = false, keys[256];				// Paddles are able to move when Active is true.
int SPEED = 22, DIFFICULTY = 17, MaxWins = 10;						// when the player clicks Start Game in menu.
char szFileName[] = "c:\\song.mp3";			
	
// Ball Coords
int ball_x	= 300;			// Starting x pos of ball
int ball_y	= 300;			// Starting y pos of ball
const int ball_cx = 50;		// Width of ball
const int ball_cy = 50;		// Height of Ball

// LPad Coords
int LPad_x	= 0;			// Default x value of LPad. Keeps the left pad on the left.
int LPad_y	= 180;			// Pad Position
const int LPad_cx = 17;		// Width of left pad
const int LPad_cy = 119;	// Height of left pad 

// RPad Coords
int RPad_x	= 776;			// Default x value of RPad. Keeps the right pad on the right.
int RPad_y	= 180;			// RPad Position
const int RPad_cx = 17;		// Width of RPad
const int RPad_cy = 119;	// Height of RPad
 
int PlayerScore = 0;		// Keeps Track of the Player's Score
int ComputerScore = 0;		// Keeps Track of the Computer's Score


// For Back Buffering
HDC back_dc = NULL;
HDC game_dc = NULL;
HBITMAP back_bmp = NULL;
HBITMAP old_bmp = NULL;
RECT back_rect = {0, 0,  WIDTH,  HEIGHT};
													
// HANDLES
HWND g_hWnd					= NULL;					// Global Handle for Parent Window
HINSTANCE g_hInstance		= NULL;					// Global Handle for Programsss's Instance
HBITMAP bmpLPad, bmpRPad, bmpBall = NULL;			// Handles to Bitmaps
RECT   rect;										// Stores the main window's rectangle (dimensions)sss
HWND hDlgOptions = NULL, hDlgStart = NULL;

CMP3_MCI CMP3;	// MCI Object For background music
CMP3_MCI MP3_Ball;	// MCI Object for HITBALL.wav
CMP3_MCI MP3_GameOver; // MCI Object for GAMEOVER.wav

// WINMAIN
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	WNDCLASSEX wc;		// Window Class Structure Variable
	HWND hWnd = NULL;	// Handle to Parent Window
	MSG Msg;			// Message Structure Variable
	bool done = FALSE;	// Determines if Game Loop should End. Default: False

	// Setting Background Color of Parent Window
	LOGBRUSH Brush;
	Brush.lbColor	= RGB(0, 0, 100);						// RGB Color Value
	Brush.lbHatch	= 0;									// Hatch Value
	Brush.lbStyle	= BS_SOLID;								// Brush Style
	HBRUSH hBrush   = CreateBrushIndirect(&Brush);			// hBrush = Brush;

	// Registering Class Window
	wc.cbClsExtra			= 0;								// Extra Class Info Space
	wc.cbWndExtra			= 0;								// Extra Window Info Space
	wc.cbSize				= sizeof(WNDCLASSEX);				// Size of the Window Class Structure
	wc.hbrBackground		= hBrush;							// Using Color created from LOGBRUSH
	wc.hCursor				= LoadCursor(NULL, IDC_ARROW);		// Cursor Icon
	wc.hIcon				= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_GAMEICON));	// Window Icon (32x32)
	wc.hIconSm				= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_GAMEICON));	// Window Icon (16x16)
	wc.hInstance			= hInstance;						// Instance of the Application
	wc.lpfnWndProc			= WndProc;							// WndProc to Use
	wc.lpszClassName		= g_szClassName;					// Class Name
	wc.lpszMenuName			= NULL;								// Menu Name
	wc.style				= CS_VREDRAW | CS_HREDRAW | CS_OWNDC | CS_DBLCLKS;	// Style
	
	// If Registering Class Window Fails, Alert the User and Close the Application
	if (!RegisterClassEx(&wc))
	{
		MessageBox(NULL, "Registering Class Window Failed!", "Error...", MB_OK | MB_ICONEXCLAMATION);
		return 0;
	}

	// Creating Parent Window
	if (!(hWnd = CreateWindowEx(NULL, g_szClassName, g_szWinTitle, WS_CAPTION | WS_BORDER | 
		WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, WIDTH, HEIGHT, NULL, 
		LoadMenu(hInstance, MAKEINTRESOURCE(MAIN_MENU)), hInstance, NULL)))	
		{
			MessageBox(NULL, "Creating Parent Window Failed!", "Error...", MB_OK | MB_ICONEXCLAMATION);
			return 0;
		}

	g_hWnd = hWnd;				// Globally Assign Parent's Window Handle
	g_hInstance = hInstance;	// Globally Assign Application's Instance

	// Show & Update Window
	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);

	// Get a Device Context for hWnd
	game_dc = GetDC(hWnd);
	
	 
	// Load Bitmaps before Game Loop Begins
	bmpLPad = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_LPAD));
	bmpRPad = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_RPAD));
	bmpBall = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BALL));
 	
   // For double buffering
   back_dc = CreateCompatibleDC(game_dc);
   back_bmp = CreateCompatibleBitmap(game_dc, WIDTH, HEIGHT);
   old_bmp = (HBITMAP)SelectObject(back_dc, back_bmp);

   
   CMP3.Load("Audio\\song.mp3");				// load background song
   MP3_Ball.Load("Audio\\HITBALL.wav");			// load HITBALL.wav
   MP3_GameOver.Load("Audio\\GAMEOVER.wav");	// load GAMEOVER.wav

   CMP3.Play();	// Play background song before game loop begins.

 	// Seed Random Number Generator
	srand(GetTickCount());

	// Game Loop
	while (!done)
	{	
		DWORD start_time = GetTickCount();
			
		if (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
		{
			// Did the Player Decide to Quit? If so, Exit the Game Loop.
			if (Msg.message == WM_QUIT)
			{
				done = TRUE;
			}
			else if ((PlayerScore == MaxWins) || (ComputerScore == MaxWins))
			{
				done = TRUE;
			}

			else
			{
				TranslateMessage(&Msg);		// Translate any Accelerator Keys
				DispatchMessage(&Msg);		// Send to WndProc
			}
		}
		else
		{ 
			if (Active == true)				// Only Get Player's Input/Physics/Collision/AI/Painting 
			{								// when Active Is set to true.			
				if (  KEYDOWN('W') || KEYDOWN('S') || KEYDOWN(VK_ESCAPE) || KEYDOWN(VK_UP) || KEYDOWN(VK_DOWN) )
				{
					// Input
					GetPlayerInput();
				}	
				
				// Physics & Collision
				GetPhysics();
				
				// GetAI
				GetAI();
			}
				
				// Paint Current LPad Position
				SelectObject(back_dc, bmpLPad); 
				BitBlt(game_dc, LPad_x, LPad_y, WIDTH, HEIGHT, back_dc, 0, 0, SRCCOPY);	
				
				// Paint Current RPad Position
				SelectObject(back_dc, bmpRPad);
				BitBlt(game_dc, 776, RPad_y, WIDTH, HEIGHT, back_dc, 0, 0, SRCCOPY);
				
				// Paint Current Ball Position
				SelectObject(back_dc, bmpBall);
				BitBlt(game_dc, ball_x, ball_y, WIDTH, HEIGHT, back_dc, 0, 0, SRCCOPY);
				
				SetScore(); // Set Score on the Window Title
 
		    // lock framerate to 33 milliseconds (30fps)
		    while((GetTickCount() - start_time) < 33);
				
		}
	}


	WinLostMessage();				// Get a Random Winning/Loosing Message for the Player

	ReleaseDC(hWnd, game_dc);		// Release the Device Context
	Active = false;					// Stop game activation
	
	CMP3.Stop();					// Stop the background music if it is still playing.
	MP3_Ball.Stop();				// Stop HITBALL.wav if it is still playing.
	MP3_GameOver.Stop();			// Stop GAMEOVER.wav if it is still playing.
	
	return Msg.wParam;
}


// Parent Window Procedure
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT ps;
	HWND hDlgAbout = NULL;		// Handle to the About Dialog & Start Menu Dialog

	switch (Msg)
	{
 		case WM_CREATE:
			{
				// Centering Parent Window
				RECT rect;
				GetWindowRect(hWnd, &rect);
				int xSize = (rect.right - rect.left);
				int ySize = (rect.bottom - rect.top);
				int x = (GetSystemMetrics(SM_CXSCREEN) - xSize) / 2;
				int y = (GetSystemMetrics(SM_CYSCREEN) - ySize) / 2;
				SetWindowPos(hWnd, 0, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);

				// Load the Start Menu after Execution
				hDlgStart = CreateDialog(NULL, MAKEINTRESOURCE(IDD_STARTMENU), hWnd, (DLGPROC)StartDlg);
				ShowWindow(hDlgStart, SW_SHOWNORMAL);
 			}
			break;

		case WM_PAINT:
			{
				InvalidateRect(hWnd, NULL, FALSE);
				// Validating the window
				game_dc = BeginPaint(hWnd, &ps);
				EndPaint(hWnd, &ps);
			}
			break;			
 
		case WM_CLOSE: 
			{
				// Destroy Parent Window upon Close-up
				DestroyWindow(hWnd);	
			}
			break;

		case WM_DESTROY:
			{	
				// Destroy Program
				PostQuitMessage(WM_QUIT);		
			}
			break;

  
		case WM_COMMAND:
			{
				// Menu Commands
				switch (LOWORD(wParam))
				{
					// EXIT
					case IDR_FILEEXIT: 
						{
							// Does the Player wish to Quit? 
							if (MessageBox(NULL, "Are you sure you want to quit?", "Exiting Pong Frenzy", 
								MB_YESNO | MB_ICONQUESTION) == IDYES) 
							{
								PostQuitMessage(WM_QUIT);							// Quit Game
							}
							else 
							{
								return DefWindowProc(hWnd, Msg, wParam, lParam);	// Else, Do Nothing
							}
						}
						break;

					// New Game
					case IDR_FILENEW:
						{
							Active = false;			// Pause Game
							PlayerScore = 0;		// Reset Player Score to 0
							ComputerScore = 0;		// Reset Computer Score to 0
							
							ball_x	= 300;			// Reset Starting x pos of ball
							ball_y	= 300;			// Reset Starting y pos of ball
							LPad_x	= 0;			// Reset  Default x value of LPad. Keeps the left pad on the left.
							LPad_y	= 180;			// Reset Pad Position
							RPad_x	= 776;			// Reset Default x value of RPad. Keeps the right pad on the right.
							RPad_y	= 180;			// Reset RPad Position

							SPEED = 22;				// Reset starting Speed of the Ball
							DIFFICULTY = 17;		// Reset starting Difficulty to Normal
							MaxWins = 10;			// Reset starting Max Wins

							// Load the Start Menu
							hDlgStart = CreateDialog(NULL, MAKEINTRESOURCE(IDD_STARTMENU), hWnd, (DLGPROC)StartDlg);
							ShowWindow(hDlgStart, SW_SHOWNORMAL);
						}
						break;

					// ABOUT
					case IDR_FILEABOUT:
						{
							Active = false;			// Pause Game
							hDlgAbout = CreateDialog(NULL, MAKEINTRESOURCE(IDD_ABOUT), hWnd, (DLGPROC)AboutDlg);
							ShowWindow(hDlgAbout, SW_SHOWNORMAL);
						}
						break;
				}
			}
			break;

		default: return DefWindowProc(hWnd, Msg, wParam, lParam);
	}

	return 0;
}



////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// About Dialog Procedure
//

BOOL CALLBACK AboutDlg(HWND hDlgAbout, UINT Msg, WPARAM wParam, LPARAM lParam)
{
	switch (Msg)
	{
		case WM_COMMAND:
			{
				switch (LOWORD(wParam))
				{
					case IDOK:
						{
							// Closing the About Dialog...
							Active = true;	// Activate the Game
							EndDialog(hDlgAbout, wParam);
							return TRUE;
						}
						break;
				}
			}
	}
	
	return FALSE;
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Start Menu Dialog Procedure
//

BOOL CALLBACK StartDlg(HWND hDlgStart, UINT Msg, WPARAM wParam, LPARAM lParam)
{
	switch (Msg)
	{
		case WM_MOVE:
			{
				// If the Player Moves the Start Menu, Move it Back to the Center!! HAHA.
				RECT rect;
				GetWindowRect(hDlgStart, &rect);
				int xSize = (rect.right - rect.left);
				int ySize = (rect.bottom - rect.top);
				int x = (GetSystemMetrics(SM_CXSCREEN) - xSize) / 2;
				int y = (GetSystemMetrics(SM_CYSCREEN) - ySize) / 2;
				SetWindowPos(hDlgStart, 0, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
			}
			break;
 

		case WM_COMMAND:
			{
				switch (LOWORD(wParam))
				{
					case IDC_STARTGAME:
						{
							// Close Dialog when Player clicks Start Game
							PlaySound(MAKEINTRESOURCE(IDW_BEEP3), 0, SND_RESOURCE | SND_ASYNC);
							Active = true;
							EndDialog(hDlgStart, wParam);
							return TRUE;
						}
						break;

					case IDC_OPTIONS:
						{
							PlaySound(MAKEINTRESOURCE(IDW_BEEP3), 0, SND_RESOURCE | SND_ASYNC);
							
							// Load Options Dialog
							hDlgOptions = CreateDialog(NULL, MAKEINTRESOURCE(IDD_OPTIONS), g_hWnd, (DLGPROC)OptionsDlg);
							SetDlgItemText(hDlgOptions, IDC_MAXWINS, "10");
							ShowWindow(hDlgOptions, SW_SHOW);
							
							// Setting Difficulty Combo Box in the Options Dialog  
							const char *LIST[] = { "Easy", "Normal", "Bring it on!" };

							for (int i = 0; i < 4; i++)
							{
								SendMessage(GetDlgItem(hDlgOptions, IDC_DIFFICULTYLEVEL), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(LIST));
							
							}

							// Setting Number of Players Combo Box in the Options Dialog
							const char *NUMPLAYERS[] = { "One Player", "Two Players" };

							for (int j = 0; j < 2; j++)
							{
								SendMessage(GetDlgItem(hDlgOptions, IDC_PLAYERS), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(NUMPLAYERS[j]));
							}

							SendMessage(GetDlgItem(hDlgOptions, IDC_DIFFICULTYLEVEL), CB_SETCURSEL, 1, 0); // Default Selection: Normal
							SendMessage(GetDlgItem(hDlgOptions, IDC_PLAYERS), CB_SETCURSEL, 0, 0); // Default Selection: 1 Player
							
						 
							return TRUE;
						}
						break;

					case IDC_EXIT:
						{
							// Exit the Game
							// Does the Player wish to Quit? 
							if (MessageBox(NULL, "Are you sure you want to quit?", "Exiting Pong Frenzy", 
								MB_YESNO | MB_ICONQUESTION) == IDYES) 
							{
								PostQuitMessage(WM_QUIT);							// Quit Game
							}
							else 
							{
								return TRUE;	// Else, Do Nothing
							}
						}
						break;
				}
			}
	}

	return FALSE;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Options Menu Dialog Procedure
//

BOOL CALLBACK OptionsDlg(HWND hDlgOptions, UINT Msg, WPARAM wParam, LPARAM lParam)
{
	switch (Msg)
	{
 		case WM_COMMAND:
			{
				switch (LOWORD(wParam))
				{
						case IDOK:
						{

							char Difficulty_Buffer[20];
							char MaxWins_Buffer[20];
							char Player_Buffer[20];

							SendDlgItemMessage(hDlgOptions, IDC_DIFFICULTYLEVEL, WM_GETTEXT, 20, (LPARAM) Difficulty_Buffer);
							
							if (strcmp(Difficulty_Buffer, "Easy") == 0)
							{
								SPEED = 17;
								DIFFICULTY = 14;
							}
							else if (strcmp(Difficulty_Buffer, "Normal") == 0)
							{
								SPEED = 22;
								DIFFICULTY = 17;
							}
							else if (strcmp(Difficulty_Buffer, "Bring it on!") == 0)
							{
								SPEED = 33;
								DIFFICULTY = 20;
							}
							else
							{
								SPEED = 17;
								DIFFICULTY = 14;
							}


							 // Setting Max Wins in the Options Dialog
							SendDlgItemMessage(hDlgOptions, IDC_PLAYERS, WM_GETTEXT, 20, (LPARAM) Player_Buffer);
							if (strcmp(Player_Buffer, "One Player") == 0)
							{
								Multiplayer = false;
							}
							else if (strcmp(Player_Buffer, "Two Players") == 0)
							{
								Multiplayer = true;
							}
							else
							{
								Multiplayer = false;
								 
							}


							// Setting Max Wins in the Options Dialog
							GetDlgItemText(hDlgOptions, IDC_MAXWINS, MaxWins_Buffer, sizeof(MaxWins_Buffer));


							// If the MaxWins text field is empty or "0", set default back to 10.
							if ((strcmp(MaxWins_Buffer, "") == 0) || (strcmp(MaxWins_Buffer, "0") == 0))
							{
								MaxWins = 10; 															 
							}
							else
							{
								// MaxWins = MaxWins_Buffer
								MaxWins = atoi(MaxWins_Buffer);
								if ( (MaxWins < 500) )
								{
									// No code needed here.
								}
								else
								{
									// If number of wins is too high, alert player and reset to 10.
									MessageBox(NULL, "Your max number of wins may be too high.", "Pong Frenzy", MB_OK | MB_ICONEXCLAMATION);
									SetDlgItemText(hDlgOptions, IDC_MAXWINS, "10"); // Set default back.
									SetFocus(GetDlgItem(hDlgOptions, IDC_MAXWINS)); // Set focus back on text field
									return TRUE;									// Don't close options.
								}
								
							}
 
							// Closing the Options Dialog. Save data here.
							EndDialog(hDlgOptions, wParam);
							return TRUE;
						}
						break;

						case IDCANCEL:
						{
							// Canceling & Closing the Options Dialog. Don't save any data here.
							EndDialog(hDlgOptions, wParam);
							return TRUE;
						}
						break;
				}
			}
			
	}
	return FALSE;
}



////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Function: GetPlayerInput()
// Purpose:  Determine what the player is requesting via keyboard.
// Dates:	December 7, 2004
////////////////////////////////////////////////////////////////////////////////////////////////////////////////

inline void GetPlayerInput()
{
	// Get Player's Movements
	if (KEYDOWN('W'))	// Did the player press up?
	{
		LPad_y = LPad_y - 15;
	}
	if (KEYDOWN('S'))	// Did the player press down?
	{
		LPad_y = LPad_y + 15;
	} 
	
	 
	if (Multiplayer == true)
	{
		// Get Second Player's Movements
		if (KEYDOWN(VK_UP))	// Did the second player press up?
		{	
			RPad_y = RPad_y - 15;
		}
		if (KEYDOWN(VK_DOWN))	// Did the second player press down?
		{
			RPad_y = RPad_y + 15;
		} 
	}



	 
	if (KEYDOWN(VK_ESCAPE))
	{
		// Does the Player wish to Quit? 
		if (MessageBox(NULL, "Are you sure you want to quit?", "Exiting Pong Frenzy", 
				MB_YESNO | MB_ICONQUESTION) == IDYES) 
		{
				PostQuitMessage(WM_QUIT); 	// Quit Game
		}
	}	

}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Function: GetPhysics()
// Purpose:  Set the game physics and collision.
// Dates:	December 7, 2004
////////////////////////////////////////////////////////////////////////////////////////////////////////////////

inline void GetPhysics()
{
	GetClientRect(g_hWnd, &rect);
	InvalidateRect(g_hWnd, NULL, TRUE);
	CMP3_MCI CMP3Ball;

	// Collision - Stop LPad if at the bottom of the screen.
	if ((LPad_y  + 172) > HEIGHT)
		LPad_y = HEIGHT - 172;

	// Collision - Stop LPad if at top of screen.
	if ((LPad_y) < 0)
		LPad_y = 0;

	// Collision - Stop RPad if at the bottom of the screen.
	if ((RPad_y  + 172) > HEIGHT)
		RPad_y = HEIGHT - 172;

	// Collision - Stop RPad if at top of screen.
	if ((RPad_y) < 0)
		RPad_y = 0;


	static bool ball_moveRight	= false;	// Should the ball be moving right?
	static bool ball_moveUp		= true;		// Should the ball be moving upward?

	// Collision Checking with X Axis
	if (ball_x > rect.right - ball_cx) { ball_x -= SPEED; ball_moveRight = false; PlayerScore++;}
	if (ball_x < rect.left) { ball_x += SPEED; ball_moveRight = true; ComputerScore++;	}

	// Collision Checking with Y Axis
	if (ball_y > rect.bottom - ball_cy) { ball_y -= SPEED; ball_moveUp = true; }
	if (ball_y < (rect.top - ball_y)) { ball_y += SPEED; ball_moveUp = false; }


	// Check Current Boolean States
	if (ball_moveRight == true)
		ball_x += SPEED;
	else
		ball_x -= SPEED;

	if (ball_moveUp == true)
		ball_y -= SPEED;

	if (ball_moveUp == false)
		ball_y += SPEED;


 	 // If the Ball hits LPad...	
	if (ball_x < LPad_cx && ball_y >= LPad_y  && ball_y <= LPad_y + LPad_cy 
		|| ball_x < LPad_cx && ball_y + ball_cy >= LPad_y && ball_y <= LPad_y +
		LPad_cy )
	{
			ball_x += SPEED; ball_moveRight = true; 
			MP3_Ball.Play();
	}
 
 	//If the Ball hits RPad...
	if (ball_x + ball_cx >= RPad_x && ball_y >= RPad_y && ball_y <= RPad_y + RPad_cy || 
	ball_x + ball_cx>= RPad_x && ball_y + ball_cy >= RPad_y && ball_y + ball_cy <= RPad_y + RPad_cy) 
	{
		ball_x -= SPEED; ball_moveRight = false;
		MP3_Ball.Play();
	}

}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Function: GetAI()
// Purpose:  Computer determines where to go to prevent the player from scoring a point. 
//			 If the game session is two players, ignore the AI.
// Dates:	December 9, 2004
////////////////////////////////////////////////////////////////////////////////////////////////////////////////

inline void GetAI()
{
	if (Multiplayer == false)
	{
		// Computer AI 
		if (RPad_y < ball_y)
		{
			RPad_y = RPad_y + DIFFICULTY - 3;
		}
		else
		{
			RPad_y = RPad_y - DIFFICULTY;
		}
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Function: WinLostMessage()
// Purpose:  After the player wins or looses, congradulate him with random messages.
// Dates:	December 9, 2004
////////////////////////////////////////////////////////////////////////////////////////////////////////////////

inline void WinLostMessage()
{
	if (PlayerScore == MaxWins)
	{
		int RandNum = rand()%6;
		
		switch (RandNum)
		{
			case 0: MP3_GameOver.Play();
					MessageBox(NULL, "Good job! You won! Now get a life.", "Pong Frenzy", MB_OK | MB_ICONINFORMATION);
					break;
			case 1: MP3_GameOver.Play();
					MessageBox(NULL, "Congratulations! You did it!", "Pong Frenzy", MB_OK | MB_ICONINFORMATION);
					break;
			case 2: MP3_GameOver.Play();
					MessageBox(NULL, "And the crowd cheers! You win!", "Pong Frenzy", MB_OK | MB_ICONINFORMATION);
					break;
			case 3: MP3_GameOver.Play();
					MessageBox(NULL, "You win the next generation console system! Just kidding. You win!", "Pong Frenzy", MB_OK | MB_ICONINFORMATION);
					break;
			case 4: MP3_GameOver.Play();
					MessageBox(NULL, "You rule!", "Pong Frenzy", MB_OK | MB_ICONINFORMATION);
					break;
			default:MP3_GameOver.Play(); 
					MessageBox(NULL, "You win!", "Pong Frenzy", MB_OK | MB_ICONINFORMATION);
					 
		}
	}
	else if (ComputerScore == MaxWins)
	{
		int RandNum = rand()%6;
		
		switch (RandNum)
		{
			case 0: MP3_GameOver.Play();
					MessageBox(NULL, "What the heck was that?! You lost.", "Pong Frenzy", MB_OK | MB_ICONINFORMATION);
					break;
			case 1: MP3_GameOver.Play();
					MessageBox(NULL, "You can do better!", "Pong Frenzy", MB_OK | MB_ICONINFORMATION);
					break;
			case 2: MP3_GameOver.Play();
					MessageBox(NULL, "Maybe next time! Til then, you lost!", "Pong Frenzy", MB_OK | MB_ICONINFORMATION);
					break;
			case 3: MP3_GameOver.Play();
					MessageBox(NULL, "How can you achieve in life if you can't defeat Pong Frenzy?", "Pong Frenzy", MB_OK | MB_ICONINFORMATION);
					break;
			case 4: MP3_GameOver.Play();
					MessageBox(NULL, "No comment. You lost.", "Pong Frenzy", MB_OK | MB_ICONINFORMATION);
					break;
			default:MP3_GameOver.Play(); 
					MessageBox(NULL, "You lost!", "Pong Frenzy", MB_OK | MB_ICONINFORMATION);
		}
	}

 
 
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Function: SetScore()
// Purpose:  Keeps the window titel bar updated with the latest scores. 
// Dates:	December 11, 2004
////////////////////////////////////////////////////////////////////////////////////////////////////////////////

inline void SetScore()
{
				sprintf(PScoreBuffer, ("%d"), PlayerScore);		// Convert PlayerScore from int to char.
				sprintf(CScoreBuffer, ("%d"), ComputerScore);	// Convert ComputerScore from int to char
				
				// Display the New Window Title that has the Current Score  
				if (Multiplayer == false)
				{
					sprintf(Buffer, "Pong Frenzy    ::: Player: %d, Computer: %d :::", PlayerScore, ComputerScore);
				}
				else
				{
					sprintf(Buffer, "Pong Frenzy    ::: Player 1: %d, Player 2: %d :::", PlayerScore, ComputerScore);
				}
				
				SetWindowText(g_hWnd, Buffer); // Set Window Title to Show Current Scores
}

Advertisement
I see you created 2 DC's game_dc and back_dc but your drawing straight to your game_dc, to do backbuffering you need draw all the sprites to your back_dc then bitblt the entire back_dc to your game_dc all at once to prevent flickering
Can you give me some code example of what you mean? I understand enough to make two BitBlt()'s, but the BitBlt() function requires two dc handles. For example,

BitBlt(back_dc, LPad_x, LPad_y, WIDTH, HEIGHT, *WHAT GOES HERE?*, 0, 0, SRCCOPY);
BitBlt(game_dc, LPad_x, LPad_y, WIDTH, HEIGHT, back_dc, 0, 0, SRCCOPY);

Would this method work, or are you thinking of a different way?
Quote:Original post by philvaira
Can you give me some code example of what you mean? I understand enough to make two BitBlt()'s, but the BitBlt() function requires two dc handles. For example,

BitBlt(back_dc, LPad_x, LPad_y, WIDTH, HEIGHT, *WHAT GOES HERE?*, 0, 0, SRCCOPY);
BitBlt(game_dc, LPad_x, LPad_y, WIDTH, HEIGHT, back_dc, 0, 0, SRCCOPY);

Would this method work, or are you thinking of a different way?

the two DC are the destinatiuon and source

-first you draw all your sprites to your backbuffer(back_DC)

-then you flip your backbuffer to screen
BitBlt(game_dc, 0, 0, WIDTH, HEIGHT, back_DC, 0, 0, SRCCOPY);

I'm starting to understand this... bear with me.

This code below then should not draw out individually, but all of them get sent to the back_dc in one shot, then use only one BitBlt() to throw it onto the screen?

				// Paint Current LPad Position				SelectObject(back_dc, bmpLPad); 				BitBlt(game_dc, LPad_x, LPad_y, WIDTH, HEIGHT, back_dc, 0, 0, SRCCOPY);									// Paint Current RPad Position				SelectObject(back_dc, bmpRPad);				BitBlt(game_dc, 776, RPad_y, WIDTH, HEIGHT, back_dc, 0, 0, SRCCOPY);								// Paint Current Ball Position				SelectObject(back_dc, bmpBall);				BitBlt(game_dc, ball_x, ball_y, WIDTH, HEIGHT, back_dc, 0, 0, SRCCOPY);


To my previous post, is it something like this? Currently, nothing is updating. You can see blocks upon blocks of the ball/lpad/rpad moving around, and so forth. I suppose it needs a page refresh if this code is correct?

Object DC = Takes hold of the current selected object.
obj_dc = CreateCompatibleDC(back_dc);

Bugs i found: Screen is black and not its origional blue background color. Full screen is flickering too.

				// Paint Current LPad Position				SelectObject(obj_dc, bmpLPad); 				BitBlt(back_dc, LPad_x, LPad_y, WIDTH, HEIGHT, obj_dc, 0, 0, SRCCOPY);									// Paint Current RPad Position				SelectObject(obj_dc, bmpRPad);				BitBlt(back_dc, 776, RPad_y, WIDTH, HEIGHT, obj_dc, 0, 0, SRCCOPY);								// Paint Current Ball Position				SelectObject(obj_dc, bmpBall);				BitBlt(back_dc, ball_x, ball_y, WIDTH, HEIGHT, obj_dc, 0, 0, SRCCOPY);				// Send back_dc to game_dc				BitBlt(game_dc, 0, 0, WIDTH, HEIGHT, back_dc, 0, 0, SRCCOPY);
ok, this is diffrent, you seem to be using your backbuffer to hold textures, you need at lest 3 HDC to make this work, i usally have HDC for every texture but your way works too

HDC game_dc, back_dc and, texture_DC

// replace all the LPad_width,LPad_HEIGHT,ball_WIDTH and so on with the dimentions of the sprite, not the screen

// Paint Current LPad Position

SelectObject(texture_dc, bmpLPad);
BitBlt(back_dc, LPad_x, LPad_y, LPad_width, LPad_HEIGHT, texture_dc, 0, 0, SRCCOPY);

//Paint Current RPad Position
SelectObject(texture_dc, bmpRPad);
BitBlt(back_dc, 776, RPad_y, RPad_WIDTH, RPad_HEIGHT, texture_dc, 0, 0, SRCCOPY);

// Paint Current Ball Position
SelectObject(texture_dc, bmpBall);
BitBlt(back_dc, ball_x, ball_y, ball_WIDTH, ball_HEIGHT, texture_dc, 0, 0, SRCCOPY);

//flip
BitBlt(game_dc, 0, 0, WIDTH, HEIGHT, back_DC, 0, 0, SRCCOPY);

Cool, so we're thinking the same thing :) Only thing now is how do I get each demensions of the bitmaps? I know it has to do with BITMAP bm; but I never used this before, and knowing how to select each object with it.

I took the demensions by looking at my art files in the game folder. I placed them in here. I compiled, and noticed the screen is still flashing and the bitmaps aren't erasing as they move. It looks like a ball is ontop of another ball - keeps happening going up and down the screen etc.

Is there suppose to be a FillRect(screencolor) in this?

				// Paint Current LPad Position				SelectObject(obj_dc, bmpLPad); 				BitBlt(back_dc, LPad_x, LPad_y, 17, 119, obj_dc, 0, 0, SRCCOPY);									// Paint Current RPad Position				SelectObject(obj_dc, bmpRPad);				BitBlt(back_dc, 776, RPad_y, 17, 119, obj_dc, 0, 0, SRCCOPY);								// Paint Current Ball Position				SelectObject(obj_dc, bmpBall);				BitBlt(back_dc, ball_x, ball_y, 42, 42, obj_dc, 0, 0, SRCCOPY);				// Send back_dc to game_dc				BitBlt(game_dc, 0, 0, WIDTH, HEIGHT, back_dc, 0, 0, SRCCOPY);
not sure how to get the dimention of a bitmap outer than manulay entering the size, note that if you just remeber it you can have only one bitmap with all your sprite on it and select the sprite you want using
BitBlt(game_dc, 0, 0, 64, 64, back_dc,//the x source goes here//, //y source here//, SRCCOPY);

if your still having problems make a hdc for every bitmap, i made a wraper class for this purpos, just go
texture goo("file.bmp");

and use goo.tex as the source dc

class texture{
private:
HBITMAP hbit;
BITMAP bmp;

public:
HDC tex;
texture(LPCTSTR Fname){
tex= CreateCompatibleDC(NULL);
hbit = (HBITMAP)LoadImage(NULL,Fname,IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

GetObject(hbit,sizeof(bmp),&bmp);
SelectObject(tex,hbit);
}
~texture(){
DeleteDC(tex);
DeleteObject(hbit);
}
};
i dont know why its still flickering but use

BitBlt(back_dc,0,0,WIDTH,HEIGHT,back_dc,0,0,BLACKNESS);

to erase the backbuffer

This topic is closed to new replies.

Advertisement