📄 demo13_8.cpp
字号:
DDraw_Shutdown();
// now directsound
DSound_Stop_All_Sounds();
DSound_Shutdown();
// shut down directinput
DInput_Shutdown();
// return success
return(1);
} // end Game_Shutdown
//////////////////////////////////////////////////////////
void Ball_Sound(void)
{
// this functions hunts for an open handle to play a collision sound
// start a hit sound
for (int sound_index=0; sound_index < 8; sound_index++)
{
// test if this sound is playing
if (DSound_Status_Sound(ball_ids[sound_index])==0)
{
DSound_Play(ball_ids[sound_index]);
break;
} // end if
} // end for
} // end Ball_Sound
///////////////////////////////////////////////////////////
void Collision_Response(void)
{
// this function does all the "real" physics to determine if there has
// been a collision between any ball and any other ball, if there is a collision
// the function uses the mass of each ball along with the intial velocities to
// compute the resulting velocities
// from the book we know that in general
// va2 = (e+1)*mb*vb1+va1(ma - e*mb)/(ma+mb)
// vb2 = (e+1)*ma*va1+vb1(ma - e*mb)/(ma+mb)
// and the objects will have direction vectors co-linear to the normal
// of the point of collision, but since we are using spheres here as the objects
// we know that the normal to the point of collision is just the vector from the
// center's of each object, thus the resulting velocity vector of each ball will
// be along this normal vector direction
// step 1: test each object against each other object and test for a collision
// there are better ways to do this other than a double nested loop, but since
// there are a small number of objects this is fine, also we want to somewhat model
// if two or more balls hit simulataneously
for (int ball_a = 0; ball_a < NUM_BALLS; ball_a++)
{
for (int ball_b = ball_a+1; ball_b < NUM_BALLS; ball_b++)
{
if (ball_a == ball_b)
continue;
// compute the normal vector from a->b
float nabx = (balls[ball_b].varsF[INDEX_X] - balls[ball_a].varsF[INDEX_X] );
float naby = (balls[ball_b].varsF[INDEX_Y] - balls[ball_a].varsF[INDEX_Y] );
float length = sqrt(nabx*nabx + naby*naby);
// is there a collision?
if (length <= 2.0*(BALL_RADIUS*.75))
{
// the balls have made contact, compute response
// compute the response coordinate system axes
// normalize normal vector
nabx/=length;
naby/=length;
// compute the tangential vector perpendicular to normal, simply rotate vector 90
float tabx = -naby;
float taby = nabx;
// draw collision
DDraw_Lock_Primary_Surface();
// blue is normal
Draw_Clip_Line(balls[ball_a].varsF[INDEX_X]+0.5,
balls[ball_a].varsF[INDEX_Y]+0.5,
balls[ball_a].varsF[INDEX_X]+20*nabx+0.5,
balls[ball_a].varsF[INDEX_Y]+20*naby+0.5,
252, primary_buffer, primary_lpitch);
// yellow is tangential
Draw_Clip_Line(balls[ball_a].varsF[INDEX_X]+0.5,
balls[ball_a].varsF[INDEX_Y]+0.5,
balls[ball_a].varsF[INDEX_X]+20*tabx+0.5,
balls[ball_a].varsF[INDEX_Y]+20*taby+0.5,
251, primary_buffer, primary_lpitch);
DDraw_Unlock_Primary_Surface();
// tangential is also normalized since it's just a rotated normal vector
// step 2: compute all the initial velocities
// notation ball: (a,b) initial: i, final: f, n: normal direction, t: tangential direction
float vait = DOT_PRODUCT(balls[ball_a].varsF[INDEX_XV],
balls[ball_a].varsF[INDEX_YV],
tabx, taby);
float vain = DOT_PRODUCT(balls[ball_a].varsF[INDEX_XV],
balls[ball_a].varsF[INDEX_YV],
nabx, naby);
float vbit = DOT_PRODUCT(balls[ball_b].varsF[INDEX_XV],
balls[ball_b].varsF[INDEX_YV],
tabx, taby);
float vbin = DOT_PRODUCT(balls[ball_b].varsF[INDEX_XV],
balls[ball_b].varsF[INDEX_YV],
nabx, naby);
// now we have all the initial velocities in terms of the n and t axes
// step 3: compute final velocities after collision, from book we have
// note: all this code can be optimized, but I want you to see what's happening :)
float ma = balls[ball_a].varsF[INDEX_MASS];
float mb = balls[ball_b].varsF[INDEX_MASS];
float vafn = (mb*vbin*(cof_E+1) + vain*(ma - cof_E*mb)) / (ma + mb);
float vbfn = (ma*vain*(cof_E+1) - vbin*(ma - cof_E*mb)) / (ma + mb);
// now luckily the tangential components are the same before and after, so
float vaft = vait;
float vbft = vbit;
// and that's that baby!
// the velocity vectors are:
// object a (vafn, vaft)
// object b (vbfn, vbft)
// the only problem is that we are in the wrong coordinate system! we need to
// translate back to the original x,y coordinate system, basically we need to
// compute the sum of the x components relative to the n,t axes and the sum of
// the y components relative to the n,t axis, since n,t may both have x,y
// components in the original x,y coordinate system
float xfa = vafn*nabx + vaft*tabx;
float yfa = vafn*naby + vaft*taby;
float xfb = vbfn*nabx + vbft*tabx;
float yfb = vbfn*naby + vbft*taby;
// store results
balls[ball_a].varsF[INDEX_XV] = xfa;
balls[ball_a].varsF[INDEX_YV] = yfa;
balls[ball_b].varsF[INDEX_XV] = xfb;
balls[ball_b].varsF[INDEX_YV] = yfb;
// update position
balls[ball_a].varsF[INDEX_X]+=balls[ball_a].varsF[INDEX_XV];
balls[ball_a].varsF[INDEX_Y]+=balls[ball_a].varsF[INDEX_YV];
balls[ball_b].varsF[INDEX_X]+=balls[ball_b].varsF[INDEX_XV];
balls[ball_b].varsF[INDEX_Y]+=balls[ball_b].varsF[INDEX_YV];
} // end if
} // end for ball2
} // end for ball1
} // end Collision_Response
//////////////////////////////////////////////////////////
int Game_Main(void *parms)
{
// this is the workhorse of your game it will be called
// continuously in real-time this is like main() in C
// all the calls for you game go here!
int index; // looping var
// start the timing clock
Start_Clock();
// clear the drawing surface
//DDraw_Fill_Surface(lpddsback, 0);
// lock back buffer and copy background into it
DDraw_Lock_Back_Surface();
// draw background
Draw_Bitmap(&background_bmp, back_buffer, back_lpitch,0);
// draw table
HLine(TABLE_MIN_X, TABLE_MAX_X, TABLE_MIN_Y, 250, back_buffer, back_lpitch);
HLine(TABLE_MIN_X, TABLE_MAX_X, TABLE_MAX_Y, 250, back_buffer, back_lpitch);
VLine(TABLE_MIN_Y, TABLE_MAX_Y, TABLE_MIN_X, 250, back_buffer, back_lpitch);
VLine(TABLE_MIN_Y, TABLE_MAX_Y, TABLE_MAX_X, 250, back_buffer, back_lpitch);
// unlock back surface
DDraw_Unlock_Back_Surface();
// read keyboard
DInput_Read_Keyboard();
// check for change of e
if (keyboard_state[DIK_RIGHT])
cof_E+=.01;
else
if (keyboard_state[DIK_LEFT])
cof_E-=.01;
float total_ke_x = 0, total_ke_y = 0;
// move all the balls and compute system momentum
for (index=0; index < NUM_BALLS; index++)
{
// move the ball
balls[index].varsF[INDEX_X]+=balls[index].varsF[INDEX_XV];
balls[index].varsF[INDEX_Y]+=balls[index].varsF[INDEX_YV];
// add x,y contributions to kinetic energy
total_ke_x+=(balls[index].varsF[INDEX_XV]*balls[index].varsF[INDEX_XV]*balls[index].varsF[INDEX_MASS]);
total_ke_y+=(balls[index].varsF[INDEX_YV]*balls[index].varsF[INDEX_YV]*balls[index].varsF[INDEX_MASS]);
} // end fof
// test for boundary collision with virtual table edge, no need for collision
// response here, I know what's going to happen :)
for (index=0; index < NUM_BALLS; index++)
{
if ((balls[index].varsF[INDEX_X] >= TABLE_MAX_X-BALL_RADIUS) ||
(balls[index].varsF[INDEX_X] <= TABLE_MIN_X+BALL_RADIUS))
{
// invert velocity
balls[index].varsF[INDEX_XV] = -balls[index].varsF[INDEX_XV];
balls[index].varsF[INDEX_X]+=balls[index].varsF[INDEX_XV];
balls[index].varsF[INDEX_Y]+=balls[index].varsF[INDEX_YV];
// start a hit sound
Ball_Sound();
} // end if
if ((balls[index].varsF[INDEX_Y] >= TABLE_MAX_Y-BALL_RADIUS) ||
(balls[index].varsF[INDEX_Y] <= TABLE_MIN_Y+BALL_RADIUS))
{
// invert velocity
balls[index].varsF[INDEX_YV] =-balls[index].varsF[INDEX_YV];
balls[index].varsF[INDEX_X]+=balls[index].varsF[INDEX_XV];
balls[index].varsF[INDEX_Y]+=balls[index].varsF[INDEX_YV];
// play sound
Ball_Sound();
} // end if
} // end for index
// draw the balls
for (index=0; index < NUM_BALLS; index++)
{
balls[index].x = balls[index].varsF[INDEX_X]+0.5-BALL_RADIUS;
balls[index].y = balls[index].varsF[INDEX_Y]+0.5-BALL_RADIUS;
Draw_BOB(&balls[index], lpddsback);
} // end for
// draw the velocity vectors
DDraw_Lock_Back_Surface();
for (index=0; index < NUM_BALLS; index++)
{
Draw_Clip_Line(balls[index].varsF[INDEX_X]+0.5,
balls[index].varsF[INDEX_Y]+0.5,
balls[index].varsF[INDEX_X]+2*balls[index].varsF[INDEX_XV]+0.5,
balls[index].varsF[INDEX_Y]+2*balls[index].varsF[INDEX_YV]+0.5,
246, back_buffer, back_lpitch);
} // end for
DDraw_Unlock_Back_Surface();
// draw the title
Draw_Text_GDI("ELASTIC Object-Object Collision Response DEMO, Press <ESC> to Exit.",10, 10,RGB(255,255,255), lpddsback);
// draw the title
sprintf(buffer,"Coefficient of Restitution e=%f, use <RIGHT>, <LEFT> arrow to change.", cof_E);
Draw_Text_GDI(buffer,10, 30,RGB(255,255,255), lpddsback);
sprintf(buffer,"Total System Kinetic Energy Sum(1/2MiVi^2)=%f ",0.5*sqrt(total_ke_x*total_ke_x+total_ke_y*total_ke_y));
Draw_Text_GDI(buffer,10, 465, RGB(255,255,255), lpddsback);
// flip the surfaces
DDraw_Flip();
// run collision response algorithm here
Collision_Response();
// sync to 30 fps = 1/30sec = 33 ms
Wait_Clock(33);
// check of user is trying to exit
if (KEY_DOWN(VK_ESCAPE) || keyboard_state[DIK_ESCAPE])
{
PostMessage(main_window_handle, WM_DESTROY,0,0);
// stop all sounds
DSound_Stop_All_Sounds();
// do a screen transition
// Screen_Transitions(SCREEN_GREENNESS,NULL,0);
} // end if
// return success
return(1);
} // end Game_Main
//////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -