Skip to main content
GameDev.net gamedev.net
🔒 Locked

Problem with Collision Detection

Started by nerd_boy Jan 18, 2004 at 8:21 PM 4 replies 1.2k views
Original Post
nerd_boy
nerd_boy
I am not sure if this is a physics question, or a coding error question. But in my breakout clone, the ball does what it is supposed to do half of the time, but the other half it doesn''t.
// Breakout Clone

//

//		A game to get me back in practice and ready for the

//	72 hour GDC.

//		It will also break in my compiler.


// INCLUDES ///////////////////////////////////////////////


#define INITGUID // make sure COM interfaces are available

// include appropriate librarys

#pragma comment(lib,"winmm")
#pragma comment(lib,"ddraw")
#pragma comment(lib,"dinput")
#pragma comment(lib,"dinput8")
#pragma comment(lib,"dsound")
#define WIN32_LEAN_AND_MEAN  // GRrrrr....


#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <objbase.h>
#include <iostream>
#include <conio.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <math.h>
#include <io.h>
#include <ios>
#include <fcntl.h>
#include <fstream>
#include <ddraw.h>
#include <dsound.h>
#include <dmksctrl.h>
#include <dmusici.h>
#include <dmusicc.h>
#include <dmusicf.h>
#include <dinput.h>
#include "resource.h" // resources (DOH!)

using namespace std;

// DEFINES ////////////////////////////////////////////////


#define WINDOW_CLASS_NAME "BREAKOUTCLASS"
#define WINDOW_TITLE	  "Breakout - Clone"
#define WINDOW_WIDTH	  640
#define WINDOW_HEIGHT	  480
#define WINDOW_BPP		  16 // sigh.. the inferiority of the PC

							 // to the Consoles....

// Game states

#define GS_TITLE			0
#define GS_MENU				1
#define GS_RUN				2

// max vel

#define MAX_VEL				16

// MACROS /////////////////////////////////////////////////


// msg box for errors

#define MSG(msg) MessageBox(main_window_handle,msg,"Error!",MB_OK|MB_ICONEXCLAMATION)

// read the keyboard asynchronously(for use till DInput

#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code)&0x8000) ? 1 : 0 )

// read the keyboard with DInput

#define DX_KEY_DOWN(n) (game_input.keystate[n] & 0x80)

// builds 16 bit color value from 5.5.5 and 5.6.5, respectively

#define _RGB16BIT555(r,g,b) ((b & 31)+((g & 31)<<5)+((r & 31)<<10))
#define _RGB16BIT565(r,g,b) ((b & 31)+((g & 63)<<5)+((r & 31)<<11))

// initialize DDStruct

#define DDRAW_INIT_STRUCT(ddstruct) {memset(&ddstruct,0,sizeof(ddstruct)); ddstruct.dwSize=sizeof(ddstruct);}

// Structs and such ///////////////////////////////////////


typedef unsigned short USHORT;
typedef unsigned short WORD;
typedef unsigned char UCHAR;
typedef unsigned char BYTE;
typedef unsigned int QUAD;
typedef unsigned int UINT;

class Bitmap_File // my personal, wonderful thing

{
public:
	int End();
	int Load(char *filename,int start_x,int start_y,int width, int height,int mem_flags=DDSCAPS_SYSTEMMEMORY);
	int Draw();
	int itsX;
	int itsY;
	int itsWidth;
	int itsHeight;
	LPDIRECTDRAWSURFACE7 itsImage;
};

class Game_Input
{
public:
	int Initiate();
	int Read();
	int End();
	UCHAR keystate[256];
	DIMOUSESTATE mouse_state;
	LPDIRECTINPUT8 lpdi;
	LPDIRECTINPUTDEVICE8 mouse;
	LPDIRECTINPUTDEVICE8 keyboard;
};

// PROTOTYPES /////////////////////////////////////////////


int Game_Init(void *parms=NULL);
int Game_Shutdown(void *parms=NULL);
int Game_Main(void *parms=NULL);
int DDraw_Fill_Surface(LPDIRECTDRAWSURFACE7 lpdds, USHORT color);
USHORT RGB16Bit565(int r,int g,int b);
USHORT RGB16Bit555(int r,int g,int b);
LRESULT CALLBACK WindowProc(HWND,UINT,WPARAM,LPARAM);
void Reset(void);
int CheckCollision(void);

// GLOBALS ////////////////////////////////////////////////


HWND main_window_handle			=NULL;
HINSTANCE main_instance			=NULL;
int index;
int game_state					=GS_TITLE;
int level						=0;
int level_done					=1;
int lives=0;
int grid[400]; // game grid

int Frames_Per_Second;
Game_Input game_input;
int key_up[256];
int ball_shot;
int ball_xv,ball_yv;
int ball_xv2,ball_yv2; // used for collision detection

int blocks_left=0;
int bx,by,gcount; // block vars


// DirectX Globals

LPDIRECTDRAW7 lpdd = NULL;
LPDIRECTDRAWSURFACE7 lpddsprimary = NULL;
LPDIRECTDRAWSURFACE7 lpddsback = NULL;
DDSURFACEDESC2 ddsd;
DDSCAPS2 ddscaps;
USHORT (*RGB16Bit)(int r,int g,int b)=NULL;
int dd_pixel_format = 16;
LPDIRECTDRAWCLIPPER lpddclipper;

// Bitmaps

Bitmap_File background;
Bitmap_File history;
Bitmap_File blocks[10];
Bitmap_File menu;
Bitmap_File paddle;
Bitmap_File ball;

// FUNCTIONS //////////////////////////////////////////////

LRESULT CALLBACK WindowProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)
{
	switch(msg)
	{
	case WM_DESTROY:
		{
			PostQuitMessage(0);
			return(0);
		}break;
	default:break;
	}
	return(DefWindowProc(hwnd,msg,wparam,lparam));
}
///////////////////////////////////////////////////////////

