Een introductie tot het KiCodil framework
Quickstart Maak een nieuw executable project Include ‘KCD.h’ (include KiCodil) Call: KCD::Run(HINSTANCE, int ShowCommand, CBGameManager); HINSTANCE & ShowCommand zijn parameter van de WinMain CBGameManager is een instance het type CBGameManager (vb: KiliRun.h) Voorzie een klasse die KCD::CBGameManager implementeerd GetContentInputPath en GetContentOutputPath en GetResourceObject: zijn voor de ContentPipeline (zie later) CreateStartupLevel : Maak een start-level aan door KCD::CreateILevel(tstring const sName, D3DXVECTOR3 const& vGravity, CBLevelManager *pManager); te callen RegisterCommands: is de plaats om Commands te registreren (zie later) CreateStartupFrameListener: optioneel
Levelstart Maak een level met KCD::CreateILevel(tstring const sName, D3DXVECTOR3 const& vGravity, CBLevelManager *pManager); sName: level-naam vGravity: level-zwaartekracht pManager: instance van een callback-klasse die de level zal managen (vb: KiliRunLevel.h) ○ LevelUpdate: Zal éénmaal per frame worden aangeroepn voor level-logic ○ LevelLoad: Zal worden aangeroepen tijdens de KCD::CreateILevel(…)-call. Dir is de enige plaats dat er ooit gebruik kan worden gemaakt van de ILevelLoader, en is dus de enige plaats om later level-inhoud in te laden ○ LevelActivate: Zal telkens worden aangeroepen wanneer een level als active wordt ingesteld (enkel het actieve level zal tijdens de GameCycle verwerkt worden) ○ LevelUnloaded: failsafe indien er nog objecten per level moeten worden verwijderd ○ LevelPhysXSceneCreated: geeft de coder de kans om direct enkele parameters van de scene te wijzigen indien nodig
ContentPipeline Verwerkt alle ingame-content (vb: textures, shaders, models, …) Heeft een input-/output-directory (zie CBGameManager) Inputdirectory: alle raw data Outputdirectory: alle data binair zoals ze ingame gebruikt zullen worden) De contentpipeline voorziet in een drieledige functionaliteit Het omzetten van raw-data naar binaire-data Het bijhouden van een interne database van alle content Het reference-counten van alle content die via de pipeline ingame gebruikt wordt Gebruikt een callback om instances van classes te linken aan content-files (zie KiliRun::GetResourceObject(tstring);)
CPResource Is de parentclass van alle objecten die door de ContentPipeline worden verwerkt Vraag een CPResource op door: Include ‘ContentPipeline.h ’ Content::ContentLoad(Content::CPResourceLoader *, tstring sTable, tstring sItem); ○ CPResourceLoader wordt opgevraagd met KCD::GetResourceLoader(); ○ sTable: De naam van de content-file die de verwijzing naar de raw-data-file bijhoudt ○ sItem: De naam van de raw-data-file binnen de table (zoals gedefinieerd in de content-file) Cast de verkregen CPResource* naar het juiste object-type
Vb:.content KiliRun\SpriteShader.fx name="KiliRun“ : zie sTable uit de vorige slide keeploaded="true“ : houdt de resources altijd in RAM resource="Effect“ : Verwijzing naar de interne klasse (zie KiliRun::GetResourceObject(tstring);) name="SpriteShader“ : zie sItem uit de vorige slide KiliRun\SpriteShader.fx : path naar de raw-data-file t.o.v. de content-file
LevelLoad Zie KiliRunLevel::LevelLoad(KCD::ILevelLoader *pLoader); (zie slide LevelStart (LevelLoad() is een overrideable method van KCD::CBGameManager)) De programmeur is verplicht om via deze LevelLoad() alle Controllers, Entities en Camera’s aan te maken die hij ooit in deze level wilt gebruiken Contollers, Entities en Cameras worden aangemaakt door de overeenkomstige methodes van KCD::ILevelLoader::Create(…) Om een Entity aan te maken kan de programmeur één of meerdere ‘DataProviders’ opgeven: (deze zijn allen optioneel) KCD::BaseMaterial* : Definieerd de color-rendering KCD:: BasePhysXCreator* : Definieerd de creatie van instances voor physx KCD:: BaseMesh* : Definieerd de vorm van de rendering KCD:: BaseLight* : Definieerd de light-rendering KCD:: BaseAnimation* : Definieerd de mogelijke animaties KCD:: BaseParticles* : Definieerd de particle emmisionµ
EntityInstancing schema
EntityInstancing legend Het level beheert alle content zoals aangegeven Een pointer naar het level moet worden meegegeve naar elk KCD::LevelObject (vb: KCD::BaseMesh*, KCD::BaseMaterial*, …) Entities worden aangemaakt via: MyLevelLoaderPointer CreateIEntity(…); Nodes worden aangemaakt als childnodes van een parent: MyLevelPointer GetRootINode() CreateChildINode(…); EntityInstances worden aangemaakt door: Een Entity (by pointer of by name) toe te kennen aan een Node: MyNodePointer CreateEntityInstance(…); Een Entity mee te geven tijdens de creatie van de Node:MyLevelPointer GetRootINode() CreateChildINode(…); EntityInstances zijn de objecten die uiteindelijk gerenderd worden
EntityInstancing vb // Create the dataproviders within the KCD::ILevel-pointer BaseMaterial *pMaterial = new MyMaterial(…params…, pLevel); BaseMesh *pMesh = new MyMesh(…params…, pLevel); BasePhysXCreator *pPhysX = new MyPhysX(…params…, pLevel); // Create the entity on the KCD::ILevelLoader-pointer pLevel->CreateIEntity(_T(“MyEntity"), pMesh, pMaterial, pPhysX); // Create a node and add the entity to it KCD::Inode *pNode = NULL; pNode = pLevel->GetIRootNode()->CreateChildINode(_T(“MyEntity“)); pNode->SetPosition(D3DXVECTOR(10, 5, 100));
Ilevel vs ILevelLoader KCD::ILevelLoader inhertits KCD::ILevel De pointer naar KCD::ILevelLoader geeft toegang tot enkele extra methods die voorzien in de mogelijkheid om Controllers, Cameras en Entities aan te maken De pointer naar KCD::ILevel heeft deze functionaliteit niet De pointer naar KCD::ILevelLoader is enkel geldig binnen de KCD::CBGameManagement::LevelLoad(ILevelLoader *pLoader) call (zie slide over LevelStart) Het is dus enkel mogelijk om nieuwe Controllers, Cameras en Entities aan te maken tijdens de levelload() !! Het aanmaken van Nodes die optioneel linken naar Entities is steeds mogelijk !! (vooropgesteld dat deze Entity is aangemaakt geweest)
Cameras Per level kunnen er meerdere cameras zijn Elke level heeft minstens één camera nodig (Er wordt automatisch een ‘GodCamera’ aangemaakt: MyLevelPointer GetICamera(_T(‘GodCamera’)); ) Cameras worden ook aangemaakt tijdens de levelload: MyLevelLoaderPointer CreateICamera(…); Cameras hebben een naam, en kunnen m.b.v. die naam uit de level opgevragen worden/geactiveerd worden Tijdens het begin van de GameCycle wordt de actieve Camera doorgegeven naar de renderer alwaar de nodige gegevens omwille van threadsafety gekopieerd worden !! Op dit moment werkt de orthogonale projectie NIET !!
Commands Om te kunnen reageren op userinput heeft KiCodil een intern systeem dat userinput linkt aan game-specifieke-commandos Deze Commands zijn game-wide (ze worden dus ingesteld tijdens de gamestartup, en NIET tijdens de levelload) Deze Commands worden bijgehouden in de ‘CommandList’ Deze CommandList kan ten allen tijde worden opgevraagd via: KCD::GetCommandList() Een Command wordt aangemaakt m.b.v. een CommandID tijdens de KCD::CBGameManager::RegisterCommand(…) call (zie Quickstart-slide en ‘KiliRun.cpp’) Een CommandID maak je aan via: ‘Commands.h’ : COMMAND_H(MyCommandIDName); ‘Commands.cpp’ : COMMAND_CPP(MyCommandIDName, MyCommandIDUniqueIdentifier);
Actions Zijn een simpele manier om objecten events aan elkaar te laten doorgeven, zonder toegang te moeten hebben tot elkaar pointers Een Action wordt aangemaakt: ‘Actions.cpp’ : ACTION_CPP(MyActionName); ‘Actions.h’ : ACTION_H(MyActionName); Een Action wordt getriggerd: MyAction.Trigger( pUserData ); pUserData is een optionele pointer Een Action wordt opgevangen: M.b.v. een controller (zie volgende slide) M.b.v. een ActionListener: ○ Implementeer KCD::ActionListener ○ Voeg de ActionListener toe aan de Action: MyAction.AddListener(MyListener)
Controllers Controllers zijn objecten die aan een level gebonden zijn: MyLevelLoaderPointer CreateIController(…); Controllers kunnen ten allen tijde worden opgevraagd vanuit de level: MyLevelPointer GetIController(_T(‘MyControllerName’)); Een object dat ‘gecontrolleerd’ moet worden erft over van KCD::Controleable Zulks een ‘controlleerbaar’ object wordt gelinkt aan één of meerdere controllers: MyControllerPointer LinkToController(MyControleablePointer); Een controller moet zichzelf registreren voor alle controls die hij nodig heeft om zijn controlleables te kunnen laten functioneren (zie volgende slides)
ControlledUpdate
ControlledUpdate example // Maak de controller aan en registreer om elk frame te updaten KCD::IController *pCont = NULL; UserDataObject *pUserData = NULL; pCont = pLevel CreateIController(_T(‘MyController’), pUserData); pCont RegisterForUpdate(); // De juiste klasse Class MyClass : public KCD::Controleable { public: void ContolledUpdate(UpdateData const&, IController*); }; // Link een instance aan de controller pCont LinkToController(MyControleablePointer);
ControlledAction
ControlledAction example // Maak de controller aan en registreer om te reageren op jouw action KCD::IController *pCont = NULL; UserDataObject *pUserData = NULL; pCont = pLevel CreateIController(_T(‘MyController’), pUserData); pCont RegisterForAction(MyAction); // De juiste klasse Class MyClass : public KCD::Controleable { public: void ContolledAction(UpdateData const&, Action&, IController*); }; // Link een instance aan de controller pCont LinkToController(MyControleablePointer);
ControlledCommand
ControlledCommand example // Maak de controller aan en registreer om te reageren op jouw command KCD::IController *pCont = NULL; UserDataObject *pUserData = NULL; pCont = pLevel CreateIController(_T(‘MyController’), pUserData); pCont RegisterForCommand(MyCommandID); // De juiste klasse Class MyClass : public KCD::Controleable { public: void ContolledCommand(UpdateData const&, ICommand*, IController*); }; // Link een instance aan de controller pCont LinkToController(MyControleablePointer);
Intermezzo: I? De meeste pointers m.b.t. het level hebben een typename die begint met I en vertonen totaal geen datamembers ? Vb: ILevel, IEntity, ICamera, ICommand, … De ‘I’ staat voor Interface a.k.a. Pure Virtual Class Hierdoor kan KiCodil een groot deel van zijn interne werking afschermen van de buitenwereld Hierdoor wordt de GamePlay programmeur niet misleid door methods en datamembers die hij niet zou mogen gebruiken ‘I’-klasses worden DLL-geëxporteerd, hun implementatie niet
KCD::INode Heeft ALTIJD een parent (uitzondering: de rootnode) Kan oneindig veel children hebben Kan gelinkt zijn naar een EntityInstance Bepaald zijn positie ALTIJD t.o.v. zijn parent Kan enkel worden aangemaakt via een reeds bestaande Inode: KCD::Inode::CreateChildINode(…) Er is in elke level steeds minstens één INode: KCD::ILevel::GetRootINode()
KCD::IEntity Is vergelijkbaar met een container: Houdt de dataproviders bij (vb: BaseMesh*, BaseMaterial*, …) Houdt een per-level unieke naam bij Kan enkel worden aangemaakt via: KCD::ILevelLoader::CreateIEntity(…)
KCD::IEntityInstance Is een klasse die intern wordt aangemaakt, telkens wanneer er een KCD::IEntity* wordt gelinkt aan een KCD::INode* (zie schema) Beheert de instancing van de data die via de KCD::IEntity beschikbaar is Intern is dit de klasse die wordt doorgegeven naar de SceneGraph en de RenderGraph tijdens de Sychronization