I. Prérequis

Image non disponible

Ok, commençons avec les en-têtes (je pense qu'il n'y a rien à en dire).

 
Sélectionnez
#include <irrlicht.h>
#include "driverChoice.h"

#ifdef _MSC_VER
#pragma comment(lib, "Irrlicht.lib")
#endif

// Espace de noms pour le moteur.
using namespace irr;
using namespace core;
using namespace video;
using namespace scene;

Maintenant, nous allons définir la résolution dans une constante pour l'utiliser dans l'initialisation du moteur et la configuration du « viewport ». De plus, nous définissons une variable globale indiquant si la division d'écran est active ou non.

 
Sélectionnez
// Résolution
const int ResX=800;
const int ResY=600;
const bool fullScreen=false;

// Utiliser la division d'écran ?
bool SplitScreen=true;

Maintenant, nous avons besoin de quatre pointeurs sur nos caméras que nous créerons plus tard.

 
Sélectionnez
// caméras
ICameraSceneNode *camera[4]={0,0,0,0};

Dans notre receveur d'événements, nous changeons la variable SplitScreen lorsque l'utilisateur presse la touche 'S'. Tous les autres événements sont envoyés à la caméra FPS.

 
Sélectionnez
class MyEventReceiver : public IEventReceiver
{
    public:
        virtual bool OnEvent(const SEvent& event)
        {
            // La touche S active/désactive la division de l'écran.
            if (event.EventType == irr::EET_KEY_INPUT_EVENT &&
                event.KeyInput.Key == KEY_KEY_S && event.KeyInput.PressedDown)
            {
                SplitScreen = !SplitScreen;
                return true;
            }
            // Envoie tous les autres événements à la caméra 4.
            if (camera[3])
                return camera[3]->OnEvent(event);
            return false;
        }
};

