#0 

20-10-2007 22:31:54

shell
Membre
Date d'inscription: 08-07-2007
Messages: 10

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 ! =>

Code:

/*
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


#1 

21-10-2007 00:13:16

firnafin
Abonné
Date d'inscription: 31-03-2007
Messages: 150

shell :

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 :

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 :

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[i]=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


#2 

21-10-2007 03:29:05

Aranoth
Abonné
Lieu: Toulouse
Date d'inscription: 25-09-2006
Messages: 242
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 :

Code:

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


#3 

23-10-2007 17:14:56

shell
Membre
Date d'inscription: 08-07-2007
Messages: 10

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 smile
A plus tard

Hors ligne


#4 

24-10-2007 11:38:42

firnafin
Abonné
Date d'inscription: 31-03-2007
Messages: 150

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 smile , 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 :

Code:

#include ClassPrincipale.h"
#define  blablablabla ....

int main(){  
   
   ClassPrincipale* cp=new cp() ;
   cp->launchgame()


}

Hors ligne


Options Liens officiels Caractéristiques Statistiques Communauté
Corrections
irrlicht
irrklang
irredit
irrxml
xhtml 1.0
css 2.1
Propulsé par FluxBB
Traduit par FluxBB.fr
883 membres
1429 sujets
11121 messages
Dernier membre inscrit: Saidov17
64 invités en ligne
Aucun membre connecté
RSS Feed