Creare Videogiochi - Game Developer

Versione completa: Tutorial 18 - Splitscreen
Al momento stai visualizzando i contenuti in una versione ridotta. Visualizza la versione completa e formattata.
Tutorial 18: Splitscreen

[Immagine: 018shot.jpg]

Un tutorial di Max Winkel.
In questo tutorial impareremo come usare lo splitscreen (e.g. La divisione dello schermo tipica dei racing-games) con Irrlicht. Creeremo un viewport diviso in 4 parti, con 3 camere fisse ed una controllata dall'utente.
Ok, partiamo dagli headers (non credo ci sia nulla da aggiungere).
Codice PHP:
#include <irrlicht.h>
#include "driverChoice.h"

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

//Namespaces for the engine
using namespace irr;
using namespace core;
using namespace video;
using namespace scene
Ora definiremo la risoluzione con una costante per inizializzare il device all'avvio e impostiamo la variabile globale viewport a true che ci indichi se la vista splitscreen è attiva o no.
Codice PHP:
//Resolution
const int ResX=800;
const 
int ResY=600;
const 
bool fullScreen=false;

//Use SplitScreen?
bool SplitScreen=true
Ci servono quattro puntatori alle camere che verranno create dopo:
Codice PHP:
//cameras
ICameraSceneNode *camera[4]={0,0,0,0}; 
Nel nostro event-receiver alterneremo la variabile per lo SplitScreen, ogni volta che verrà premuto il tasto 'S'. Il resto degli eventi verranno inviati alla camera FPS dell'utente.
Codice PHP:
class MyEventReceiver : public IEventReceiver
{
    public:
        
virtual bool OnEvent(const SEventevent)
        {
            
//Key S enables/disables SplitScreen
            
if (event.EventType == irr::EET_KEY_INPUT_EVENT &&
                
event.KeyInput.Key == KEY_KEY_S && event.KeyInput.PressedDown)
            {
                
SplitScreen = !SplitScreen;
                return 
true;
            }
            
//Send all other events to camera4
            
if (camera[3])
                return 
camera[3]->OnEvent(event);
            return 
false;
        }
}; 
Adesso la funzione main: prima inizializziamo il device, otteniamo i riferimenti allo SourceManager e al VideoDriver, carichiamo una mesh animata da un file .md2 e una mappa da un file .pk3. Essendo cose già viste non spiegherò ogni passo. Interessiamoci solo della posizione iniziale nella mappa.
Codice PHP:
int main()
{
    
// ask user for driver
    
video::E_DRIVER_TYPE driverType=driverChoiceConsole();
    if (
driverType==video::EDT_COUNT)
        return 
1;

    
//Instance of the EventReceiver
    
MyEventReceiver receiver;

    
//Initialise the engine
    
IrrlichtDevice *device createDevice(driverType,
            
dimension2du(ResX,ResY), 32fullScreen,
            
falsefalse, &receiver);
    if (!
device)
        return 
1;

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

    
//Load model
    
IAnimatedMesh *model smgr->getMesh("../../media/sydney.md2");
    if (!
model)
        return 
1;
    
IAnimatedMeshSceneNode *model_node smgr->addAnimatedMeshSceneNode(model);
    
//Load texture
    
if (model_node)
    {
        
ITexture *texture driver->getTexture("../../media/sydney.bmp");
        
model_node->setMaterialTexture(0,texture);
        
model_node->setMD2Animation(scene::EMAT_RUN);
        
//Disable lighting (we've got no light)
        
model_node->setMaterialFlag(EMF_LIGHTING,false);
    }
    
//Load map
    
device->getFileSystem()->addFileArchive("../../media/map-20kdm2.pk3");
    
IAnimatedMesh *map smgr->getMesh("20kdm2.bsp");
    if (
map)
    {
        
ISceneNode *map_node smgr->addOctreeSceneNode(map->getMesh(0));
        
//Set position
        
map_node->setPosition(vector3df(-850,-220,-850));
    } 
Creiamo le nostre quattro camere. Una guarda il nostro modello di fronte, una dall'alto ed una di lato. Poi la nostra camera FPS controllata dall'utente.
Codice PHP:
// Create 3 fixed and one user-controlled cameras
    //Front
    
camera[0] = smgr->addCameraSceneNode(0vector3df(50,0,0), vector3df(0,0,0));
    
//Top
    
camera[1] = smgr->addCameraSceneNode(0vector3df(0,50,0), vector3df(0,0,0));
    
//Left
    
camera[2] = smgr->addCameraSceneNode(0vector3df(0,0,50), vector3df(0,0,0));
    
//User-controlled
    
camera[3] = smgr->addCameraSceneNodeFPS();
    
// don't start at sydney's position
    
if (camera[3])
        
camera[3]->setPosition(core::vector3df(-50,0,-50)); 
Pensiamo ad una variabile per tenere conto dei frame per secondo e nascondiamo il puntatore del mouse:
Codice PHP:
//Hide mouse
    
device->getCursorControl()->setVisible(false);
    
//We want to count the fps
    
int lastFPS = -1
Fino ad ora non c'è niente di nuovo! Solo con la definizione delle quattro camere il gioco non mostrerà mai lo splitscreen. Per farlo servono alcuni passi:
. Impostare il viewport a tutto schermo
. Avviare una scena nuova (un clear screen per ripulire lo schermo)
I seguenti 3 passi vanno ripetuti per ciascun viewport dello splitscreen
. Impostare il viewport sull'area desiderata
. Attivare la camera che volete sia linkata a quel viewport
. Fare il render di tutto
Se avete una GUI:
. Rimettere il viewport a tutto schermo
. Mostrare la GUI
. Fine della scena
Sembra complicato ma vedrete che non lo è:
Codice PHP:
while(device->run())
    {
        
//Set the viewpoint to the whole screen and begin scene
        
driver->setViewPort(rect<s32>(0,0,ResX,ResY));
        
driver->beginScene(true,true,SColor(255,100,100,100));
        
//If SplitScreen is used
        
if (SplitScreen)
        {
            
//Activate camera1
            
smgr->setActiveCamera(camera[0]);
            
//Set viewpoint to the first quarter (left top)
            
driver->setViewPort(rect<s32>(0,0,ResX/2,ResY/2));
            
//Draw scene
            
smgr->drawAll();
            
//Activate camera2
            
smgr->setActiveCamera(camera[1]);
            
//Set viewpoint to the second quarter (right top)
            
driver->setViewPort(rect<s32>(ResX/2,0,ResX,ResY/2));
            
//Draw scene
            
smgr->drawAll();
            
//Activate camera3
            
smgr->setActiveCamera(camera[2]);
            
//Set viewpoint to the third quarter (left bottom)
            
driver->setViewPort(rect<s32>(0,ResY/2,ResX/2,ResY));
            
//Draw scene
            
smgr->drawAll();
            
//Set viewport the last quarter (right bottom)
            
driver->setViewPort(rect<s32>(ResX/2,ResY/2,ResX,ResY));
        }
        
//Activate camera4
        
smgr->setActiveCamera(camera[3]);
        
//Draw scene
        
smgr->drawAll();
        
driver->endScene(); 
Come avrete visto, le immagini sono renderizzate per ciascun viewport separatamente. Questo significa che si perderà un po' in performance. OK, se vi state chiedendo “Come faccio ad impostare i viewport in questa o quella parte dello schermo?”, niente panico è veramente semplice: nella funzione rect definite 4 coordinate:
. Coordinata X dell'angolo in alto a sinistra
. Coordinata Y dell'angolo in alto a sinistra
. Coordinata X dell'angolo in basso a destra
. Coordinata Y dell'angolo in basso a sinistra
Questo significa che se volete tagliare lo schermo in 2 parti in 2 viewports dovrete dare le seguenti coordinate:
. 1mo viewport: 0,0,ResX/2,ResY
. 2ndo viewport: ResX/2,0,ResX,ResY
Se non lo capite completamente, provate a cambiare i valori nell'esempio e vedete cosa accade.
Mostriamo il conteggio corrente degli fps e chiudiamo l'engine quando l'utente lo richiederà:
Codice PHP:
//Get and show fps
        
if (driver->getFPS() != lastFPS)
        {
            
lastFPS driver->getFPS();
            
core::stringw tmp L"Irrlicht SplitScreen-Example (FPS: ";
            
tmp += lastFPS;
            
tmp += ")";
            
device->setWindowCaption(tmp.c_str());
        }
    }
    
//Delete device
    
device->drop();
    return 
0;

E' tutto! Compiliamo e proviamo il programma. Notare: con il tasto 'S' possiamo passare tra la modalità splitscreen e non.

Versione scaricabile da QUI