int WINAPI WinMain(HINSTANCE hinstance,HINSTANCE hprevinstance,LPSTR lpcmdline,int ncmdshow)
{
	WNDCLASSEX winclass;
	HWND hwnd;
	MSG msg;

	// fill in window class struct

	winclass.cbSize = sizeof(WNDCLASSEX);
	winclass.style = CS_DBLCLKS|CS_OWNDC|CS_HREDRAW|CS_VREDRAW;
	winclass.lpfnWndProc = WindowProc;
	winclass.cbClsExtra = 0;
	winclass.cbWndExtra = 0;
	winclass.hInstance = hinstance;
	winclass.hIcon = LoadIcon(hinstance,MAKEINTRESOURCE(IDI_ICON1));
	winclass.hCursor = LoadCursor(NULL,IDC_ARROW);
	winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
	winclass.lpszMenuName = NULL;
	winclass.lpszClassName = WINDOW_CLASS_NAME;
	winclass.hIconSm = winclass.hIcon;

	// register window class

	if(!RegisterClassEx(&winclass))
	{
		MSG("Unable to register Window.");
		return(0);
	}

	// create window

	if(!(hwnd = CreateWindowEx(NULL,WINDOW_CLASS_NAME,WINDOW_TITLE,WS_POPUP|WS_VISIBLE,
							   0,0,WINDOW_WIDTH,WINDOW_HEIGHT,NULL,NULL,hinstance,NULL)))
	{
		MSG("Unable to create Window.");
		return(0);
	}

	// save window info into globals

	main_window_handle = hwnd;
	main_instance = hinstance;

	// Initiate game

	if(!Game_Init())
	{
		MSG("Unable to Initiate Game.");
		return(0);
	}
	
	// Run Game

	while(1)
	{
		if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
		{
			if(msg.message == WM_QUIT)
				break;
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}

		// Start Frame Counter

		srand(Frames_Per_Second = GetTickCount());

		if(!Game_Main())
		{
			MSG("Unable to continue game.");
			return(0);
		}

		// Wait so that we get appr. 33 fps

		while((GetTickCount()-Frames_Per_Second) < 30);

		// Flip the two buffers

		while(FAILED(lpddsprimary->Flip(NULL,DDFLIP_WAIT)));

		// take this out when done with game

		//if(KEY_DOWN(VK_ESCAPE))

		//	PostMessage(main_window_handle,WM_DESTROY,0,0);

	}

	// Shutdown Game

	Game_Shutdown();

	return((int)msg.wParam);
}
///////////////////////////////////////////////////////////

