Sunday, July 19, 2009

The power of Polymorphism in OOP

Game programming ေတြ အမ်ားစုက OOP language ေတြကို သံုးပါတယ္။ အထူးသျဖင့္ C++ programming language ကို console game ေတြအတြက္ေရာ၊ PC ေတြ အတြက္လည္း အမ်ားႀကီး သံုးၾက ပါတယ္။
OOP (Object-Oriented Programming) language လို႔ ေျပာလိုက္ရင္ (ကၽြန္ေတာ္ သိသေလာက္) အဓိက အားျဖင့္ ရိွရမယ့္ features ေတြ ရိွတယ္ေလ။ Customized Data Creation, Data Encapsulation, Data Hiding, Operator Overloading, Inheritance and Polymorphism ဆိုတဲ့ features ေတြပါတာကို ကၽြန္ေတာ္တို႔ အားလံုး သိၾကပါတယ္။ C++ programmer ေတြဆို ပိုသိမွာပါ။
OOP language ျဖစ္တဲ့ C++ မွာ class/object ေတြသံုးၿပီး user defined data type ေတြကို စိတ္ၾကိဳက္ ကိုယ့္ လိုအပ္ခ်က္နဲ႔ ကိုက္ညီေအာင္ ဖန္တီးလို႔ ရေစပါတယ္။ ေနာက္ၿပီ member data ေတြကို class တစ္ခု အတြင္းမွာ ကိုယ့္လိုအပ္ခ်က္ နဲ႔ အညီ ထည့္ထားၿပီး သူတို႔အတြက္ manipulation function ေတြကို ထည့္ထား လို႔ရတယ္ေလ။ ဒါက Data Encapsulation ေပါ့။ Member Data ေတြကို ကိုင္တြယ္တဲ့ ေနရာမွာ မလိုအပ္ပဲ မျပင္မိေအာင္၊ class အျပင္ကေန လုပ္ခ်င္တိုင္း လုပ္မရေအာင္ privae/protected/public စသည္ ျဖင့္ အဆင္ေျပေအာင္ သတ္မွတ္လို႔ရတာကလည္း OOP ရဲ႕ေကာင္းတဲ့ Data Hiding အခ်က္တစ္ခုပါ။
OOP ရဲ႕ တစ္ကယ္ အရမ္းထူးျခားတဲ့ feature ေတြက Operator Overloading နဲ႔ Polymorphism ေတြပါပဲ။ Maths operators, logic operators စတဲ့ အမ်ိဳးမ်ိဳးေသာ operation ေတြကို ကၽြန္ေတာ္တို႔ စိတ္ၾကိဳက္ ဖန္တီး တည္ေဆာက္ ထားတဲ့ class/object ေတြအေပၚမွာapply လုပ္လို႔ ရတာကလည္း အရမ္း သေဘာက်စရာ ေကာင္းတဲ့ Operator Overloading အခ်က္ပါပဲ။
ကၽြန္ေတာ္တုိ႔ game creation မွာ လိုအပ္ၿပီး သေဘာက်စရာ ေကာင္းတဲ့ OOP language ရဲ႕ အရမ္းထူးျခား တဲ့ အခ်က္တစ္ခု က Polymorphism ဆိုတဲ့ အခ်က္ပါပဲ။ ကၽြန္ေတာ္ ကိုယ္တိုင္လည္း အေတာ္မ်ားမ်ားေသာ ကိစၥေတြအတြက္ အဲဒါကို သေဘာက်မိပါတယ္။ တစ္ကယ္တမ္း Polymorphism လို႔ ေျပာလိုက္ရင္ အမ်ားႀကီး ရိွမယ္ ထင္ပါတယ္။ ကၽြန္ေတာ္ သေဘာက်တဲ့ (game မွာလည္း သံုးျဖစ္တဲ့) Polymorphism ရဲ႕ feature တစ္ခုက “ပံုစံအမ်ိဳးမ်ိဳး ေျပာင္းသံုးႏိုင္ျခင္း” လို႔ ေျပာရမယ္ ထင္ပါတယ္။
Polymorphism နဲ႔ ပါတ္သက္ၿပီး ကၽြန္ေတာ္ သေဘာက်တဲ့ game programming မွာ သံုးတဲ့ အေၾကာင္း အရာေလး တစ္ခုကို ေျပာခ်င္ပါတယ္။ Pointer နဲ႔လည္း ဆိုင္ပါတယ္။ Pointer ဆိုလို႔ ေျပာရဦးမယ္။ C/C++ မွာ တြင္တြင္က်ယ္က်ယ္ သံုးလို႔ရတဲ့ pointer ေတြကို အေတာ္ သေဘာက်မိပါတယ္။ ကၽြန္ေတာ့ အတြက္ေတာ့ သံုးရတာ အဆင္ေျပတယ္။ Dynamic ျဖစ္တာကိုလည္း သေဘာက်မိတယ္။
ကၽြန္ေတာ္ အခု discuss လုပ္ခ်င္တာက pointer ကို သံုးၿပီး မတူညီတဲ့ class ေတြကို တစ္မ်ိဳးထဲေသာ point နဲ႔ point လုပ္သြားတာကို ေျပာခ်င္တာပါ။ အဲဒီအခ်က္က Gamestate manager (Game mode manager) လို မ်ိဳး လုပ္တဲ့ ေနရာမွာ အရမ္း အသံုးတည့္ပါတယ္။ အေတာ္ေလး အဆင္ေျပေစ တယ္လို႔ ထင္မိ၊ သေဘာက်မိ ပါတယ္။ Gamestate manager အေၾကာင္းကို သပ္သပ္ ေရးပါဦးမယ္။
Programming မွာ ပံုမွန္ အားျဖင့္ ကၽြန္ေတာ္တို႔ သိထားတာက pointer တစ္ခု ဟာ သူသတ္မွတ္ထားတဲ့ data အမ်ိဳးအစား တစ္ခုကိုပဲ point လုပ္လို႔ရတယ္။ ၿပီးေတာ့ Array တစ္ခုဟာလည္း same data type ေတြကိုပဲ သိမ္းလို႔ ရတယ္လို႔ အေျခခံက်က် သတ္မွတ္ထားပါတယ္။ ဒါေပမယ့္ pointer တစ္ခုထဲ ကေန မတူညီတဲ့ data type ေတြကို point လုပ္ခ်င္တယ္ ဆိုရင္ ဘယ္လို လုပ္မလည္း။ အထူးသျဖင့္ မတူညီတဲ့ class ေတြရဲ႕ object ေတြကို ကၽြန္ေတာ္တို႔က တစ္မ်ဳိးထဲေသာ pointer နဲ႔ ထိန္းခ်င္ တယ္ဆို၇င္ OOP ရဲ႕ feature ေတြကို သံုးၿပီး လုပ္ယူလို႔ ရပါတယ္။ Gamestate manager ကို ဖန္တီးရာမွာ အသံုးတည့္ ေစပါတယ္။
ဥပမာ- ကၽြန္ေတာ္က မတူညီတဲ့ အရာသံုးခုကို draw လုပ္ခ်င္တဲ့ ဆိုပါေတာ့။ တစ္ခုက Circle, တစ္ခုက Rectangle နဲ႔ ေနာက္တစ္ခုက triangle ဆိုပါေတာ့။ အဲဒီ သံုးခုက ပံုစံေတြလည္း မတူတဲ့အတြက္ သူတို႔မွာ ပါတဲ့ data ေတြနဲ႔ အခ်က္အလက္ေတြလည္း မတူႏိုင္ဘူးေလ။ မတူတဲ့ class (၃) ခု ဆိုပါေတာ့။


