Jumat, 23 April 2010

Membuat Skenario

Sebuah Game apalagi pada genre2 khusus seperti RPG (Role Playing Game), RTS (Real Time Strategy), Adventure dll. tanpa sebuah skenario yang menarik seolah sayur tanpa kuah, walaupun game tersebut sangat adiktif tetapi tanpa adanya suatu cerita khusus yang melatarbelakangi kejadian2 dalam game tersebut, rasa-rasanya game tersebut jadi hambar begitu kita menyelesaikannya.



Sebagai seorang developer game, tentunya ingin tahu khan bagaimana cara membuat skenario game yang keren agar setiap orang yang memainkan game kita akan terus teringat sepanjang masa, ada beberapa tips yang mau saya bagikan pada para pembaca semua, semoga dapat bermanfaat. OK, mari kita mulai pada tips yang pertama…

Tips Number One:

Jangan memulai dengan cara yang biasa-biasa saja, contohnya:

Pada Suatu hari terdapat seorang anak yang baik hati dan tidak sombong,
namanya...

atau begini:

Cerita ini berkisah tentang seorang pahlawan yang menyelamatkan seorang
putri dari cengkraman monster yang jahat...

nah model cerita seperti ini akan membuat orang yang membaca ceritanya akan bosan sejak awal. Atau ceritanya mudah ditebak.

Alangkah lebih baik kalau ceritanya dimulai dengan cara yang lebih sensasional seperti:

Lari..., dan aku terus berlari,
Suara-suara itu terus menderu di belakangku,
"kembalilah pada kami...," seru salah satu suara yang memekakkan telingaku,
"Kami tidak akan melukaimu...," seru suara serak lain,
Aku tidak pedulikan suara-suara itu, aku terus berlari...

Atau seperti ini:

Enthrea...,
Tempat di mana perang terus terjadi...,
Tempat di mana pertikaian tak kuasa tuk berhenti...,
Tolong..., tolonglah kami...,
Kami butuh seseorang untuk menghentikan penderitaan kami...
Tapi siapa...?

Buatlah orang yang mengikuti cerita penasaran sejak awal kali mereka mengikuti ceritanya, hal seperti ini sering saya temui pada cerita Game seperti Final Fantasy, contohnya FFVII (Cloud dkk. turun dari Kereta Api lalu meledakkan Mako Reactor No.1), hal ini menimbulkan pertanyaan mengapa mereka meledakkan Mako Reactor? Siapa sebenarnya Cloud dkk? FFVIII (Scene awal di mana Squall bertarung melawan Seifer) yang membawa kita pada pertanyaan Mengapa Squall bertarung melawan Seifer? Ada hubungan apa mereka sebenarnya?, dll, kemudian pada Valkyrie Profile: Silmeria (Tiba-tiba Alicia/Silmeria dikejar-kejar oleh Hrist). Cerita model begini juga sering terdapat pada banyak RPG lainnya.

Begitu sesorang penasaran akan ceritanya, maka cerita dalam game tersebut akan selalu diikuti dan akan selalu ditunggu kelanjutannya. Jadi jangan buat awalan yang biasa-biasa saja. Nah untuk tips berikutnya, saya tunggu dulu komentar dari para pembaca, OK…

Nah udah baca tips pertama tentang membuat skenario game yang keren bagian 1? Tulisan tersebut saya post juga di gamedevid dan mendapat sambutan cukup hangat, hal ini bisa kita klik di gamedevid forum ada yang mau beri komentar lain? saya tunggu ya…, nah tanpa berlama-lama lagi, maka saya akan menambahkan sebuah tips lagi. Yuk kita lihat bareng-bareng.

Tips number two:

Jangan lupakan latar belakang tiap karakter utama, mengapa mereka terlibat dalam cerita.

Namun jangan langsung mengeksposnya habis-habisan, tetapi, biarkan pemain membuka sedikit demi sedikit tentang latar belakang sang karakter melalui event dalam game, ketika sang karakter berdialog dengan karakter lain, pikiran sang karakter, atau perkataan orang lain tentang karakter tersebut, bahkan dari skill yang dipelajari sang karakter ketika dia naik level.

Apabila sepanjang game, ternyata karakter utama kita memiliki latar belakang tipikal cerita yang biasa-biasa saja, mungkin kita tidak akan terlalu kaget ketika mengetahuinya, misalnya:

