19.4.: I made some changes. The ball will be reflected correctly now, when it hits a box.
i made a little game for the wizards of OS convention last year, to show what's possible with free 3D engines.
You can get the whole game with source and media (2.7MB) here:
http://www.dirk-hoeschen.de/temp/arkanoid.zip
... main part
Code: Select all
/* let the game begin */
while(device->run() && driver)
{
if (device->isWindowActive())
{
/* start the scene*/
driver->beginScene(true, true, SColor(255,100,101,140));
smgr->drawAll();
env->drawAll();
driver->endScene();
if (!gamestart) { // game not started, show information
int fps = driver->getFPS();
if (lastFPS != fps)
{
wchar_t tmp[256];
_snwprintf(tmp, 255, L"%ls fps: %d", driver->getName(), driver->getFPS());
statusText->setText(tmp);
lastFPS = fps;
}
} else { // game started, show level and ballsleft
wchar_t tmp[256];
_snwprintf(tmp, 255, L"Level: %d Balls: %d", level+1, ballsleft);
statusText->setText(tmp);
}
bpos = ball->getAbsolutePosition();
/* check boundaries */
if (bpos.X > 50) { speedx = -abs(speedx); bpos.X=50.0f; changedir=true; }
if (bpos.X < -50) { speedx = abs(speedx); bpos.X=-50.0f; changedir=true; }
if (bpos.Z > 50) { speedz = -200; changedir=true; bpos.Z = 50.0f; }
else if (bpos.Z <= -60) { // Z -60 is behind the batter
bpos.Z = -49.0f;
changedir=true;
if (!gamestart) {
speedz = 200;
} else {
ballsleft--;
ball->removeAnimator(anim);
bpos.Z = -45.0f; bpos.X = 0;
speedz = 200; speedx = 40;
if (ballsleft<1) // Game over
{
gamestart=false;
ballsleft = 3;
level = 0;
InitLevel();
// show menu
butt1->setVisible(true);
butt2->setVisible(true);
device->getCursorControl()->setVisible(true);
// animate camera
cam->setTarget(core::vector3df(0,0,0));
anim2 = smgr->createFlyCircleAnimator(core::vector3df(0,30,-100), 30.0f);
cam->addAnimator(anim2);
}
}
} else if ((bpos.Z > -3) || (bpos.Z < 33)) {
/* check collision to crate */
int n;
for (n=0; n<=26; ++n) {
cbox = crates[n]->getTransformedBoundingBox(); // get the bounding box
core::vector3df bmin = cbox.MinEdge; core::vector3df bmax = cbox.MaxEdge;
// blow the box up a little bit, because of the size of the ball
cbox.MinEdge = core::vector3df(bmin.X-1,bmin.Y,bmin.Z-1);
cbox.MaxEdge = core::vector3df(bmax.X+1,bmax.Y,bmax.Z+1);
if (cbox.isPointInside(bpos)) { // is the Ball inside the box
if (crates[n]->isVisible()) { // destroy only visible crates
/* from which direction the ball hits? not very elegant, but fast. */
f32 bdir[4] = { fabs(bpos.X-bmax.X), fabs(bpos.X-bmin.X),
fabs(bpos.Z-bmax.Z), fabs(bpos.Z-bmin.Z) };
int i = 0; int k = 0;
for (i=0; i<4; ++i) {
if (bdir[i]<bdir[k]) { k=i; } // get the nearest side
}
if ((k%2)==0) { i=1; } else { i=-1; } // vector + or -
if (k<2){ // change X-Speed
speedx = (i * abs(speedx)) + (1 + ( rand() % 5 ));
} else { // change Z-Speed
speedz = (i * abs(speedz)) + (1 + ( rand() % 15 ));
}
changedir=true;
if (lev[level][n]<5) { // crate 5 is undestroyable
crates[n]->setVisible(false); // disable crate
cratesleft--;
/* all crates destroyed? */
if (cratesleft<=0) {
level++;
if (level>=numlevels) { // last level = restart
level=0;
}
InitLevel();
// ball to startposition
ball->removeAnimator(anim);
bpos.Z = -45.0f; bpos.X = 0;
speedz = 200; speedx = 40;
}
}
}
}
}
}
btw: I know the code is dirty and has no structure. But maybe you like it.
It would be nice if I get some responses and hints for improvement.
The game is reduced to the basics, to be compatible with Linux too.