20-10-2007 20:31:54
- shell
- Membres
- Date d'inscription:
- Messages: 10
- IP: 90.22.102.112
- Courriel
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 !
Hors ligne
20-10-2007 22:13:16
- firnafin
- Membres

- Date d'inscription:
- Messages: 150
- IP: 88.141.135.108
- Courriel
shell Ecris:
gérer leur IA globale, sans traiter au cas par cas
c'est un peut difficile de ne pas faire du cas par cas pour une ia.
shell Ecris:
je voudrais que dès que je suis à proximité de l'un d'eux, ce dernier se dirige vers moi et m'attaque.
ca c'est du cas par cas puisqu'a chaque golem tu dois verifier si la distance est inferieur a une certaine valeur et le faire bouger si c'est le "cas" .
shell Ecris:
je ne sais ni comment créer plusieurs nodes comme dans un tableau
bien il y existe plusieur methode le tableau (c++ : [] ) le tableau/vecteur de irrlicht (irr::core::array) ( identique a std::vector<T>), la liste irr::core::list (qui existe en version STL std::list<T>) tu crées une de ces chose ( ex le tableau ac Golem* Golems=new Golem[n] ) est y met des golems ( for( int i...){ Golem=new Golem() ....} ) je ne vois pas ou il peut bien y avoir de probleme .
Je ne sais pas ce que tu entends par "ia global" mais si tu parles d'un "factorisation" du code ( ne pas mettre pour chaque class de monstre des methodes d'un system d'ia) tu crées une class IA qui regroupe toute les fonctions necessaires ( distance , ange de vue , prise de desicion : fuite,appeller de l'aide,defendre,attaquer ...)et tu y fais appel pour chaque monstre.
Hors ligne
21-10-2007 01:29:05
- Aranoth
- Membres

- Date d'inscription:
- Messages: 242
- IP: 86.221.19.216
- Courriel Site web
Perso je ferais une classe "Monstre" qui comporterait un pointeur vers une instance d'une classe "MonstreType" et un pointeur vers une instance d'une autre classe nommée "IA"
MonstreType serait pour stocker tes types de monstres :
MonstreType* Golem = new MonstreType("Golem");
Monstre monstre1;
monstre1.SetType( Golem );Ca permettrait de ne pas hardcoder les différents monstres (tu ne vas pas faire une classe par monstre, c'est du délire !)
Donc Monstre symboliserait une des bestioles de ton jeu, à laquelle serait associée un type (ici Golem) et un objet de type "IA".
Pour l'IA je ferais plusieurs classes filles d'IA comme : IAPassif , IAAgressif, IADefensif, etc.
Histoire d'avoir un choix de comportement pour les monstres.
La classe Monstre aurait une méthode "Update" qui mettrait à jour le monstre et appellerait la méthode "Update" de l'objet IA associé.
Et c'est cette IA::Update() qui serait chargé de vérifier la distance avec le joueur et de les attaquer. Ou pas, selon l'IA (ex: IADefensif ne ferait que riposter, IAFaible fuirait si le nombre de PV est inférieur à tant, etc)
C'est peut être pas très clair (l'heure n'aide pas ^^) mais l'idée est là, n'hésites pas à demander plus de précisions, là je suis un peu fatigué.
Hors ligne
23-10-2007 15:14:56
- shell
- Membres
- Date d'inscription:
- Messages: 10
- IP: 81.80.104.100
- Courriel
Sisi, c'était très clair. Je vois comment faire dans la programmation et la mise en ordre du code !
Juste une question, mon code (même si tout n'est pas de moi, bien sûr) est-il en revanche bien organisé ? J'ai quelques soucis de soins là dessus, et si pouviez juste jeter un oeil (pas en profondeur, évidemment) et me dire si c'est correct ou si avec le temps je risque d'être submergé par des lignes parasites...
Merci de votre patience à aider des nouveaux dans irrlicht comme moi ![]()
A plus tard
Hors ligne
24-10-2007 09:38:42
- firnafin
- Membres

- Date d'inscription:
- Messages: 150
- IP: 78.114.39.27
- Courriel
bien si le code reste petit en taille ( juste un exercice ) tu peux laisser comme ca mais pour un projet ( meme tres modeste ) il faut mieu separer les classes ( chaque classe dans un .h et .cpp ) ainsi tu ne fais pas fondre ta mollette quand tu recherches une ligne particuliere
, tu pourra réutiliser le code plus facilement ( puisque regroupé ) et surtout que c'est comme ca que ca se fait .Faire aussi un classe principale ou tu y mets ta boucle principale le main devient simplement :
#include ClassPrincipale.h"
#define blablablabla ....
int main(){
ClassPrincipale* cp=new cp() ;
cp->launchgame()
}Hors ligne