Sebut saja si A, seorang pria tampan yang baik hati, lugu dan memiliki rasa keadilan tinggi dia harus berjuang melawan seorang raja yang kejam dan bertangan besi untuk membebaskan para penduduk dari cengkraman raja tersebut...

hal ini memang bagus untuk karakter utama, hanya saja gregetnya kurang, apalagi kalau karakter tersebut kita buat tanpa cacat, misalnya dia tidak pernah berbuat salah, selalu menolong dan selalu menang melawan kejahatan, mungkin ini cocok untuk game2 bagi adik2 kita yang perlu diajari tentang kebaikan selalu menang melawan kejahatan. Tetapi untuk remaja dan dewasa, mungkin hal ini sudah klise dan membosankan.

Coba buat karakter utama, yang pada akhirnya akan membentuk latar belakang seperti contoh ini:

Floodz Amadeus, seorang pria yang merupakan seorang prajurit dari pasukan pembebas, pasukan ini mulanya bertujuan mulia untuk membebaskan rakyat dari kekejaman pemerintah yang ada di Enthrea saat itu, namun tujuan pasukan pembebas ini berbelok setelah merasakan enaknya berkuasa, sehingga mereka mulai menghancurkan para penduduk yang menjadi pendukung sang pemerintah.
Floodz yang mengetahui hal tersebut berusaha dihabisi oleh salah satu pimpinan dari pasukan pembebas yang ternyata adalah sahabatnya sendiri. Saat ia akan dibunuh, beberapa rekan prajurit pasukan tersebut mengorbankan diri agar ia selamat. Floodz depresi, apalagi masyarakat memandang prajurit pasukan pembebas adalah pembunuh berdarah dingin dan pemerintah mengejar2 dia sebagai buronan hukuman mati. Saat itulah dia menemukan secercah harapan…

(diambil dari Soldiers of Heaven, proyek game RPG saya yang saya buat dengan RPG Maker 2003)

Di lain pihak kita akan membuat karakter wanita untuk mendampingi karakter utama seperti ini:

Si B, putri dari kerajaan X yang jatuh cinta pada A dan mengikuti petualangan si A untuk membasmi kejahatan.

Karakter B dengan latar belakang seperti ini akan mudah dilupakan orang, dan tampaknya porsi perannya hanya sebagai pendamping dan pelengkap bagi karakter A. Jadi alangkah lebih baik jika karakter tersebut dibuat seperti ini melalui event-event dalam game:

Simphony Harmonia, seorang gadis desa yang desanya telah dihancurkan oleh pasukan pembebas di mana Simphony melihat dengan mata kepalanya sendiri Floodz terlibat dalam menghabisi penduduk desa termasuk keluarganya. Pertemuan berikutnya dengan Floodz adalah saat Floodz hampir dibunuh oleh sang pemimpin pasukan.
Hati kecil Simphony bergetar untuk menolongnya, tetapi ia mengingat akan masa lalu Floodz yang membunuh keluarganya dan menghancurkan masa depannya. Dengan berlinang air mata akhirnya Simphony memutuskan untuk menolong Floodz, dan…

(diambil dari Soldiers of Heaven, proyek game RPG saya yang saya buat dengan RPG Maker 2003)

Lalu untuk karakter musuh utama, biasanya akan muncul seperti ini:

Seorang raja yang serakah dan kejam, ia haus kekuasaan dan ingin menguasai seluruh dunia.

Tipikal musuh seperti ini juga sudah tidak asing lagi di telinga kita dan sudah kurang menarik bagi sebuah game yang seperti RPG. Coba buat seperti ini:

Sarx, ia tidak pernah dikenal orang, ia tidak pernah diingat orang, ia hanyalah seorang anak yang ibunya dihukum mati di depan rakyat banyak karena disangka penyihir dan ia tidak pernah mengenal sang ayah yang meninggalkan ibunya saat ia masih dalam kandungan. Sarx kecil hidup kesepian dan tanpa kasih sayang, bahkan kalau ia matipun tidak ada yang peduli. Di balik itu semua ia adalah seorang yang sangat cerdas dan pekerja keras, dengan berbekal kegigihan dan kerja kerasnya, akhirnya ia berhasil duduk sebagai seorang yang paling berkuasa dalam pemerintahan.
Sarx hanya ingin membuktikan kalau seorang anak yang tak diinginkan dapat menjadi orang besar yang berhasil. Sayang, pertemuannya dengan Mardhuk, sang penasehat pemerintahan, membuat sifatnya berubah menjadi orang yang penuh angkara murka dan kedengkian. Ia selalu menuruti keinginan Mardhuk walaupun hal tersebut menghancurkan reputasi dan masa depannya, karena Mardhuk berjanji akan menghidupkan kembali sang ibu yang sangat ia cintai…

