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

collision problem

Started by pascalosti Sep 22, 2006 at 2:55 AM 0 replies 1.3k views
Original Post
pascalosti
pascalosti
I'm trying to get this collision thing working with minimal luck. Right now 1 ball, one wall. Reflections are off. Can someone run it and point me in the right direction. Im positive my dot product is correct, im using fake collision around the borders. I just need a hint. (left or right click to change wall or ball location) win32 project using vs 2005

// really basic GDI program
#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <math.h>
#include <cstdlib>
#include <ctime>

// ==== DEFINES ==========================================================

#define WINDOW_CLASS_NAME "WINCLASS1"
#define WIN_WID 640
#define WIN_HGT 480
#define X_OFFSET (WIN_WIDTH/2)
#define Y_OFFSET (WIN_HEIGHT/2)
#define WIN_LEFT    0
#define WIN_TOP     0
#define BALL_WIDTH 5
#define BALL_SPACING 2
#define BALL_SPEED 5

#define DEG2RAD(a)  ((a) * 0.0174533f)	// = deg x PI/180
#define X_START 100
#define Y_START 100
#define START_ANGLE_DEG 53.0f		// launch angle in degrees
#define START_VELOCITY   8.0f		// length of velocity vector


COLORREF BallColor = RGB(255, 0, 0);
COLORREF WallColor = RGB(0, 250, 100);




// ==== STRUCTURES ===============================================
typedef struct tVector2
{
	float x;
	float y;
} tPoint2;

struct tLineSeg
{
	tPoint2 p0;
	tPoint2 p1;
	bool isVertical; // slope infinite, no b
	float m;
	float b;
	tVector2 n;
};


// ==== GLOBALS ==========================================================

HWND g_hWnd; // main window handle
POINT gCursorPos;


COLORREF gBallColor = 0x00FFFFFF;

			bool ticker = false;
			float counter = 0;
			float counter1 = 0;
			float counter2 = 0;
			float counter3 = 0;
			float counter4 = 20;


#define NUM_WALLS 11
tLineSeg gWallArray[NUM_WALLS] = 
{
//   p0.x,        p0.y,         p1.x,         p1.y,        isVert,m, b, n.x, n.y
	{20.0f,        20.0f,	      20.0f,        (WIN_HGT-55), false, 0, 0, 0,   0},   // left bounding edge
	{20.0f,        (WIN_HGT-55), (WIN_WID-50), (WIN_HGT-55), false, 0, 0, 0,   0},   // top bounding edge
	{(WIN_WID-30), (WIN_HGT-55), (WIN_WID-50), 20.0f,         false, 0, 0, 0,   0},   // right bounding edge
	{(WIN_WID-30), 20.0f,         20.0f,        20.0f,         false, 0, 0, 0,   0},   // bottom bounding edge

	{400.0f,      350.0f,       500.0f,      230.0f,       false, 0, 0, 0,   0},   // obstacle 1
	{100.0f,      250.0f,       200.0f,      400.0f,       false, 0, 0, 0,   0},   // obstacle 2
	{600.0f,      150.0f,       500.0f,       50.0f,       false, 0, 0, 0,   0},   // obstacle 3
	{150.0f,      100.0f,       225.0f,      120.0f,       false, 0, 0, 0,   0},   // obstacle 4

	{225.0f,      300.0f,       350.0f,      250.0f,       false, 0, 0, 0,   0},   // triangle side 1
	{225.0f,      300.0f,       260.0f,      200.0f,       false, 0, 0, 0,   0},   // triangle side 2
	{260.0f,      200.0f,       350.0f,      250.0f,       false, 0, 0, 0,   0},   // triangle side 3
};

tLineSeg OneLine = {20.0f,      250.0f,       400.0f,      150.0f,       false, 0, 0, 0,   0};

tLineSeg gBall = { 20.0f, 400.0f, 450.0f, 200.0f, false, 0, 0, 0, 0};

HDC memDC;		// handle to memory device context for back buffer

// ==== PROTOTYPES =======================================================

LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
void ClearScreen(HDC hDC);
void DrawWalls();
void DrawLine(HDC hDC, tPoint2 p0, tPoint2 p1, COLORREF color);
void ClearScreen();
void DrawCircle(HDC dc, int xOrg, int yOrg, int radius, int spacing, COLORREF color);
void MoveBall();
void FakeCollision();

//bool BorderCollision(); // fake collision
tVector2 Normalize(tVector2 A);
void InitializLine(tLineSeg *A);
bool Intersection(tLineSeg &ball, tLineSeg &wall, tVector2 *hitPT);
float hitTime(tLineSeg A, tVector2 *hitPT);
float Dott(tVector2 A, tVector2 B);
tVector2 Reflect(tVector2 B, tVector2 W);
float Vec2Mag(tVector2 v);
tVector2 hitPT = {0, 0};
tVector2 Vel = { 40, 30};
int tit = 0;
int nearest = 0;
bool nextWall = false;
int wall = 0;


// ==== FUNCTIONS ========================================================

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	WNDCLASSEX wc;	// this will hold the window class
	MSG msg;		// message container

	HDC hDC;		// handle to device context
//HDC memDC;		// handle to memory device context for back buffer
	HBITMAP memBM;	// bitmap to size the memory device context


	// Fill the window class structure
	wc.cbSize			= sizeof(WNDCLASSEX);
	wc.style			= CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc		= WindowProc;
	wc.cbClsExtra		= 0;
	wc.cbWndExtra		= 0;
	wc.hInstance		= hInstance;
	wc.hIcon			= LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor			= LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground	= (HBRUSH)GetStockObject(BLACK_BRUSH);
	wc.lpszMenuName		= NULL;
	wc.lpszClassName	= WINDOW_CLASS_NAME;
	wc.hIconSm			= LoadIcon(NULL, IDI_APPLICATION);

	// Register the window class
	if (!RegisterClassEx(&wc))
		return 0;

	// Create the window
	if (!(g_hWnd = CreateWindowEx(NULL,
					WINDOW_CLASS_NAME,
					"GDI Window",
					WS_OVERLAPPEDWINDOW | WS_VISIBLE,
					WIN_LEFT,  WIN_TOP,
					WIN_WID, WIN_HGT,
					NULL,
					NULL,
					hInstance,
					NULL)))
		return 0;

	// Show the window
	ShowWindow(g_hWnd, SW_SHOWDEFAULT);
	UpdateWindow(g_hWnd);

	// create an offscreen drawing surface
	hDC = GetDC(g_hWnd);
	memDC = CreateCompatibleDC(hDC);
	memBM = CreateCompatibleBitmap(hDC, WIN_WID, WIN_HGT);
	SelectObject(memDC, memBM);
	ReleaseDC(NULL, NULL);

	//  --------------------------------------

ShowCursor(false);