int Game_Init(void *parms)
{
	// hide the cursor

	ShowCursor(FALSE);

	// create interface 7.0

	if(FAILED(DirectDrawCreateEx(NULL,(void **)&lpdd,IID_IDirectDraw7,NULL)))
	{
		MSG("Unable to create DirectDraw interface.");
		return(0);
	}

	// set cooperation level

	if(FAILED(lpdd->SetCooperativeLevel(main_window_handle,DDSCL_NORMAL | DDSCL_ALLOWMODEX | DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT | DDSCL_MULTITHREADED)))
	{
		MSG("Unable to set cooperation level.");
		return(0);
	}

	// set display mode

	if(FAILED(lpdd->SetDisplayMode(WINDOW_WIDTH,WINDOW_HEIGHT,WINDOW_BPP,0,0)))
	{
		MSG("Unable to set the display mode.");
		return(0);
	}

	// create primary surface

	memset(&ddsd,0,sizeof(ddsd));
	ddsd.dwSize=sizeof(ddsd);

	// complex flippable surface structure

	ddsd.dwFlags=DDSD_CAPS|DDSD_BACKBUFFERCOUNT;
	ddsd.ddsCaps.dwCaps=DDSCAPS_PRIMARYSURFACE|DDSCAPS_FLIP|DDSCAPS_COMPLEX;
	ddsd.dwBackBufferCount=1;

	// create primary surface

	if(FAILED(lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL)))
	{
		MSG("Unable to create surface.");
		return(0);
	}

	// check color

	DDPIXELFORMAT ddpf;
	DDRAW_INIT_STRUCT(ddpf);
	if(FAILED(lpddsprimary->GetPixelFormat(&ddpf)))
	{
		MSG("Unable to get Pixel Format.");
		return(0);
	}
	if(ddpf.dwGBitMask==0x000007E0)
	{
		dd_pixel_format=16;
		RGB16Bit=RGB16Bit565;
	}
	else
	{
		dd_pixel_format=15;
		RGB16Bit=RGB16Bit555;
	}

	// get a back buffer

	ddscaps.dwCaps=DDSCAPS_BACKBUFFER;

	if(FAILED(lpddsprimary->GetAttachedSurface(&ddscaps,&lpddsback)))
	{
		MSG("Unable to attach secondary surface.");
		return(0);
	}
	DDraw_Fill_Surface(lpddsprimary,0);
	DDraw_Fill_Surface(lpddsback,0);

	// try to add clipper

	RECT screen_rect={0,0,WINDOW_WIDTH,WINDOW_HEIGHT};
	LPRGNDATA region_data;

	// first create clipper

	if(FAILED(lpdd->CreateClipper(0,&lpddclipper,NULL)))
	{
		MSG("NO CLIPPER!");
		exit(0);
	}

	region_data=(LPRGNDATA)malloc(sizeof(RGNDATAHEADER)+sizeof(RECT));
	memcpy(region_data->Buffer,&screen_rect,sizeof(RECT));
	//set up filed

	region_data->rdh.dwSize=sizeof(RGNDATAHEADER);
	region_data->rdh.iType=RDH_RECTANGLES;
	region_data->rdh.nCount=1;
	region_data->rdh.nRgnSize=sizeof(RECT);

	region_data->rdh.rcBound.left    = screen_rect.left;
	region_data->rdh.rcBound.top     = screen_rect.top;
	region_data->rdh.rcBound.right   = screen_rect.right;
	region_data->rdh.rcBound.bottom  = screen_rect.bottom;

	if(FAILED(lpddclipper->SetClipList(region_data,0)))
	{
		free(region_data);
		MSG("NO CLIPPER");
		exit(0);
	}

	if(FAILED(lpddsback->SetClipper(lpddclipper)))
	{
		free(region_data);
		MSG("NO CLIPPER");
		exit(0);
	}

	free(region_data);

	// Initiate input

	if(!game_input.Initiate())
	{
		MSG("Unable to Initiate Input.");
		return(0);
	}

	// Load bitmaps here

	if(!background.Load("Media\\Background.bmp",0,0,640,480,DDSCAPS_SYSTEMMEMORY))
	{
		MSG("Unable to load background bitmap.");
		return(0);
	}
	if(!history.Load("Media\\History.bmp",0,0,640,480,DDSCAPS_SYSTEMMEMORY))
	{
		MSG("Unable to load History bitmap.");
		return(0);
	}
	if(!menu.Load("Media\\Menu.bmp",0,0,640,480,DDSCAPS_SYSTEMMEMORY))
	{
		MSG("Unable to load background bitmap.");
		return(0);
	}
	if(!blocks[0].Load("Media\\BlockPaddleBall.bmp",1,1,31,15,DDSCAPS_SYSTEMMEMORY))
	{
		MSG("Unable to load block bitmap.");
		return(0);
	}
	if(!blocks[1].Load("Media\\BlockPaddleBall.bmp",33,1,31,15,DDSCAPS_SYSTEMMEMORY))
	{
		MSG("Unable to load block bitmap.");
		return(0);
	}
	if(!blocks[2].Load("Media\\BlockPaddleBall.bmp",65,1,31,15,DDSCAPS_SYSTEMMEMORY))
	{
		MSG("Unable to load block bitmap.");
		return(0);
	}
	if(!blocks[3].Load("Media\\BlockPaddleBall.bmp",97,1,31,15,DDSCAPS_SYSTEMMEMORY))
	{
		MSG("Unable to load block bitmap.");
		return(0);
	}
	if(!blocks[4].Load("Media\\BlockPaddleBall.bmp",129,1,31,15,DDSCAPS_SYSTEMMEMORY))
	{
		MSG("Unable to load block bitmap.");
		return(0);
	}
	if(!blocks[5].Load("Media\\BlockPaddleBall.bmp",161,1,31,15,DDSCAPS_SYSTEMMEMORY))
	{
		MSG("Unable to load block bitmap.");
		return(0);
	}
	if(!blocks[6].Load("Media\\BlockPaddleBall.bmp",193,1,31,15,DDSCAPS_SYSTEMMEMORY))
	{
		MSG("Unable to load block bitmap.");
		return(0);
	}
	if(!blocks[7].Load("Media\\BlockPaddleBall.bmp",225,1,31,15,DDSCAPS_SYSTEMMEMORY))
	{
		MSG("Unable to load block bitmap.");
		return(0);
	}
	if(!blocks[8].Load("Media\\BlockPaddleBall.bmp",257,1,31,15,DDSCAPS_SYSTEMMEMORY))
	{
		MSG("Unable to load block bitmap.");
		return(0);
	}
	if(!blocks[9].Load("Media\\BlockPaddleBall.bmp",289,1,31,15,DDSCAPS_SYSTEMMEMORY))
	{
		MSG("Unable to load block bitmap.");
		return(0);
	}
	if(!ball.Load("Media\\BlockPaddleBall.bmp",1,17,10,10,DDSCAPS_SYSTEMMEMORY))
	{
		MSG("Unable to load ball bitmap.");
		return(0);
	}
	if(!paddle.Load("Media\\BlockPaddleBall.bmp",12,17,100,10,DDSCAPS_SYSTEMMEMORY))
	{
		MSG("Unable to load paddle bitmap.");
		return(0);
	}

	// set variables

	Reset();

	return(1);
}
///////////////////////////////////////////////////////////

int Game_Main(void *parms)
{
	// clear drawing surface

	DDraw_Fill_Surface(lpddsback,0);

	// read input

	game_input.Read();
	
	// Draw background

	background.Draw();

	switch(game_state)
	{
	case GS_TITLE:
		{
			// Draw history bitmap as title screen

			history.Draw();
			if(DX_KEY_DOWN(DIK_RETURN))
			{
				__asm mov key_up[DIK_RETURN * TYPE int],1 //key_up[DIK_RETURN]=1;

			}

			if(key_up[DIK_RETURN] && !DX_KEY_DOWN(DIK_RETURN))
			{
				_asm mov game_state,GS_MENU //game_state = GS_MENU;

				_asm mov key_up[DIK_RETURN * TYPE int],0 //key_up[DIK_RETURN]=0;

			}

		}break;
	case GS_MENU:
		{
			menu.Draw();
			if(DX_KEY_DOWN(DIK_ESCAPE))
				_asm mov key_up[DIK_ESCAPE * TYPE int],1 //key_up[DIK_ESCAPE]=1;


			if(key_up[DIK_ESCAPE]  && !DX_KEY_DOWN(DIK_ESCAPE))
			{
				PostMessage(main_window_handle,WM_DESTROY,0,0);
				_asm mov key_up[DIK_ESCAPE * TYPE int],0 //key_up[DIK_ESCAPE]=0;

			}

			if(DX_KEY_DOWN(DIK_RETURN))
				_asm mov key_up[DIK_RETURN * TYPE int],1 //key_up[DIK_RETURN]=1;


			if(key_up[DIK_RETURN] && !DX_KEY_DOWN(DIK_RETURN))
			{
				Reset();
				_asm mov game_state,GS_RUN //game_state=GS_RUN;

				_asm mov key_up[DIK_RETURN * TYPE int],0 //key_up[DIK_RETURN]=0;

			}

		}break;
	case GS_RUN:
		{
			if(DX_KEY_DOWN(DIK_ESCAPE))
				_asm mov key_up[DIK_ESCAPE * TYPE int],1 //key_up[DIK_ESCAPE]=1;


			if(key_up[DIK_ESCAPE]  && !DX_KEY_DOWN(DIK_ESCAPE))
			{
				_asm mov game_state,GS_MENU //game_state = GS_MENU;

				_asm mov key_up[DIK_ESCAPE * TYPE int],0 //key_up[DIK_ESCAPE]=0;

			}

			// temp take this out

			if(DX_KEY_DOWN(DIK_SPACE))
				blocks_left=0;

			// Move the paddle with the mouse

			if(game_input.mouse_state.lX>64)
				paddle.itsX+=64;
			else if(game_input.mouse_state.lX<-64)
				paddle.itsX-=64;
			else
				paddle.itsX+=game_input.mouse_state.lX;

			// take care of the different levels

			if(level_done)
			{
				level_done=0;
				level++;
				//if(level>25)

				// open next level and load it in

				char filename[100];
				memset(grid,0,sizeof(grid));
				sprintf(filename,"Media//LEVEL%d",level);

				std::ifstream fin(filename,std::ios::binary);
				fin.read((char*)&grid,sizeof(grid));
				fin.close();
				// set all numbers one back

				for(index = 0;index <400;index++)
				{
					if(grid[index]>0 && grid[index]<8)
					{
						blocks_left++;
					}
					// knock all block numbers down one 

					// to account for the blank block

					grid[index]--;
					if(grid[index]==7)
						grid[index]=11;
				}
			}

			// pause shortly after level cleared

			if(blocks_left<=0)
			{
				if((blocks_left--)<-60)
				{
					// Display Level Cleared

					blocks_left=0;
					level_done=1;
				}
			}

			// don''t let paddle off the screen

			if(paddle.itsX>530)
				paddle.itsX=530;
			else if(paddle.itsX<10)
				paddle.itsX=10;

			// if ball_shot = 0 follow paddle

			if(ball_shot==0)
			{
				// if mouse clicked, ball is shot

				if(game_input.mouse_state.rgbButtons[0])
				{
					_asm mov ball_shot, 1 //ball_shot=1;

					_asm mov ball_yv, -4 //ball_yv=-4;

					ball_xv=-(ball.itsX-paddle.itsX-45)/MAX_VEL;
				}

				ball.itsX=paddle.itsX+45;
			}
			else
			{
				// actually move the ball, etc

				_asm mov eax, ball.itsX _asm add eax, ball_xv _asm mov ball.itsX, eax //ball.itsX+=ball_xv;

				_asm mov eax, ball.itsY _asm add eax, ball_yv _asm mov ball.itsY, eax //ball.itsY+=ball_yv;

				// don''t let ball off the screen

				if(ball.itsX>620)
				{
					_asm neg ball_xv //ball_xv=-ball_xv;

					_asm mov eax,1240 _asm sub eax,ball.itsX _asm mov ball.itsX,eax //ball.itsX=620-ball.itsX+620;

				}
				else if(ball.itsX<10)
				{
					_asm neg ball_xv //ball_xv=-ball_xv;

					_asm mov eax,20 _asm sub eax,ball.itsX _asm mov ball.itsX,eax //ball.itsX=10-ball.itsX+10;

				}
	
				if(ball.itsY>470)
				{
					// change to lose life

					_asm mov ball_shot,0 //ball_shot = 0;

					_asm mov eax,paddle.itsX _asm add eax,45 _asm mov ball.itsX,eax //ball.itsX=paddle.itsX+45;

					_asm mov ball.itsY, 440 //ball.itsY=440;

				}
				else if(ball.itsY<60)
				{
					_asm neg ball_yv //ball_yv=-ball_yv;

					_asm mov eax,120 _asm sub eax,ball.itsY _asm mov ball.itsY,eax //ball.itsY=60-ball.itsY+60;

				}
				else if((ball.itsY > 439 && ball.itsY < (439+MAX_VEL)) && (ball.itsX > paddle.itsX-10 && ball.itsX < paddle.itsX+110))
				{
					// bounce off of paddle

					_asm neg ball_yv //ball_yv=-ball_yv;

					//_asm mov eax,game_input.mouse_state.lX

					//_asm shl eax,2

					//_asm add eax,ball_xv

					//_asm mov ball_xv,eax

					ball_xv+=game_input.mouse_state.lX/4;
					_asm mov eax,880 _asm sub eax,ball.itsY _asm mov ball.itsY,eax //ball.itsY=440-ball.itsY+440;

				}
				
				// make sure vel is not excessive

				if(ball_xv > MAX_VEL)
					_asm MOV ball_xv,MAX_VEL //ball_xv=MAX_VEL;

				else if(ball_xv < -MAX_VEL)
				{
					_asm mov eax,MAX_VEL _asm neg eax _asm mov ball_xv,eax //ball_xv=-MAX_VEL;

				}

				if(ball_yv > MAX_VEL)
					_asm mov ball_yv,MAX_VEL //ball_yv=MAX_VEL;

				else if(ball_yv < -MAX_VEL)
				{
					_asm mov eax,MAX_VEL _asm neg eax _asm mov ball_yv,eax //ball_yv=-MAX_VEL;

				}
				// collision detect blocks

				ball_xv2=ball_xv;
				ball_yv2=ball_yv;
				bx=0;
				by=0;
				gcount=0;
				for(int inddy=0;inddy<3;inddy++)
				{
					for(int index=0;index<400;index++)
					{
						// first, check to see if box is actually hit

						if(grid[index]>=0 && CheckCollision())
						{
							if(grid[index]==8)
							{
								// do nothing, just let it bounce

								// since it is a brick block

							}
							else if(grid[index]==9)
							{
								// up life here

								lives++;
								grid[index]=-1;
							}
							else if(grid[index]==11)
							{
								// make hidden block veiwable

								grid[index]=7;
								blocks_left++;
							}
							else
							{
								// colored blocks and now-not-hidden-hidden blocks

								blocks_left--;
								grid[index]=-1;
							}
								goto here;
						}
						by+=15;
						gcount++;
						if(gcount>19)
						{
							gcount=0;
							by=0;
							bx+=31;
						}
					}
				}
here:
			_asm nop
			}
	
			bx=0,by=0;
			gcount=0;
			// draw blocks

			for(index = 0;index<400;index++)
			{
				if(grid[index]<=10 && grid[index]>=0)
				{
					blocks[grid[index]].itsX=bx+10;
					blocks[grid[index]].itsY=by+60;
					blocks[grid[index]].Draw();
				}
				by+=15;
				gcount++;
				if(gcount>19)
				{
					gcount=0;
					by=0;
					bx+=31;
				}
			}

			// Draw paddle

			paddle.Draw();

			// Draw ball

			ball.Draw();

		}break;
	default:
		{
		_asm mov game_state,GS_TITLE //game_state=GS_TITLE;

		break;
		}
	}


	return(1);
}
///////////////////////////////////////////////////////////