(diambil dari Soldiers of Heaven, proyek game RPG saya yang saya buat dengan RPG Maker 2003)

Nah dengan latar belakang yang kompleks begitu, maka sang karakter utama akan mendapat porsi yang selayaknya dalam game tersebut, dan pemain menjadi turut merasakan perasaan si karakter utama, karena menurut saya karakter yang menarik adalah karakter yang “tidak sempurna”, dan karakter seperti ini lebih manusiawi dan dekat dengan para pemainnya.

Ada beberapa game yang sangat bagus dengan memberikan peran karakter utama pada lebih dari 1 orang, contohnya Final Fantasy VI, di mana setiap karakter memiliki latar belakang yang sangat kompleks (Saya sampai bingung, karakter utamanya Terra, Celes atau Locke sih? Tapi semua karakter lainnya punya latar belakang yang bagus), kemudian pada Riviera:The Promised Land di mana setiap karakter (Ein, Lina, Fia, Serene, Cierra) memiliki latar belakang yang sama kuat untuk melawan kehendak dewa, dan tokoh antagonisnya (Ledah) memiliki suatu latar belakang khusus mengapa ia harus melawan sang tokoh utama.

Dengan latar belakang yang mengena, saya rasa cerita dalam game kita akan semakin ditunggu dikenang oleh siapapun yang memainkannya.




Sumber 1 | 2

Minggu, 11 April 2010

tutorial ogre




OGRE Basic tutorial












Pada Saat setting applikasi kita masih menggunakan class (tutorial application) yang inherit dari class OGRE example Application. Sekarang kita akan mencoba buat class applikasi OGRE sendiri. Ubah Main.cpp seperti dibawah ini :


#include
#include

using namespace Ogre ;

class TutorialApplication
{

public:
TutorialApplication()
{
}
~TutorialApplication()
{
}
void go()
{
}
};

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"

INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
int main(int argc, char **argv)
#endif
{
// Create application object
TutorialApplication app;
try {
app.go();
} catch( Exception& e ) {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
MessageBoxA( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
fprintf(stderr, "An exception has occured: %s\n",
e.getFullDescription().c_str());
#endif
}

return 0;
}




Pada kode diatas kita membaut class TutorialApplication dengan sebuah fungsi void go(), yang nantinya akan dipanggil di fungsi main. Jika kita membuka ExampleApplication.h maka akan banyak kita temui fungsi – fungsi seperti setup(), createCamera,createViewport,dll.

Pada latihan kali ini kita hanya membuat 1 fungsi go() saja dan semua code untuk class TutorialApplication akan kita letakkan disana. Ok, kita mulai saja letakkan code berikut pada Main.cpp class TutorialApplication, fugnsi Void go() :

1. Hal yang pertama akan kita buat adalah objek Ogre::Root, yang merupakan inti dari Ogre

// Create OGRE Root
Ogre::Root *mRoot = new Root();


2. Kita beri tahu Ogre dimana letak Resource ( scripts, texture, model, particle, dll ). Path untuk Resource ada di file resources.cfg, file tersebut bisa kita temukan di cobaOgre/bin/debug. Kita akan meLoad resources.cfg dengan menggunakan Ogre::ConfigFile dan memparsing isinya (path dari resources) kedalam ResourceGroupManager

Ogre::ConfigFile cf;
cf.load("resources.cfg");
ConfigFile::SectionIterator seci = cf.getSectionIterator();
while (seci.hasMoreElements())
{
String secName = seci.peekNextKey();
ConfigFile::SettingsMultiMap *settings = seci.getNext();
ConfigFile::SettingsMultiMap::iterator i;
for (i = settings->begin(); i != settings->end(); ++i)
{
String typeName = i->first;
String archName = i->second;
ResourceGroupManager::getSingleton().addResourceLocation(archName, typeName, secName);
}
}




3. Memunculkan Ogre config Dialog ( Gambar 1.2 ) agar user bisa mengeset Rendering Subsystem (DirectX / OpenGL ) dan Rendering System Options (FullScreen, video Mode, dll). Apabila user membatalkan config Dialog maka Ogre::Root akan dihapus.



// Show OGRE config Dialog
if(!mRoot->showConfigDialog())
{
delete mRoot;
throw Exception(52, "User canceled the config dialog!","Ogre Config Dialog");
}

4.Membuat Ogre::RenderWindow, Window untuk tempat kita merender Ogre

Ogre::RenderWindow* window = mRoot->initialise(true, "Ogre Head Application");

5.Membuat Scene , menambah Camera pade scene dan menambah Viewport pada Camera

//create Scene
Ogre::SceneManager* sceneMgr = mRoot->createSceneManager(ST_EXTERIOR_CLOSE);
//createCamera
Ogre::Camera* camera = sceneMgr->createCamera("SimpleCamera");
camera->setPosition(Vector3(100,100,200));
camera->lookAt(Vector3(0,0,0));
camera->setNearClipDistance(4);
// Create one viewport
Ogre::Viewport* viewPort = window->addViewport(camera);


6.initialisasi Resource Group

// init Resource Group
ResourceGroupManager::getSingleton().initialiseAllResourceGroups();


7.Menambah Sesuatu ( OgreHead.mesh dan SkyDome ) pada Scene

// insert something
sceneMgr->setAmbientLight( ColourValue( 1, 1, 1 ) );
Ogre::Entity *ent1 = sceneMgr->createEntity( "OgreHead", "ogrehead.mesh" );
Ogre::SceneNode *node1 = sceneMgr->getRootSceneNode()->createChildSceneNode( "OgreHeadNode" );
node1->attachObject( ent1 );
node1->setPosition(Vector3(0,0,0));
sceneMgr->setSkyDome(true, "Examples/CloudySky", 5, 8);



8.Setup OIS ( Object Oriented Input System ) dengan Ogre

// Setup Input System OIS with OGRE
size_t windowHnd = 0;
std::ostringstream windowHndStr;
OIS::ParamList pl;
Ogre::RenderWindow *win = mRoot->getAutoCreatedWindow();

win->getCustomAttribute("WINDOW", &windowHnd);
windowHndStr << minputmanager =" OIS::InputManager::createInputSystem(pl);" mkeyboard =" static_cast(mInputManager-">createInputObject(OIS::OISKeyboard, false));


9. Membuat class Exit Listener, sekarang kita keluar dari class TutorialApplication, kita buat class ExitListener taruh saja diatas classtutorialApplication. kegunaan dari ExitListener adalah untuk mengCapture keyboard dan mengembalikan nilai false pada FrameStarted apabila tombol Esc ditekan. Sehingga Render Loop akan berhenti.


class ExitListener : public FrameListener
{
private:
OIS::Keyboard *mKeyboard;
public:
ExitListener(OIS::Keyboard *keyboard)
: mKeyboard(keyboard)
{
}
bool frameStarted(const FrameEvent& evt)
{
mKeyboard->capture();
return !mKeyboard->isKeyDown(OIS::KC_ESCAPE);
}
};


10. Menambahkan Exit Listener pada aplikasi, kembali lagi pada class TutorialApplication, fungsi void go() setelah class ExitListener selesai dibuat tambahkan pada applikasi

// add EXIT Listener
ExitListener* mListener = new ExitListener(mKeyboard);
mRoot->addFrameListener(mListener);

11. Waktunya Render!!!

//start rendering

mRoot->startRendering();

12. bersih bersih

//Cleaning
mInputManager->destroyInputObject(mKeyboard);
OIS::InputManager::destroyInputSystem(mInputManager);
delete mListener;
delete mRoot;


13. Contoh Hasil Akhir, yang sudah complete :

#include
#include

using namespace Ogre ;
class ExitListener : public FrameListener
{
private:
OIS::Keyboard *mKeyboard;

public:
ExitListener(OIS::Keyboard *keyboard)
: mKeyboard(keyboard)
{
}

bool frameStarted(const FrameEvent& evt)
{
mKeyboard->capture();
return !mKeyboard->isKeyDown(OIS::KC_ESCAPE);
}

};

