Posted: Sat Sep 18, 2004 9:56 pm
poop I forgot the tags. Sorry, once again.
Code: Select all
#include <irrlicht.h>
#include <qthread.h>
#include <qptrlist.h>
#include <qdatetime.h>
#include <qmutex.h>
#include <stdlib.h>
using namespace irr;
#pragma comment(lib, "Irrlicht.lib")
scene::ISceneManager* smgr;
video::IVideoDriver* driver;
IrrlichtDevice *device;
video::SMaterial material;
scene::ITriangleSelector* selector;
bool s_bDebug = false;
bool s_bRun = true;
QMutex smgrAccess;
int random()
{
return QTime::currentTime().msec() + rand();
}
scene::ISceneNodeAnimatorCollisionResponse* AnimateObj(scene::ISceneNode* pNode, bool bFixedRadius = false)
{
core::aabbox3df box = pNode->getBoundingBox();
core::vector3df radius = bFixedRadius ? core::vector3df(30,50,30) : box.MaxEdge - box.getCenter();
scene::ISceneNodeAnimatorCollisionResponse* anim = smgr->createCollisionResponseAnimator(
selector, pNode,
radius, // how big the object is (radius of an ellipsoid)
core::vector3df(0,-100,0), // direction and speed of gravity (0,0,0 to disable gravity)
100.0f, // acceleration value when falling down
core::vector3df(0,0,0)); // translation from the center of the ellipsoid
pNode->addAnimator(anim);
anim->drop();
return anim;
}
class MyEventReceiver : public IEventReceiver
{
public:
virtual bool OnEvent(SEvent event)
{
if (event.EventType == irr::EET_KEY_INPUT_EVENT) { //&& !event.KeyInput.PressedDown)
switch (event.KeyInput.Key) {
case KEY_SPACE:
s_bDebug = true;
return true;
}
}
return false;
}
};
class Fairy
{
public:
Fairy()
: m_direction(90), m_bShouldRenderMove(false)
,m_id(0), m_jump(0),m_stepWidth(6)
{
static int id = 0;
m_id = id++;
m_pFairyNode = createFairy();
static int x = -150;
x += 5;
m_oldPos = core::vector3df(x,50,5);
m_pFairyNode->setPosition(core::vector3df(x,50,0));
m_pFairyNode->setRotation(core::vector3df(0,m_direction,0));
m_pCollRespAnim = AnimateObj(m_pFairyNode);
}
void move()
{
// really set to queued position
m_pFairyNode->setPosition(m_newPos);
}
void signalFinishedMove()
{
// reset queue flag
m_bShouldRenderMove = false;
}
bool shouldMove()
{
return m_bShouldRenderMove;
}
bool isDying()
{
if (m_pFairyNode->getPosition().Y < -1000) {
// falling in the depth
return true;
}
return false;
}
void live()
{
// if the queued new position is not already rendered, don't do further steps
if (m_bShouldRenderMove) {
return;
}
if (s_bDebug) {
s_bDebug = false;
}
core::vector3df pos = m_pFairyNode->getPosition();
core::vector3df move = computeNextStep();
bool bCanWalk = !moodForDirectionChange();
bool bDecidedNewDirection = false;
do {
if (!bCanWalk) {
decideNewDirection();
bDecidedNewDirection = true;
move = computeNextStep();
}
bCanWalk = canWalk(pos, move);
}
while (!bCanWalk);
if (bDecidedNewDirection) {
turnToNewDirection();
}
// compute the new position where we'll be after the step
// and queue it for rendering
m_newPos = pos + computeNextStep();
m_bShouldRenderMove = true;
// store her old position for further checking if the queued step will be successful
m_oldPos = pos;
}
protected:
scene::IAnimatedMeshSceneNode* createFairy()
{
// add animated fairy.
material.Texture1 = driver->getTexture("../../media/faerie2.bmp");
material.Lighting = true;
scene::IAnimatedMeshSceneNode* node = 0;
scene::IAnimatedMesh* pFairy = smgr->getMesh("../../media/faerie.md2");
if (pFairy) {
node = smgr->addAnimatedMeshSceneNode(pFairy);
node->setPosition(core::vector3df(-70,0,-90));
node->setMD2Animation(scene::EMAT_STAND); // EMAT_RUN
node->getMaterial(0) = material;
}
material.Texture1 = 0;
material.Lighting = false;
return node;
}
bool moodForDirectionChange()
{
int r = random();
if ((r % 40) == 0) {
return true;
}
else {
return false;
}
}
bool canWalk(const core::vector3df& pos, const core::vector3df& move)
{
core::triangle3df triangle;
core::vector3df resultPos;
bool f = false;
smgrAccess.lock();
resultPos = smgr->getSceneCollisionManager()->getCollisionResultPosition(
m_pCollRespAnim->getWorld(), pos,
m_pCollRespAnim->getEllipsoidRadius(), move, triangle, f);
smgrAccess.unlock();
if (resultPos.X-(pos.X+move.X) < 0.1 &&
resultPos.Y-(pos.Y+move.Y) < 0.1 &&
resultPos.Z-(pos.Z+move.Z) < 0.1)
{
return true;
}
return false;
}
void decideNewDirection()
{
int oldDirection = m_direction;
int diff;
do {
m_direction = random() % 360;
diff = abs(oldDirection - m_direction);
}
while (diff < 60 || diff > 300);
}
void turnToNewDirection()
{
m_pFairyNode->setRotation(core::vector3df(0, m_direction, 0));
}
core::vector3df computeNextStep()
{
// 0° +X, 0
// 90° 0, -Z
// 180° -X, 0
// 270° 0, +Z
core::vector3df move = core::vector3df(m_stepWidth * cos(m_direction), m_jump, m_stepWidth * -sin(m_direction));
return move;
}
scene::IAnimatedMeshSceneNode* m_pFairyNode;
scene::ISceneNodeAnimatorCollisionResponse* m_pCollRespAnim;
core::vector3df m_oldPos;
core::vector3df m_newPos;
int m_direction;
bool m_bShouldRenderMove;
int m_id;
int m_jump;
int m_stepWidth;
};
class AiControl : public QThread
{
public:
AiControl() : QThread()
,m_bRunning(true)
{
// create a number of fairies, each one doing its action every 100 milliseconds
for (int i = 0; i < 3; i++) {
Fairy* pFairy = new Fairy;
m_fairies.append(pFairy);
}
}
virtual ~AiControl()
{
// destroys all fairies
QPtrListIterator<Fairy> it(m_fairies);
while (*it) {
delete *it;
++it;
}
}
void doExit()
{
m_bRunning = false;
}
bool isSomethingToDo()
{
QPtrListIterator<Fairy> it(m_fairies);
while (*it) {
Fairy* pFairy = *it;
if (pFairy->shouldMove()) {
return true;
}
++it;
}
return false;
}
void doAI()
{
// check all fairies if they've queued a new step.
// if so, do the walk
QPtrListIterator<Fairy> it(m_fairies);
while (*it) {
Fairy* pFairy = *it;
if (pFairy->shouldMove()) {
pFairy->move();
}
++it;
}
}
void signalFinishedRendering()
{
QPtrListIterator<Fairy> it(m_fairies);
while (*it) {
Fairy* pFairy = *it;
if (pFairy->shouldMove()) {
pFairy->signalFinishedMove();
}
++it;
}
}
protected:
virtual void run()
{
while (m_bRunning) {
// wait some milliseconds until the next action of the fairy
msleep(50);
// from time to time let the fairies do something intelligent
QPtrListIterator<Fairy> it(m_fairies);
while (*it) {
Fairy* pFairy = *it;
if (pFairy->isDying()) {
QPtrListIterator<Fairy> it2 = it;
++it;
m_fairies.remove(it2);
delete pFairy;
if (!m_fairies.count()) {
s_bRun = false;
}
}
else {
pFairy->live();
++it;
}
}
}
}
protected:
QPtrList<Fairy> m_fairies;
bool m_bRunning;
};
int main()
{
MyEventReceiver receiver;
device = createDevice(video::EDT_DIRECTX9, core::dimension2d<s32>(640, 480), 16, false, false, &receiver);
driver = device->getVideoDriver();
smgr = device->getSceneManager();
device->getFileSystem()->addZipFileArchive("../../media/map-20kdm2.pk3");
scene::IAnimatedMesh* q3levelmesh = smgr->getMesh("20kdm2.bsp"); if (!q3levelmesh) return 1;
scene::IMesh* pMesh = q3levelmesh->getMesh(0);
scene::ISceneNode* q3node = smgr->addOctTreeSceneNode(pMesh); if (!q3node) return 1;
q3node->setPosition(core::vector3df(-1370,-130,-1400));
selector = smgr->createOctTreeTriangleSelector(pMesh, q3node, 128);
q3node->setTriangleSelector(selector);
selector->drop();
scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS(0, 100.0f, 300.0f);
camera->setPosition(core::vector3df(0,50,0));
camera->setRotation(core::vector3df(0,270,0));
AnimateObj(camera, true);
AiControl aiControl;
aiControl.start();
smgr->addLightSceneNode(0, core::vector3df(-60,100,400), video::SColorf(1.0f,1.0f,1.0f,1.0f), 600.0f); // Add a light
device->getCursorControl()->setVisible(false); // disable mouse cursor
// infinite rendering loop
while (s_bRun && device->run()) {
bool bDoAI = false;
if (aiControl.isSomethingToDo()) {
bDoAI = true;
aiControl.doAI();
}
driver->beginScene(true, true, 0);
smgrAccess.lock();
smgr->drawAll();
smgrAccess.unlock();
driver->endScene();
if (bDoAI) {
aiControl.signalFinishedRendering();
}
}
device->drop();
return 0;
}