bool quit = false;
	// Enter main loop
	while (!quit)
	{
		// handle messages first
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			if (msg.message == WM_QUIT)
			{ 
				quit = true;
				break;
			}
			else
			{
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}
		else // no messages? draw stuff
		{		
			ClearScreen(memDC);

//######## DRAWING CODE GOES HERE #############################################

		
		InitializLine(&OneLine);
		

		// numbers on the screen to help understand whats going on

			char Stir[40];
			sprintf(Stir,"X reflect: %f", counter);
			TextOut(memDC, 20, 40, Stir, (int)strlen(Stir));

			char Stirr[40];
			sprintf(Stirr,"Y reflect: %f", counter1);
			TextOut(memDC, 20, 60, Stirr, (int)strlen(Stirr));

			char String[40];
			sprintf(String,"Ball hit: %f", counter2);
			TextOut(memDC, 20, 80, String, (int)strlen(String));

			char Strring[40];
			sprintf(Strring,"Wall hit: %f", counter3);
			TextOut(memDC, 20, 100, Strring, (int)strlen(Strring));

			char Strringg[40];
			sprintf(Strringg,"R click to change walls");
			TextOut(memDC, 20, 120, Strringg, (int)strlen(Strringg));

			char iinng[40];
			sprintf(iinng,"L click new B loc");
			TextOut(memDC, 20, 140, iinng, (int)strlen(iinng));

			char ring[40];
			sprintf(ring,"Ball p0.x: %f", gBall.p0.x);
			TextOut(memDC, 200, 40, ring, (int)strlen(ring));

			char rring[40];
			sprintf(rring,"Ball p0.y: %f", gBall.p0.y);
			TextOut(memDC, 200, 60, rring, (int)strlen(rring));

			char fring[40];
			sprintf(fring,"Ball p1.x: %f", gBall.p1.x);
			TextOut(memDC, 200, 80, fring, (int)strlen(fring));

			char frring[40];
			sprintf(frring,"Ball p1.y: %f", gBall.p1.y);
			TextOut(memDC, 200, 100, frring, (int)strlen(frring));

			char ing[40];
			sprintf(ing,"hitPT.x: %f", hitPT.x);
			TextOut(memDC, 200, 120, ing, (int)strlen(ing));

			char iing[40];
			sprintf(iing,"hitPT.y: %f", hitPT.y);
			TextOut(memDC, 200, 140, iing, (int)strlen(iing));

			
////////////////////////////////////////////////////


MoveBall();

//ClearScreen();

FakeCollision();
			
DrawWalls();


if(nextWall){
			OneLine = gWallArray[wall];
			wall++;
			nextWall = false; 
			if(wall >= NUM_WALLS){
				wall = 0;}}

		



		

Sleep(20);

//#############################################################################

			// copy back buffer to screen
			BitBlt(hDC, 0, 0, WIN_WID, WIN_HGT, memDC, 0, 0, SRCCOPY);

			// lock to 60 fps
			
		}
	}

ShowCursor(true);

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

// Window's message procedure
LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT ps;		// used in WM_PAINT
	HDC hDC;			// handle to a device context

	int i = 4;
	if(i >= NUM_WALLS)
			i = 0;
	// Handle messages
	switch (msg)
	{
	case WM_CREATE:
		return 0;
		break;
	case WM_PAINT:
		hDC = BeginPaint(hWnd, &ps);
		EndPaint(hWnd, &ps);
		return 0;
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
		break;
	case WM_RBUTTONDOWN:
	//GetCursorPos(&gCursorPos);
		nextWall = true;
		break;
	case WM_LBUTTONDOWN:
		
		gBall.p1.x = 250;
		gBall.p1.y = 250;
		
		
		break;
	}

	// Process any messages that we didn't take care of
	return DefWindowProc(hWnd, msg, wParam, lParam);
}
//---------------------------------------------------------------------------------

// Function to clear the screen
void ClearScreen(HDC hDC)
{
	RECT rect;
	rect.left = 0;
	rect.top = 0;
	rect.right = WIN_WID;
	rect.bottom = WIN_HGT;
	FillRect(hDC, ▭, (HBRUSH)GetStockObject(BLACK_BRUSH));
}

//----------------------------------------------------------------------------------

