آموزش ExtremePhysics در گیم میکر به صورت پیشرفته

این مطلب از سایت قدیمی منتقل شده و ممکن است اشکالات زیادی دشته باشد. لطفا در صورت مشاهده ی هر گونه ایراد، گزارش دهید

در این آموزش از سایت ای تاتس می خوام کار با ExtremePhysics در گیم میکر رو به طور کامل به شما آموزش بدم. با ما همراه باشید.

همان طور که می دانید ExtremePhysics یک موتور شبیه سازی فیزیک در گیم میکر می باشد. قصد دارم کار با این کتابخانه را در چند بخش به شما آموزش دهم.

اولین آموزش، راه اندازی این موتور و ایجاد یک مثال ساده کار با آن می باشد.

ep-box2d-performance-screenshot

  • ساختار ExtremePhysics

ExtremePhysics از چند کلاس تشکیل شده است که هر کدام را به طور مختصر توضیح می دهم:

World: این کلاس جهانی را برای ایجاد فیزیک در آن می سازد. در واقع این کلاس راه ارتباطی کلاس های دیگر می باشد. شما می توانید چند جهان بسازید، اما معمولا یک جهان کافیست.

Polygon: برای تعریف رئوس یک چندضلعی استفاده می شود.

Body: هر بدنه معادل یک Object در گیم میکر می باشد. معمولا هر آبجکت در گیم میکر با یک بدنه در ارتباط می باشد.

Shape: این کلاس برای تعریف قالب هر بدنه می باشد. معادل آن در گیم میکر را می توان mask نامید. سه نوع قالب وجود دارد: قالب مربعی، قالب دایره ای و قالب چندضلعی. هر بدنه می تواند دارای چند قالب باشد.

Force: این کلاس برای افزودن نیرو به بدنه ها می باشد. مثلا نیروی پرتاپ یک موشک!

Contact: برخوردها هنگام شبیه سازی به وجود می آیند. هنگامی که دو قالب با هم برخورد می کنند یک برخورد به وجود می آید.

Joints: برای اتصال چند بدنه به هم استفاده می شود. اتصالات انواع مختلفی دارند.

View: نماها برای افزایش سرعت شبیه سازی استفاده می شوند. این کلاس زمانی کاربرد دارد که شما از view در گیم میکر استفاده می کنید. با استفاده از نما می توانید بخش های از جهان فیزیک که خارج از نما می باشند را بدون پردازش رها کنید.

  • راه اندازی ExtremePhysics

ابتدا ExtremePhysics را از آدرس زیر دانلود نمایید:

http://www.maartenbaert.be/extremephysics/

سپس یک پروژه جدید بسازید.

پنجره Extension Packages را باز نمایید. دکمه ی Install را بزنید. در پنجره ی جدید دوباره دکمه ی Install را بزنید. از بسته ی دانلود شده فایل ExtremePhysics.gex را انتخاب کنید. ExtremePhysics در لیست Installed packages افزوده می شود. دکمه ی OK را بزنید تا به پنجره Extension Packages بازگردید. در این پنجره ExtremePhysics را در لیست Available packages مشاهده می کنید. آن را انتخاب کنید تا دکمه ی افزودن ظاهر شود. با زدن دکمه آن را به لیست Used packages انتقال دهید. دکمه ی OK را بزنید.

ExtremePhysics به بازی شما اضافه شد.

  • ساخت یک جهان

مرحله ی اول استفاده از ExtremePhysics ساختن یک جهان می باشد.

برای ساختن آن ابتدا یک آبجکت بسازید.

در رویداد Create آن کد زیر را وارد نمایید:

global.world = ep_world_create();
ep_world_set_settings(global.world, 1, 20, 10, 0.1, 0.5, 0, 0.6, 1);

خط اول یک جهان جدید ایجاد می کند و شناسه آن را درون متغیر عمومی world می ریزد.
خط دوم تنظیماتی را به جهان مورد نظر اعمال می کند که بعدا توضیح می دهم.
حال در رویداد End Step کد زیر را وارد کنید:

ep_world_update_contacts(global.world);
ep_world_simulate_step(global.world);

