Original Post
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.
Being that I am human, I am prone to (MANY)mistakes.
Check everything I post with Google, etc.
-- Chronic sufferer of OCD
// 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.