الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

ال Tile .. أحد مفاهيم برمجة الالعاب الثنائية(مناقشة)

مغلق
بدأه Abdullah.Alshammeri في 30 يونيو 2006 · 5 رد · 2,278 مشاهدة · في OpenGL
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

الموضوع متوسط المستوى .

ممكن تطبيق هذا الموضوع على أي لغة وباستخدام أي مكتبة متى ما فهمت الفكرة .

التطبيق النهائي لهذا الدرس سيكون باستخدام OpenGL و لغة السي .

طبعا أنا توني عرفت فائدتها ... :) فأجبتني الفكرة .. وجيت طاير على الكيبورد .. وقعدت اكتب .

Tile:

هذه أحد مفاهيم الالعاب الثنائية .

سأعتمد في تقديمي لهذا الموضوع على عدة مصادر من أهمها :

opengl :

http://www.gamedev.net/reference/articles/article1256.asp

directx:

http://www.gamedev.net/reference/articles/article1134.asp

تستطيع أن تطبق Tile باستخدام أي مكتبة وبأي لغة .

نحن سنطبق هذا الدرس باستخدام OpenGL .

انظر لهذه الصورة :

29_06_06_09_23_06_11516413861.JPG

لو تلاحظ :

هي عبارة عن مربعات صغيرة "مكسوة" بصورة .

ومستخدمة بكثرة في الالعاب الثنائية .

----

كيف يمكن تصميم هذا Tile الذي نتكلم عنه ..

إنه مجرد صور موضوعة في أماكن محددة,

لكن تم تطوير عدة طرق لتسهيل تصميم هذا Tile .

طبعا حسب متطلبات اللعبة .

في الغالب ستعتمد الطريقة التي سنتكلم عنها في هذا الموضوع :

لنفرض عندك صورة شبيه بالتالي

29_06_06_09_23_28_1151641408_.JPG

لنتفق على أعطائها الرقم صفر ( 0) .

اذا اذا قلنا يا لغةالبرمجة .. ارسمي الصورة 0 فانها سترسم الصورة البنية .

29_06_06_09_23_48_11516414283.JPG

اما الصورة الخضراء .. فسنعطيه الرقم (1) اذا .. اذا استدعينا الصورة رقم واحد فان البرنامج سيرسم الصورة الخضراء ,

اذا انظر لهذه الخريطة الرقمية

int Arry[150] = {	   0 , 0 , 0 , 0  , 0  , 0 , 0 ,0  ,0  ,0 , 
		 1 , 1 , 1 , 1  , 1  , 1 , 1 ,1  ,1  ,1,	
		 0 , 0 , 0 , 0  , 0  , 0 , 0 ,0  ,0  ,0 ,	 
		   1 , 1 , 1 , 1  , 1  , 1 , 1 ,1  ,1  ,1,	
		  0 , 0 , 0 , 0  , 0  , 0 , 0 ,0  ,0  ,0 ,	 
		   1 , 1 , 1 , 1  , 1  , 1 , 1 ,1  ,1  ,1,	
		0 , 0 , 0 , 0  , 0  , 0 , 0 ,0  ,0  ,0 ,	 
		   1 , 1 , 1 , 1  , 1  , 1 , 1 ,1  ,1  ,1,	
		   0 , 0 , 0 , 0  , 0  , 0 , 0 ,0  ,0  ,0 ,	 
		   1 , 1 , 1 , 1  , 1  , 1 , 1 ,1  ,1  ,1,	
		  0 , 0 , 0 , 0  , 0  , 0 , 0 ,0  ,0  ,0 ,	 
		   1 , 1 , 1 , 1  , 1  , 1 , 1 ,1  ,1  ,1,	
		  0 , 0 , 0 , 0  , 0  , 0 , 0 ,0  ,0  ,0 ,	 
		   1 , 1 , 1 , 1  , 1  , 1 , 1 ,1  ,1  ,1,	
		  0 , 0 , 0 , 0  , 0  , 0 , 0 ,0  ,0  ,0   };

