Bonjour !
Je voudrais savoir s'il vous plait comment je peux créer "massivement" des ennemis et gérer leur IA globale, sans traiter au cas par cas (évidemment!) ?
Je m'explique : je ne veux pas de code d'IA ni de code de monstres, juste un code qui me permet de créer plusieurs nodes et de leur faire executer des fonctions à tous...
Par exemple je veux pouvoir créer quelques golems, et je voudrais que dès que je suis à proximité de l'un d'eux, ce dernier se dirige vers moi et m'attaque.
Problème, je ne sais ni comment créer plusieurs nodes comme dans un tableau, de leur affecter un mesh, ni comment gérer leur IA de façon globale...
Question qui peut vous sembler être comme "comment on fait un mmorpg trop bien, pliz ?" mais détrompez vous ma question est juste pour savoir, comment ca fonctionne au niveau classe et code...
Merci d'avance !
Voilà mon code en ce moment ! =>
/*
This tutorial will show how to implement a camera and character display which is a copy of the
one used in World of Warcraft.
Its purpose is to offer the Community an example for a camera and movement system for rpg or
as a base to develop theyr own movement/camera system.
It is based on the irrlicht Tutorial 12 and
NightBirds NWN Camera example http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=3245
Atm its all a bitt messy and very unclean but its still work in progress , althought comments
or suggestions are always welcome.
You can contact me in the Irrlicht Forums
Username: Jonchaos
or per Email
Antharon@Hotmail.com
*/
#include <irrlicht.h>
#include <iostream>
using namespace irr;
#pragma comment(lib, "Irrlicht.lib")
#define CAMERASPEED 0.1f
#define PI 3.14159265f
#define WIDTH 1024
class Golem
{
public:
Golem(){
this->gIsRunning = false;
this->gIsAttacking = 0;
this->gIsAttacked = 0;
life = 100;
}
void Pain()
{
if (this->gIsAttacked == 1)
{
this->gIsAttacked++;
}
}
private:
bool gIsRunning;
int gIsAttacking;
int gIsAttacked;
int life;
};
class MyEventReceiver : public IEventReceiver
{
public:
MyEventReceiver(scene::ISceneNode* terrain ,
scene::IAnimatedMeshSceneNode* ptrCharacter,
IrrlichtDevice* ptrDevice,
scene::ICameraSceneNode* ptrCamera)
{
// store pointer to terrain so we can change its drawing mode
this->Terrain = terrain;
this->Character = ptrCharacter;
this->device = ptrDevice;
this->pCamera = ptrCamera;
this->m_yRotationAngle = 3.14159265*0.5f;
this->distance = 130;
this->bIsRunning = false;
this->bIsAttacking = 0;
}
void Update()
{
if (!pCamera || !Character) return;
if (m_lastTargetPos != Character->getPosition())
{
m_updated = true;
m_lastTargetPos = Character->getPosition();
}
if (m_updated)
{
m_updated = false;
irr::core::vector3df m_Camerapos = m_lastTargetPos;
m_Camerapos.X += distance*sin(m_yRotationAngle);
m_Camerapos.Z += distance*cos(m_yRotationAngle);
m_Camerapos.Y += distance;
pCamera->setPosition(m_Camerapos);
pCamera->setTarget(m_lastTargetPos);
}
}
void attack()
{
if (this->bIsAttacking != 0){
this->bIsAttacking ++;
}
if (this->bIsAttacking >= 105)
{
this->bIsAttacking = 0;
if(!this->bIsRunning){
Character->setMD2Animation(scene::EMAT_STAND);
}else{
Character->setMD2Animation(scene::EMAT_RUN);
}
}
if (this->bIsAttacking == 1)
{
}
}
void Zoom(float amount)
{
distance *= amount;
if (distance == 0) distance = 2; //there should be more elaborate capping of things here..
m_updated = true;
}
bool OnEvent(SEvent event)
{
Update();
if (event.EventType == EET_MOUSE_INPUT_EVENT)
{
switch (event.MouseInput.Event)
{
case EMIE_MOUSE_WHEEL:
Zoom(((-event.MouseInput.Wheel)+1)/2+.5f); //make it be from .5 to 1.5
return true;
break;
} ;
}
if (event.EventType == irr::EET_KEY_INPUT_EVENT && !event.KeyInput.PressedDown)
{
switch (event.KeyInput.Key)
{
case irr::KEY_ESCAPE:
this->device->closeDevice();
return true;
}
}
if (event.EventType == irr::EET_KEY_INPUT_EVENT && event.KeyInput.PressedDown )
{
switch (event.KeyInput.Key)
{
case irr::KEY_UP:
Charpos = Character->getPosition();
Charpos.X = Charpos.X - 10.0f ;
Character->setPosition(Charpos);
Character->setRotation(core::vector3df(0,180,0));
if (!this->bIsRunning)
{
Character->setMD2Animation(scene::EMAT_RUN);
this->bIsRunning = true;
}
return true;
case irr::KEY_DOWN:
Charpos = Character->getPosition();
Charpos.X = Charpos.X + 10.0f ;
Character->setPosition(Charpos);
Character->setRotation(core::vector3df(0,0,0));
if (!this->bIsRunning)
{
Character->setMD2Animation(scene::EMAT_RUN);
this->bIsRunning = true;
}
return true;
case irr::KEY_LEFT:
Charpos = Character->getPosition();
Charpos.Z = Charpos.Z - 10.0f ;
Character->setPosition(Charpos);
Character->setRotation(core::vector3df(0,90,0));
if (!this->bIsRunning)
{
Character->setMD2Animation(scene::EMAT_RUN);
this->bIsRunning = true;
}
return true;
case irr::KEY_RIGHT:
Charpos = Character->getPosition();
Charpos.Z = Charpos.Z + 10.0f ;
Character->setPosition(Charpos);
Character->setRotation(core::vector3df(0,-90,0));
if (!this->bIsRunning)
{
Character->setMD2Animation(scene::EMAT_RUN);
this->bIsRunning = true;
}
return true;
case irr::KEY_SPACE:
if (this->bIsAttacking == 0)
{
Character->setMD2Animation(scene::EMAT_ATTACK);
this->bIsAttacking = 1;
}
return true;
}
}
// if one of the walk keys is lifted -> stop run animation
if (event.EventType == irr::EET_KEY_INPUT_EVENT && !event.KeyInput.PressedDown)
{
switch (event.KeyInput.Key)
{
case irr::KEY_UP:
this->bIsRunning = false;
Character->setMD2Animation(scene::EMAT_STAND);
return true;
case irr::KEY_DOWN:
this->bIsRunning = false;
Character->setMD2Animation(scene::EMAT_STAND);
return true;
case irr::KEY_LEFT:
this->bIsRunning = false;
Character->setMD2Animation(scene::EMAT_STAND);
return true;
case irr::KEY_RIGHT:
this->bIsRunning = false;
Character->setMD2Animation(scene::EMAT_STAND);
return true;
case irr::KEY_SPACE:
return true;
}
}
return false;
}
private:
bool bIsRunning;
int bIsAttacking;
scene::ISceneNode* Terrain;
scene::IAnimatedMeshSceneNode* Character;
IrrlichtDevice* device;
scene::ICameraSceneNode* pCamera;
irr::core::vector3df m_lastTargetPos;
irr::core::vector3df Charpos;
bool m_updated;
int MouseX;
float distance;
float m_yRotationAngle; //the angle about the Y axis
};
/*
The start of the main function starts like in most other example. We ask the user
for the desired renderer and start it up.
*/
int main()
{
// let user select driver type
video::E_DRIVER_TYPE driverType = video::EDT_OPENGL;
// create device
IrrlichtDevice* device = createDevice(driverType, core::dimension2d<s32>(1040, 780));
if (device == 0)
return 1; // could not create selected driver.
/*
First, we add standard stuff to the scene: A nice irrlicht engine
logo, a small help text, a user controlled camera, and we disable
the mouse cursor.
*/
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
gui::IGUIEnvironment* env = device->getGUIEnvironment();
driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true);
//set other font
env->getSkin()->setFont(env->getFont("../../media/fontlucida.png"));
// add some help text
gui::IGUIStaticText* text = env->addStaticText(
L"Vie : 100/100",
core::rect<s32>(10,740,250,775), true, true, 0, -1, true);
// add camera
scene::ICameraSceneNode* camera = smgr->addCameraSceneNode();
camera->setPosition(core::vector3df(1900*2,255*2,3700*2));
camera->setTarget(core::vector3df(2397*2,343*2,2700*2));
camera->setFarValue(12000.0f);
//mouse cursor
device->getCursorControl()->setVisible(false);
smgr->setAmbientLight ( video::SColorf ( 0x00c0c0c0 ) );
// add terrain scene node
scene::ITerrainSceneNode* terrain = smgr->addTerrainSceneNode(
"../../media/terrain-heightmap2.bmp",
0, // parent node
-1, // node id
core::vector3df(0.f, 0.f, 0.f), // position
core::vector3df(0.f, 0.f, 0.f), // rotation
core::vector3df(40.f, 4.4f, 40.f), // scale
video::SColor ( 255, 255, 255, 255 ), // vertexColor,
5, // maxLOD
scene::ETPS_17, // patchSize
4 // smoothFactor
);
terrain->setMaterialFlag(video::EMF_LIGHTING, true);
terrain->setMaterialTexture(0, driver->getTexture("../../media/wall.bmp"));
terrain->setMaterialTexture(1, driver->getTexture("../../media/Floor09.jpg"));
terrain->setMaterialType(video::EMT_DETAIL_MAP);
terrain->scaleTexture(1.0f, 40.0f);
//terrain->setDebugDataVisible ( true );
/*
To be able to do collision with the terrain, we create a triangle selector.
If you want to know what triangle selectors do, just take a look into the
collision tutorial. The terrain triangle selector works together with the
terrain. To demonstrate this, we create a collision response animator
and attach it to the camera, so that the camera will not be able to fly
through the terrain.
*/
// create triangle selector for the terrain
scene::ITriangleSelector* selector
= smgr->createTerrainTriangleSelector(terrain, 0);
terrain->setTriangleSelector(selector);
selector->drop();
// create event receiver
// create skybox
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true);
smgr->addSkyBoxSceneNode(
driver->getTexture("../../media/irrlicht2_up.jpg"),
driver->getTexture("../../media/irrlicht2_dn.jpg"),
driver->getTexture("../../media/irrlicht2_lf.jpg"),
driver->getTexture("../../media/irrlicht2_rt.jpg"),
driver->getTexture("../../media/irrlicht2_ft.jpg"),
driver->getTexture("../../media/irrlicht2_bk.jpg"));
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true);
smgr->setShadowColor(video::SColor(150,0,255,0));
scene::IAnimatedMeshSceneNode* Character = smgr->addAnimatedMeshSceneNode(smgr->getMesh("knight.md2"));
Character->setMaterialFlag(video::EMF_LIGHTING, true);
Character->setFrameLoop(160, 183);
Character->setAnimationSpeed(40);
Character->setMD2Animation(scene::EMAT_STAND);
Character->setRotation(core::vector3df(0,180.0f,0));
Character->setMaterialTexture(0, driver->getTexture("knight.bmp"));
Character->addShadowVolumeSceneNode();
Character->setPosition(core::vector3df(1900*2,255*2,3700*2));
scene::ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator(
selector, Character, core::vector3df(60,10,60),
core::vector3df(0,-100,0),
core::vector3df(0,50,0));
Character->addAnimator(anim);
anim->drop();
//Iron Golem
scene::IAnimatedMesh* mesh = smgr->getMesh("Iron_Golem_X.x");
scene::IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode(mesh);
node->setMaterialFlag(video::EMF_LIGHTING, true);
node->setMaterialTexture(0,driver->getTexture("c_golem_iron.tga"));
node->setPosition(core::vector3df(1900*2, 255*2, 3650*2));
node->setRotation(core::vector3df(-90,-90,0));
node->setScale(core::vector3df(0.3,0.3,0.3));
node->setFrameLoop(200, 260);
node->setAnimationSpeed(20);
node->setLoopMode(true);
node->addShadowVolumeSceneNode();
scene::ISceneNodeAnimator* anim2 = smgr->createCollisionResponseAnimator(
selector, node, core::vector3df(60,10,60),
core::vector3df(0,-100,0),
core::vector3df(0,10,0));
node->addAnimator(anim2);
anim2->drop();
MyEventReceiver receiver(terrain,Character,device,camera);
device->setEventReceiver(&receiver);
int lastFPS = -1;
while(device->run())
if (device->isWindowActive())
{
driver->beginScene(true, true, 0 );
receiver.attack();
smgr->drawAll();
env->drawAll();
driver->endScene();
// display frames per second in window title
int fps = driver->getFPS();
if (lastFPS != fps)
{
core::stringw str = L"Messiah for all lights - OpenGL [";
str += driver->getName();
str += "] FPS:";
str += fps;
// Also print terrain height of current camera position
// We can use camera position because terrain is located at coordinate origin
str += " Height: ";
str += terrain->getHeight(camera->getAbsolutePosition().X, camera->getAbsolutePosition().Z);
device->setWindowCaption(str.c_str());
lastFPS = fps;
}
}
device->drop();
return 0;
}
Merci beaucoup !