Clrcle, Rectangle နဲ႔ Triangle ဆိုၿပီး class ၃ ခုရိွတယ္ ဆိုပါေတာ့။ ပံုမွန္အတိုင္းဆိုရင္ အဲဒီ class တစ္ခုခ်င္းစီကို point လုပ္ဖို႔ အတြက္ သူတို႔အတြက္ သီးသန္႔ pointer ေတြ လိုတယ္ေလ။
Circle *c = new Circle( );
Rectangle *r = new Rectangle( );
Triangle *t = new Triangle( );

စသည္ျဖင့္ေပါ့။ အဲဒါက တစ္ကယ္တမ္းမွာ အဆင္မေျပပါဘူး။ ကၽြန္ေတာ္တို႔က base pointer တစ္ခုထဲနဲ႔ အဲဒီ class သံုးခုရဲ႕ မတူတဲ့ object သံုးခုလံုးကို point လုပ္ၿပီး သံုးခ်င္တယ္ ဆိုရင္ ဘယ္လိုလုပ္မလည္း။ Inheritance နဲ႔ virtual function ပံုစံကို သံုးၿပီး လုပ္ယူလို႔ရပါတယ္။

class Base
{
private:

public:
virtual void Initialize ( );
virtual void Draw( );
virtual void CleanUp( );
};

class Circle : public Base
{
private:
// any private data here for circle

public:
void Initialize( )
{
//whatever you want to initialize
}

void Draw( )
{
//this is main draw function for your circle
}
void CleanUp( )
{
//to clean up any resources
}
} ;

