Jump to content
  • Advertisement
Sign in to follow this  
pascalosti

collision problem

This topic is 4351 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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, &rect, (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]

Share this post


Link to post
Share on other sites
Advertisement
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)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!