عقول الأعداء
جزء من قسم هندسة الألعاب في Unity في رحلة Unity على Coddy. الدرس 39 من 64.
دماغ العدو عبارة عن آلة حالات لها حالة واحدة لكل سلوك. يتحرك هذا الهيكل العظمي بين مواقعه، ويطارد اللاعب إذا اقترب إلى مسافة 6 وحدات، ويضرب بسيفه مرة كل ثانية عندما يكون قريبًا. تحدد كل حالة مسار الخروج منها، ويحتفظ الهيكل العظمي بالمساعدات المشتركة بينها:
public class Skeleton : MonoBehaviour
{
public Transform player;
public Transform[] posts;
public float speed = 2f;
public StateMachine machine = new StateMachine();
public IState patrol, chase, attack;
void Start()
{
patrol = new PatrolState(this);
chase = new ChaseState(this);
attack = new AttackState(this);
machine.ChangeState(patrol);
}
void Update() { machine.Tick(); }
public float PlayerDistance() { return Vector3.Distance(transform.position, player.position); }
public void WalkTo(Vector3 target)
{
target.y = transform.position.y;
transform.position = Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime);
}
}
public class PatrolState : IState
{
private Skeleton skel;
private int next;
public PatrolState(Skeleton skel) { this.skel = skel; }
public void Enter() { }
public void Exit() { }
public void Tick()
{
if (skel.PlayerDistance() < 6f) { skel.machine.ChangeState(skel.chase); return; }
Vector3 post = skel.posts[next].position;
post.y = skel.transform.position.y;
skel.WalkTo(post);
if (skel.transform.position == post) next = (next + 1) % skel.posts.Length;
}
}
public class ChaseState : IState
{
private Skeleton skel;
public ChaseState(Skeleton skel) { this.skel = skel; }
public void Enter() { }
public void Exit() { }
public void Tick()
{
float d = skel.PlayerDistance();
if (d > 6f) { skel.machine.ChangeState(skel.patrol); return; }
if (d < 1.5f) { skel.machine.ChangeState(skel.attack); return; }
skel.WalkTo(skel.player.position);
}
}
public class AttackState : IState
{
private Skeleton skel;
private float cooldown;
public AttackState(Skeleton skel) { this.skel = skel; }
public void Enter() { cooldown = 0f; }
public void Exit() { }
public void Tick()
{
if (skel.PlayerDistance() > 1.5f) { skel.machine.ChangeState(skel.chase); return; }
cooldown -= Time.deltaTime;
if (cooldown <= 0f) { Debug.Log("Swing!"); cooldown = 1f; }
}
}تُنشأ الحالات مرة واحدة وتبقى طوال مدة حياة الهيكل العظمي، لذا تظل حقولها محتفظة بقيمها بين الزيارات. تظل قيمة next في PatrolState كما هي بعد المطاردة، ويواصل الهيكل العظمي السير نحو الموقع الذي كان متجهًا إليه. تعيد Enter ضبط ما ينبغي أن يبدأ من جديد فقط: تضبط cooldown في AttackState إلى 0، لذا تحدث الضربة الأولى بمجرد وصول الهيكل العظمي إلى اللاعب.
تمر كل الحركة عبر WalkTo، التي تستخدم هنا MoveTowards على transform، وهذا يجعل الهيكل العظمي يمشي عبر الجدران. لتحريك الهيكل العظمي باستخدام Rigidbody بدلًا من ذلك، تضبط WalkTo سرعة الجسم، ويحدّث الهيكل العظمي الآلة في FixedUpdate، حيث تمثل Time.deltaTime خطوة الفيزياء. لا تتغير الحالات الثلاث: فهي تحدد إلى أين يذهب، أما الكائن المالك فيحدد كيف.
التحدي
متوسطأضف إلى الفارس PatrolState وChaseState في KnightStates.cs، ومرّر الفارس إلى كل منهما.
- الدورية: تحرّك إلى
waypoints[next]؛ وعندما تصبح المسافة أقل من0.3، انتقل إلىnextالتالي بالتتابع، مع الاحتفاظ بقيمته بين الزيارات. إذا أصبحت المسافة أقل منsightRange، فابدأ المطاردة. - المطاردة: تحرّك نحو اللاعب؛ وإذا تجاوزت المسافة
loseRange، فابدأ الدورية. - في
Knight، أنشئ آلة الحالات والحالات في Awake، وابدأ بالدورية في Start، ونفّذ التحديث في FixedUpdate.
اضغط «العب»، ثم اقترب واركض. ثم اضغط «تحقق».
جرّب بنفسك
using UnityEngine;
// PatrolState و ChaseState
جميع دروس هندسة الألعاب في Unity
1المكوّنات، لا التسلسلات الهرمية
مكوّنات صغيرةنص برمجي أساسي للعدومكوّنات مجرّدةالمكوّنات تعمل معًامراجعة: برج معياريمراجعة: مدفع مزدوج4البيانات المُسلسلة
الأصناف القابلة للتسلسلالقوائم في Inspectorالتعدادات في Inspectorمراجعة: جدول الغنائممراجعة: اختيار الغنائم عشوائيًا7آلات الحالات
الحالات كأصنافحالة التنبيهآلة حالاتالانتقالاتعقول الأعداءالفارس يهاجممراجعة: حالات الباب2الواجهات في Unity
IDamageableالواجهات وTryGetComponentGetComponentsمراجعة: مفتاح التفاعلمراجعة: أقرب عنصر ضمن النطاقتدرّب بنفسك: Playground لـ Unity