اذا طلبنا من البرنامج رسم محتوى المصفوفة ..(وسنعرف كيف )

فإنه سيرسم الصورة البنية اذا واجه الرقم صفر ..

وسيرسم الصورة الخضراء اذا واجه الرقم واحد ,

النتيجة

29_06_06_09_24_24_11516414644.JPG

هنا تبدأ الاثارة .

إذا أردنا أن نصمم مراحل ألعابنا .. ما علينا من الكود .

فقط نضع مصفوفة .. من الارقام .. ونغير في الارقام وينتج الشكل .

تطبيق رقم 1 :

سيعتمد هذا التطبيق على OpenGL . ولكن سأتكلم بشكل عام ..

حتى يمكن التطبيق على Win API – Directx – و أي مكتبة أو أي لغة .

اولا .. قم بعمل دالة تقوم بتحميل الصورة الاولى .

LoadImage( string image_name );

واذا كنت تعمل على opengl او directx فلابد من عمل الاكساء وتطبيقه على شكل رباعي

CreateTexture(int ID);

CreateRectangle(long width  , long height );

الان نبدأ بالتطبيق :

int Arry[10] = { 	   0 , 0 , 1 , 1  , 0  , 1 , 0 ,0  ,1  ,1 };
unsigned int ID_0  ,  ID_1 ; // متغيران يمثلان الصورتين

مصفوفة ..

ثم

	for ( long i=1; i<=10; i++)
	{
 				if(Arry==0)
				{
			glBindTexture(GL_TEXTURE_2D,  ID_0);//الصورة الاولى
				}
				if(Arry==1)
				{
			glBindTexture(GL_TEXTURE_2D,  ID_1);//الصورة الثانية  

				}



					  glPushMatrix();

						glLoadIdentity(); 
 						glTranslatef( i*40 ,40,0);
						DrawRectangle( 30,30);

					glPopMatrix();
   }

اذا قمنا في البداية بعمل الدوال اللازمة اللازمة لتحميل الصورة وتطبيق الاكساء على الاشكال .

ثم أنشأنا متغيرين .

ID_0 يمثل الصورة الاولى

ID_1 يمثل الصورة الثانية

ثم أنشأنا المصفوفة ..

ثم

for ( long i=1; i<=10; i++)
	{
 				if(Arry==0)
				{
			glBindTexture(GL_TEXTURE_2D,  ID_0);//الصورة الاولى
				}
				if(Arry==1)
				{
			glBindTexture(GL_TEXTURE_2D,  ID_1);//الصورة الثانية  

				}

نمر على عناصر المصفوفة ..

نختبر قيمة كل عنصر .

اذا كانت قيمة العنصر صفر ... فحمل الصورة الاولى .

اذا كانت قيمة العنصر واحد حمل الصورة الثانية .

وهكذا مع جميع العناصر العشرة .

ثم رسمنا الصور ..

glPushMatrix();
glLoadIdentity(); 
 glTranslatef( i*40 ,40,0);
DrawRectangle( 30,30);
 glPopMatrix();

---------------------------

المثال في المرفقات .

المرفق الاول opengl+glut

المرفق الثاني opengl+ windows

طبعا نفس المثال .

يتبع ..... + نريد الاضافة لمن لديه معلومات .

Tile_1_glut.zip

Tile_1_WND.zip

تم تعديل هذه المشاركة بواسطة الشمري في 30 يونيو 2006 في 07:37

logo1.png تطبيق طمأنينة ، نسخة بيتا على أندرويد

عبدالله الشمّري - Al-Shammari

CodingAlone.com

twitter @abshammeri

abshammeri AT gmail.com

github : abshammeri

#2

درس جميل و مثال رائع . ;)

و لكن الطريقة ليست عملية . مثلا تود ان تنطلق في لعبة كبيرة RPG مثلا حينها سيصعب عليك انشاء الخرائط من خلال المصفوفات فقط . يمكن تطوير هده الطريقة لتصبح عملية اكثر . ساستخدم SDL ودلك لانني مبتدئ opengl :rolleyes:

لدلك سنقوم بتقسيم الشاشة هكدا

tiles2qb.jpg

ناخد مثلا ملف define.h و نضع فيه بعض المتغيرات العامة .

#ifndef DEF_DEFINE
#define DEF_DEFINE

   #define SIZE_BLOCK		   34 //PIXEL
   #define BLOCK_PER_WIDTH	  18 
   #define BLOCK_PER_HEIGHT	 18  
   #define WIN_WIDTH			(SIZE_BLOCK * BLOCK_PER_WIDTH ) 
   #define WIN_HEIGHT		   (SIZE_BLOCK * BLOCK_PER_HEIGHT) 


   enum  {EMPTY = 0 ,WALL = 1 , BOX = 2 , BOX_OK = 3 , OBJECTIVE = 4 , PLAYER = 5 };

#endif

SIZE_BLOCK هي حجم المربع بالبكسيل طبعا .

BLOCK_PER_WIDTH هو عدد المربعات حسب عرض الشاشة .

WIN_HEIGHT هو طول الشاشة ...الخ

بالنسبة enum فهي الشيء الدي يوجد بالمربع .

الان نمر لتقسيم الشاشة . من اجل دلك سنقوم بانشاء مصفوفة ثنائية الابعاد :wacko: .

int map[BLOCK_PER_HEIGHT][BLOCK_PER_WIDTH];

بعد ان قمنا بتحميل صورنا سنقوم بانشاء دالة لعمل blit ( لصق ) لها في screen .

void Show(SDL_Surface *screen)
{

	 SDL_Rect position;

	 int i = 0 , j=0;

	 SDL_FillRect(screen, NULL , SDL_MapRGB(screen->format ,255 , 255 , 255 ) );

	 for ( i = 0; i<BLOCK_PER_HEIGHT; i++)
	 {

		 for( j = 0; j<BLOCK_PER_WIDTH; j++)
		 {
			position.x = j*SIZE_BLOCK;
			position.y = i*SIZE_BLOCK;


			switch(map[j])
			{

				   case WALL :

						SDL_BlitSurface(wall, NULL , screen , &position);
						break;

				   case BOX :

						SDL_BlitSurface(box, NULL , screen , &position);
						break;

				   case BOX_OK :

						SDL_BlitSurface(box_ok, NULL , screen , &position); 
						break;

				   case OBJECTIVE :

						SDL_BlitSurface(objective, NULL , screen , &position);
						break;

				   case PLAYER :

						SDL_BlitSurface(player, NULL , screen , &position );
						break;

			}





		 }


	 }




}

لنقم الان بشرح الكود .

الدالة show تاخد مؤشر الشاشة الرئيسية ك argument

SDL_Rect position هي offset او الاحداثيات . بحيث position.x هي الافصول و position.y هي الارتوب ( صححولي ادا كنت مخطئا فالامور تختلط علي ) .

اول شيئ نقوم به هو ملئ الشاشة بالابيض عبر الدالة .

SDL_FillRect(screen, NULL , SDL_MapRGB(screen->format ,255 , 255 , 255 ) );

و من بعدها نقوم بالبحث عن العناصر و لصقها في الشاشة عبر دالة

 SDL_BlitSurface(player, NULL , screen , &position );

وهي تاخد في البارامتر الاول الصورة التي نود الصاقها . البارامتر الثاني و هو الجزء من الصورة التي نود الصاقها وهو عبارة عن مؤشر SDL_Rect *clip . البارامتر الثالث وهو الشاشة الرئيسية . واخيرا الاحداثيات التي نود ان نلصق الصورة فيها .

يعني الان كيف سنجد الاحداثيات :huh: . سهلة تتدكرون هده العبارة SIZE_BLOCK . هي الحل و من اجل الحصول على الاحداثيات سنقوم بضرب المتغيرات التي بحثنا من خلالها في المصفوفة i and j في حجم المربع مثلا لدينا i= 5 سنضربها في 34 لتصبح 140 يعني position.y = 140 .