void MoveBall(){
	
Vel.x = gBall.p1.x - gBall.p0.x;
Vel.y = gBall.p1.y - gBall.p0.y;
Vel = Normalize(Vel);
gBall.p1.x += Vel.x * 10;
gBall.p1.y += Vel.y * 10;
//trail of ball
gBall.p0.x += Vel.x * 9;
gBall.p0.y += Vel.y * 9;

InitializLine(&gBall);
int lastTime = 999;
int timex = 999;
int timexx = 999;
bool reflect = false;
tVector2 tempHit = {0, 0};
tVector2 tempHit2 = {0, 0};

tit = Intersection(gBall, OneLine, &hitPT);


double BallHit = hitTime(gBall, &hitPT);
counter2 = BallHit;
double WallHit = hitTime(OneLine, &hitPT);
counter3 = WallHit;

if(BallHit >= 0 && BallHit <= 1){
	if(WallHit >= 0 && WallHit <= 1){


		tempHit = Reflect(gBall.p1, OneLine.n);
		// show reflection
		tempHit2 = hitPT;

		tempHit2.x = hitPT.x + (tempHit.x * 5);
		tempHit2.y = hitPT.y + (tempHit.y * 5);

		tempHit.x = hitPT.x + (tempHit.x * 2);
		tempHit.y = hitPT.y + (tempHit.y * 2);


		gBall.p1 = tempHit2;
		gBall.p0 = tempHit;
		counter = tempHit2.x;
		counter1 = tempHit2.y;

		RECT r;
	GetClientRect(g_hWnd, &r);
	int xOff = 0;
	int yOff = (r.bottom - r.top);
	HDC hDC = GetDC(g_hWnd);

	HPEN hPen = CreatePen(PS_SOLID, 5, RGB(250,250,250));
	SelectObject(hDC, hPen);
	MoveToEx(hDC, (int)(hitPT.x + xOff), (int)(yOff - hitPT.y), NULL);
	LineTo(hDC,   (int)(tempHit2.x + xOff*1), (int)(yOff - tempHit2.y*1));

	DeleteObject(hPen);
	// left to right ball goes through wall
	// and bot to top same





	}}
	

// draw main ball
DrawCircle(memDC, (int)gBall.p1.x , (int)(gBall.p1.y), BALL_WIDTH, BALL_SPACING, BallColor);
// hitpt where the lines would connect
DrawCircle(memDC, (int)hitPT.x , (int)(hitPT.y), 10, BALL_SPACING, RGB(00,200,250));


RECT r;
	GetClientRect(g_hWnd, &r);
	int xOff = 0;
	int yOff = (r.bottom - r.top);
	HDC hDC = GetDC(g_hWnd);

	HPEN hPen = CreatePen(PS_SOLID, 2, RGB(50,200,100));
	SelectObject(hDC, hPen);
	MoveToEx(hDC, (int)(gBall.p0.x + xOff), (int)(yOff - gBall.p0.y), NULL);
	LineTo(hDC,   (int)(gBall.p1.x + xOff), (int)(yOff - gBall.p1.y));

	DeleteObject(hPen);


}






void DrawWalls()
{
	

	HDC hDC = GetDC(g_hWnd);
	
		DrawLine(hDC, OneLine.p0, OneLine.p1, RGB(255,239,0));
		
	
	ReleaseDC(g_hWnd, hDC);
}

void DrawLine(HDC hDC, tPoint2 p0, tPoint2 p1, COLORREF color)
{
	RECT r;
	GetClientRect(g_hWnd, &r);
	int xOff = 0;
	int yOff = (r.bottom - r.top);

	HPEN hPen = CreatePen(PS_SOLID, 2, color);
	SelectObject(hDC, hPen);
	MoveToEx(hDC, (int)(p0.x + xOff), (int)(yOff - p0.y), NULL);
	LineTo(hDC,   (int)(p1.x + xOff), (int)(yOff - p1.y));

	DeleteObject(hPen);
}

void ClearScreen()
{
	HDC hDC = GetDC(g_hWnd);
	
	RECT rScreen = {0,0,WIN_WID,WIN_HGT};

	FillRect(hDC, &rScreen, (HBRUSH)GetStockObject(BLACK_BRUSH));
	ReleaseDC(g_hWnd, hDC);
}


void DrawCircle(HDC dc, int xOrg, int yOrg, int radius, int spacing, COLORREF color)
{
	float x,y;
	float rad = 0;
	RECT r;
	GetClientRect(g_hWnd, &r);
	int xOff = 0;
	int yOff = (r.bottom - r.top);

	for(int i = 0; i < 360; i+= spacing)
	{
		rad = (i * 3.14159f) / 180.0f;

		x = xOrg + (float)radius * cos(rad);
		y = yOrg + (float)radius * sin(rad);

		SetPixel(dc, (int)(x + xOff), (int)(yOff- y), color); 
	}
}

tVector2 Normalize(tVector2 A){

float mag;

mag = sqrt(A.x * A.x + A.y * A.y);
A.x/=mag;
A.y/=mag;

return A;

}