class TutorialApplication
{
public:
TutorialApplication()
{
}
~TutorialApplication()
{
}
void go()
{
// Create OGRE Root
Ogre::Root *mRoot = new Root();
// Load n parsing Resource.cfg
Ogre::ConfigFile cf;
cf.load("resources.cfg");
ConfigFile::SectionIterator seci = cf.getSectionIterator();
while (seci.hasMoreElements())
{
String secName = seci.peekNextKey();
ConfigFile::SettingsMultiMap *settings = seci.getNext();
ConfigFile::SettingsMultiMap::iterator i;
for (i = settings->begin(); i != settings->end(); ++i)
{
String typeName = i->first;
String archName = i->second;
ResourceGroupManager::getSingleton().addResourceLocation(archName, typeName, secName);
}
}

// Show OGRE config Dialog
if(!mRoot->showConfigDialog())

{
delete mRoot;
throw Exception(52, "User canceled the config dialog!","Ogre Config Dialog");

//return false; // Exit the application on cancel
}
// Create Render Window
Ogre::RenderWindow* window = mRoot->initialise(true, "Ogre Head Application");

//create Scene
Ogre::SceneManager* sceneMgr = mRoot->createSceneManager(ST_EXTERIOR_CLOSE);
//createCamera
Ogre::Camera* camera = sceneMgr->createCamera("SimpleCamera");
camera->setPosition(Vector3(100,100,200));
camera->lookAt(Vector3(0,0,0));
camera->setNearClipDistance(4);
// Create one viewport
Ogre::Viewport* viewPort = window->addViewport(camera);

// add Loading bar
ExampleLoadingBar mLoadingBar;

mLoadingBar.start(window, 1, 1, 0.7f);
sceneMgr->clearSpecialCaseRenderQueues();
sceneMgr->addSpecialCaseRenderQueue(RENDER_QUEUE_OVERLAY);
sceneMgr->setSpecialCaseRenderQueueMode(SceneManager::SCRQM_INCLUDE);

// init Resource Group
ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
//ResourceGroupManager::getSingleton().loadResourceGroup(
//ResourceGroupManager::getSingleton().getWorldResourceGroupName(),
//false, true);
// Back to full rendering
sceneMgr->clearSpecialCaseRenderQueues();
sceneMgr->setSpecialCaseRenderQueueMode(SceneManager::SCRQM_EXCLUDE);
mLoadingBar.finish();

// insert something
sceneMgr->setAmbientLight( ColourValue( 1, 1, 1 ) );
Ogre::Entity *ent1 = sceneMgr->createEntity( "OgreHead", "ogrehead.mesh" );
Ogre::SceneNode *node1 = sceneMgr->getRootSceneNode()->createChildSceneNode( "OgreHeadNode" );
node1->attachObject( ent1 );
node1->setPosition(Vector3(0,0,0));
sceneMgr->setSkyDome(true, "Examples/CloudySky", 5, 8);

// Setup Input System OIS with OGRE
size_t windowHnd = 0;
std::ostringstream windowHndStr;
OIS::ParamList pl;
Ogre::RenderWindow *win = mRoot->getAutoCreatedWindow();

win->getCustomAttribute("WINDOW", &windowHnd);
windowHndStr << minputmanager =" OIS::InputManager::createInputSystem(pl);" mkeyboard =" static_cast(mInputManager-">createInputObject(OIS::OISKeyboard, false));

// add EXIT Listener
ExitListener* mListener = new ExitListener(mKeyboard);
mRoot->addFrameListener(mListener);

//start rendering
mRoot->startRendering();

//Cleaning
mInputManager->destroyInputObject(mKeyboard);
OIS::InputManager::destroyInputSystem(mInputManager);

delete mListener;
delete mRoot;
}

};

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"

INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
int main(int argc, char **argv)
#endif
{
// Create application object

TutorialApplication app;

try {
app.go();
} catch( Exception& e ) {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
MessageBoxA( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
fprintf(stderr, "An exception has occured: %s\n",
e.getFullDescription().c_str());
#endif
}

return 0;
}


14. Silahkan di Build & Run


referensi:
http://www.ogre3d.org/wiki/index.php/Basic_Tutorial_6