الان مادا لو اردنا اضافة عنصر الى مصفوفتنا . سنقوم بانشاء دالة بسيطة لاضافة العنصر .

void Set_object(int object , SDL_Rect *position)
{

	 int w=0 , h=0;

	 h = position->y / SIZE_BLOCK;
	 w = position->x / SIZE_BLOCK;

	 level[h][w] = object;


}

الدالة تاخد في البارامتر الاول "العنصر" مثل . EMPTY او BOX المحدد في enum . و البارامتر الثاني الاحداثيات .

هدا كل ما في الامر . و شكرا استاد الشمري على الموضوع الجميل .

الكود مقتبس عن مشروع بداته ولم اتممه :unsure: وهو محرر خرائط للعبة sokoban .

map_editor.rar

تم تعديل هذه المشاركة بواسطة pengo في 30 يونيو 2006 في 23:38

#3

رائع ,

انا أيضا اقوم بعمل map editor .. سأضع النسخة النهائية هنا خلال اسبوع على الاكثر ان شاء الله .

انا تعبت حتى استطعت تثبيت SDL .. وعندما قمت بتنفيذ مثالك .. وبعد ضغط عدة ازرار يحصل خطأ ويغلق البرنامج ,,

لكن اذا كنت اضغط ازرار الماوس لا يحدث هذا الخطأ .

انا فهمت فكرت الاداة .

لكن .. هل العاب التي على نسق سوبر ماريو تستخدم هذه الطريقة .

لانه وكما تعلم ..

المرحلة في تلك الالعاب ... طويلة جدا .. ومن الصعب رسم كل تلك المرحلة..

لانه يجب حينها أن تكون عرض النافذة ... اكثر من عشرة آلاف بكسل , للمرحلة الواحدة .

ماهو الحل برأيك ! .

سبق أن سألت الاخوة هنا حول هذا الموضوع .

وفهمت انه بامكاننا تحميل جزء من المرحلة اثناء اللعب وكلما تقدم اللاعب في المرحلة تحمل الجزء التالي منها .

أي تقسم المرحلة الواحدة الى عدة مراحل كل مرحلة طولها محدد .

انا لا زلت اقرأ المثال ...

وفي بالي سؤال ... سأحاول ان اجد اجابته بنفسي :)

سأضيف لهذا الموضوع بعد اسبوع ان شاء الله .

logo1.png تطبيق طمأنينة ، نسخة بيتا على أندرويد

عبدالله الشمّري - Al-Shammari

CodingAlone.com

twitter @abshammeri

abshammeri AT gmail.com

github : abshammeri

#4

بسم اللخ الرحمن الرحيم

الموضوع ممتاز , ومبتكر..

فكرة اللبنة Tile مستخدمة في كل الألعاب بلا استثناء سواء كانت ثنائية أو ثلاثية, فمثلا نرسم ثلاثة أو أربعة لبنات خضراء مختلفة ومتناسقة , ونضعها في ترتيب منتظم أو عشوائي لنصنع حديقة, أو غير ذلك...

ألعاب مثل RED ALERT تعمل باستخدام Tiles ولعل من استخدم برامج صنع الخرائط الخاصة بهذه اللعبة يفهم ما أريد قوله...

حسنا.. هناك طريقتين لتكوين المراحل كبيرة الحجم سواء في الألعاب ثنائية أو ثلاثية الأبعاد...

الطريقة الأولى وهي الأسهل والتي استخدمها أنا , ولكنها بالتأكيد أبطأ في المراحل الكبيرة عن طريق تحميل جميع أجزاء الكون (العالم) في متغيرات أو مصفوفات, ولكن لا نرسم إلا الأجزاء التي تظهر في الشاشة فقط, (الأجزاء القريبة من نقطة تواجد الكاميرا).

