افزودن دشمن
تا حالا باید با مراحل اضافه کردن اسپرایت و انیمیشن آشنا شده باشید. بنابراین برای طولانی نشدن این آموزش دوباره تکرار نمیشوند. بیایید اسپرایت جدیدی برای دشمن وارد کنیم.
1. شیء اسپرایت جدیدی در لیوت اضافه کنید.
2. اسپرایت استریپ Enemiws\Snail را وارد کنید.
3. اولین فریم انیمیشن که خالی است را حذف کنید.
4. تنظیم کنید انیمیشن تکرار شود، و سرعت آن 15 باشد.
5. نقطهی مبدأ را در پایین تصویر حلزون قرار دهید، و آن را به تمام انیمیشن اعمال کنید.
6. قسمتهای اضافی همهی فریمها را ببرید (shift + crop)
7. ویرایشگر انیمیشن را ببندید و نام شیء را به SnailEnemy تغییر دهید.
8. همان طور که نشان داده شده است آن را روی زمین قرار دهید.
حالا ما میخواهیم از منطق زیر پیروی کنیم:
- اگر پلیر از کنار به حلزون برخورد کند، چشمک میزند و صدمه میبیند.
- اگر پلیر از بالا روی حلزون بپرد، حلزون میمیرد.
برای چشمک زدن پلیر، پلیر را انتخاب کنید و به آن رفتار Flash بدهید. یادتان باشد پلیر واقعی را انتخاب کنید، نه شیء PlayerBox را (چون ما میخواهیم آن پلیری که دیده میشود چشمک بزند) ما از اکشن Flash این رفتار استفاده خواهیم کرد.
به نمای ایونت شیت بروید، و ایونتی جدید اضافه کنید:
PlayerBox -> On collision with another object -> SnailEnemy
این ایونت وقتی اجرا میشود که با هر زاویهای به حلزون برخورد کنیم. ما میتوانیم از ساب-ایونتها برای اینکه آیا پلیر از بالا روی حلزون پریده یا از کنار به آن برخورد کرده استفاده کنیم. بیایید اوّل تست کنیم که آیا پلیر بالا است.
یک ساب-ایونت به ایونت برخورد اضافه کنید:
PlayerBox -> Is falling
ما باید بررسی کنیم که آیا پلیر واقعاً بالای دشمن قرار دارد. این کار از کشته شدن تصادفی حلزون جلوگیری میکند، مثلاً اگر از گوشهای پایین بیفتیم. روی شرط Is falling کلیک راست کنید و گزینهیAdd another condition را انتخاب کنید. یادتان باشد برای اجرا شدن یک ایونت باید همهی شرطهایش درست باشد. افزودن شرطها:
PlayerBox -> Compare Y -> Less than, SnailEnemy.Y
محور Yها به سمت پایین افزایش مییابد، بنابراین اگر مختصهی Y پلیر کمتر از مال حلزون باشد، پلیر بالاتر از آن قرار دارد.
در این ایونت، این اکشن را اضافه کنید:
SnailEnemy -> Destroy
ما میتوانیم با افزودن اکشن دیگری باعث شویم پلیر به سمت بالا نیز بجهد:
PlayerBox -> Set vector Y -> -700
'Set vector Y' basically just sets the vertical speed of the platform movement; setting it to a negative value sets it upwards (again, the Y axis increases downwards), and 700 is a little less than the jump strength of 1100. So this will make the player bounce off as if they did a weak jump. Set vector Y اساساً فقط سرعت عمودی حرکت پلت فرم را تنظیم میکند؛ تنظیم آن به عددی منفی آن را به سمت بالا تنظیم میکند (چون محور Y به سمت پایین افزایش مییابد)، و 700 کمی از قدرت پرش پلیر یعنی از 1100 کمتر است. پس این کار باعث میشود پلیر بجهد مثل پرشی ضعیف.
We're not quite done: right-click the margin of the 'Is falling' event (the space just to the left of the PlayerBox icon) and select Add -> Else. 'Else' is a special condition that runs if the previous event did not run. So this event will run if we collided with the snail but we weren't jumping on top of it - we ran in to it from the side, say. In this event we want the player to be hurt. Add the action هنوز تمام نشده است: روی حاشیهی ایونت Is falling کلیک راست کنید (فضایی که در سمت چپ آیکون PlayerBox قرار دارد) و Add -> Else را انتخاب کنید. Else یک شرط مخصوص است که اگر ایونت قبلی اجرا نشود آن اجرا میشود. پس اگر ما به حلزون برخورد کنیم امّا روی آن نپریده باشیم این ایونت اجرا خواهد شد - یعنی از کنار به حلزون برخورد کردیم. در این ایونت میخواهیم که پلیر آسیب ببیند. این اکشن را اضافه کنید:
Player -> Flash -> (leave default values and click Done) Player -> Flash -> (مقادیر پیشفرض را تغییر ندهید و روی Done کلیک کنید)
Remember the Flash behavior is in the Player object, not PlayerBox. یادتان باشد که رفتار Flash در شیء Player است نه PlayerBox.
OK, so the player will never die, they'll just flash. But we've got the detection set up of whether they jumped on top or ran in to the side. This tutorial won't cover all the bells and whistles, but hopefully you can see where to create kill effects (try creating a 'poof' sprite on the SnailEnemy when it is destroyed, using the SnailEnemy's 'Spawn object' action) and where to take off health (in the event that makes the player flash - you can learn about health using instance variables in the top-down shooter tutorial which you might want to look at afterwards). خوب، چون پلیر هیچوقت نمیمیرد، فقط چشمک میزند. امّا تشخیص اینکه آیا از بالا روی آن پریدیم یا از کنار به آن برخورد کردیم را راهاندازی کرده ایم. این آموزش تمام ویژگیها و جزئیات را پوشش نمیدهد، امّا میتوانید ببینید کجا افکتهای مردن را ایجاد میکنیم (سعی کنید وقتی حلزون نابود شد یک اسپرایت poof روی آن ایجاد کنید، با استفاده از اکشن Spawn object حلزون) و کجا از سلامتیاش کم کنیم (در ایونتی که باعث میشود پلیر چشمک بزند - میتوانید در مورد سلامتی با استفاده از متغیرهای اینستنس در آموزش ساخت تاپ-دون شوتر اطلاعات کسب کنید که شاید بخواهید بعداً نگاهی به آن بیندازید).
Let's make the snail enemy move back and forth across the platform. بیایید باعث شویم حلزون در پلت فرم عقب و جلو برود.
Moving the enemy
حرکت دشمن
The main problem with moving the snail is how to detect when it's reached the edge of a platform. The easiest way to do this is with invisible 'edge' markers. These are just invisible sprites that flip the direction of the snail when it touches them. مشکل اصلی حرکت حلزون این است که چگونه تشخیص دهد که به لبهی پلت فرمی رسیده است. سادهترین راه انجام این کار نشانگذارهای نامرئی لبههاست. اینها فقط اسپرایتهای نامرئیای هستند که وقتی حلزون به آنها برخورد کند جهت حرکتش را قرینه میکنند.
We can also use the Platform behavior again for the snail. This is convenient because: ما میتوانیم برای حلزون نیز دوباره از رفتار Platform استفاده کنیم. این کار مناسب است زیرا:
- it can get it moving left and right - میتواند به چپ و راست حرکت کند
- it will go up and down slopes just like the player can - میتواند از شیب پایین و بالا برود درست همان طور که پلیر میتواند
- it will fall off ledges if you want it to - از لبهها پایین میافتد اگر بخواهید
- if you want to make a jumping enemy, you can make the enemy automatically jump too using the 'simulate control' action. - اگر بخواهید دشمنی بسازید که بتواند بپرد، میتوانید با اکشن simulate control باعث شوید که به صورت خودکار بپرد.
Add the Platform behavior to the SnailEnemy sprite. Since we are not using complicated animations on this object, we can get away with using the platform behavior directly on the object without an invisible 'box' object. Note if you make a different platform game with enemies with complicated animations, you should use the same box technique we used on the player. به اسپرایت SnailEnemy رفتار پلت فرم را اضافه کنید. چون ما از انیمیشنهای زیادی روی این شیء استفاده نکردیم، میتوانیم با استفاده از رفتار پلت فرم شیء به طور مستقیم بدون شیئی نامرئی این کار را انجام دهید. توجه داشته باشید اگر بازی پلت فرم دیگری با دشمنهایی که انیمیشنهایی زیاد دارند بسازید، باید از همان تکنیک اسپرایت نامرئی که برای پلیر استفاده کردیم استفاده کنیم.
We don't want the player to control the SnailEnemy - we want to automatically control it. We can do this by setting its Default controls property to No, then using the Simulate control action. Since snails are also pretty slow, set the Max speed to 50 and its Acceleration and Deceleration to 100! ما نمیخواهیم بازیکننده دشمن را کنترل کند - ما میخواهیم به طور خودکار کنترل شود. ما میتوانیم این کار را با تنظیم ویژگی Default controls به No و بعد با استفاده از اکشن Simulate control انجام دهیم. چون حلزونها نسبتاً آهسته حرکت میکنند، Max speed را به 50 تنظیم کنید و Acceleration و Deceleration را به 100 تنظیم کنید!
We'll also need our 'Edge' markers. Add a new Sprite object and just load in an opaque rectangle. Call it EdgeMarker. Size the object to about 40 x 40 and set its Initial visibility to Invisible so we don't see it. Place one at each end of the snail's platform like so: (don't forget you can create a new instance by control+dragging it) ما همچنین به نشانگذارهای لبهها نیاز داریم. اسپرایتی جدید اضافه کنید و فقط یک مستطیل کدر بارگذاری کنید. آن را EdgeMarker بنامید. سایز شیء را به 40×40 تغییر دهید و Intial visibility آن را به Invisible تغییر دهید تا نتوانیم آن را ببینیم. در آخر هر یک از پلت فرمها یکی از آنها را قرار دهید مثل این: (فراموش نکنید با نگه داشتن کلید کنترل و درگ کردن میتوانید نمونههایی جدید از شیئتان ایجاد کنید)
The snail also needs to know which way it is currently moving - either left or right. We can do this with instance variables. These are simply numbers or text stored in each instance of the object. If we have multiple snails, they each store their instance variables separately. This allows them to have unique values for their health, current direction, and so on. A simple technique to control enemies automatically is to create an "action" instance variable which holds its current state. For example, it could be "run away", "chase player" or "idle". In this case we only need "left" and "right", but it's useful to set it up the same way. حلزون باید بداند که الآن در چه راهی حرکت میکند – چپ یا راست. میتوانیم این کار را با متغیّرهای اینستنس (instance variables) انجام دهیم. اینها اعداد یا متنهایی هستند که در هر اینستنس شیء ذخیره میشوند. اگر چند حلزون داشته باشیم، این متغیّرها برای هر کدام از آنها به طور مجزّا ذخیره میشوند. این به آنها اجازه میدهد که سلامتی، جهت فعلی و چیزهای دیگر منحصر به فرد داشته باشند. ایجاد متغیّر اینستنسی که موقعیت فعلی دشمن را نگه میدارد تکنیکی ساده برای کنترل شدن خودکار دشمنهاست. مثلاً میتواند فرار کند، پلیر را تعقیب کند یا بیکار باشد. در این مورد ما فقط به چپ و راست نیاز داریم، ولی راه اندازی آن به این روش مفید است.
Select the SnailEnemy object. In the properties bar, click Add / Edit under 'Instance variables'. شیء SnailEnemy را انتخاب کنید. در نوار ویژگیها، روی Add / Edit زیر Instance variables کلیک کنید.
A dialog listing all instance variables for the object appears. Click the 'add' icon to add a new one. Set the name to action, the type to text, and the initial value to right (for moving right). پنجرهای که در آن تمام متغیّرهای اینستنس لیست شده ظاهر میشود. روی آیکون add کلیک کنید تا یکی جدید اضافه کنید. نام آن را به action تغییر دهید، نوع را به text (متن) ، و مقدار اوّلیّه (intial value) را به right تنظیم کنید (برای حرکت).
Click OK and close the instance variables dialog. Switch to the event sheet. روی OK کلیک کنید و پنجرهی متغیّرهای اینستنس را ببندید. به ایونت شیت برگردید.
We want to implement the following logic: ما میخواهیم منطق زیر را اجرا کنیم:
- if action is "right", simulate the platform movement holding the 'right' key to move the snail right. - اگر مقدار action برابر right باشد، برای اینکه حلزون به راست حرکت کند نگه داشته شدن کلید راست شبیهسازی شود.
- if action is "left", simulate the platform movement holding the 'left' arrow key to move the snail left. - اگر مقدار action برابر left باشد، برای اینکه حلزون به چپ حرکت کند نگه داشتن کلید چپ شبیهسازی شود.
Also: همچنین:
- if the snail hits the EdgeMarker, flip its action (if "left" set it to "right"; if "right" set it to "left"). - وقتی حلزون به نشانگذارهای لبهها برخورد کرد، مقدار action قرینه شود (اگر left بود right شود و برعکس)
We can set up the movement with the following two events: ما با این دو ایونت میتوانیم حرکت حلزون را راه اندازی کنیم.
Event: SnailEnemy -> Compare instance variable -> action equal to "right" (use double quotes here to indicate text) " Event: SnailEnemy -> Compare instance variable -> action equal to ""right"" (برای اینکه نشان دهید متن است از دابل کوتیشن استفاده کنید)"
Action: SnailEnemy -> Simulate control -> Right Action: SnailEnemy -> Simulate control -> Right
It should be straightforward to do the same for left. We also want the image to mirror left and right like we did for the player. So add SnailEnemy -> Set mirrored in the "left" event, and SnailEnemy -> Set not mirrored in the "right" event. You should finish with this: باید درست همین کار را برای چپ هم انجام دهید. درضمن ما میخواهیم روی حلزون به سمت چپ و راست تغییر کند مثل پلیر. بنابراین در ایونت مربوط به چپ SnailEnemy -> Set mirrored را اضافه کنید، و SnailEnemy -> Set not mirrored را در ایونت مربوط به راست اضافه کنید. باید با این تمام شده باشد:
Now to flip the snail's direction on the edges: حالا برای اینکه وقتی حلزون به لبهها رسید جهتش قرینه شود:
Event: SnailEnemy -> On collision with another object -> EdgeMarker "Event: SnailEnemy -> On collision with another object -> EdgeMarker
Subevent: SnailEnemy -> Compare instance variable -> action equal to ""right""
Action: SnailEnemy -> Set value -> action to ""left""
Subevent: Else
Action: SnailEnemy -> Set value -> action to ""right""
"
Subevent: SnailEnemy -> Compare instance variable -> action equal to "right"
Action: SnailEnemy -> Set value -> action to "left"
Subevent: Else
Action: SnailEnemy -> Set value -> action to "right"
It's important to use Else here, because events are run from top-to-bottom. If instead of 'else' we said 'action equal to "left"', notice the previous event would have just set it to that. So it'd just set it right back again, having no overall effect. By using 'else', we prevent the second event running if the first was true. اینجا استفاده از Else مهم است، چون ایونتها از بالا به پایین اجرا میشوند. اگر به جای else (وگرنه) بگوییم اگر متغیّر action برابر left بود، در هر صورت برابر left است چون ایونت قبلی آن را برابر left قرار میدهد. بنابراین دوباره به راست حرکت میکند، بدون اثری کلی. با استفاده از else، ما از اجرای ایونت دوم درصورتی که اوّلی درست باشد جلوگیری میکنیم.
Run the project. Notice the snail is moving back and forth on its platform. This makes it a bit harder to jump on! This is a very rudimentary "AI" system, but hopefully you can imagine that you could create more intelligent enemies by controlling the movement with more events, possibly even allowing them to fall off edges, or using other markers to trigger a jump to make it look like the enemy knew to jump up on to a platform. بازیتان را اجرا کنید. میبینید که حلزون دارد به عقب و جلو حرکت میکند. این باعث میشود که پریدن روی حلزون کمی سختتر شود! این یک سیستم هوش مصنوعی بسیار ابتدایی است، امّا تصور کنید که میتوانید دشمنانی باهوشتر که حرکتشان با ایونتهای بیشتر کنترل میشود خلق کنید. ممکن است حتّی به آنها اجازه دهید از لبهها بیفتند، یا از نشانگذارهای دیگری استفاده کنید تا با رسیدن به آنها پرش شبیهسازی شود تا اینطور به نظر برسد که دشمن میداند باید از لبهها بپرد.
Try creating a platform with two snails on it. Notice they control themselves individually, since they each have their own individual action instance variable holding their current state. Hopefully you can begin to see how important instance variables are for controlling instances independently - they don't all have to be doing exactly the same thing as each other! سعی کنید پلت فرمی بسازید با دو حلزون روی آن. توجّه کنید که آنها شخصاً خودشان را کنترل میکنند، چون هر یک از آنها متغیّر اینستنس action مربوط به خود را دارند که وضعیتشان را مشخص میکند. امیدوارم ببینید که چه قدر متغیرهای اینستنس برای حرکت به طور مستقل مهم هستند – همهی آنها مجبور نیستند دقیقاً همان کاری را انجام دهند که دیگری انجام میدهد.