خط اول برای اجرای پردازش و به روزرسانی برخوردها در جهان مورد نظر می باشد.

خط دوم هم برای اجرای عملیات شبیه سازی می باشد.

دقت نمایید که این دو تابع می بایست پشت سر هم فراخوانی شوند.

قدم بعدی تخریب جهان پس از اتمام کار با آن می باشد که کد آن را در رویداد Room End قرار دهید:

ep_world_destroy(global.world);

تا به این جا کنترل کننده ی فیزیک ما ساخته شد. آن را در Room مورد نظر قرار دهید.

ساخت یک جسم ایستا

دو نوع بدنه در ExtremePhysics وجود دارد. ایستا و پویا. بدنه های ایستا می توانند حرکت کنند، اما حرکت آن ها تاثیری بر دیگر بدنه ها ندارد. در حالی که حرکت بدنه های پویا بر دیگر بدنه ها حتی بدنه های ایستا تاثیر می گذارد.

از بدنه های ایستا معمولا برای اشیایی مثل زمین، درخت، دیوار و اجسامی با سرعت ثابت استفاده می شود.

حال می خواهیم یک جسم ایستا ایجاد کنیم.

آبجکت جدیدی ایجاد کنید و برای آن یک سپرایت مربعی شکل انتخاب کنید.

در رویداد Create آن کد زیر را وارد کنید:

body = ep_body_create_static(global.world);

این کد یک بدنه ی ایستا در جهان مورد نظر می سازد و شناسه آن را در متغیر body میریزد.

حال بدنه ی ما نیاز به یک قالب دارد تا بتواند با اجسام دیگر برخورد کند. کد زیر را ادامه ی کد قبل اضافه کنید.

shape1 = ep_shape_create_box(global.world, body, sprite_width, sprite_height, 0, 0, 0, 1);

این کد یک قالب مربعی شکل تعریف می کند.

پارامتر اول آن شناسه ی جهان مورد نظر می باشد.

پارامتر دوم بدنه مورد نظر می باشد.

پارامتر سوم و چهارم عرض و ارتفاع مربع (مستطیل) را تعیین می کند که ما عرض و ارتفاع سپرایت آبجکت را به آن داده ایم.

پارامتر پنجم و ششم مختصات مرکز مربع را تعیین می کند. این مختصات نسبی و وابسته به مکان بدنه می باشد.

پارامتر هفتم زاویه مربع را مشخص می کند. توجه نمایید تمامی زوایا در ExtremePhysics بر حسب رادیان می باشد.

پارامتر آخر تراکم مربع را مشخص می کند.

قالب بدنه ساخته شده است، اما برخوردی به وجود نمی آورد. سیستم برخورد ExtremePhysics سه مقدار استفاده می کند:

Collision Mask 1: یک عدد 32 بیتی می باشد و لایه ای را تعیین می کند که قالب متعلق به آن است.

Collision Mask 2: یک عدد 32 بیتی می باشد و لایه ای را تعیین می کند که قالب با آن برخورد می کند.

هر بیت یک لایه می باشد، پس در مجموع 32 لایه می توانیم داشته باشیم.

Group: برای گروه بندی قالب ها کاربرد دارد. توجه کنید قالب هایی که در یک گروه قرار دارند با هم برخورد نمی کنند. همچنین این قانون در مورد گروه شماره صفر صدق نمی کند و انتخاب صفر به عنوان شماره گروه به معنای عدم گروه بندی می باشد.

حال می بایست برخورد را به قالب مورد نظر اضافه کنیم:

ep_shape_set_collision(global.world, body, shape1, 1, 1, 0);

سه پارامتر آخر این تابع همان پارامترهای ذکر شده (به ترتیب) می باشند.

مرحله ی بعد دادن یک متریال به قالب می باشد:

ep_shape_set_material(global.world, body, shape1, 0.4, 0.4, 0, 0);

پارامتر چهارم ضریب ارتجاع متریال می باشد.

پارامتر پنجم ضریب اصطکاک متریال می باشد.

پارامتر ششم سرعت نرمال سطح می باشد و برای ایجاد متریال های فنری استفاده می شود.

پارامتر آخر سرعت مماسی سطح می باشد و برای شبیه سازی سطوح متحرک مثل تسمه نقاله کاربرد دارد.

مرحله آخر قرار دادن بدنه در مکان مورد نظر در جهان می باشد.

ep_body_set_position(global.world, body, x, y, degtorad(image_angle));

ما در اینجا جهان فیزیک را با room بازی تناسب دادیم و مختصات بدنه در جهان فیزیک را x و y آبجکت قرار دادیم.

پارامتر آخر هم زاویه بدنه می باشد که از زاویه ی آبجکت استفاده شده.

کد رویداد Create در انتها به صورت زیر می شود:

body = ep_body_create_static(global.world);
shape1 = ep_shape_create_box(global.world, body, sprite_width, sprite_height, 0, 0, 0, 1);
ep_shape_set_collision(global.world, body, shape1, 1, 1, 0);
ep_shape_set_material(global.world, body, shape1, 0.4, 0.4, 0, 0);
ep_body_set_position(global.world, body, x, y, degtorad(image_angle));

حال در رویداد Destroy آبجکت کد زیر را قرار دهید تا پس از نابودی آبجکت، بدنه ی متناسب با آن در جهان فیزیک نیز حذف شود:

ep_body_destroy(global.world, body);

جسم ایستای ما ساخته شد.
ساختن جسم پویا

ساختن جسم پویا همانند ساختن جسم ایستا می باشد. با تفاوتی اندک!

آبجکت جدیدی ایجاد کنید و یک سپرایت مربعی شکل به آن اختصاص دهید.

کد ایجاد بدنه پویا یک پارامتر اضافه دارد:

body = ep_body_create_dynamic(global.world, false);

پارامتر دوم در صورتی که true باشد از چرخش جسم در اثر برخورد با دیگر اجسام جلوگیری می کند.

سه خط دیگر کد جسم ایستا را نیز در اینجا اضافه می کنیم:

 

shape1 = ep_shape_create_box(global.world, body, sprite_width, sprite_height, 0, 0, 0, 1);
ep_shape_set_collision(global.world, body, shape1, 1, 1, 0);
ep_shape_set_material(global.world, body, shape1, 0.4, 0.4, 0, 0);

در اینجا ما می خواهیم جسم پویا جاذبه داشته باشد.

ep_body_calculate_mass(global.world, body);
ep_body_set_gravity(global.world, body, 0, 0.2);

کد اول مرکز ثقل بدنه را محاسبه می کند.

کد دوم به بدنه جاذبه می دهد. پارامتر های آخر به ترتیب جاذبه ی افقی و عمودی می باشد.

در انتها نیز مکان بدنه را تعیین می کنیم:

ep_body_set_position(global.world, body, x, y, degtorad(image_angle));

کد رویداد Create در انتها به صورت زیر می شود:

body = ep_body_create_dynamic(global.world, false);
shape1 = ep_shape_create_box(global.world, body, sprite_width, sprite_height, 0, 0, 0, 1);
ep_shape_set_collision(global.world, body, shape1, 1, 1, 0);
ep_shape_set_material(global.world, body, shape1, 0.4, 0.4, 0, 0);
ep_body_calculate_mass(global.world, body);
ep_body_set_gravity(global.world, body, 0, 0.2);
ep_body_set_position(global.world, body, x, y, degtorad(image_angle));

همانند جسم ایستا کد نابودی بدنه را در رویداد Destroy این آبجکت قرار دهید:

ep_body_destroy(global.world, body);

در این جا به دلیل افزودن جاذبه و همچنین پویا بودن بدنه، مکان بدنه تغییر می کند. پس می بایست مختصات مکان را به آبجکت بازگردانیم.

در رویداد End Step کد زیر را وارد کنید:

x = ep_body_get_x(global.world, body);
y = ep_body_get_y(global.world, body);
image_angle = radtodeg(ep_body_get_rot(global.world, body));

جسم پویای ما آماده شد.

حال با جسم ایستا زمینی در Room مورد نظر بسازید و اجسام پویا را در بالای آن قرار دهید.

بازی را اجرا کنید و نتیجه را ببینید.

ساخت جسم دایره ای شکل

تا به اینجای کار تنها اجسام مربعی شکل ایجاد کردیم. برای ایجاد جسم دایره ای شکل تنها قالب آن متفاوت می باشد.

از جسم پویا یا ایستای خود کپی بگیرید. سپرایت آن را به شکل دایره تغییر دهید و کد زیر را به جای قالب قبلی آن در رویداد Create قرار دهید:

shape1 = ep_shape_create_circle(global.world,body,sprite_width / 2,0,0,0,1);

پارامتر سوم شعاع دایره می باشد.

پارامتر چهارم و پنجم مختصات مرکز دایره می باشند.

پارامتر ششم زاویه ی قالب می باشد.

پارامتر هفتم تراکم قالب می باشد که در بدنه های ایستا کاربرد ندارد.

ساخت جسم چندضلعی

برای استفاده از یک چندضلعی برای قالب یک بدنه ابتدا باید آن چند ضلعی را ایجاد کنیم:

global.poly_triangle1 = ep_polygon_create(global.world,3);

من در اینجا یک 3 ضلعی (مثلث) تعریف کرده ام.

حال می بایست رئوس آن را مشخص نمایم:

ep_polygon_set_vertex(global.world,global.poly_triangle1,0,0,-41);
ep_polygon_set_vertex(global.world,global.poly_triangle1,1,41,41);
ep_polygon_set_vertex(global.world,global.poly_triangle1,2,-41,41);

پارامتر سوم در هر تابع اندیس راس را مشخص می کند و پارامترهای بعدی مختصات اندیس نسبت به مرکز چند ضلعی را مشخص می کند.

توجه نمایید که رئوس چند ضلعی می بایست به صورت ساعت گرد تعیین شوند و همچنین هر چند ضلعی باید محدب باشد. در صورتی که بخواهیم یک قالب مقعر داشته باشید می بایست از چند قالب محدب استفاده کنید که در آموزش های بعدی توضیح داده خواهد شد.

پس از تعیین مکان رئوس می بایست چندضلعی را مقداردهی کنیم:

ep_polygon_initialize(global.world,global.poly_triangle1);

حال قالب ما ساخته شد، آن را به بدنه نسبت می دهیم:

shape1 = ep_shape_create_polygon(global.world,body,global.poly_triangle1,0,0,0,1);

اگر ایجاد چندضلعی و تعیین مکان رئوس برای شما سخت است می توانید برنامه ی Polygon Creator را از آدرس زیر دانلود نمایید و چندضلعی خود را راحت تر از روی شکل بسازید:

 

http://www.maartenbaert.be/extremephysics/polygon-creator/

example-02

  • تشخیص برخورد

ExtremePhysics برخوردها را به طور خودکار مدیریت می کند، بنابراین نیازی نیست شما برای برخورد بدنه ها و واکنش آن ها کاری انجام دهید. اما بعضی اوقات ممکن است شما بخواهید هنگام برخورد دو بدنه کار خاصی را انجام دهید، مثلا بخواهید یکی از آن ها نابود شود. اگر شما بخواهید از رویداد یا توابع برخورد خود گیم میکر استفاده کنید، ممکن است نتیجه ی درست ندهد، زیرا سیستم برخورد گیم میکر بر اساس سپرایت ها می باشد. اگر شما از ExtremePhysics استفاده می کنید، پس بهتر است از توابع تشخیص برخورد آن استفاده کنید.

تشخیص برخورد بین بدنه ها

برخورد بین بدنه ها می تواند توسط contact ها تشخیص داده شود. زمانی که دو بدنه به هم برخورد می کنند، ExtremePhysics هنگامی که شما تابع ep_world_update_contacts را فراخوانی می کنید یک contact ایجاد می کند.

شما می توانید از کد زیر برای چک کردن برخورد دو بدنه استفاده کنید:

// bodies_touch(world,body1_id,body2_id)
// returns whether two bodies are touching
var s, c;
for(s = ep_body_first_shape(argument0, argument1); s!=0; s = ep_shape_next(argument0, argument1, s))
{
for(c = ep_shape_get_first_contact(argument0, argument1, s); c!=0; c = ep_shape_get_next_contact(argument0, argument1, s, c))
{
if(ep_contact_get_body1(argument0, c) == argument2 || ep_contact_get_body2(argument0, c) == argument2)
return true;
}
}
return false;

در کد بالا حلقه for اول برای تک تک قالب های بدنه اول تکرار می شود. حلقه دوم برای تک تک تماس هایی که قالب در آن دخیل است اجرا می شود. در شرط if بررسی می شود که اگر یکی از دو بدنه ی دخیل در تماس یا همان contact برابر بدنه دوم باشد پس بین دو بدنه برخورد وجود دارد و مقدار صحیح برگردانده می شود.

این کد یک مشکل کوچک پیش می آورد. ما در گیم میکر می گوییم اگر آبجکت با آبجکت خاصی برخورد کرد، دستور خاصی انجام شود، اما این کد نمی تواند آبجکت را شناسایی کند. برای این کار می توانید با کد زیر شناسه نمونه آبجکت را در بدنه ذخیره نمایید:

ep_body_set_uservar(global.world, body, 0, id);

این کد را بعد از ساختن هر بدنه اضاقه نمایید. تابع مورد نظر متغیر id که شناسه آبجکت می باشد را در اندیس اول (صفر) بدنه مورد نظر ذخیره می کند.
حال شما می توانید از کد زیر به جای رویداد Collision استفاده کنید:

var s, c, b, object;
for(s = ep_body_first_shape(global.world, body); s!=0; s = ep_shape_next(global.world, body, s))
{
for(c = ep_shape_get_first_contact(global.world, body, s); c!=0; c = ep_shape_get_next_contact(global.world, body, s, c))
{
b = ep_contact_get_body1(global.world, c);
if(b == body){b = ep_contact_get_body2(global.world, c);}

object = ep_body_get_uservar(global.world, b, 0);
if(object.object_index == obj_block)
{
// this instance is touching a block
}
}
}

در این کد آبجکت کاندید برای چک کردن برخورد آبجکت obj_block می باشد.

روش دیگری نیز برای تشخیص برخورد وجود دارد که می تواند در حالت هایی بهتر باشد:

var c, b1, b2, object1, object2;

for(c = ep_world_first_contact(global.world); c!=0; c = ep_contact_next(global.world, c))
{
b1 = ep_contact_get_body1(global.world, c);
b2 = ep_contact_get_body2(global.world, c);

object1 = ep_body_get_uservar(global.world, b1, 0);
object2 = ep_body_get_uservar(global.world, b2, 0);

if(object1.object_index == obj_block && object2.object_index == obj_player)
{
collision_block_player(object1, object2);
}
else if(object1.object_index == obj_player && object2.object_index == obj_block)
{
collision_block_player(object2, object1);
}
else if(object1.object_index == obj_player && object2.object_index == obj_ball)
{
collision_player_ball(object1, object2);
}
else if(object1.object_index == obj_ball && object2.object_index ==obj_player)
{
collision_player_ball(object2, object1);
}
@Lyo=@ … @Ki8=@
}

توجه کنید توابع collision_block_player و collision_player_ball توابع تعریف شده توسط شما خواهد بود. این کد زمانی کارآمد خواهد بود که شما بخواهید هر برخورد بین دو آبجکت در هر step فقط یک بار بررسی شود.

ممکن است شما بخواهید از ارث بری در آبجکت ها استفاده کنید. مثلا سه نوع مانع دارید و همگی آن ها فرزند obj_block هستند. برای کارآمدی کد بالا در این مورد می توانید از تابع obj_is_ancestor گیم میکر استفاده کنید که تشخیص می دهد آبجکت اول فرزند آبجکت دوم می باشد یا خیر. استفاده از آن در این جا به صورت زیر می باشد:

if(object_is_ancestor(object1.object_index, obj_block) && object2.object_index == obj_player)
{
collision_block_player(object1, object2);
}
else if(object1.object_index == obj_player && object_is_ancestor(object2.object_index, obj_block))
{
collision_block_player(object2, object1);
}

برخورد با قالب های مجازی

قالب های مجازی (virtual shapes) قالب هایی هستند که در حقیقت وجود ندارند و تنها برای بررسی برخورد می باشند. تفاوت آن ها با قالب های معمولی در این است که برخورد را تشخیص می دهند، contact به وجود می آورند، اما واکنشی نشان نمی دهند (مثل قالب های معمولی در اثر برخورد متوقف نمی شوند و یا بر نمی گردند).

توابع زیر برای تشخیص برخورد با قالب مجازی می باشد:

ep_world_collision_test_box
ep_world_collision_test_line
ep_world_collision_test_circle
ep_world_collision_test_polygon
ep_body_collision_test_box
ep_body_collision_test_line
ep_body_collision_test_circle
ep_body_collision_test_polygon
ep_shape_collision_test_box
ep_shape_collision_test_line
ep_shape_collision_test_circle
ep_shape_collision_test_polygon

هر کدام از توابع بالا یک قالب مجازی ایجاد می کند و تعداد قالب هایی که با آن برخورد دارند را برمی گرداند. می توانید پارامترهای آن ها را در بخش Refrence های سایت سازنده مشاهده نمایید.
پس از استفاده از این توابع شما می توانید برای پیدا کردن بدنه یا قالب طرف دیگر برخورد با این قالب مجازی از توابع ep_world_get_collision_body و ep_world_get_collision_shape استفاده نمایید.
همچنین توابع زیر برای بررسی برخورد بین دو قالب مجازی استفاده نمایید:

ep_collision_test_box_box
ep_collision_test_box_line
ep_collision_test_box_circle
ep_collision_test_box_polygon
ep_collision_test_line_line
ep_collision_test_line_circle
ep_collision_test_line_polygon
ep_collision_test_circle_circle
ep_collision_test_circle_polygon
ep_collision_test_polygon_polygon

  • چند ضلعی ها

همان طور که گفتیم قانون استفاده از Polygon در ExtremePhysics محدب بودن آن هاست.

برای این کار باید از Multipolygon ها استفاده کنیم که کار با آن ها بسیار راحت می باشد، البته با برنامهPolygon Creator راحت تر!

کار با Multipolygon ها همانند Polygon هاست، با اندکی تفاوت:

// this has to be done only once
ep_world_multipoly_begin(global.world,10);
ep_world_multipoly_set_vertex(global.world,0,10,10);
ep_world_multipoly_set_vertex(global.world,1,20,10);
ep_world_multipoly_set_vertex(global.world,2,20,20);
// …
ep_world_multipoly_end(global.world,true);
poly_first = ep_world_multipoly_get_first(global.world);
poly_last = ep_world_multipoly_get_last(global.world);

توجه نمایید که ترتیب رئوس باید ساعت گرد باشد.

همچنین اضلاع نباید یک دیگر را قطع نمایند.

حال قدم بعدی دادن قالب به چندضلعی می باشد که یکم پیچیده تر از چندضلعی های معمولی می باشد:

for(i=poly_first;i<=poly_last;i+=1)
{
shape = ep_shape_create_polygon(global.world,body,i,0,0,0,0.1);
ep_shape_set_collision(global.world,body,shape,1,1,0);
ep_shape_set_material(global.world,body,shape,0.2,0.5,0,0);
}

همان طور که در کد بالا می بینید Multipolygon ها ترکیبی از چند Polygon می باشند.

 

example-03

 

مطالب مرتبط

آموزش کد سیستم های عامل در گیم میکر

آموزش ایجاد نوار سلامتی در Game Maker

آموزش کار با Registry در گیم میکر

آموزش ساختمان داده ها در Game Maker (قسمت دوم)

آموزش ساختمان داده ها در Game Maker (قسمت اول)

آموزش تایپ فارسی در Game Maker

آموزش ExtremePhysics در گیم میکر به صورت پیشرفته

محتوای مطلب

کامنت ها

لطفا اگر سوالی نامرتبط با این مطلب دارید، از تب «پرسیدن سوال» استفاده کنید

پاسخ دهید

نشانی ایمیل شما منتشر نخواهد شد.

<