الطريقة الثانية وهي الأكثر احترافية هي عن طريق تحميل الأجزاء القريبة من الكاميرا في مصفوفات ومتغيرات ورسمها مباشرة, وتحميل الأجزاء الجديدة كلما اقتربت الكاميرا منها مع تدمير الأجزاء التي تبتعد الكاميرا عنها...

كان هناك مثال ثلاثي الأبعاد صممته منذ مدة بسيطة يعمل باستخدام الطريقة الأولى, وعلى الرغم من أن الخريطة كانت مساحتها كبيرة إلا أن سرعة اللعبة كانت جيدة.

ولكني أظن أن السرعة ستختلف كثيرا في حالة وجود أعداء ومتغيرات أخرى غير الشخصية الرئيسية والخريطة, لذا فإنني أظن أن الطريقة الثانية هي الأكثر احترافية...

شكرا على الموضوع.

تحياتي

What really progammer can do??? Please answer..

#5

السلام عليكم ورحمة الله وبركاته

تحيه إلى أعضاء المنتدى, وتحيه خاصه للشمري , والنمر المصري (زملاء في منتدى vb4arab, وللأسف لم أشاركهما كثيرا في المنابر)

بالنسبه لل Tile فكما ذكر أخي النمر المصري من حيث استخدامها في كلا النوعين, ففي التطبيق ثلاثي الابعاد, أعتقد انك ستستخدم الطريقه الثانيه بمجرد استخدامك لخرائط BSP, حيث لا يتم تصيير مجسم ليس في مجال الكاميرا, وبالتالي سرعه اكبر مع زيادة المساحات والأجسام في التطبيق, أما في التطبيق الثنائي, فالأمر بسيط في حالة انك بنيت الـ Scroll scene على اساس ان الأجسام تتحرك عكس اتجاه ازرار التحكم.

فعلى سبيل المثال : لديك Tile في المشهد لن يتحرك مالم تضغط على زر توجيه, فإذا ضغطت الإتجاه الأيمن فإن فكرة المحرك ان يستمر الـ Tile بالاستمرار في الحركه إلى اليسار حتى يبلغ آخر حد في الشاشه(صفر) , وبالتالي غن بلغت احداثياته قيما سالبه فانه لن يرسم. ولذا ان بنيت محركك على هذه الفكره , فاجعل المجسم لا يتم رسمه إلا إن كانت احداثياته أكبر من الصفر, وأصغر من 800(أو الـ screen weight حسبما تضعه انت).وفي هذه الحاله تقريبا ستستخدم الطريقه الثانيه.أليس كذلك أخي EGY_Tiger ؟

وإن كان شرحي صحيحا, فقريبا ساضع مثالا توضيحيا لفكرة عمل Scroll scene تعتمد على تحرك الأجسام عكس إتجاه اسهم التوجيه .

تحياتي, وشكرا على الموضوع

تم تعديل هذه المشاركة بواسطة High volt في 3 يوليو 2006 في 00:18

#6

حياكم الله يالنمر المصري و يا هاي فولت .. اشتقنا لكم .

اقتباس
الطريقة الأولى وهي الأسهل والتي استخدمها أنا , ولكنها بالتأكيد أبطأ في المراحل الكبيرة عن طريق تحميل جميع أجزاء الكون (العالم) في متغيرات أو مصفوفات, ولكن لا نرسم إلا الأجزاء التي تظهر في الشاشة فقط, (الأجزاء القريبة من نقطة تواجد الكاميرا.

نعم .. سألت كثيرا حول هذه النقطة وهذا هو الجواب الذي حصلت عليه ,

لكن لاجل هذا يجب ان نعمل scroll للمشهد .. ولكن كيف .. ؟

سأجرب طريقة هاي فولت .. .

تم تعديل هذه المشاركة بواسطة الشمري في 7 يوليو 2006 في 08:27

logo1.png تطبيق طمأنينة ، نسخة بيتا على أندرويد

عبدالله الشمّري - Al-Shammari

CodingAlone.com

twitter @abshammeri

abshammeri AT gmail.com

github : abshammeri

هذا الموضوع مغلق.

مواضيع مشابهة