int Game_Shutdown(void *parms)
{
	// release bitmaps

	background.End();
	history.End();
	blocks[0].End();
	blocks[1].End();
	blocks[2].End();
	blocks[3].End();
	blocks[4].End();
	blocks[5].End();
	blocks[6].End();
	blocks[7].End();
	blocks[8].End();
	blocks[9].End();

	game_input.End();

	if(lpdd)
		lpdd->Release();

	if(lpddsback)
		lpddsback->Release();

	if(lpddsprimary)
		lpddsprimary->Release();

	// show the cursor

	ShowCursor(TRUE);

	return(1);
}
///////////////////////////////////////////////////////////

int DDraw_Fill_Surface(LPDIRECTDRAWSURFACE7 lpdds,USHORT color)
{
	DDBLTFX ddbltfx;
	DDRAW_INIT_STRUCT(ddbltfx);
	ddbltfx.dwFillColor=color;
	lpdds->Blt(NULL,NULL,NULL,DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
	return(1);
}
///////////////////////////////////////////////////////////

USHORT RGB16Bit565(int r,int g,int b)
{
	r>>=3;
	g>>=3;
	b>>=3;
	return(_RGB16BIT565(r,g,b));
}
///////////////////////////////////////////////////////////

USHORT RGB16Bit555(int r,int g,int b)
{
	r>>=3;
	g>>=2;
	b>>=3;
	return(_RGB16BIT555(r,g,b));
}
///////////////////////////////////////////////////////////

int Bitmap_File::End()
{
	if(this->itsImage)
		this->itsImage->Release();

	return(1);
}

int Bitmap_File::Load(char *filename,int start_x,int start_y,int width,int height,int mem_flags)
{


	// WARNING!!!

	//    This class function does no check to make sure that the color is the

	//			proper bit depth.


	// first set up vars

		itsImage=NULL;
		itsHeight=height;
		itsWidth=width;
		itsX=0;
		itsY=0;

	// now load the bitmap

		int file_handle;
		BITMAPFILEHEADER bitmapfileheader;
		BITMAPINFOHEADER bitmapinfoheader;
		UCHAR *buffer;
		OFSTRUCT file_data;
		
		// open file IF it exists

		if((file_handle=OpenFile(filename,&file_data,OF_READ))==-1)
		{
			return(0);
		}

		// load bitmap file header

		_lread(file_handle,&bitmapfileheader,sizeof(BITMAPFILEHEADER));

		// is it a bitmap?

		if(bitmapfileheader.bfType!=0x4D42)// 0x4D42 means it is a bitmap

		{
			_lclose(file_handle);
			return(0);
		}

		// load the info header

		_lread(file_handle,&bitmapinfoheader,sizeof(BITMAPINFOHEADER));

		// find image data

		_lseek(file_handle,-(int)bitmapinfoheader.biSizeImage,SEEK_END);

		// change 24 bit to 16

		UCHAR *temp_buff;

		if(!(temp_buff = (UCHAR *)malloc(bitmapinfoheader.biSizeImage)))
		{
			_lclose(file_handle);
			return(0);
		}

		if(!(buffer=(UCHAR *)malloc(2*bitmapinfoheader.biWidth*bitmapinfoheader.biHeight)))
		{
			_lclose(file_handle);
			free(temp_buff);
			return(0);
		}

		_lread(file_handle,temp_buff,bitmapinfoheader.biSizeImage);

		for(index=0;index<bitmapinfoheader.biWidth*bitmapinfoheader.biHeight;index++)
		{
			USHORT color;
			if(dd_pixel_format==16)
			{
				UCHAR blue = (temp_buff[index*3+0]>>3),
					green = (temp_buff[index*3+1]>>2),
					red = (temp_buff[index*3+2]>>3);
				color=_RGB16BIT565(red,green,blue);
			}
			else
			{
				UCHAR blue = (temp_buff[index*3+0]>>3),
					green = (temp_buff[index*3+1]>>3),
					red = (temp_buff[index*3+2]>>3);
				color=_RGB16BIT555(red,green,blue);
			}
			((USHORT *)buffer)[index]=color;
		}
		bitmapinfoheader.biBitCount=16;
		free(temp_buff);


		// close file

		_lclose(file_handle);

	// Flip bitmap


		UCHAR *tempbuffer;

		// allocate memory for tempbuffer

		if(!(tempbuffer = (UCHAR *)malloc(bitmapinfoheader.biWidth*(bitmapinfoheader.biBitCount/8)*bitmapinfoheader.biHeight)))
		{
			return(0);
		}

		// copy image to work area

		memcpy(tempbuffer,buffer,(bitmapinfoheader.biWidth*(bitmapinfoheader.biBitCount/8)*bitmapinfoheader.biHeight));

		// flip vertically

		for(index=0;index<bitmapinfoheader.biHeight;index++)
			memcpy(&buffer[((bitmapinfoheader.biHeight-1)-index)*bitmapinfoheader.biWidth*(bitmapinfoheader.biBitCount/8)],
				&tempbuffer[index*(bitmapinfoheader.biWidth*(bitmapinfoheader.biBitCount/8))], 
				bitmapinfoheader.biWidth*(bitmapinfoheader.biBitCount/8));

		// release tempbuffer memory

		free(tempbuffer);


	// Prepare DDsurface


		DDSURFACEDESC2 itsddsd;
		// create surface

		memset(&itsddsd,0,sizeof(itsddsd));
		itsddsd.dwSize=sizeof(itsddsd);
		itsddsd.dwFlags=DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
		itsddsd.dwWidth=itsWidth;
		itsddsd.dwHeight=itsHeight;
		itsddsd.ddsCaps.dwCaps=DDSCAPS_OFFSCREENPLAIN | mem_flags;
		if(FAILED(lpdd->CreateSurface(&itsddsd,&itsImage,NULL)))
		{
			return(0);
		}

		// set color for blitting

		DDCOLORKEY its_color_key;
		its_color_key.dwColorSpaceHighValue=its_color_key.dwColorSpaceLowValue=0;
		itsImage->SetColorKey(DDCKEY_SRCBLT,&its_color_key);

	// place picture onto bitmap

		DDRAW_INIT_STRUCT(itsddsd);
		USHORT *its_source,*its_dest;

		its_source = (USHORT *)buffer + start_y * bitmapinfoheader.biWidth + start_x;
		itsddsd.dwSize = sizeof(itsddsd);

		// lock surface

		itsImage->Lock(NULL,&itsddsd,DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,NULL);

		its_dest = (USHORT *)itsddsd.lpSurface;
		for(index=0;index<itsHeight;index++)
		{
			memcpy(its_dest,its_source,(itsWidth*2));
			its_dest+=(itsddsd.lPitch>>1);
			its_source+=bitmapinfoheader.biWidth;
		}
		itsImage->Unlock(NULL);

		return(1);
}

int Bitmap_File::Draw()
{
	RECT its_dest, its_source;
	its_dest.left=itsX;
	its_dest.top=itsY;
	its_dest.right=itsX+itsWidth;
	its_dest.bottom=itsY+itsHeight;
	its_source.left=0;
	its_source.top=0;
	its_source.right=itsWidth;
	its_source.bottom=itsHeight;

	//blt it

	if(FAILED(lpddsback->Blt(&its_dest,this->itsImage,&its_source,(DDBLT_WAIT | DDBLT_KEYSRC),NULL)))
		return(0);
	
	return(1);
}
///////////////////////////////////////////////////////////

int Game_Input::Initiate()
{
	//startup DirectInput

	if(FAILED(DirectInput8Create(main_instance,DIRECTINPUT_VERSION,IID_IDirectInput8,(void **)&lpdi,NULL)))
	{
		MSG("Unable to initiate DirectInput.");
		return(0);
	}

	// first, setup the keyboard

	if(this->lpdi->CreateDevice(GUID_SysKeyboard,&this->keyboard,NULL)!=DI_OK)
	{
		MSG("Unable Create Keyboard Device.");
		return(0);
	}

	if(this->keyboard->SetCooperativeLevel(main_window_handle,DISCL_NONEXCLUSIVE|DISCL_BACKGROUND)!=DI_OK)
	{
		MSG("Unable to set keyboard cooperation level.");
		return(0);
	}

	if(this->keyboard->SetDataFormat(&c_dfDIKeyboard)!=DI_OK)
	{
		MSG("Unable to set keyboard data format.");
		return(0);
	}
	
	if(this->keyboard->Acquire()!=DI_OK)
	{
		MSG("Unable to acquire keyboard.");
		return(0);
	}

	// setup mouse

	if(this->lpdi->CreateDevice(GUID_SysMouse,&this->mouse,NULL)!=DI_OK)
	{
		MSG("Unable to Create Mouse Device.");
		return(0);
	}

	if(this->mouse->SetCooperativeLevel(main_window_handle,DISCL_NONEXCLUSIVE|DISCL_BACKGROUND)!=DI_OK)
	{
		MSG("Unable to set mouse cooperation level.");
		return(0);
	}

	if(this->mouse->SetDataFormat(&c_dfDIMouse)!=DI_OK)
	{
		MSG("Unable to set mouse data format.");
		return(0);
	}

	if(this->mouse->Acquire()!=DI_OK)
	{
		MSG("Unable to acquire mouse.");
		return(0);
	}

	return(1);
}

int Game_Input::Read()
{
	if(this->keyboard)
	{
		if(this->keyboard->GetDeviceState(256,(LPVOID)this->keystate)!=DI_OK)
		{
			return(0);
		}
	}
	else
	{
		memset(this->keystate,0,sizeof(this->keystate));
		return(0);
	}

	if(this->mouse)
	{
		if(this->mouse->GetDeviceState(sizeof(DIMOUSESTATE),(LPVOID)&this->mouse_state)!=DI_OK)
		{
			return(0);
		}
	}
	else
	{
		memset(&this->mouse_state,0,sizeof(this->mouse_state));
		return(0);
	}
	return(1);
}

int Game_Input::End()
{
	if(this->keyboard)
	{
		this->keyboard->Unacquire();
		this->keyboard->Release();
	}

	if(this->mouse)
	{
		this->mouse->Unacquire();
		this->mouse->Release();
	}

	if(lpdi)
		lpdi->Release();

	return(1);
}
///////////////////////////////////////////////////////////

void Reset(void)
{
	memset(grid,0,sizeof(grid));
	_asm mov paddle.itsX,270 //paddle.itsX=270;

	_asm mov paddle.itsY,450 //paddle.itsY=450;

	_asm mov ball.itsX,315 //ball.itsX=315;

	_asm mov ball.itsY,440 //ball.itsY=440;

	_asm mov level,0 //level=0;

	_asm mov level_done,1 //level_done=1;

	_asm mov ball_shot,0 //ball_shot=0;

	_asm mov ball_xv,0 //ball_xv=0;

	_asm mov ball_yv,0 //ball_yv=0;

	_asm mov lives,0 // lives=0;

}
///////////////////////////////////////////////////////////

int CheckCollision(void)
{
	// Going to try computing a line in a 16 by 16 grid

	// using the Bresenham Line method while incrementing

	// a counter for each pixel, then going through array

	// and putting it all in a 2x(counter) array

	// and then checking each pixel, pixel.x +10, pixel.y+10,

	// and (pixel.y pixel.x)+10 of the line array to see

	// if it is inside the block and then use the data

	// of the line array to see if it is on top,right,left,bottom

	// and reflect ball velocity accordingly. Depending on 

	// where the block was hit, reflect the ball so that

	// it appears to bounce and not be inside of the block


	// Computing line

	int line_grid[16][16];
	memset(line_grid,0,sizeof(line_grid));
	int dx = 0,
		dy = 0,
		dx2 = 0,
		dy2 = 0,
		x_inc = 0,
		y_inc = 0,
		error = 0,
		x0 = ball.itsX, // starting pos

		y0 = ball.itsY, // starting pos

		x1 = ball.itsX+ball_xv2, // ending pos

		y1 = ball.itsY+ball_yv2, // ending pos

		gridx=x0,
		gridy=y0;

	// compute hor and vert deltas

	dx=x1-x0;
	dy=y1-y0;

	// test line direction

	if(dx>=0)
	{
		x_inc=1;
	}
	else
	{
		x_inc=-1;
		dx=-dx; // abs value

	}

	// test y component of slope

	if(dy>=0)
	{
		y_inc=1;
	}
	else
	{
		y_inc=-1;
		dy=-dy; // abs value

	}

	// compute(dx,dy)*2

	dx2=dx<<1;
	dy2=dy<<1;

	// draw line based on comparison of deltas

	if(dx>dy)
	{
		// init error term

		error=dy2-dx;

		// check collision with this pixel

			int gridx10=gridx+10;
			int gridy10=gridy+10;
			int bx10=bx+10;
			int bx41=bx+41;
			int by60=by+60;
			int by75=by+75;
				// first, check normal x,y

			if(((gridx>bx10)&&(gridx<bx41)&&(gridy>by60)&&(gridy<by75))||
			   // now check x+10,y

			   ((gridx10>bx10)&&(gridx10<bx41)&&(gridy>by60)&&(gridy<by75))||
			   // now check x,y+10

			   ((gridx>bx10)&&(gridx<bx41)&&(gridy10>by60)&&(gridy10<by75))||
			   // now check x+10,y+10

			   ((gridx10>bx10)&&(gridx10<bx41)&&(gridy10>by60)&&(gridy10<by75)))
			{
				// check to see if it came from the top or bottom

				if((gridy-y_inc == by75+1)||
				   (gridy-y_inc == by60-1))
				{
					ball_yv2=gridy-y1;
					ball_yv=-ball_yv;
					ball.itsY+=ball_yv2;
				}
				else // left and right

				{
					ball_xv2=gridx-x1;
					ball_xv=-ball_xv;
					ball.itsX+=ball_xv2;
				}
				return 1;
			}

			// has error overflowed?

			if(error >= 0)
			{
				error-=dx2;
				// move to next line

				gridy+=y_inc;
			}
			// adjust error term

			error+=dy2;

			// move to next pixel

			gridx+=x_inc;
	}
	else
	{
		// init error term

		error=dx2-dy;

		// draw line

		for(int ind=0;ind<=dy;ind++)
		{
			// check collision with this pixel

			int gridx10=gridx+10;
			int gridy10=gridy+10;
			int bx10=bx+10;
			int bx41=bx+41;
			int by60=by+60;
			int by75=by+75;
				// first, check normal x,y

			if(((gridx>bx10)&&(gridx<bx41)&&(gridy>by60)&&(gridy<by75))||
			   // now check x+10,y

			   ((gridx10>bx10)&&(gridx10<bx41)&&(gridy>by60)&&(gridy<by75))||
			   // now check x,y+10

			   ((gridx>bx10)&&(gridx<bx41)&&(gridy10>by60)&&(gridy10<by75))||
			   // now check x+10,y+10

			   ((gridx10>bx10)&&(gridx10<bx41)&&(gridy10>by60)&&(gridy10<by75)))
			{
				// check to see if it came from the top or bottom

				if((gridy-y_inc == by75+1)||
				   (gridy-y_inc == by60-1))
				{
					ball_yv2=gridy-y1;
					ball_yv=-ball_yv;
					ball.itsY+=ball_yv2;
				}
				else // left and right

				{
					ball_xv2=gridx-x1;
					ball_xv=-ball_xv;
					ball.itsX+=ball_xv2;
				}
				return 1;
			}

			// has error overflowed

			if(error>=0)
			{
				error=-dy2;
				// move to next line

				gridx+=x_inc;
			}
			// adjust error term

			error+=dx2;

			// move to next pixel

			gridy+=y_inc;
		}
	}
	return 0;
}
I apologize for my code style. I believe the error lies in the Check Collision Function:
int CheckCollision(void)
{
	// Going to try computing a line in a 16 by 16 grid

	// using the Bresenham Line method while incrementing

	// a counter for each pixel, then going through array

	// and putting it all in a 2x(counter) array

	// and then checking each pixel, pixel.x +10, pixel.y+10,

	// and (pixel.y pixel.x)+10 of the line array to see

	// if it is inside the block and then use the data

	// of the line array to see if it is on top,right,left,bottom

	// and reflect ball velocity accordingly. Depending on 

	// where the block was hit, reflect the ball so that

	// it appears to bounce and not be inside of the block


	// Computing line

	int line_grid[16][16];
	memset(line_grid,0,sizeof(line_grid));
	int dx = 0,
		dy = 0,
		dx2 = 0,
		dy2 = 0,
		x_inc = 0,
		y_inc = 0,
		error = 0,
		x0 = ball.itsX, // starting pos

		y0 = ball.itsY, // starting pos

		x1 = ball.itsX+ball_xv2, // ending pos

		y1 = ball.itsY+ball_yv2, // ending pos

		gridx=x0,
		gridy=y0;

	// compute hor and vert deltas

	dx=x1-x0;
	dy=y1-y0;

	// test line direction

	if(dx>=0)
	{
		x_inc=1;
	}
	else
	{
		x_inc=-1;
		dx=-dx; // abs value

	}

	// test y component of slope

	if(dy>=0)
	{
		y_inc=1;
	}
	else
	{
		y_inc=-1;
		dy=-dy; // abs value

	}

	// compute(dx,dy)*2

	dx2=dx<<1;
	dy2=dy<<1;

	// draw line based on comparison of deltas

	if(dx>dy)
	{
		// init error term

		error=dy2-dx;

		// check collision with this pixel

			int gridx10=gridx+10;
			int gridy10=gridy+10;
			int bx10=bx+10;
			int bx41=bx+41;
			int by60=by+60;
			int by75=by+75;
				// first, check normal x,y

			if(((gridx>bx10)&&(gridx<bx41)&&(gridy>by60)&&(gridy<by75))||
			   // now check x+10,y

			   ((gridx10>bx10)&&(gridx10<bx41)&&(gridy>by60)&&(gridy<by75))||
			   // now check x,y+10

			   ((gridx>bx10)&&(gridx<bx41)&&(gridy10>by60)&&(gridy10<by75))||
			   // now check x+10,y+10

			   ((gridx10>bx10)&&(gridx10<bx41)&&(gridy10>by60)&&(gridy10<by75)))
			{
				// check to see if it came from the top or bottom

				if((gridy-y_inc == by75+1)||
				   (gridy-y_inc == by60-1))
				{
					ball_yv2=gridy-y1;
					ball_yv=-ball_yv;
					ball.itsY+=ball_yv2;
				}
				else // left and right

				{
					ball_xv2=gridx-x1;
					ball_xv=-ball_xv;
					ball.itsX+=ball_xv2;
				}
				return 1;
			}

			// has error overflowed?

			if(error >= 0)
			{
				error-=dx2;
				// move to next line

				gridy+=y_inc;
			}
			// adjust error term

			error+=dy2;

			// move to next pixel

			gridx+=x_inc;
	}
	else
	{
		// init error term

		error=dx2-dy;

		// draw line

		for(int ind=0;ind<=dy;ind++)
		{
			// check collision with this pixel

			int gridx10=gridx+10;
			int gridy10=gridy+10;
			int bx10=bx+10;
			int bx41=bx+41;
			int by60=by+60;
			int by75=by+75;
				// first, check normal x,y

			if(((gridx>bx10)&&(gridx<bx41)&&(gridy>by60)&&(gridy<by75))||
			   // now check x+10,y

			   ((gridx10>bx10)&&(gridx10<bx41)&&(gridy>by60)&&(gridy<by75))||
			   // now check x,y+10

			   ((gridx>bx10)&&(gridx<bx41)&&(gridy10>by60)&&(gridy10<by75))||
			   // now check x+10,y+10

			   ((gridx10>bx10)&&(gridx10<bx41)&&(gridy10>by60)&&(gridy10<by75)))
			{
				// check to see if it came from the top or bottom

				if((gridy-y_inc == by75+1)||
				   (gridy-y_inc == by60-1))
				{
					ball_yv2=gridy-y1;
					ball_yv=-ball_yv;
					ball.itsY+=ball_yv2;
				}
				else // left and right

				{
					ball_xv2=gridx-x1;
					ball_xv=-ball_xv;
					ball.itsX+=ball_xv2;
				}
				return 1;
			}

			// has error overflowed

			if(error>=0)
			{
				error=-dy2;
				// move to next line

				gridx+=x_inc;
			}
			// adjust error term

			error+=dx2;

			// move to next pixel

			gridy+=y_inc;
		}
	}
	return 0;
}
I appreciate any help and apologize for my noobishness. Being that I am human, I am prone to (MANY)mistakes. Check everything I post with Google, etc. -- Chronic sufferer of OCD
VThornheart
VThornheart
Do you mean that it doesn''t collide at all, or that the response to collision doesn''t work as predicted (ie: what happens to the objects after they collide)?

If you can be as specific as possible with how it doesn''t work as expected, we''ll see what we can see.
-Vendal Thornheart=) Programming for a better tomorrow... well,for a better simulated tomorrow. ;)
nerd_boy
nerd_boy
It kinda bounces from the middle then goes off in the wrong direction, sometimes taking a bunch of blocks out without bouncing, and sometimes getting stuck in a little circle of the other blocks.

Edit: Whoops! Forgot webaccount doesn't support hotlinking.


Being that I am human, I am prone to (MANY)mistakes.
Check everything I post with Google, etc.

-- Chronic sufferer of OCD

[edited by - Luke Thompson on January 19, 2004 5:36:12 AM]

[edited by - Luke Thompson on January 19, 2004 5:36:50 AM]
oliii
oliii
phew dude, integer maths and asm. Brings back the good old days

I''m not sure a bresendham algo is good enough for this. I mean, the ball will sweep though the grid, as it''s got a radius. So, it would be like, drawing a thick line on the grid, so you''d get a width of gridpoints.

Then you need to find the first block intersected, move the ball on the surface, reflect the ball velocity, and find the next block.

and I''d use floating point maths
Everything is better with Metal.
nerd_boy
nerd_boy
But if you notice in CheckCollision, I check for ball(x,y), ball(x+10,y),ball(x,y+10),ball(x+10,y+10). Isn''t that checking the whole "thick line"?

Being that I am human, I am prone to (MANY)mistakes.
Check everything I post with Google, etc.

-- Chronic sufferer of OCD
oliii
oliii
aah, that''s what the ''+10'' is about.

well, you could get aliasing I guess. Try to render the grid somewhere, and render what the bresendham gives you. see if there are gaps in the line.

Everything is better with Metal.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.