Tutorial 21a - Quake3 Explorer - Chip - 23-08-2015
Tutorial 21: Quake3 Explorer
In questo tutorial mostreremo come caricare più mappe Quake 3.
Specifiche:
. Carico Load archivio BSP a Runtime dal menù
. Carico di una mappa dal menù. Mostriamo uno Screenshot
. Impsotazione del VideoDriver a runtime dal menù
. Variazione del GammaLevel a runtime
. Creazione SceneNodes per gli Shaders
. Carico della EntityList e creazione delle Entity come SceneNodes
. Creazione giocatori con armi e rispettive collisioni
. Musica
E' possibile scaricare Quake III Arena demo ( copyright id software ) al seguente path ftp://ftp.idsoftware.com/idstuff/quake3/win32/q3ademo.exe
Copyright 2006-2011 Burningwater, Thomas Alten
Codice PHP: #include "driverChoice.h" #include <irrlicht.h> #include "q3factory.h" #include "sound.h"
La struttura Game Data è usata per mantenere i dati del gioco e gestirne il funzionamento
Codice PHP: struct GameData { GameData ( const path &startupDir) : retVal(0), StartupDir(startupDir), createExDevice(0), Device(0) { setDefault (); }
void setDefault (); s32 save ( const path &filename ); s32 load ( const path &filename );
s32 debugState; s32 gravityState; s32 flyTroughState; s32 wireFrame; s32 guiActive; s32 guiInputActive; f32 GammaValue; s32 retVal; s32 sound;
path StartupDir; stringw CurrentMapName; array<path> CurrentArchiveList;
vector3df PlayerPosition; vector3df PlayerRotation;
tQ3EntityList Variable;
Q3LevelLoadParameter loadParam; SIrrlichtCreationParameters deviceParam; funcptr_createDeviceEx createExDevice; IrrlichtDevice *Device; };
Impostazione dei valori di default
Codice PHP: void GameData::setDefault () { debugState = EDS_OFF; gravityState = 1; flyTroughState = 0; wireFrame = 0; guiActive = 1; guiInputActive = 0; GammaValue = 1.f;
// default deviceParam; #if defined ( _IRR_WINDOWS_ ) deviceParam.DriverType = EDT_DIRECT3D9; #else deviceParam.DriverType = EDT_OPENGL; #endif deviceParam.WindowSize.Width = 800; deviceParam.WindowSize.Height = 600; deviceParam.Fullscreen = false; deviceParam.Bits = 24; deviceParam.ZBufferBits = 16; deviceParam.Vsync = false; deviceParam.AntiAlias = false;
// default Quake3 loadParam loadParam.defaultLightMapMaterial = EMT_LIGHTMAP; loadParam.defaultModulate = EMFN_MODULATE_1X; loadParam.defaultFilter = EMF_ANISOTROPIC_FILTER; loadParam.verbose = 2; loadParam.mergeShaderBuffer = 1; // merge meshbuffers with same material loadParam.cleanUnResolvedMeshes = 1; // should unresolved meshes be cleaned. otherwise blue texture loadParam.loadAllShaders = 1; // load all scripts in the script directory loadParam.loadSkyShader = 0; // load sky Shader loadParam.alpharef = 1;
sound = 0;
CurrentMapName = ""; CurrentArchiveList.clear ();
// Explorer Media directory CurrentArchiveList.push_back ( StartupDir + "../../media/" );
// Add the original quake3 files before you load your custom map // Most mods are using the original shaders, models&items&weapons CurrentArchiveList.push_back("/q/baseq3/");
CurrentArchiveList.push_back(StartupDir + "../../media/map-20kdm2.pk3"); }
Carica lo stato attuale del gioco da un tipico file di configurazione quake3 cfg
Codice PHP: s32 GameData::load ( const path &filename ) { if (!Device) return 0;
// the quake3 mesh loader can also handle *.shader and *.cfg file IQ3LevelMesh* mesh = (IQ3LevelMesh*) Device->getSceneManager()->getMesh ( filename ); if (!mesh) return 0;
tQ3EntityList &entityList = mesh->getEntityList ();
stringc s; u32 pos;
for ( u32 e = 0; e != entityList.size (); ++e ) { //dumpShader ( s, &entityList[e], false ); //printf ( s.c_str () );
for ( u32 g = 0; g != entityList[e].getGroupSize (); ++g ) { const SVarGroup *group = entityList[e].getGroup ( g );
for ( u32 index = 0; index < group->Variable.size (); ++index ) { const SVariable &v = group->Variable[index]; pos = 0; if ( v.name == "playerposition" ) { PlayerPosition = getAsVector3df ( v.content, pos ); } else if ( v.name == "playerrotation" ) { PlayerRotation = getAsVector3df ( v.content, pos ); } } } }
return 1; }
Salva lo stato del gioco nel file di configurazione quake3
Codice PHP: s32 GameData::save ( const path &filename ) { return 0; if (!Device) return 0;
c8 buf[128]; u32 i;
// Store current Archive for restart CurrentArchiveList.clear(); IFileSystem *fs = Device->getFileSystem(); for ( i = 0; i != fs->getFileArchiveCount(); ++i ) { CurrentArchiveList.push_back ( fs->getFileArchive(i)->getFileList()->getPath() ); }
// Store Player Position and Rotation ICameraSceneNode * camera = Device->getSceneManager()->getActiveCamera (); if ( camera ) { PlayerPosition = camera->getPosition (); PlayerRotation = camera->getRotation (); }
IWriteFile *file = fs->createAndWriteFile ( filename ); if (!file) return 0;
snprintf ( buf, 128, "playerposition %.f %.f %.f\nplayerrotation %.f %.f %.f\n", PlayerPosition.X, PlayerPosition.Z, PlayerPosition.Y, PlayerRotation.X, PlayerRotation.Z, PlayerRotation.Y); file->write ( buf, (s32) strlen ( buf ) ); for ( i = 0; i != fs->getFileArchiveCount(); ++i ) { snprintf ( buf, 128, "archive %s\n",stringc ( fs->getFileArchive(i)->getFileList()->getPath() ).c_str () ); file->write ( buf, (s32) strlen ( buf ) ); }
file->drop (); return 1; }
La struttura per rappresentare il giocatre
Codice PHP: struct Q3Player : public IAnimationEndCallBack { Q3Player () : Device(0), MapParent(0), Mesh(0), WeaponNode(0), StartPositionCurrent(0) { animation[0] = 0; memset(Anim, 0, sizeof(TimeFire)*4); }
virtual void OnAnimationEnd(IAnimatedMeshSceneNode* node);
void create ( IrrlichtDevice *device, IQ3LevelMesh* mesh, ISceneNode *mapNode, IMetaTriangleSelector *meta ); void shutdown (); void setAnim ( const c8 *name ); void respawn (); void setpos ( const vector3df &pos, const vector3df& rotation );
ISceneNodeAnimatorCollisionResponse * cam() { return camCollisionResponse ( Device ); }
IrrlichtDevice *Device; ISceneNode* MapParent; IQ3LevelMesh* Mesh; IAnimatedMeshSceneNode* WeaponNode; s32 StartPositionCurrent; TimeFire Anim[4]; c8 animation[64]; c8 buf[64]; };
Fine struttura per il giocatore
Codice PHP: void Q3Player::shutdown () { setAnim ( 0 );
dropElement (WeaponNode);
if ( Device ) { ICameraSceneNode* camera = Device->getSceneManager()->getActiveCamera(); dropElement ( camera ); Device = 0; }
MapParent = 0; Mesh = 0; }
Creazione di un nuovo giocatore
Codice PHP: void Q3Player::create ( IrrlichtDevice *device, IQ3LevelMesh* mesh, ISceneNode *mapNode, IMetaTriangleSelector *meta ) { setTimeFire ( Anim + 0, 200, FIRED ); setTimeFire ( Anim + 1, 5000 );
if (!device) return; // load FPS weapon to Camera Device = device; Mesh = mesh; MapParent = mapNode;
ISceneManager *smgr = device->getSceneManager (); IVideoDriver * driver = device->getVideoDriver();
ICameraSceneNode* camera = 0;
SKeyMap keyMap[10]; keyMap[0].Action = EKA_MOVE_FORWARD; keyMap[0].KeyCode = KEY_UP; keyMap[1].Action = EKA_MOVE_FORWARD; keyMap[1].KeyCode = KEY_KEY_W;
keyMap[2].Action = EKA_MOVE_BACKWARD; keyMap[2].KeyCode = KEY_DOWN; keyMap[3].Action = EKA_MOVE_BACKWARD; keyMap[3].KeyCode = KEY_KEY_S;
keyMap[4].Action = EKA_STRAFE_LEFT; keyMap[4].KeyCode = KEY_LEFT; keyMap[5].Action = EKA_STRAFE_LEFT; keyMap[5].KeyCode = KEY_KEY_A;
keyMap[6].Action = EKA_STRAFE_RIGHT; keyMap[6].KeyCode = KEY_RIGHT; keyMap[7].Action = EKA_STRAFE_RIGHT; keyMap[7].KeyCode = KEY_KEY_D;
keyMap[8].Action = EKA_JUMP_UP; keyMap[8].KeyCode = KEY_KEY_J;
keyMap[9].Action = EKA_CROUCH; keyMap[9].KeyCode = KEY_KEY_C;
camera = smgr->addCameraSceneNodeFPS(0, 100.0f, 0.6f, -1, keyMap, 10, false, 0.6f); camera->setName ( "First Person Camera" ); //camera->setFOV ( 100.f * core::DEGTORAD ); camera->setFarValue( 20000.f );
IAnimatedMeshMD2* weaponMesh = (IAnimatedMeshMD2*) smgr->getMesh("gun.md2"); if ( 0 == weaponMesh ) return;
if ( weaponMesh->getMeshType() == EAMT_MD2 ) { s32 count = weaponMesh->getAnimationCount(); for ( s32 i = 0; i != count; ++i ) { snprintf ( buf, 64, "Animation: %s", weaponMesh->getAnimationName(i) ); device->getLogger()->log(buf, ELL_INFORMATION); } }
WeaponNode = smgr->addAnimatedMeshSceneNode( weaponMesh, smgr->getActiveCamera(), 10, vector3df( 0, 0, 0), vector3df(-90,-90,90) ); WeaponNode->setMaterialFlag(EMF_LIGHTING, false); WeaponNode->setMaterialTexture(0, driver->getTexture( "gun.jpg")); WeaponNode->setLoopMode ( false ); WeaponNode->setName ( "tommi the gun man" );
//create a collision auto response animator ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator( meta, camera, vector3df(30,45,30), getGravity ( "earth" ), vector3df(0,40,0), 0.0005f );
camera->addAnimator( anim ); anim->drop();
if ( meta ) { meta->drop (); }
respawn (); setAnim ( "idle" ); }
Ci serve un buon punto di partenza dentro il livello. Possiamo chiedere al Quake3 Loader tutte le entità che appartengono alla classe "info_player_deathmatch"
Codice PHP: void Q3Player::respawn () { if (!Device) return; ICameraSceneNode* camera = Device->getSceneManager()->getActiveCamera();
Device->getLogger()->log( "respawn" );
if ( StartPositionCurrent >= Q3StartPosition ( Mesh, camera,StartPositionCurrent++, cam ()->getEllipsoidTranslation() ) ) { StartPositionCurrent = 0; } }
Impostiamo la posizione del giocatore prendendo quelle salvate
Codice PHP: void Q3Player::setpos ( const vector3df &pos, const vector3df &rotation ) { if (!Device) return; Device->getLogger()->log( "setpos" );
ICameraSceneNode* camera = Device->getSceneManager()->getActiveCamera(); if ( camera ) { camera->setPosition ( pos ); camera->setRotation ( rotation ); camera->OnAnimate ( 0 ); } }
Impostiamo l'animazione e l'arma del giocatore
Codice PHP: void Q3Player::setAnim ( const c8 *name ) { if ( name ) { snprintf ( animation, 64, "%s", name ); if ( WeaponNode ) { WeaponNode->setAnimationEndCallback ( this ); WeaponNode->setMD2Animation ( animation ); } } else { animation[0] = 0; if ( WeaponNode ) { WeaponNode->setAnimationEndCallback ( 0 ); } } }
// Callback void Q3Player::OnAnimationEnd(IAnimatedMeshSceneNode* node) { setAnim ( 0 ); }
Gli elementi della GUI
Codice PHP: struct GUI { GUI () { memset ( this, 0, sizeof ( *this ) ); }
void drop() { dropElement ( Window ); dropElement ( Logo ); }
IGUIComboBox* VideoDriver; IGUIComboBox* VideoMode; IGUICheckBox* FullScreen; IGUICheckBox* Bit32; IGUIScrollBar* MultiSample; IGUIButton* SetVideoMode;
IGUIScrollBar* Tesselation; IGUIScrollBar* Gamma; IGUICheckBox* Collision; IGUICheckBox* Visible_Map; IGUICheckBox* Visible_Shader; IGUICheckBox* Visible_Fog; IGUICheckBox* Visible_Unresolved; IGUICheckBox* Visible_Skydome; IGUIButton* Respawn;
IGUITable* ArchiveList; IGUIButton* ArchiveAdd; IGUIButton* ArchiveRemove; IGUIFileOpenDialog* ArchiveFileOpen; IGUIButton* ArchiveUp; IGUIButton* ArchiveDown;
IGUIListBox* MapList; IGUITreeView* SceneTree; IGUIStaticText* StatusLine; IGUIImage* Logo; IGUIWindow* Window; }; Classe CQuake3EventHandler per il controllo del gioco class CQuake3EventHandler : public IEventReceiver { public:
CQuake3EventHandler( GameData *gameData ); virtual ~CQuake3EventHandler ();
void Animate(); void Render();
void AddArchive ( const path& archiveName ); void LoadMap ( const stringw& mapName, s32 collision ); void CreatePlayers(); void AddSky( u32 dome, const c8 *texture ); Q3Player *GetPlayer ( u32 index ) { return &Player[index]; }
void CreateGUI(); void SetGUIActive( s32 command);
bool OnEvent(const SEvent& eve);
private:
GameData *Game;
IQ3LevelMesh* Mesh; ISceneNode* MapParent; ISceneNode* ShaderParent; ISceneNode* ItemParent; ISceneNode* UnresolvedParent; ISceneNode* BulletParent; ISceneNode* FogParent; ISceneNode * SkyNode; IMetaTriangleSelector *Meta;
c8 buf[256];
Q3Player Player[2];
struct SParticleImpact { u32 when; vector3df pos; vector3df outVector; }; array<SParticleImpact> Impacts; void useItem( Q3Player * player); void createParticleImpacts( u32 now );
void createTextures (); void addSceneTreeItem( ISceneNode * parent, IGUITreeViewNode* nodeParent);
GUI gui; void dropMap (); };
Costruttore della CQuake3EventHandler
Codice PHP: CQuake3EventHandler::CQuake3EventHandler( GameData *game ) : Game(game), Mesh(0), MapParent(0), ShaderParent(0), ItemParent(0), UnresolvedParent(0), BulletParent(0), FogParent(0), SkyNode(0), Meta(0) { buf[0]=0; // Also use 16 Bit Textures for 16 Bit RenderDevice if ( Game->deviceParam.Bits == 16 ) { game->Device->getVideoDriver()->setTextureCreationFlag(ETCF_ALWAYS_16_BIT, true); }
// Quake3 Shader controls Z-Writing game->Device->getSceneManager()->getParameters()->setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true);
// create internal textures createTextures ();
sound_init ( game->Device );
Game->Device->setEventReceiver ( this ); }
// destructor CQuake3EventHandler::~CQuake3EventHandler () { Player[0].shutdown (); sound_shutdown ();
Game->save( "explorer.cfg" );
Game->Device->drop(); }
// create runtime textures smog, fog void CQuake3EventHandler::createTextures() { IVideoDriver * driver = Game->Device->getVideoDriver();
dimension2du dim(64, 64);
video::IImage* image; u32 i; u32 x; u32 y; u32 * data; for ( i = 0; i != 8; ++i ) { image = driver->createImage ( video::ECF_A8R8G8B8, dim); data = (u32*) image->lock (); for ( y = 0; y != dim.Height; ++y ) { for ( x = 0; x != dim.Width; ++x ) { data [x] = 0xFFFFFFFF; } data = (u32*) ( (u8*) data + image->getPitch() ); } image->unlock(); snprintf ( buf, 64, "smoke_%02d", i ); driver->addTexture( buf, image ); image->drop (); }
// fog for ( i = 0; i != 1; ++i ) { image = driver->createImage ( video::ECF_A8R8G8B8, dim); data = (u32*) image->lock (); for ( y = 0; y != dim.Height; ++y ) { for ( x = 0; x != dim.Width; ++x ) { data [x] = 0xFFFFFFFF; } data = (u32*) ( (u8*) data + image->getPitch() ); } image->unlock(); snprintf ( buf, 64, "fog_%02d", i ); driver->addTexture( buf, image ); image->drop (); } }
Creazione della GUI
Codice PHP: void CQuake3EventHandler::CreateGUI() {
IGUIEnvironment *env = Game->Device->getGUIEnvironment(); IVideoDriver * driver = Game->Device->getVideoDriver();
gui.drop();
// set skin font IGUIFont* font = env->getFont("fontlucida.png"); if (font) env->getSkin()->setFont(font); env->getSkin()->setColor ( EGDC_BUTTON_TEXT, video::SColor(240,0xAA,0xAA,0xAA) ); env->getSkin()->setColor ( EGDC_3D_HIGH_LIGHT, video::SColor(240,0x22,0x22,0x22) ); env->getSkin()->setColor ( EGDC_3D_FACE, video::SColor(240,0x44,0x44,0x44) ); env->getSkin()->setColor ( EGDC_EDITABLE, video::SColor(240,0x44,0x44,0x44) ); env->getSkin()->setColor ( EGDC_FOCUSED_EDITABLE, video::SColor(240,0x54,0x54,0x54) ); env->getSkin()->setColor ( EGDC_WINDOW, video::SColor(240,0x66,0x66,0x66) );
// minimal gui size 800x600 dimension2d<u32> dim ( 800, 600 ); dimension2d<u32> vdim ( Game->Device->getVideoDriver()->getScreenSize() );
if ( vdim.Height >= dim.Height && vdim.Width >= dim.Width ) { //dim = vdim; } else { }
gui.Window = env->addWindow ( rect<s32> ( 0, 0, dim.Width, dim.Height ), false, L"Quake3 Explorer" ); gui.Window->setToolTipText ( L"Quake3Explorer. Loads and show various BSP File Format and Shaders." ); gui.Window->getCloseButton()->setToolTipText ( L"Quit Quake3 Explorer" );
// add a status line help text gui.StatusLine = env->addStaticText( 0, rect<s32>( 5,dim.Height - 30,dim.Width - 5,dim.Height - 10), false, false, gui.Window, -1, true );
env->addStaticText ( L"VideoDriver:", rect<s32>( dim.Width - 400, 24, dim.Width - 310, 40 ),false, false, gui.Window, -1, false ); gui.VideoDriver = env->addComboBox(rect<s32>( dim.Width - 300, 24, dim.Width - 10, 40 ),gui.Window); gui.VideoDriver->addItem(L"Direct3D 9.0c", EDT_DIRECT3D9 ); gui.VideoDriver->addItem(L"Direct3D 8.1", EDT_DIRECT3D8 ); gui.VideoDriver->addItem(L"OpenGL 1.5", EDT_OPENGL); gui.VideoDriver->addItem(L"Software Renderer", EDT_SOFTWARE); gui.VideoDriver->addItem(L"Burning's Video (TM) Thomas Alten", EDT_BURNINGSVIDEO); gui.VideoDriver->setSelected ( gui.VideoDriver->getIndexForItemData ( Game->deviceParam.DriverType ) ); gui.VideoDriver->setToolTipText ( L"Use a VideoDriver" );
env->addStaticText ( L"VideoMode:", rect<s32>( dim.Width - 400, 44, dim.Width - 310, 60 ),false, false, gui.Window, -1, false ); gui.VideoMode = env->addComboBox(rect<s32>( dim.Width - 300, 44, dim.Width - 10, 60 ),gui.Window); gui.VideoMode->setToolTipText ( L"Supported Screenmodes" ); IVideoModeList *modeList = Game->Device->getVideoModeList(); if ( modeList ) { s32 i; for ( i = 0; i != modeList->getVideoModeCount (); ++i ) { u16 d = modeList->getVideoModeDepth ( i ); if ( d < 16 ) continue;
u16 w = modeList->getVideoModeResolution ( i ).Width; u16 h = modeList->getVideoModeResolution ( i ).Height; u32 val = w << 16 | h;
if ( gui.VideoMode->getIndexForItemData ( val ) >= 0 ) continue;
f32 aspect = (f32) w / (f32) h; const c8 *a = ""; if ( core::equals ( aspect, 1.3333333333f ) ) a = "4:3"; else if ( core::equals ( aspect, 1.6666666f ) ) a = "15:9 widescreen"; else if ( core::equals ( aspect, 1.7777777f ) ) a = "16:9 widescreen"; else if ( core::equals ( aspect, 1.6f ) ) a = "16:10 widescreen"; else if ( core::equals ( aspect, 2.133333f ) ) a = "20:9 widescreen";
snprintf ( buf, sizeof ( buf ), "%d x %d, %s",w, h, a ); gui.VideoMode->addItem ( stringw ( buf ).c_str(), val ); } } gui.VideoMode->setSelected ( gui.VideoMode->getIndexForItemData ( Game->deviceParam.WindowSize.Width << 16 | Game->deviceParam.WindowSize.Height ) );
gui.FullScreen = env->addCheckBox ( Game->deviceParam.Fullscreen, rect<s32>( dim.Width - 400, 64, dim.Width - 300, 80 ), gui.Window,-1, L"Fullscreen" ); gui.FullScreen->setToolTipText ( L"Set Fullscreen or Window Mode" );
gui.Bit32 = env->addCheckBox ( Game->deviceParam.Bits == 32, rect<s32>( dim.Width - 300, 64, dim.Width - 240, 80 ), gui.Window,-1, L"32Bit" ); gui.Bit32->setToolTipText ( L"Use 16 or 32 Bit" );
env->addStaticText ( L"MultiSample:", rect<s32>( dim.Width - 235, 64, dim.Width - 150, 80 ),false, false, gui.Window, -1, false ); gui.MultiSample = env->addScrollBar( true, rect<s32>( dim.Width - 150, 64, dim.Width - 70, 80 ), gui.Window,-1 ); gui.MultiSample->setMin ( 0 ); gui.MultiSample->setMax ( 8 ); gui.MultiSample->setSmallStep ( 1 ); gui.MultiSample->setLargeStep ( 1 ); gui.MultiSample->setPos ( Game->deviceParam.AntiAlias ); gui.MultiSample->setToolTipText ( L"Set the MultiSample (disable, 1x, 2x, 4x, 8x )" );
gui.SetVideoMode = env->addButton (rect<s32>( dim.Width - 60, 64, dim.Width - 10, 80 ), gui.Window, -1,L"set" ); gui.SetVideoMode->setToolTipText ( L"Set Video Mode with current values" );
env->addStaticText ( L"Gamma:", rect<s32>( dim.Width - 400, 104, dim.Width - 310, 120 ),false, false, gui.Window, -1, false ); gui.Gamma = env->addScrollBar( true, rect<s32>( dim.Width - 300, 104, dim.Width - 10, 120 ), gui.Window,-1 ); gui.Gamma->setMin ( 50 ); gui.Gamma->setMax ( 350 ); gui.Gamma->setSmallStep ( 1 ); gui.Gamma->setLargeStep ( 10 ); gui.Gamma->setPos ( core::floor32 ( Game->GammaValue * 100.f ) ); gui.Gamma->setToolTipText ( L"Adjust Gamma Ramp ( 0.5 - 3.5)" ); Game->Device->setGammaRamp ( Game->GammaValue, Game->GammaValue, Game->GammaValue, 0.f, 0.f );
env->addStaticText ( L"Tesselation:", rect<s32>( dim.Width - 400, 124, dim.Width - 310, 140 ),false, false, gui.Window, -1, false ); gui.Tesselation = env->addScrollBar( true, rect<s32>( dim.Width - 300, 124, dim.Width - 10, 140 ), gui.Window,-1 ); gui.Tesselation->setMin ( 2 ); gui.Tesselation->setMax ( 12 ); gui.Tesselation->setSmallStep ( 1 ); gui.Tesselation->setLargeStep ( 1 ); gui.Tesselation->setPos ( Game->loadParam.patchTesselation ); gui.Tesselation->setToolTipText ( L"How smooth should curved surfaces be rendered" );
gui.Collision = env->addCheckBox ( true, rect<s32>( dim.Width - 400, 150, dim.Width - 300, 166 ), gui.Window,-1, L"Collision" ); gui.Collision->setToolTipText ( L"Set collision on or off ( flythrough ). \nPress F7 on your Keyboard" ); gui.Visible_Map = env->addCheckBox ( true, rect<s32>( dim.Width - 300, 150, dim.Width - 240, 166 ), gui.Window,-1, L"Map" ); gui.Visible_Map->setToolTipText ( L"Show or not show the static part the Level. \nPress F3 on your Keyboard" ); gui.Visible_Shader = env->addCheckBox ( true, rect<s32>( dim.Width - 240, 150, dim.Width - 170, 166 ), gui.Window,-1, L"Shader" ); gui.Visible_Shader->setToolTipText ( L"Show or not show the Shader Nodes. \nPress F4 on your Keyboard" ); gui.Visible_Fog = env->addCheckBox ( true, rect<s32>( dim.Width - 170, 150, dim.Width - 110, 166 ), gui.Window,-1, L"Fog" ); gui.Visible_Fog->setToolTipText ( L"Show or not show the Fog Nodes. \nPress F5 on your Keyboard" ); gui.Visible_Unresolved = env->addCheckBox ( true, rect<s32>( dim.Width - 110, 150, dim.Width - 10, 166 ), gui.Window,-1, L"Unresolved" ); gui.Visible_Unresolved->setToolTipText ( L"Show the or not show the Nodes the Engine can't handle. \nPress F6 on your Keyboard" ); gui.Visible_Skydome = env->addCheckBox ( true, rect<s32>( dim.Width - 110, 180, dim.Width - 10, 196 ), gui.Window,-1, L"Skydome" ); gui.Visible_Skydome->setToolTipText ( L"Show the or not show the Skydome." );
//Respawn = env->addButton ( rect<s32>( dim.Width - 260, 90, dim.Width - 10, 106 ), 0,-1, L"Respawn" );
env->addStaticText ( L"Archives:", rect<s32>( 5, dim.Height - 530, dim.Width - 600,dim.Height - 514 ),false, false, gui.Window, -1, false );
gui.ArchiveAdd = env->addButton ( rect<s32>( dim.Width - 725, dim.Height - 530, dim.Width - 665, dim.Height - 514 ), gui.Window,-1, L"add" ); gui.ArchiveAdd->setToolTipText ( L"Add an archive, usually packed zip-archives (*.pk3) to the Filesystem" ); gui.ArchiveRemove = env->addButton ( rect<s32>( dim.Width - 660, dim.Height - 530, dim.Width - 600, dim.Height - 514 ), gui.Window,-1, L"del" ); gui.ArchiveRemove->setToolTipText ( L"Remove the selected archive from the FileSystem." ); gui.ArchiveUp = env->addButton ( rect<s32>( dim.Width - 575, dim.Height - 530, dim.Width - 515, dim.Height - 514 ), gui.Window,-1, L"up" ); gui.ArchiveUp->setToolTipText ( L"Arrange Archive Look-up Hirachy. Move the selected Archive up" ); gui.ArchiveDown = env->addButton ( rect<s32>( dim.Width - 510, dim.Height - 530, dim.Width - 440, dim.Height - 514 ), gui.Window,-1, L"down" ); gui.ArchiveDown->setToolTipText ( L"Arrange Archive Look-up Hirachy. Move the selected Archive down" );
gui.ArchiveList = env->addTable ( rect<s32>( 5,dim.Height - 510, dim.Width - 450,dim.Height - 410 ), gui.Window ); gui.ArchiveList->addColumn ( L"Type", 0 ); gui.ArchiveList->addColumn ( L"Real File Path", 1 ); gui.ArchiveList->setColumnWidth ( 0, 60 ); gui.ArchiveList->setColumnWidth ( 1, 284 ); gui.ArchiveList->setToolTipText ( L"Show the attached Archives" );
env->addStaticText ( L"Maps:", rect<s32>( 5, dim.Height - 400, dim.Width - 450,dim.Height - 380 ),false, false, gui.Window, -1, false ); gui.MapList = env->addListBox ( rect<s32>( 5,dim.Height - 380, dim.Width - 450,dim.Height - 40 ), gui.Window, -1, true ); gui.MapList->setToolTipText ( L"Show the current Maps in all Archives.\n Double-Click the Map to start the level" );
// create a visible Scene Tree env->addStaticText ( L"Scenegraph:", rect<s32>( dim.Width - 400, dim.Height - 400, dim.Width - 5,dim.Height - 380 ),false, false, gui.Window, -1, false ); gui.SceneTree = env->addTreeView( rect<s32>( dim.Width - 400, dim.Height - 380, dim.Width - 5, dim.Height - 40 ), gui.Window, -1, true, true, false ); gui.SceneTree->setToolTipText ( L"Show the current Scenegraph" ); gui.SceneTree->getRoot()->clearChildren(); addSceneTreeItem ( Game->Device->getSceneManager()->getRootSceneNode(), gui.SceneTree->getRoot() );
IGUIImageList* imageList = env->createImageList( driver->getTexture ( "iconlist.png" ), dimension2di( 32, 32 ), true );
if ( imageList ) { gui.SceneTree->setImageList( imageList ); imageList->drop (); }
// load the engine logo gui.Logo = env->addImage( driver->getTexture("irrlichtlogo3.png"), position2d<s32>(5, 16 ), true, 0 ); gui.Logo->setToolTipText ( L"The great Irrlicht Engine" );
AddArchive ( "" ); }
Aggiunta di un archivio Archive al FileSystems e aggiornamento della GUI
Codice PHP: void CQuake3EventHandler::AddArchive ( const path& archiveName ) { IFileSystem *fs = Game->Device->getFileSystem(); u32 i;
if ( archiveName.size () ) { bool exists = false; for ( i = 0; i != fs->getFileArchiveCount(); ++i ) { if ( fs->getFileArchive(i)->getFileList()->getPath() == archiveName ) { exists = true; break; } }
if (!exists) { fs->addFileArchive(archiveName, true, false); } }
// store the current archives in game data // show the attached Archive in proper order if ( gui.ArchiveList ) { gui.ArchiveList->clearRows();
for ( i = 0; i != fs->getFileArchiveCount(); ++i ) { IFileArchive * archive = fs->getFileArchive ( i );
u32 index = gui.ArchiveList->addRow(i);
core::stringw typeName; switch(archive->getType()) { case io::EFAT_ZIP: typeName = "ZIP"; break; case io::EFAT_GZIP: typeName = "gzip"; break; case io::EFAT_FOLDER: typeName = "Mount"; break; case io::EFAT_PAK: typeName = "PAK"; break; case io::EFAT_TAR: typeName = "TAR"; break; default: typeName = "archive"; }
gui.ArchiveList->setCellText ( index, 0, typeName ); gui.ArchiveList->setCellText ( index, 1, archive->getFileList()->getPath() ); } }
// browse the archives for maps if ( gui.MapList ) { gui.MapList->clear();
IGUISpriteBank *bank = Game->Device->getGUIEnvironment()->getSpriteBank("sprite_q3map"); if ( 0 == bank ) bank = Game->Device->getGUIEnvironment()->addEmptySpriteBank("sprite_q3map");
SGUISprite sprite; SGUISpriteFrame frame; core::rect<s32> r;
bank->getSprites().clear(); bank->getPositions().clear (); gui.MapList->setSpriteBank ( bank );
u32 g = 0; core::stringw s;
// browse the attached file system fs->setFileListSystem ( FILESYSTEM_VIRTUAL ); fs->changeWorkingDirectoryTo ( "/maps/" ); IFileList *fileList = fs->createFileList (); fs->setFileListSystem ( FILESYSTEM_NATIVE );
for ( i=0; i< fileList->getFileCount(); ++i) { s = fileList->getFullFileName(i); if ( s.find ( ".bsp" ) >= 0 ) { // get level screenshot. reformat texture to 128x128 path c ( s ); deletePathFromFilename ( c ); cutFilenameExtension ( c, c ); c = path ( "levelshots/" ) + c;
dimension2du dim ( 128, 128 ); IVideoDriver * driver = Game->Device->getVideoDriver(); IImage* image = 0; ITexture *tex = 0; path filename;
filename = c + ".jpg"; if ( fs->existFile ( filename ) ) image = driver->createImageFromFile( filename ); if ( 0 == image ) { filename = c + ".tga"; if ( fs->existFile ( filename ) ) image = driver->createImageFromFile( filename ); }
if ( image ) { IImage* filter = driver->createImage ( video::ECF_R8G8B8, dim ); image->copyToScalingBoxFilter ( filter, 0 ); image->drop (); image = filter; }
if ( image ) { tex = driver->addTexture ( filename, image ); image->drop (); }
bank->setTexture ( g, tex );
r.LowerRightCorner.X = dim.Width; r.LowerRightCorner.Y = dim.Height; gui.MapList->setItemHeight ( r.LowerRightCorner.Y + 4 ); frame.rectNumber = bank->getPositions().size(); frame.textureNumber = g;
bank->getPositions().push_back(r);
sprite.Frames.set_used ( 0 ); sprite.Frames.push_back(frame); sprite.frameTime = 0; bank->getSprites().push_back(sprite);
gui.MapList->addItem ( s.c_str (), g ); g += 1; } } fileList->drop ();
gui.MapList->setSelected ( -1 ); IGUIScrollBar * bar = (IGUIScrollBar*)gui.MapList->getElementFromId( 0 ); if ( bar ) bar->setPos ( 0 );
}
}
Pulisce e rilascia la mappa in memoria
Codice PHP: void CQuake3EventHandler::dropMap () { IVideoDriver * driver = Game->Device->getVideoDriver();
driver->removeAllHardwareBuffers (); driver->removeAllTextures ();
Player[0].shutdown ();
dropElement ( ItemParent ); dropElement ( ShaderParent ); dropElement ( UnresolvedParent ); dropElement ( FogParent ); dropElement ( BulletParent );
Impacts.clear();
if ( Meta ) { Meta = 0; }
dropElement ( MapParent ); dropElement ( SkyNode );
// clean out meshes, because textures are invalid // TODO: better texture handling;-) IMeshCache *cache = Game->Device->getSceneManager ()->getMeshCache(); cache->clear (); Mesh = 0; }
Caricamento di una nuova mappa
Codice PHP: void CQuake3EventHandler::LoadMap ( const stringw &mapName, s32 collision ) { if ( 0 == mapName.size() ) return;
dropMap ();
IFileSystem *fs = Game->Device->getFileSystem(); ISceneManager *smgr = Game->Device->getSceneManager ();
IReadFile* file = fs->createMemoryReadFile(&Game->loadParam, sizeof(Game->loadParam), L"levelparameter.cfg", false);
// load cfg file smgr->getMesh( file ); file->drop ();
// load the actual map Mesh = (IQ3LevelMesh*) smgr->getMesh(mapName); if ( 0 == Mesh ) return;
Aggiunta delle mesh presenti nella nostra Scene ( polygon & patches ) la geometria delle mesh è ottimizzata per un disegno più veloce (alberi Octree)
Codice PHP: IMesh *geometry = Mesh->getMesh(E_Q3_MESH_GEOMETRY); if ( 0 == geometry || geometry->getMeshBufferCount() == 0) return;
Game->CurrentMapName = mapName;
//create a collision list Meta = 0;
ITriangleSelector * selector = 0; if (collision) Meta = smgr->createMetaTriangleSelector();
//IMeshBuffer *b0 = geometry->getMeshBuffer(0); //s32 minimalNodes = b0 ? core::s32_max ( 2048, b0->getVertexCount() / 32 ) : 2048; s32 minimalNodes = 2048;
MapParent = smgr->addOctreeSceneNode(geometry, 0, -1, minimalNodes); MapParent->setName ( mapName ); if ( Meta ) { selector = smgr->createOctreeTriangleSelector( geometry,MapParent, minimalNodes); //selector = smgr->createTriangleSelector ( geometry, MapParent ); Meta->addTriangleSelector( selector); selector->drop (); }
// logical parent for the items ItemParent = smgr->addEmptySceneNode(); if ( ItemParent ) ItemParent->setName ( "Item Container" );
ShaderParent = smgr->addEmptySceneNode(); if ( ShaderParent ) ShaderParent->setName ( "Shader Container" );
UnresolvedParent = smgr->addEmptySceneNode(); if ( UnresolvedParent ) UnresolvedParent->setName ( "Unresolved Container" );
FogParent = smgr->addEmptySceneNode(); if ( FogParent ) FogParent->setName ( "Fog Container" );
// logical parent for the bullets BulletParent = smgr->addEmptySceneNode(); if ( BulletParent ) BulletParent->setName ( "Bullet Container" );
Ora costruiamo uno SceneNodes per ogni Shader presente gli oggetti sono registrati nella quake mesh E_Q3_MESH_ITEMS e gli Shader ID sono registrati nel MaterialParameters come i teschi scuri, la lava animata e.. tubi verdi lampeggianti?
Codice PHP: Q3ShaderFactory ( Game->loadParam, Game->Device, Mesh, E_Q3_MESH_ITEMS,ShaderParent, Meta, false ); Q3ShaderFactory ( Game->loadParam, Game->Device, Mesh, E_Q3_MESH_FOG,FogParent, 0, false ); Q3ShaderFactory ( Game->loadParam, Game->Device, Mesh, E_Q3_MESH_UNRESOLVED,UnresolvedParent, Meta, true );
Ora costruiamo i modelli dalla Entity List
Codice PHP: Q3ModelFactory ( Game->loadParam, Game->Device, Mesh, ItemParent, false ); }
Aggiungo un SceneNode con un'icona all'albero della scena
Codice PHP: void CQuake3EventHandler::addSceneTreeItem( ISceneNode * parent, IGUITreeViewNode* nodeParent) { IGUITreeViewNode* node; wchar_t msg[128];
s32 imageIndex; list<ISceneNode*>::ConstIterator it = parent->getChildren().begin(); for (; it != parent->getChildren().end(); ++it) { switch ( (*it)->getType () ) { case ESNT_Q3SHADER_SCENE_NODE: imageIndex = 0; break; case ESNT_CAMERA: imageIndex = 1; break; case ESNT_EMPTY: imageIndex = 2; break; case ESNT_MESH: imageIndex = 3; break; case ESNT_OCTREE: imageIndex = 3; break; case ESNT_ANIMATED_MESH: imageIndex = 4; break; case ESNT_SKY_BOX: imageIndex = 5; break; case ESNT_BILLBOARD: imageIndex = 6; break; case ESNT_PARTICLE_SYSTEM: imageIndex = 7; break; case ESNT_TEXT: imageIndex = 8; break; default:imageIndex = -1; break; }
if ( imageIndex < 0 ) { swprintf ( msg, 128, L"%hs,%hs", Game->Device->getSceneManager ()->getSceneNodeTypeName ( (*it)->getType () ), (*it)->getName() ); } else { swprintf ( msg, 128, L"%hs",(*it)->getName() ); }
node = nodeParent->addChildBack( msg, 0, imageIndex );
// Add all Animators list<ISceneNodeAnimator*>::ConstIterator ait = (*it)->getAnimators().begin(); for (; ait != (*it)->getAnimators().end(); ++ait) { imageIndex = -1; swprintf ( msg, 128, L"%hs", Game->Device->getSceneManager ()->getAnimatorTypeName ( (*ait)->getType () ) );
switch ( (*ait)->getType () ) { case ESNAT_FLY_CIRCLE: case ESNAT_FLY_STRAIGHT: case ESNAT_FOLLOW_SPLINE: case ESNAT_ROTATION: case ESNAT_TEXTURE: case ESNAT_DELETION: case ESNAT_COLLISION_RESPONSE: case ESNAT_CAMERA_FPS: case ESNAT_CAMERA_MAYA: default: break; } node->addChildBack( msg, 0, imageIndex ); }
addSceneTreeItem ( *it, node ); } }
// Adds life! void CQuake3EventHandler::CreatePlayers() { Player[0].create ( Game->Device, Mesh, MapParent, Meta ); }
// Adds a skydome to the scene void CQuake3EventHandler::AddSky( u32 dome, const c8 *texture) { ISceneManager *smgr = Game->Device->getSceneManager (); IVideoDriver * driver = Game->Device->getVideoDriver();
bool oldMipMapState = driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS); driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
if ( 0 == dome ) { // irrlicht order //static const c8*p[] = { "ft", "lf", "bk", "rt", "up", "dn" }; // quake3 order static const c8*p[] = { "ft", "rt", "bk", "lf", "up", "dn" };
u32 i = 0; snprintf ( buf, 64, "%s_%s.jpg", texture, p[i] ); SkyNode = smgr->addSkyBoxSceneNode( driver->getTexture ( buf ), 0, 0, 0, 0, 0 );
if (SkyNode) { for ( i = 0; i < 6; ++i ) { snprintf ( buf, 64, "%s_%s.jpg", texture, p[i] ); SkyNode->getMaterial(i).setTexture ( 0, driver->getTexture ( buf ) ); } } } else if ( 1 == dome ) { snprintf ( buf, 64, "%s.jpg", texture ); SkyNode = smgr->addSkyDomeSceneNode( driver->getTexture( buf ), 32,32, 1.f, 1.f, 1000.f, 0, 11); } else if ( 2 == dome ) { snprintf ( buf, 64, "%s.jpg", texture ); SkyNode = smgr->addSkyDomeSceneNode( driver->getTexture( buf ), 16,8, 0.95f, 2.f, 1000.f, 0, 11); }
if (SkyNode) SkyNode->setName("Skydome"); //SkyNode->getMaterial(0).ZBuffer = video::EMDF_DEPTH_LESS_EQUAL;
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, oldMipMapState); }
// enable GUI elements void CQuake3EventHandler::SetGUIActive( s32 command) { bool inputState = false;
ICameraSceneNode * camera = Game->Device->getSceneManager()->getActiveCamera ();
switch ( command ) { case 0: Game->guiActive = 0; inputState = !Game->guiActive; break; case 1: Game->guiActive = 1; inputState = !Game->guiActive;;break; case 2: Game->guiActive ^= 1; inputState = !Game->guiActive;break; case 3: if ( camera ) inputState = !camera->isInputReceiverEnabled(); break; }
if ( camera ) { camera->setInputReceiverEnabled ( inputState ); Game->Device->getCursorControl()->setVisible( !inputState ); }
if ( gui.Window ) { gui.Window->setVisible ( Game->guiActive != 0 ); }
if ( Game->guiActive && gui.SceneTree && Game->Device->getGUIEnvironment()->getFocus() != gui.SceneTree ) { gui.SceneTree->getRoot()->clearChildren(); addSceneTreeItem ( Game->Device->getSceneManager()->getRootSceneNode(), gui.SceneTree->getRoot() ); }
Game->Device->getGUIEnvironment()->setFocus ( Game->guiActive ? gui.Window: 0 ); }
Gestione dell'input nel gioco
Codice PHP: bool CQuake3EventHandler::OnEvent(const SEvent& eve) { if ( eve.EventType == EET_LOG_TEXT_EVENT ) { return false; }
if ( Game->guiActive && eve.EventType == EET_GUI_EVENT ) { if ( eve.GUIEvent.Caller == gui.MapList && eve.GUIEvent.EventType == gui::EGET_LISTBOX_SELECTED_AGAIN ) { s32 selected = gui.MapList->getSelected(); if ( selected >= 0 ) { stringw loadMap = gui.MapList->getListItem ( selected ); if ( 0 == MapParent || loadMap != Game->CurrentMapName ) { printf ( "Loading map %ls\n", loadMap.c_str() ); LoadMap ( loadMap , 1 ); if ( 0 == Game->loadParam.loadSkyShader ) { AddSky ( 1, "skydome2" ); } CreatePlayers (); CreateGUI (); SetGUIActive ( 0 ); return true; } } } else if ( eve.GUIEvent.Caller == gui.ArchiveRemove && eve.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED ) { Game->Device->getFileSystem()->removeFileArchive( gui.ArchiveList->getSelected() ); Game->CurrentMapName = ""; AddArchive ( "" ); } else if ( eve.GUIEvent.Caller == gui.ArchiveAdd && eve.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED ) { if ( 0 == gui.ArchiveFileOpen ) { Game->Device->getFileSystem()->setFileListSystem ( FILESYSTEM_NATIVE ); gui.ArchiveFileOpen = Game->Device->getGUIEnvironment()->addFileOpenDialog ( L"Add Game Archive" , false,gui.Window ); } } else if ( eve.GUIEvent.Caller == gui.ArchiveFileOpen && eve.GUIEvent.EventType == gui::EGET_FILE_SELECTED ) { AddArchive ( gui.ArchiveFileOpen->getFileName() ); gui.ArchiveFileOpen = 0; } else if ( eve.GUIEvent.Caller == gui.ArchiveFileOpen && eve.GUIEvent.EventType == gui::EGET_DIRECTORY_SELECTED ) { AddArchive ( gui.ArchiveFileOpen->getDirectoryName() ); } else if ( eve.GUIEvent.Caller == gui.ArchiveFileOpen && eve.GUIEvent.EventType == gui::EGET_FILE_CHOOSE_DIALOG_CANCELLED ) { gui.ArchiveFileOpen = 0; } else if ( ( eve.GUIEvent.Caller == gui.ArchiveUp || eve.GUIEvent.Caller == gui.ArchiveDown ) && eve.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED ) { s32 rel = eve.GUIEvent.Caller == gui.ArchiveUp ? -1 : 1; if ( Game->Device->getFileSystem()->moveFileArchive ( gui.ArchiveList->getSelected (), rel ) ) { s32 newIndex = core::s32_clamp ( gui.ArchiveList->getSelected() + rel, 0, gui.ArchiveList->getRowCount() - 1 ); AddArchive ( "" ); gui.ArchiveList->setSelected ( newIndex ); Game->CurrentMapName = ""; } } else if ( eve.GUIEvent.Caller == gui.VideoDriver && eve.GUIEvent.EventType == gui::EGET_COMBO_BOX_CHANGED ) { Game->deviceParam.DriverType = (E_DRIVER_TYPE) gui.VideoDriver->getItemData ( gui.VideoDriver->getSelected() ); } else if ( eve.GUIEvent.Caller == gui.VideoMode && eve.GUIEvent.EventType == gui::EGET_COMBO_BOX_CHANGED ) { u32 val = gui.VideoMode->getItemData ( gui.VideoMode->getSelected() ); Game->deviceParam.WindowSize.Width = val >> 16; Game->deviceParam.WindowSize.Height = val & 0xFFFF; } else if ( eve.GUIEvent.Caller == gui.FullScreen && eve.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED ) { Game->deviceParam.Fullscreen = gui.FullScreen->isChecked(); } else if ( eve.GUIEvent.Caller == gui.Bit32 && eve.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED ) { Game->deviceParam.Bits = gui.Bit32->isChecked() ? 32 : 16; } else if ( eve.GUIEvent.Caller == gui.MultiSample && eve.GUIEvent.EventType == gui::EGET_SCROLL_BAR_CHANGED ) { Game->deviceParam.AntiAlias = gui.MultiSample->getPos(); } else if ( eve.GUIEvent.Caller == gui.Tesselation && eve.GUIEvent.EventType == gui::EGET_SCROLL_BAR_CHANGED ) { Game->loadParam.patchTesselation = gui.Tesselation->getPos (); } else if ( eve.GUIEvent.Caller == gui.Gamma && eve.GUIEvent.EventType == gui::EGET_SCROLL_BAR_CHANGED ) { Game->GammaValue = gui.Gamma->getPos () * 0.01f; Game->Device->setGammaRamp ( Game->GammaValue, Game->GammaValue, Game->GammaValue, 0.f, 0.f ); } else if ( eve.GUIEvent.Caller == gui.SetVideoMode && eve.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED ) { Game->retVal = 2; Game->Device->closeDevice(); } else if ( eve.GUIEvent.Caller == gui.Window && eve.GUIEvent.EventType == gui::EGET_ELEMENT_CLOSED ) { Game->Device->closeDevice(); } else if ( eve.GUIEvent.Caller == gui.Collision && eve.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED ) { // set fly through active Game->flyTroughState ^= 1; Player[0].cam()->setAnimateTarget ( Game->flyTroughState == 0 );
printf ( "collision %d\n", Game->flyTroughState == 0 ); } else if ( eve.GUIEvent.Caller == gui.Visible_Map && eve.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED ) { bool v = gui.Visible_Map->isChecked();
if ( MapParent ) { printf ( "static node set visible %d\n",v ); MapParent->setVisible ( v ); } } else if ( eve.GUIEvent.Caller == gui.Visible_Shader && eve.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED ) { bool v = gui.Visible_Shader->isChecked();
if ( ShaderParent ) { printf ( "shader node set visible %d\n",v ); ShaderParent->setVisible ( v ); } } else if ( eve.GUIEvent.Caller == gui.Visible_Skydome && eve.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED ) { if ( SkyNode ) { bool v = !SkyNode->isVisible(); printf ( "skynode set visible %d\n",v ); SkyNode->setVisible ( v ); } } else if ( eve.GUIEvent.Caller == gui.Respawn && eve.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED ) { Player[0].respawn (); }
return false; }
// fire if ((eve.EventType == EET_KEY_INPUT_EVENT && eve.KeyInput.Key == KEY_SPACE && eve.KeyInput.PressedDown == false) || (eve.EventType == EET_MOUSE_INPUT_EVENT && eve.MouseInput.Event == EMIE_LMOUSE_LEFT_UP) ) { ICameraSceneNode * camera = Game->Device->getSceneManager()->getActiveCamera (); if ( camera && camera->isInputReceiverEnabled () ) { useItem( Player + 0 ); } }
// gui active if ((eve.EventType == EET_KEY_INPUT_EVENT && eve.KeyInput.Key == KEY_F1 && eve.KeyInput.PressedDown == false) || (eve.EventType == EET_MOUSE_INPUT_EVENT && eve.MouseInput.Event == EMIE_RMOUSE_LEFT_UP) ) { SetGUIActive ( 2 ); }
// check if user presses the key if ( eve.EventType == EET_KEY_INPUT_EVENT && eve.KeyInput.PressedDown == false) { // Escape toggles camera Input if ( eve.KeyInput.Key == irr::KEY_ESCAPE ) { SetGUIActive ( 3 ); } else if (eve.KeyInput.Key == KEY_F11) { // screenshot are taken without gamma! IImage* image = Game->Device->getVideoDriver()->createScreenShot(); if (image) { core::vector3df pos; core::vector3df rot; ICameraSceneNode * cam = Game->Device->getSceneManager()->getActiveCamera (); if ( cam ) { pos = cam->getPosition (); rot = cam->getRotation (); }
static const c8 *dName[] = { "null", "software", "burning", "d3d8", "d3d9", "opengl" };
snprintf(buf, 256, "%s_%ls_%.0f_%.0f_%.0f_%.0f_%.0f_%.0f.jpg", dName[Game->Device->getVideoDriver()->getDriverType()], Game->CurrentMapName.c_str(), pos.X, pos.Y, pos.Z, rot.X, rot.Y, rot.Z ); path filename ( buf ); filename.replace ( '/', '_' ); printf ( "screenshot : %s\n", filename.c_str() ); Game->Device->getVideoDriver()->writeImageToFile(image, filename, 100 ); image->drop(); } } else if (eve.KeyInput.Key == KEY_F9) { s32 value = EDS_OFF;
Game->debugState = ( Game->debugState + 1 ) & 3;
switch ( Game->debugState ) { case 1: value = EDS_NORMALS | EDS_MESH_WIRE_OVERLAY | EDS_BBOX_ALL; break; case 2: value = EDS_NORMALS | EDS_MESH_WIRE_OVERLAY | EDS_SKELETON; break; }
Imposta il debug della mappa on/off
Codice PHP: debugState = debugState == EDS_OFF ? EDS_NORMALS | EDS_MESH_WIRE_OVERLAY | EDS_BBOX_ALL: EDS_OFF; if ( ItemParent )
{ list<ISceneNode*>::ConstIterator it = ItemParent->getChildren().begin(); for (; it != ItemParent->getChildren().end(); ++it) { (*it)->setDebugDataVisible ( value ); } }
if ( ShaderParent ) { list<ISceneNode*>::ConstIterator it = ShaderParent->getChildren().begin(); for (; it != ShaderParent->getChildren().end(); ++it) { (*it)->setDebugDataVisible ( value ); } }
if ( UnresolvedParent ) { list<ISceneNode*>::ConstIterator it = UnresolvedParent->getChildren().begin(); for (; it != UnresolvedParent->getChildren().end(); ++it) { (*it)->setDebugDataVisible ( value ); } }
if ( FogParent ) { list<ISceneNode*>::ConstIterator it = FogParent->getChildren().begin(); for (; it != FogParent->getChildren().end(); ++it) { (*it)->setDebugDataVisible ( value ); } }
if ( SkyNode ) { SkyNode->setDebugDataVisible ( value ); }
} else if (eve.KeyInput.Key == KEY_F8) { // set gravity on/off Game->gravityState ^= 1; Player[0].cam()->setGravity ( getGravity ( Game->gravityState ? "earth" : "none" ) ); printf ( "gravity %s\n", Game->gravityState ? "earth" : "none" ); } else if (eve.KeyInput.Key == KEY_F7) { // set fly through active Game->flyTroughState ^= 1; Player[0].cam()->setAnimateTarget ( Game->flyTroughState == 0 ); if ( gui.Collision ) gui.Collision->setChecked ( Game->flyTroughState == 0 );
printf ( "collision %d\n", Game->flyTroughState == 0 ); } else if (eve.KeyInput.Key == KEY_F2) { Player[0].respawn (); } else if (eve.KeyInput.Key == KEY_F3) { if ( MapParent ) { bool v = !MapParent->isVisible (); printf ( "static node set visible %d\n",v ); MapParent->setVisible ( v ); if ( gui.Visible_Map ) gui.Visible_Map->setChecked ( v ); } } else if (eve.KeyInput.Key == KEY_F4) { if ( ShaderParent ) { bool v = !ShaderParent->isVisible (); printf ( "shader node set visible %d\n",v ); ShaderParent->setVisible ( v ); if ( gui.Visible_Shader ) gui.Visible_Shader->setChecked ( v ); } } else if (eve.KeyInput.Key == KEY_F5) { if ( FogParent ) { bool v = !FogParent->isVisible (); printf ( "fog node set visible %d\n",v ); FogParent->setVisible ( v ); if ( gui.Visible_Fog ) gui.Visible_Fog->setChecked ( v ); }
} else if (eve.KeyInput.Key == KEY_F6) { if ( UnresolvedParent ) { bool v = !UnresolvedParent->isVisible (); printf ( "unresolved node set visible %d\n",v ); UnresolvedParent->setVisible ( v ); if ( gui.Visible_Unresolved ) gui.Visible_Unresolved->setChecked ( v ); } } }
// check if user presses the key C ( for crouch) if ( eve.EventType == EET_KEY_INPUT_EVENT && eve.KeyInput.Key == KEY_KEY_C ) { // crouch ISceneNodeAnimatorCollisionResponse *anim = Player[0].cam (); if ( anim && 0 == Game->flyTroughState ) { if ( false == eve.KeyInput.PressedDown ) { // stand up anim->setEllipsoidRadius ( vector3df(30,45,30) ); anim->setEllipsoidTranslation ( vector3df(0,40,0));
} else { // on your knees anim->setEllipsoidRadius ( vector3df(30,20,30) ); anim->setEllipsoidTranslation ( vector3df(0,20,0)); } return true; } } return false; }
metodo useItem
Codice PHP: void CQuake3EventHandler::useItem( Q3Player * player) { ISceneManager* smgr = Game->Device->getSceneManager(); ICameraSceneNode* camera = smgr->getActiveCamera();
if (!camera) return;
SParticleImpact imp; imp.when = 0;
// get line of camera
vector3df start = camera->getPosition();
if ( player->WeaponNode ) { start.X += 0.f; start.Y += 0.f; start.Z += 0.f; }
vector3df end = (camera->getTarget() - start); end.normalize(); start += end*20.0f;
end = start + (end * camera->getFarValue());
triangle3df triangle; line3d<f32> line(start, end);
// get intersection point with map scene::ISceneNode* hitNode; if (smgr->getSceneCollisionManager()->getCollisionPoint( line, Meta, end, triangle,hitNode)) { // collides with wall vector3df out = triangle.getNormal(); out.setLength(0.03f);
imp.when = 1; imp.outVector = out; imp.pos = end;
player->setAnim ( "pow" ); player->Anim[1].next += player->Anim[1].delta; } else { // doesnt collide with wall vector3df start = camera->getPosition(); if ( player->WeaponNode ) { //start.X += 10.f; //start.Y += -5.f; //start.Z += 1.f; }
vector3df end = (camera->getTarget() - start); end.normalize(); start += end*20.0f; end = start + (end * camera->getFarValue()); }
// create fire ball ISceneNode* node = 0; node = smgr->addBillboardSceneNode( BulletParent,dimension2d<f32>(10,10), start);
node->setMaterialFlag(EMF_LIGHTING, false); node->setMaterialTexture(0, Game->Device->getVideoDriver()->getTexture("fireball.bmp")); node->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false); node->setMaterialType(EMT_TRANSPARENT_ADD_COLOR);
f32 length = (f32)(end - start).getLength(); const f32 speed = 5.8f; u32 time = (u32)(length / speed);
ISceneNodeAnimator* anim = 0;
// set flight line
anim = smgr->createFlyStraightAnimator(start, end, time); node->addAnimator(anim); anim->drop();
snprintf ( buf, 64, "bullet: %s on %.1f,%1.f,%1.f", imp.when ? "hit" : "nohit", end.X, end.Y, end.Z ); node->setName ( buf );
anim = smgr->createDeleteAnimator(time); node->addAnimator(anim); anim->drop();
if (imp.when) { // create impact note imp.when = Game->Device->getTimer()->getTime() + (time + (s32) ( ( 1.f + Noiser::get() ) * 250.f )); Impacts.push_back(imp); }
// play sound }
// rendered when bullets hit something void CQuake3EventHandler::createParticleImpacts( u32 now ) { ISceneManager* sm = Game->Device->getSceneManager();
struct smokeLayer { const c8 * texture; f32 scale; f32 minparticleSize; f32 maxparticleSize; f32 boxSize; u32 minParticle; u32 maxParticle; u32 fadeout; u32 lifetime; };
smokeLayer smoke[] = { { "smoke2.jpg", 0.4f, 1.5f, 18.f, 20.f, 20, 50, 2000, 10000 }, { "smoke3.jpg", 0.2f, 1.2f, 15.f, 20.f, 10, 30, 1000, 12000 } };
u32 i; u32 g; s32 factor = 1; for ( g = 0; g != 2; ++g ) { smoke[g].minParticle *= factor; smoke[g].maxParticle *= factor; smoke[g].lifetime *= factor; smoke[g].boxSize *= Noiser::get() * 0.5f; }
for ( i=0; i < Impacts.size(); ++i) { if (now < Impacts[i].when) continue;
// create smoke particle system IParticleSystemSceneNode* pas = 0;
for ( g = 0; g != 2; ++g ) { pas = sm->addParticleSystemSceneNode(false, BulletParent, -1, Impacts[i].pos);
snprintf ( buf, 64, "bullet impact smoke at %.1f,%.1f,%1.f", Impacts[i].pos.X,Impacts[i].pos.Y,Impacts[i].pos.Z); pas->setName ( buf );
// create a flat smoke vector3df direction = Impacts[i].outVector; direction *= smoke[g].scale; IParticleEmitter* em = pas->createBoxEmitter( aabbox3d<f32>(-4.f,0.f,-4.f,20.f,smoke[g].minparticleSize,20.f), direction,smoke[g].minParticle, smoke[g].maxParticle, video::SColor(0,0,0,0),video::SColor(0,128,128,128), 250,4000, 60);
em->setMinStartSize (dimension2d<f32>( smoke[g].minparticleSize, smoke[g].minparticleSize)); em->setMaxStartSize (dimension2d<f32>( smoke[g].maxparticleSize, smoke[g].maxparticleSize));
pas->setEmitter(em); em->drop();
// particles get invisible IParticleAffector* paf = pas->createFadeOutParticleAffector( video::SColor ( 0, 0, 0, 0 ), smoke[g].fadeout); pas->addAffector(paf); paf->drop();
// particle system life time ISceneNodeAnimator* anim = sm->createDeleteAnimator( smoke[g].lifetime); pas->addAnimator(anim); anim->drop();
pas->setMaterialFlag(video::EMF_LIGHTING, false); pas->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false); pas->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR ); pas->setMaterialTexture(0, Game->Device->getVideoDriver()->getTexture( smoke[g].texture )); }
// play impact sound #ifdef USE_IRRKLANG if (irrKlang) { audio::ISound* sound = irrKlang->play3D(impactSound, Impacts[i].pos, false, false, true); if (sound) { // adjust max value a bit to make to sound of an impact louder sound->setMinDistance(400); sound->drop(); } } #endif // delete entry Impacts.erase(i); i--; } }
..continua nel Tutorial 21b
|