OK, maintenant la fonction main : premièrement, nous initialisons le moteur, obtenons le gestionnaire de sources et le pilote vidéo, chargeons un objet animé à partir du fichier .md2 et une carte à partir du fichier .pk3. Parce que ce sont de vieilles choses, je n'expliquerai pas toutes les étapes. Faites juste attention à la position de la carte.

 
Sélectionnez
int main()
{
    // Demande à l'utilisateur un pilote.
    video::E_DRIVER_TYPE driverType=driverChoiceConsole();
    if (driverType==video::EDT_COUNT)
        return 1;

    // Instance de EventReceiver.
    MyEventReceiver receiver;

    // Initialise le moteur.
    IrrlichtDevice *device = createDevice(driverType,
            dimension2du(ResX,ResY), 32, fullScreen,
            false, false, &receiver);
    if (!device)
        return 1;

    ISceneManager *smgr = device->getSceneManager();
    IVideoDriver *driver = device->getVideoDriver();

    // Charge le modèle.
    IAnimatedMesh *model = smgr->getMesh("../../media/sydney.md2");
    if (!model)
        return 1;
    IAnimatedMeshSceneNode *model_node = smgr->addAnimatedMeshSceneNode(model);
    // Charge la texture.
    if (model_node)
    {
        ITexture *texture = driver->getTexture("../../media/sydney.bmp");
        model_node->setMaterialTexture(0,texture);
        model_node->setMD2Animation(scene::EMAT_RUN);
        // Désactive l'éclairage (nous n'avons pas de lumière).
        model_node->setMaterialFlag(EMF_LIGHTING,false);
    }

    // Charge la carte.
    device->getFileSystem()->addFileArchive("../../media/map-20kdm2.pk3");
    IAnimatedMesh *map = smgr->getMesh("20kdm2.bsp");
    if (map)
    {
        ISceneNode *map_node = smgr->addOctreeSceneNode(map->getMesh(0));
        // Définit la position.
        map_node->setPosition(vector3df(-850,-220,-850));
    }

II. Création des caméras

Maintenant nous créons quatre caméras. L'une regarde vers le modèle en face, une autre d'en haut et une sur un côté. De plus, il y a une caméra FPS qui peut être contrôlée par l'utilisateur.

 
Sélectionnez
    // Crée trois caméras fixes et une contrôlée par l'utilisateur.
    // Devant
    camera[0] = smgr->addCameraSceneNode(0, vector3df(50,0,0), vector3df(0,0,0));
    // Dessus
    camera[1] = smgr->addCameraSceneNode(0, vector3df(0,50,0), vector3df(0,0,0));
    // Gauche
    camera[2] = smgr->addCameraSceneNode(0, vector3df(0,0,50), vector3df(0,0,0));
    // Contrôlée par l'utilisateur.
    camera[3] = smgr->addCameraSceneNodeFPS();
    // Ne commence pas à la position de Sydney.
    if (camera[3])
        camera[3]->setPosition(core::vector3df(-50,0,-50));

Créer une variable pour compter le nombre d'images par secondes et cacher la souris.

 
Sélectionnez
    // Cacher la souris.
    device->getCursorControl()->setVisible(false);
    // Nous voulons compter le nombre d'images par secondes.
    int lastFPS = -1;

III. Rendu de l'écran partagé

Ce n'était pas nouveau, jusqu'à maintenant ! Définir quatre caméras n'est pas suffisant pour diviser l'écran du jeu. Pour le faire, vous devez suivre quelques étapes :

  • mettre le « viewport » sur la totalité de l'écran ;
  • commencer une scène (effacer la scène) ;
  • les trois étapes suivantes sont répétées pour chaque « viewport » dans la division d'écran :
  • mettre le « viewport » là où vous le souhaitez ;
  • activer la caméra qui doit être liée au « viewport » ;
  • dessiner tous les objets ;
  • si vous avez une interface utilisateur :
  • mettre le « viewport » sur tout l'écran ;
  • afficher l'interface utilisateur ;
  • fin de la scène.

Cela paraît un petit peu compliqué, mais vous verrez ça ne l'est pas :

 
Sélectionnez
    while(device->run())
    {
        // Définit la zone de rendu sur la totalité de l'écran et commence la scène.
        driver->setViewPort(rect<s32>(0,0,ResX,ResY));
        driver->beginScene(true,true,SColor(255,100,100,100));
        // Si la division d'écran est utilisée.
        if (SplitScreen)
        {
            // Active la caméra 1.
            smgr->setActiveCamera(camera[0]);
            // Définit la zone de rendu sur le premier quart (en haut à gauche).
            driver->setViewPort(rect<s32>(0,0,ResX/2,ResY/2));
            // Dessine la scène.
            smgr->drawAll();
            // Active la caméra 2.
            smgr->setActiveCamera(camera[1]);
            // Définit la zone de rendu sur le deuxième quart (en haut à droite).
            driver->setViewPort(rect<s32>(ResX/2,0,ResX,ResY/2));
            // Dessine la scène.
            smgr->drawAll();
            // Active la caméra 3.
            smgr->setActiveCamera(camera[2]);
            // Définit la zone de rendu sur le troisième quart (en bas à gauche).
            driver->setViewPort(rect<s32>(0,ResY/2,ResX/2,ResY));
            // Dessine la scène.
            smgr->drawAll();
            // définit la zone de rendu sur le dernier quart (en bas à droite )
            driver->setViewPort(rect<s32>(ResX/2,ResY/2,ResX,ResY));
        }
        // Active la caméra 4.
        smgr->setActiveCamera(camera[3]);
        // Dessine la scène.
        smgr->drawAll();
        driver->endScene();

Comme vous pouvez le voir, l'image est dessinée séparément pour chaque « viewport ». Ce qui veut dire que vous perdrez de la performance. OK, si vous vous demandez « Comment je dois mettre le « viewport » pour avoir cet écran ou celui-là ? », ne paniquez pas, c'est très simple : dans la fonction rect, vous définissez quatre coordonnées :

  • la coordonnée X du coin en haut à gauche ;
  • la coordonnée Y du coin en haut à gauche ;
  • la coordonnée X du coin en bas à droite ;
  • la coordonnée Y du coin en bas à droite ;

Ce qui veut dire que si vous voulez séparer l'écran en deux « viewport », vous donnerez les coordonnées suivantes :

  • 1er « viewport » : 0,0,ResX/2,ResY
  • 2ème « viewport » : ResX/2,0,ResX,ResY

Si vous n'avez pas tout compris, testez juste l'exemple pour voir ce qu'il se passe.

Maintenant, nous affichons juste le nombre d'images par seconde et arrêtons le moteur quand l'utilisateur le souhaite :

 
Sélectionnez
        // Obtient et montre le nombre d'images par secondes.
        if (driver->getFPS() != lastFPS)
        {
            lastFPS = driver->getFPS();
            core::stringw tmp = L"Irrlicht SplitScreen-Example (FPS: ";
            tmp += lastFPS;
            tmp += ")";
            device->setWindowCaption(tmp.c_str());
        }
    }
    // Supprime le moteur.
    device->drop();
    return 0;
}

Voilà ! Compilez et testez le programme.

Note : la touche 'S' peut être utilisée pour utiliser ou non la division d'écran.

IV. Conclusion

Vous pouvez désormais diviser votre écran en plusieurs parties.

Dans le prochain tutoriel Souris et manettes de jeux, nous verrons comment traiter les événements de souris et de manettes de jeux.

V. Remerciements

Merci à Nikolaus Gebhardt de nous permettre de traduire ce tutoriel.

Merci à LittleWhite pour sa relecture technique ainsi qu'à ced pour sa relecture orthographique.