Discuss Help optimize Infinite bouncing program. in the C Programming forum on Dev Shed. Help optimize Infinite bouncing program. C programming forum discussing all C derivatives, including C#, C++, Object-C, and even plain old vanilla C. These languages are low level languages, and used on projects such as device drivers, compilers, and even whole computer operating systems.
Posts: 12
Time spent in forums: 3 h 58 m 22 sec
Reputation Power: 0
Help optimize Infinite bouncing program.
Hi,
I had created a program to cause an object to bounce infinitely within a 40x20 grid. Upon colliding with the boundary, it will change the object trajectory with a new vector that is preset from a list randomly according to the boundary restrictions.
However, the vectors are hardcoded and I wonder if there is any intelligent way to optimize it?
This is the code, thanks!!
Code:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
typedef struct
{
int x,y;
}ObjCoord;
void randDir(ObjCoord *vec, int randcounter);
void intBeep(ObjCoord *vec); // prints vector information on hit
int main()
{
srand(time(NULL));
int gridscale = 2;
ObjCoord obj;
ObjCoord vec;
obj.x=10*gridscale;
obj.y=5*gridscale;
vec.x=2;
vec.y=1;
do
{
if(obj.x>20*gridscale) // If obj shoots out of border when vector = 2, set back to 0.
obj.x=20*gridscale;
else if(obj.y>10*gridscale)
obj.y=10*gridscale;
else if(obj.x<0)
obj.x=0;
else if(obj.y<0)
obj.y=0;
Sleep(50); // refresh rate.
system("cls"); // refresh the screen.
printf("Obj.x: %i", obj.x/2); // Print Coord data
if (obj.x>20*gridscale || obj.x<0)
printf("ERROR\n");
else
printf("\n");
printf("Obj.y: %i", obj.y);
if (obj.y>10*gridscale || obj.y<0)
printf("ERROR\n");
else
printf("\n\n");
for (int i = 0; i<obj.y; i++)
printf("\n");
for (int i = 0; i<obj.x; i++) // Print the empty space till obj
printf(" ");
printf("%c%c", 178,178); //Print the obj
int randcounter;
if(obj.x>20*gridscale-1 && obj.y>10*gridscale-1) // IF greater than bottom right
{
do
{
randcounter=(rand() %16)+1;
randDir(&vec,randcounter);
}
while(randcounter ==1 || randcounter ==3 || randcounter ==5 || randcounter ==6 || randcounter ==7 || randcounter ==8 || randcounter ==9 || randcounter ==10 || randcounter ==13 || randcounter ==14 || randcounter ==15);
intBeep(&vec);
}
else if(obj.x<1 && obj.y<1) // IF greater than top left
{
do
{
randcounter=(rand() %16)+1;
randDir(&vec,randcounter);
}
while(randcounter ==2 || randcounter ==4 || randcounter ==7 || randcounter ==8 || randcounter ==9 || randcounter ==10 || randcounter ==11 || randcounter ==12 || randcounter ==14 || randcounter ==15 || randcounter ==16);
intBeep(&vec);
}
else if(obj.x>20*gridscale-1 && obj.y<1) // IF greater than top right
{
do
{
randcounter=(rand() %16)+1;
randDir(&vec,randcounter);
}
while(randcounter ==2 || randcounter ==3 || randcounter ==5 || randcounter ==6 || randcounter ==9 || randcounter ==10 || randcounter ==11 || randcounter ==12 || randcounter ==13 || randcounter ==14 || randcounter ==16);
intBeep(&vec);
}
else if(obj.x<1 && obj.y>10*gridscale-1) // IF greater than bottom left
{
do
{
randcounter=(rand() %16)+1;
randDir(&vec,randcounter);
}
while(randcounter ==1 || randcounter ==4 || randcounter ==5 || randcounter ==6 || randcounter ==7 || randcounter ==8 || randcounter ==11 || randcounter ==12 || randcounter ==13 || randcounter ==15 || randcounter ==16);
intBeep(&vec);
}
else if(obj.x<1) // IF greater than left
{
if ( !((vec.x == 0 && vec.y == 1)||(vec.x == 0 && vec.y == -1)) )
{
do
{
randcounter=(rand() %16)+1;
randDir(&vec,randcounter);
}
while(randcounter ==4 || randcounter ==7 || randcounter ==8 || randcounter ==11 || randcounter ==12 || randcounter ==15 || randcounter ==16);
intBeep(&vec);
}
}
else if(obj.y<1) // IF greater than top
{
if ( !((vec.x == 2 && vec.y == 0)||(vec.x == -2 && vec.y == 0)) )
{
do
{
randcounter=(rand() %16)+1;
randDir(&vec,randcounter);
}
while(randcounter ==2 || randcounter ==9 || randcounter ==10 || randcounter ==11 || randcounter ==12 || randcounter ==14 || randcounter ==16);
intBeep(&vec);
}
}
else if(obj.x>20*gridscale-1) // IF greater than right
{
if ( !((vec.x == 0 && vec.y == 1)||(vec.x == 0 && vec.y == -1)) )
{
do
{
randcounter=(rand() %16)+1;
randDir(&vec,randcounter);
}
while(randcounter ==3 || randcounter ==5 || randcounter ==6 || randcounter ==9 || randcounter ==10 || randcounter ==13 || randcounter ==14);
intBeep(&vec);
}
}
else if(obj.y>10*gridscale-1) // IF greater than bottom
{
if ( !((vec.x == 2 && vec.y == 0)||(vec.x == -2 && vec.y == 0)) )
{
do
{
randcounter=(rand() %16)+1;
randDir(&vec,randcounter);
}
while(randcounter ==1 || randcounter ==5 || randcounter ==6 || randcounter ==7 || randcounter ==8 || randcounter ==13 || randcounter ==15);
intBeep(&vec);
}
}
obj.x=obj.x+vec.x; //add vector to obj for next frame
obj.y=obj.y+vec.y;
}
while(gridscale<100); //seet infinite loop
return 0;
}
void randDir(ObjCoord *vec, int randcounter)
{
switch (randcounter) // List of all possible vectors
{
case 1:
{
vec->x=0;
vec->y=1;
break;
}
case 2:
{
vec->x=0;
vec->y=-1;
break;
}
case 3:
{
vec->x=2;
vec->y=0;
break;
}
case 4:
{
vec->x=-2;
vec->y=0;
break;
}
case 5:
{
vec->x=2;
vec->y=1;
break;
}
case 6:
{
vec->x=4;
vec->y=1;
break;
}
case 7:
{
vec->x=-2;
vec->y=1;
break;
}
case 8:
{
vec->x=-4;
vec->y=1;
break;
}
case 9:
{
vec->x=2;
vec->y=-1;
break;
}
case 10:
{
vec->x=4;
vec->y=-1;
break;
}
case 11:
{
vec->x=-2;
vec->y=-1;
break;
}
case 12:
{
vec->x=-4;
vec->y=-1;
break;
}
case 13:
{
vec->x=2;
vec->y=2;
break;
}
case 14:
{
vec->x=2;
vec->y=-2;
break;
}
case 15:
{
vec->x=-2;
vec->y=2;
break;
}
case 16:
{
vec->x=-2;
vec->y=-2;
break;
}
}
}
void intBeep(ObjCoord *vec) // prints vector information on hit
{
printf("%i,", vec->x/2);
printf("%i", vec->y);
Beep(500,100);
}
Then I would eliminate the guessing loops, by having an array of valid values
Code:
if(obj.x>20*gridscale-1 && obj.y>10*gridscale-1) // IF greater than bottom right
{
static int r[] = { 2, 4, 11, 12, 16 }; // valid directions
randcounter=(rand() % (sizeof(r)/sizeof(*r)); // a random array element
randDir(&vec,r[randcounter]); // a random valid direction
intBeep(&vec);
}
Posts: 249
Time spent in forums: 3 Days 17 h 55 m 47 sec
Reputation Power: 110
Yeah, sure is a way to optimize the program. So long as by optimize, you don't mean in terms of execution speed..
You could use vector reflection to calculate the new direction based on (1) a direction vector of the item to bounce and (2) the surface normal of the surface being bounced off.
Here's the code to reflect a vector around another. I use this code for calculating the reflected vector of a light source on a 3d plane, but it's the same math for 2d vectors.
Code:
vec3 reflectVector(vec3 &surfaceNormal, vec3 &lightDir)
{
vec3 reflected;
vec3 N, L;
double NdotL;
N = normalize(surfaceNormal);
L = normalize(lightDir);
NdotL = dotProduct(N, L);
reflected = L - (N * 2.0 * NdotL);
return reflected;
}
Calling the function with a surface normal of (0,1,0) and a direction vector of (-1,-1,0) results in a reflected vector of (-1,1,0)
That is to say, if we bounce an object moving downwards and to the left, it's reflection on the floor causes it to continue moving to the left, but moving upwards instead of down.
Here's the auxillary code - just remove the .z term from the dotProduct and you're basically done. I actually have it all wrapped up as a class, but that should be of no consequence for the purposes of this discussion. Though you will notice the definition of the * operator for a vec3 and a double.
Posts: 12
Time spent in forums: 3 h 58 m 22 sec
Reputation Power: 0
Hi, can you explain the last 2 line? I tired inputing (0,1,0) and (-1,-1,0) but the reflected vector is not (-1,1,0).
Also, you can multiply the whole struct by a variable?
Code:
vec3 reflectVector(vec3 &surfaceNormal, vec3 &lightDir)
{
vec3 reflected;
vec3 N, L;
double NdotL;
N = normalize(surfaceNormal); //Gets normalized vector of surface to unit length (0,1,0). Surface is pointing upwards towards y.
L = normalize(lightDir); //Gets normalized vector of dir to unit length (-0.707106,-0.707106,0). Light approaching surface 45degree in south-west direction.
NdotL = dotProduct(N, L); //Gets (0,-0.707106,0)?? What is this for?
reflected = L - (N * 2.0 * NdotL); //(-0.707,-0.707,0) - [(0,1,0)*2*(0,-0.707,0)] = (-0.707,-0.707,0) - (0, -1.414, 0) = (-0.707, -2.12, 0)?? Totally don't understand this formula.
return reflected;
}
Do have have any sites or books to recommend to learn such stuffs more in depth?
Posts: 249
Time spent in forums: 3 Days 17 h 55 m 47 sec
Reputation Power: 110
Quote:
Originally Posted by KaiserBreath
Hi, can you explain the last 2 line? I tired inputing (0,1,0) and (-1,-1,0) but the reflected vector is not (-1,1,0).
Also, you can multiply the whole struct by a variable?
Do have have any sites or books to recommend to learn such stuffs more in depth?
Thanks!
Yeah sure.
The problem appears to be in the term you are using for NdotL. Notice, it's actually a scalar, not a vector (its 1D, not 3D)
I just added code to print N, L and NdotL. They're:
Code:
N = < 0.000, 1.000, 0.000>
L = <-0.707,-0.707, 0.000>
NdotL = -0.707107
So, this would make the calculation of reflected look something like this:
Ah! I just realized that there is something implied but not said - the reflected vector is a unit vector. It's the same direction, but of unit length. To make sure that the reflected vector is <-1, 1, 0>, you have to multiply <-0.707, 0.707, 0> by the length of the original L ( <-1, -1, 0> ), which is sqrt(2), which is 1.414
So VecLen(L) = 1.414
VecLen(L) * Reflected = reflected vector of same length as L
1.414 * <-0.707,0.707,0> = <-1, 1, 0>
And nah, I don't have any books or sites to recommend. I just use google for whatever is presenting itself as a problem at the time. I bought a few books back in the 90s, but technology changes so fast I barely get any use. They'd be good references for vector/matrix math and for some shading equations, but I can get that online, and the books authors were still using PHIGS as a 3d library with their VAX 11/780's
Here's a a quick sampler I whipped up, give it a try. It draws a horizontal line in the middle of the box which acts as the mirror. It then draws a blue line from your mouse cursor to the middle of the mirror and a red line that indicates the reflection of the blue line.
main.cpp
Code:
#include <windows.h>
#include "vec3.h"
// Declare Windows procedure
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK outputWindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
// Make the class name into a global variable
char szClassName[ ] = "vectorReflectionApp";
int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
{
HWND hwnd; // This is the handle for our window
MSG messages; // Here messages to the application are saved
WNDCLASSEX wincl; // Data structure for the windowclass
// The Window structure
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; // This function is called by windows
wincl.style = CS_DBLCLKS; // Catch double-clicks
wincl.cbSize = sizeof (WNDCLASSEX);
// Use default icon and mouse-pointer
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_CROSS);
wincl.lpszMenuName = NULL; // No menu
wincl.cbClsExtra = 0; // No extra bytes after the window class
wincl.cbWndExtra = 0; // structure or the window instance
// Use Windows's default colour as the background of the window
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
// Register the window class, and if it fails quit the program
if (!RegisterClassEx (&wincl))
return 0;
RECT mRect = {0,0,276,276};
DWORD dwStyle, dwExStyle;
dwStyle = WS_CAPTION | WS_VISIBLE | WS_SYSMENU;// GetWindowLong(hwnd, GWL_STYLE);
dwExStyle = NULL; //GetWindowLong(hwnd, GWL_EXSTYLE);
AdjustWindowRectEx(&mRect,dwStyle,false,dwExStyle);
// The class is registered, let's create the program
hwnd = CreateWindowEx (
0, // Extended possibilites for variation
szClassName, // Classname
"vectorReflection", // Title Text
WS_CAPTION | WS_VISIBLE | WS_SYSMENU, // default window
CW_USEDEFAULT, // Windows decides the position
CW_USEDEFAULT, // where the window ends up on the screen
mRect.right-mRect.left, //544, // The programs width
mRect.bottom-mRect.top, //375, // and height in pixels
HWND_DESKTOP, // The window is a child-window to desktop
NULL, // No menu
hThisInstance, // Program Instance handler
NULL // No Window Creation data
);
CreateWindow("static","",WS_CHILD|WS_VISIBLE,10,10,256,256,hwnd,(HMENU)1000,hThisInstance,NULL);
SetWindowLong(GetDlgItem(hwnd, 1000), GWL_WNDPROC, (long)outputWindowProcedure);
// Make the window visible on the screen
ShowWindow (hwnd, nCmdShow);
// Run the message loop. It will run until GetMessage() returns 0
while (GetMessage (&messages, NULL, 0, 0))
{
// Translate virtual-key messages into character messages
TranslateMessage(&messages);
// Send message to WindowProcedure
DispatchMessage(&messages);
}
// The program return-value is 0 - The value that PostQuitMessage() gave
return messages.wParam;
}
vec3 makeVec(int posX, int posY, int originX, int originY)
{
return vec3(originX-posX,originY-posY,0);
}
// This function is called by the Windows function DispatchMessage()
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) // handle the messages
{
case WM_CREATE:
return 0;
case WM_DESTROY:
PostQuitMessage (0); // send a WM_QUIT to the message queue
break;
default: // for messages that we don't deal with
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK outputWindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
RECT mRect;
HBRUSH mBrush;
HPEN mPen, oldPen;
static POINT mousePos;
static bool mouseOver = false;
vec3 norm(0,1,0), incoming, reflected;
double len;
switch (message)
{
case WM_ERASEBKGND:
return 0;
case WM_SETCURSOR: // use parent's cursor
return 0;
case WM_MOUSEMOVE:
mouseOver = true;
mousePos.x = LOWORD(lParam);
mousePos.y = HIWORD(lParam);
InvalidateRect(hwnd,NULL,false);
return 0;
case WM_PAINT:
BeginPaint(hwnd, &ps);
mBrush = (HBRUSH)CreateSolidBrush(RGB(255,200,200));
mRect = {0,0,256,256};
FillRect(ps.hdc, &mRect, mBrush);
DeleteObject(mBrush);
MoveToEx(ps.hdc, 0,128,NULL);
LineTo(ps.hdc,256,128);
if (mouseOver)
{
incoming = makeVec(mousePos.x,mousePos.y,128,128);
len = vecLen(incoming);
reflected = reflectVector(norm, incoming) * len;
reflected.x += 128;
reflected.y += 128;
mPen = CreatePen(PS_SOLID,1,RGB(0,0,255));
oldPen = (HPEN)SelectObject(ps.hdc, mPen);
MoveToEx(ps.hdc,mousePos.x,mousePos.y,NULL);
LineTo(ps.hdc,128,128);
SelectObject(ps.hdc,oldPen);
DeleteObject(mPen);
mPen = CreatePen(PS_SOLID,1,RGB(255,0,0));
SelectObject(ps.hdc, mPen);
LineTo(ps.hdc,reflected.x,reflected.y);
SelectObject(ps.hdc,oldPen);
DeleteObject(mPen);
}
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
return 0;
}
return DefWindowProc (hwnd, message, wParam, lParam);
}
Posts: 249
Time spent in forums: 3 Days 17 h 55 m 47 sec
Reputation Power: 110
Quote:
Originally Posted by KaiserBreath
Hi,
Great stuffs!! But for a beginner like me, these are too much for me to absorb, I can't even compile it with codeblocks. Which compiler did you use?
Anyway I think now I understand the reflection part.
Thanks!
Great, oh that's a shame. I'd hoped running the executable would help make it more understandable.
Not sure why it wouldn't compile. I've not used any new features of c++ in it. At the moment, I'm using Code::Blocks 12.11 and gcc(g++) version v 4.7.2
Well, if the reflection is understood, then that sounds like a win, even if it's not a resounding one.. Oh well, time for a
Posts: 3,840
Time spent in forums: 2 Months 3 Weeks 2 Days 20 h 31 m
Reputation Power: 1774
> Hmm, not sure.. first error is unknown type name 'class' when read till the header.
Yeah, you get that when you try to compile C++ code with a C compiler.