bool Intersection(tLineSeg &ball, tLineSeg &wall, tVector2 *hitPT){

//// check if wall or ball is a dot you cant solve 
	if(ball.p0.x == ball.p1.y && ball.p1.x ==  ball.p0.x){
		return false;}
	if(wall.p0.x == wall.p1.y && wall.p1.x ==  wall.p0.x){
		return false;}

	// if lines parallel
	if(ball.m == wall.m){
		return false;
	}


	// -	If 1 line vertical, xHit = x from 
	//vertical line, use m & b from non-vertical line to find yHit.

	if(ball.isVertical){
		hitPT->x = ball.p1.x;
		hitPT->y = ( wall.m * hitPT->x) + wall.b;}

	else if(wall.isVertical){
		hitPT->x = wall.p0.x;
		hitPT->y= (ball.m * hitPT->x) + ball.b;
	}

//-	If 1 line horizontal, yHit = y from horizontal line, solve for xHit(already solved)
	else if(ball.p0.y == ball.p1.y){
		hitPT->y = ball.p0.y;
	hitPT->x = (ball.b - wall.b)/(wall.m - ball.m);
	}

	else if(wall.p0.y  == wall.p1.y){
		hitPT->y = wall.p1.y;
	hitPT->x = (ball.b - wall.b)/(wall.m - ball.m);
	}

	else {
		hitPT->x = (ball.b - wall.b)/(wall.m - ball.m);
		hitPT->y = (ball.m * hitPT->x) + ball.b;
	}

	


return true;
}

void InitializLine(tLineSeg *A){


	

	if(A->p0.x == A->p1.x){
		A->m = 0;
		A->b = 0;
		A->isVertical = true;}
	else{
		A->m = (A->p1.y - A->p0.y)/(A->p1.x - A->p0.x); // slope
		A->b = -(A->m * A->p0.x) + A->p0.y;
		A->isVertical = false;

	}
// 

	A->n.x = A->p1.y -  A->p0.y;
	A->n.y = -(A->p1.x - A->p0.x);
	//A->n = Normalize(A->n);

	
}

float hitTime(tLineSeg A, tVector2 *hitPT){
	float time = 0;

	if(A.isVertical){
		time = (hitPT->y - A.p0.y)/(A.p1.y - A.p0.y);}

	else
		time = (hitPT->x - A.p0.x)/ (A.p1.x - A.p0.x);
	//(time <= 0 && time <= 1) means it hit inside line



	return time;

}

tVector2 Reflect(tVector2 B, tVector2 W){
	tVector2 tmp, tmp1;
// w already normalized
tmp = Normalize(W);
tmp1 =Normalize(B);




tmp1.x *= -1.0f; 
tmp1.y *= -1.0f;


tmp1.x = 2 * (tmp.x * Dott(tmp, B)) - B.x;
tmp1.y = 2 * (tmp.y * Dott(tmp, B)) - B.y;

return tmp = Normalize(tmp1);


}

float Dott(tVector2 A, tVector2 B){
float tmp;


return tmp =(A.x * B.x + A.y * B.y);




}

float Vec2Mag(tVector2 v)
{
	return sqrt(v.x*v.x + v.y*v.y);
}


void FakeCollision(){

	if(gBall.p1.x > ( WIN_WID)){
		int tmp = 0;
		tmp = gBall.p1.x - gBall.p0.x;
		gBall.p0.x = tmp + gBall.p1.x;
	
	}

	if(gBall.p1.x < 0){
		int tmp = 0;
tmp = gBall.p1.x - gBall.p0.x;
		gBall.p0.x = tmp - gBall.p1.x;
		
	
	}

	if(gBall.p1.y > ( WIN_HGT)){
		int tmp = 0;
		tmp = gBall.p1.y - gBall.p0.y;
		gBall.p0.y = tmp + gBall.p1.y;
		
	}

	if(gBall.p1.y < 0){
		int tmp = 0;
		tmp = gBall.p1.y - gBall.p0.y;
		gBall.p0.y = tmp - gBall.p1.y;
	
	}
}

[scource]
Bob Janova
Bob Janova
Sorry, I didn't read all through your code (the use of globals and non-descriptive variable names put me off a bit, plus it's long). The correct formula for a moving object with velocity v colliding with an immovable wall with normal n is v1 = v0-2v0.n. It looks like you're just 'reflecting' based on the position of your ball (gBall.p1) ... that's never going to work. Something like ...
if(hit(ball, walls)){ ball.velocity -= 2*Vector.DotProduct(ball.velocity, walls.normal); break; // assume one collision per frame!}


(edit: screwed up a tag)

Topic Locked

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

Sign in to reply to this topic.