void Rectangle : public Base
{
private:
// any private data here for rectangle

public:
void Initialize( )
{
//whatever you want to initialize
}

void Draw( )
{
//this is main draw function
}
void CleanUp( )
{
//to clean up any resources
}
};

အဲဒီလိုပဲ triangle လိုပဲ တစ္ျခား လုပ္ခ်င္တာေတြကိုလည္း inherit လုပ္ယူလို႔ ရပါတယ္။ Circle, Triangle လုိ class ေတြမွာ base class က function, data ေတြ အျပင္စိတ္ၾကိဳက္ ထည့္ခ်င္တာ ရိွရင္လည္း ထည့္ဦးေပါ့။ တစ္ခု သတိထားရမွာက base class ရဲ႕ pointer နဲ႔ သူ႔ကို inherit လုပ္တဲ့ derived class ေတြကို ညႊန္ၿပီး function ေတြကို ေခၚမယ္ ဆိုရင္ derive class (child class) က ေခၚခ်င္တဲ့ function အားလံုးဟာ base class မွာ virtual function အေနနဲ႔ ရိွရပါမယ္။ မဟုတ္၇င္ error ျပႏိုင္ပါတယ္။
ဒါဆိုရင္ ကၽြန္ေတာ္တို႔က base class ရဲ႕ pointer တစ္ခု နဲ႔ child class ေတြကို point လုပ္ၿပီး သူတို႔ထဲက function ေတြကို ေခၚလို႔ ရၿပီေပါ့။

Base * p[3];

p[0] = new Circle( );
p[1] = new Rectangle( );
p[2] = new Triangle( );

p[0] -> Draw( ); //this will draw a circle using Circle’s draw function
p[1] -> Draw( ); //this will draw a rectangle using its draw function
p[2] -> Draw( ); //this will draw a triangle using its draw function

ကဲ ဘယ္ေလာက္ အဆင္ေျပလည္း။ ကၽြန္ေတာ္တို႔က base class pointer ေတြ နဲ႔ array တစ္ခုကုိ ဖန္တီးထားလိုက္ၿပီး အလုပ္ လုပ္ခ်င္တဲ့ မတူညီတဲ့ child class ေတြကို ထည့္ထား လိုက္ရံုပဲေလ။ ဒါဆိုရင္ base class pointer array တစ္ခုထဲ နဲ႔ ဆိုေတာ့ ထိန္းရတာလည္း ေကာင္းတာေပါ့။
အဲဒီလို ပံုစံ မတူတာေတြကို တူသလိုမ်ိဳး သံုးတာကိုက polymorphism ရဲ႕ အခ်က္တစ္ခုပါပဲ။ အခုလို သံုးတဲ့ ပံုစံက gamestate (game modes) ေတြကို ကိုင္တြယ္တဲ့ ေနရာမွာ အဆင္ေျပေစပါတယ္။ Singleton နည္းပညာကို သံုးလို႔ရေပမယ့္ အဲဒါက ရႈပ္ပါတယ္။ ၿပီးေတာ့ Singleton မွာ အားနည္းခ်က္ ေတြလည္း ရိွပါတယ္။
Game တစ္ခုမွာ ဆိုရင္ (ဥပမာ) Title mode, Main Menu mode, Option mode, Gameplay mode, Score display mode စသည္ျဖင့္ မတူတဲ့ mode (state) ေတြ အမ်ားႀကီး ပါႏိုင္ပါတယ္။ ကၽြန္ေတာ္တို႔က အခု ေျပာခဲ့တဲ့ Polymorphism ရဲ႕ စြမ္းရည္ ကို သံုးၿပီး mode ေတြကို ကိုင္တြယ္ မယ္ ဆိုရင္ အေတာ္ေလး အဆင္ေျပ လြယ္ကူေစ ပါတယ္။ Gamestate ေတြကို ဘယ္လို ထိန္းခ်ဳပ္တယ္ ဆိုတာ သပ္သပ္ ေဆြးေႏြးခ်င္ပါ ေသးတယ္။
အခု ကၽြန္ေတာ္ ေျပာတဲ့ article ေလးက game programming ကို ေလ့လာေနတဲ့ beginner ေတြ အတြက္ အသံဳးတည့္မယ္ လို႔ ယူဆပါတယ္။ အေတြ႕ အႀကံဳရိွတဲ့ programmer ေတြ အတြက္ေတာ့ ဘာမွ မဟုတ္ဘူး ေပါ့ေနာ္။

0 comments:

Post a Comment