إنشاء تفاعلات ذكاء اصطناعي بسيطة مع كائنات البيئة


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

هذا المقال مأخوذ من كتاب Programming Game AI Programming ، من تأليف مايكل داغراك ونشره Packt Publishing. يسمح لك هذا الكتاب بتعلم كيفية إنشاء لعبة ذكاء اصطناعي ومن الصفر تنفيذ خوارزميات الذكاء الاصطناعي الأكثر تقدمًا.

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

يمكن العثور على أحد الأمثلة الأولى للتفاعل مع البيئات في أول Castlevania ، الذي صدر عام 1986 لنظام الترفيه Nintendo. منذ البداية ، يمكن للاعب استخدام السوط لتدمير الشموع والحرائق ، والتي كانت في الأصل جزءًا من الخلفية.


فتحت هذه اللعبة وبعض الألعاب في ذلك الوقت العديد من الأبواب والفرص من حيث التصور الحديث لخلفيات وبيئات الشخصيات في اللعبة. من الواضح أنه نظرًا لقيود الأجهزة لهذا الجيل من وحدات التحكم ، كان من الصعب جدًا إنشاء أشياء بسيطة مقبولة عمومًا بالمعايير الحالية. لكن كل جيل من وحدات التحكم جلب ميزات جديدة واستخدمها المطورون لإنشاء ألعاب مذهلة.

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

الآن يمكننا الانتقال إلى المثال التالي - كائنات في اللعبة متحركة أو تتحرك عندما تمر الشخصيات من خلالها. المبدأ هنا هو نفسه كما هو الحال مع الأشياء القابلة للتدمير ، ولكن هذه المرة يكون التفاعل أكثر دقة - يتطلب الأمر أن تنتقل الشخصية إلى النقطة التي يكون فيها الكائن. يمكن تطبيق هذا على عناصر مختلفة من اللعبة ، من حركة العشب أو الغبار أو الماء إلى الطيور الطائرة أو الأشخاص الذين يقومون بإيماءات مضحكة ؛ الاحتمالات لا حصر لها.

عند تحليل هذه التفاعلات ، يمكننا بسهولة تحديد أنها لا تستخدم بالضرورة الذكاء الاصطناعي ، وفي معظم الحالات تكون مجرد وظيفة منطقية يتم تنشيطها وفقًا لبعض الإجراءات المحددة. ولكنها جزء من البيئة وبالتالي يجب أن تؤخذ في الاعتبار عند تنفيذ تفاعل عالي الجودة بين البيئة والذكاء الاصطناعي.

إنشاء تفاعلات بسيطة مع البيئة


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


لتوضيح مثال واحد على بيئة تؤثر بشكل مباشر على اللعب ، سنأخذ مثالًا ممتازًا - امتياز Tomb Raider. في هذا المثال ، يجب أن تدفع شخصيتنا ، لارا كروفت ، المكعب حتى يهبط على المنطقة المحددة. سيؤدي ذلك إلى تغيير البيئة وفتح مسار جديد ، مما يسمح للاعب بالتحرك أكثر في المستوى.

يمكن العثور على هذه الألغاز في العديد من الألعاب: يجب عليك تنفيذ إجراء في نقطة معينة على الخريطة حتى يحدث شيء ما في جزء آخر منها ، ويمكن استخدامه لتحقيق بعض الأهداف في اللعبة. عادة ما نحتاج إلى تغيير البيئة نفسها من أجل التقدم أكثر في المستوى. لذلك ، عندما يخطط المطورون لخريطة أو مستوى ، يأخذون ذلك في الاعتبار وينشئون جميع القواعد المتعلقة بكل تفاعل. على سبيل المثال:

if(cube.transform.position == mark.transform.position)
{
  openDoor = true;
}

تخيل الآن للحظة أن لارا كروفت لديها شخصية حليف مهمتها الرئيسية هي مساعدتها على وضع هذا الصندوق في مكانه. وفي هذا الفصل ، سننظر في هذا النوع من التفاعل فقط: تتعرف شخصية الذكاء الاصطناعي على كيفية عمل البيئة وكيفية استخدامها.

تتحرك البيئة في تومب رايدر


دعنا نذهب مباشرة إلى هذا السيناريو ومحاولة إعادة إنشاء موقف فيه شخصية AI يمكن أن تساعد اللاعب على تحقيق هدفه. في هذا المثال ، سنتخيل أن لاعبًا محاصرًا لا يمكنه الوصول إلى كائن تفاعلي يمكنه تحريره. يجب أن تكون الشخصية التي ننشئها قادرة على العثور على المكعب ودفعه في الاتجاه الصحيح.


حتى الآن لدينا كل الشخصيات والأشياء. دعونا نخطط كيف يجب أن تتصرف شخصية الذكاء الاصطناعي في هذه الحالة. أولاً ، يجب أن يرى أن اللاعب قريب ، حتى يتمكن من البدء في البحث وتحريك المكعب إلى الموضع المطلوب. افترض أنه إذا كان المكعب عند العلامة ، فستظهر كتلة جديدة من الرمال ، مما يسمح للاعب بالتقدم أكثر في المستوى. يمكن لشخصية الذكاء الاصطناعي دفع المكعب في أربعة اتجاهات: اليسار واليمين والأمام والخلف ، بحيث تتناسب تمامًا مع علامة الموضع.


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

إذا لم يصل اللاعب إلى هناك بعد ، فيجب أن تنتظر شخصيتنا وتبقى في مكانها. إذا وصل اللاعب بالفعل إلى العلامة ، فإن شخصية AI تستمر في التنفيذ وتسأل نفسها عن بعده عن كائن المكعب. إذا لم يكن الأمر كذلك ، فيجب أن تتحرك الشخصية نحو المكعب ، وبمجرد تأكيد هذا الإجراء ، يجب عليه طرح نفس السؤال. عندما تصبح الإجابة إيجابية وتكون الشخصية بجوار المكعب ، يحتاج إلى معرفة الطريقة التي يجب عليك أولاً دفع المكعب بها.

ثم يبدأ في دفع المكعب على طول المحور Y أو X حتى يتطابق مع وضع العلامات وإكمال المهمة.

public GameObject playerMesh;
public Transform playerMark;
public Transform cubeMark;
public Transform currentPlayerPosition;
public Transform currentCubePosition;

public float proximityValueX;
public float proximityValueY;
public float nearValue;

private bool playerOnMark;


void Start () {

}

void Update () {

  // Calculates the current position of the player
  currentPlayerPosition.transform.position = playerMesh.transform.position;

  // Calculates the distance between the player and the player mark of the X axis
  proximityValueX = playerMark.transform.position.x - currentPlayerPosition.transform.position.x;

  // Calculates the distance between the player and the player mark of the Y axis
  proximityValueYplayerMark.transform.position.y - currentPlayerPosition.transform.position.y;

  // Calculates if the player is near of his MARK POSITION
  if((proximityValueX + proximityValueY) < nearValue)
  {
     playerOnMark = true;
  }
}

بدأنا في إضافة معلومات إلى الرمز الذي يسمح للشخص بالتحقق مما إذا كان اللاعب بجانب موقعه المميز. للقيام بذلك ، نقوم بإنشاء جميع المتغيرات اللازمة لحساب المسافات بين اللاعب والموضع الذي يجب أن يكون فيه. playerMeshيشير إلى النموذج ثلاثي الأبعاد للاعب ، الذي نستخرج منه موقعه ونستخدمه كـ currentPlayerPosition.

لمعرفة ما إذا كانت قريبة من العلامة ، نحتاج إلى متغير يمثل موضع العلامة ، وفي مثالنا أنشأنا متغيرًا playerMarkيمكننا فيه كتابة الموضع الذي يجب أن يكون فيه اللاعب. ثم أضفنا ثلاثة متغيرات تخبرنا ما إذا كان اللاعب قريبًا. proximityValueXسيحسب المسافة بين اللاعب وعلامة المحور س. proximityValueYيحسب المسافة بين اللاعب وعلامة المحور ص.

بعد ذلك ، لدينا nearValue، حيث يمكننا تحديد المدى الذي يمكن للاعب أن يكون فيه بعيدًا عن موضع العلامة ، عندما يمكن لشخصية AI أن تبدأ في العمل على تحقيق الهدف. بمجرد أن يقترب اللاعب من العلامة ، playerOnMarkيغير المتغير Boolean القيمة إلى true.

لحساب المسافة بين اللاعب والعلامة استخدمنا ما يلي: المسافة بين اللاعب وعلامته متشابهة (mark.position - player.position).

الآن ، لتحديد ما إذا كان حرف AI بالقرب من المكعب ، نحسب نفس المعادلة عن طريق حساب المسافة بين AI والمكعب. بالإضافة إلى ذلك ، قمنا بتكملة الرمز بمواضع على كلا العلامات (اللاعب والمكعب):

public GameObject playerMesh;
public Transform playerMark;
public Transform cubeMark;
public Transform currentPlayerPosition;
public Transform currentCubePosition;

public float proximityValueX;
public float proximityValueY;
public float nearValue;

public float cubeProximityX;
public float cubeProximityY;
public float nearCube;

private bool playerOnMark;
private bool cubeIsNear;


void Start () {

   Vector3 playerMark = new Vector3(81.2f, 32.6f, -31.3f);
   Vector3 cubeMark = new Vector3(81.9f, -8.3f, -2.94f);
   nearValue = 0.5f;
   nearCube = 0.5f;
}

void Update () {

  // Calculates the current position of the player
  currentPlayerPosition.transform.position = playerMesh.transform.position;

  // Calculates the distance between the player and the player mark of the X axis
  proximityValueX = playerMark.transform.position.x - currentPlayerPosition.transform.position.x;

  // Calculates the distance between the player and the player mark of the Y axis
  proximityValueY = playerMark.transform.position.y - currentPlayerPosition.transform.position.y;

  // Calculates if the player is near of his MARK POSITION
  if((proximityValueX + proximityValueY) < nearValue)
  {
     playerOnMark = true;
  }

  cubeProximityX = currentCubePosition.transform.position.x - this.transform.position.x;
  cubeProximityY = currentCubePosition.transform.position.y - this.transform.position.y;

  if((cubeProximityX + cubeProximityY) < nearCube)
  {
     cubeIsNear = true;
  }

  else
  {
     cubeIsNear = false;
  }
}

الآن بعد أن عرف شخصيتنا بالذكاء الاصطناعي إذا كان بجوار المكعب ، يتيح لنا هذا الإجابة على السؤال وتحديد ما إذا كان يمكنه الانتقال إلى الفرع التالي الذي خططنا له. ولكن ماذا يحدث عندما لا تكون الشخصية بجانب المكعب؟ سيحتاج إلى الاقتراب من المكعب. لذلك ، سنضيف هذا إلى الرمز:

public GameObject playerMesh;
public Transform playerMark;
public Transform cubeMark;
public Transform cubeMesh;
public Transform currentPlayerPosition;
public Transform currentCubePosition;

public float proximityValueX;
public float proximityValueY;
public float nearValue;

public float cubeProximityX;
public float cubeProximityY;
public float nearCube;

private bool playerOnMark;
private bool cubeIsNear;

public float speed;
public bool Finding;


void Start () {

   Vector3 playerMark = new Vector3(81.2f, 32.6f, -31.3f);
   Vector3 cubeMark = new Vector3(81.9f, -8.3f, -2.94f);
   nearValue = 0.5f;
   nearCube = 0.5f;
   speed = 1.3f;
}

void Update () {

  // Calculates the current position of the player
  currentPlayerPosition.transform.position = playerMesh.transform.position;

  // Calculates the distance between the player and the player mark of the X axis
  proximityValueX = playerMark.transform.position.x - currentPlayerPosition.transform.position.x;

  // Calculates the distance between the player and the player mark of the Y axis
  proximityValueY = playerMark.transform.position.y - currentPlayerPosition.transform.position.y;

  // Calculates if the player is near of his MARK POSITION
  if((proximityValueX + proximityValueY) < nearValue)
  { 
      playerOnMark = true;
  }

  cubeProximityX = currentCubePosition.transform.position.x - this.transform.position.x;
  cubeProximityY = currentCubePosition.transform.position.y - this.transform.position.y;

  if((cubeProximityX + cubeProximityY) < nearCube)
  {
      cubeIsNear = true;
  }

  else
  {
      cubeIsNear = false;
  }

  if(playerOnMark == true && cubeIsNear == false && Finding == false)
  {
     PositionChanging();
  }

  if(playerOnMark == true && cubeIsNear == true)
  {
     Finding = false;
  }

}

void PositionChanging () {

  Finding = true;
  Vector3 positionA = this.transform.position;
  Vector3 positionB = cubeMesh.transform.position;
  this.transform.position = Vector3.Lerp(positionA, positionB, Time.deltaTime * speed);
}

حتى الآن ، فإن شخصية AI لدينا قادرة على حساب المسافة بينه وبين المكعب ؛ إذا كانا بعيدان جدا ، فسيذهب إلى المكعب. بعد الانتهاء من هذه المهمة ، يمكنه الانتقال إلى المرحلة التالية والبدء في دفع المكعب. آخر شيء يحتاج إلى حسابه هو إلى أي مدى يكون المكعب بعيدًا عن موضع العلامة ، وبعد ذلك يقرر أي طريقة للدفع ، مع مراعاة أي جانب من المكعب أقرب إلى العلامة.


لا يمكن دفع المكعب إلا على طول محوري X و Z ، ولا يعد تدويره مهمًا بالنسبة لنا بعد ، لأن الزر يتم تنشيطه عند تثبيت المكعب عليه. بالنظر إلى كل هذا ، يجب أن تحسب شخصية الذكاء الاصطناعي مدى المكعب من موضع العلامة على X وموضع العلامة على Z.

ثم يقارن القيمتين على المحورين ويختار أيهما أبعد عن الموضع المطلوب ، ثم يبدأ في الدفع على طول هذا محور. سيستمر الحرف في الدفع في هذا الاتجاه حتى يتم محاذاة المكعب مع موضع العلامة ، ثم ينتقل إلى الجانب الآخر ، ويدفعه حتى يصبح تمامًا فوق موضع العلامة:

public GameObject playerMesh;
public Transform playerMark;
public Transform cubeMark;
public Transform cubeMesh;
public Transform currentPlayerPosition;
public Transform currentCubePosition;

public float proximityValueX;
public float proximityValueY;
public float nearValue;

public float cubeProximityX;
public float cubeProximityY;
public float nearCube;

public float cubeMarkProximityX;
public float cubeMarkProximityZ;

private bool playerOnMark;
private bool cubeIsNear;

public float speed;
public bool Finding;


void Start () {

        Vector3 playerMark = new Vector3(81.2f, 32.6f, -31.3f);
        Vector3 cubeMark = new Vector3(81.9f, -8.3f, -2.94f);
        nearValue = 0.5f;
        nearCube = 0.5f;
        speed = 1.3f;
}

void Update () {

  // Calculates the current position of the player
  currentPlayerPosition.transform.position = playerMesh.transform.position;

  // Calculates the distance between the player and the player mark of the X axis
  proximityValueX = playerMark.transform.position.x - currentPlayerPosition.transform.position.x;

  // Calculates the distance between the player and the player mark of the Y axis
  proximityValueY = playerMark.transform.position.y - currentPlayerPosition.transform.position.y;

  // Calculates if the player is near of his MARK POSITION
  if((proximityValueX + proximityValueY) < nearValue)
  {
     playerOnMark = true;
  }

  cubeProximityX = currentCubePosition.transform.position.x - this.transform.position.x;
  cubeProximityY = currentCubePosition.transform.position.y - this.transform.position.y;

  if((cubeProximityX + cubeProximityY) < nearCube)
  {
     cubeIsNear = true;
  }

  else
  {
     cubeIsNear = false;
  }

  if(playerOnMark == true && cubeIsNear == false && Finding == false)
  {
      PositionChanging();
  }

  if(playerOnMark == true && cubeIsNear == true)
  {
      Finding = false;
    }

   cubeMarkProximityX = cubeMark.transform.position.x - currentCubePosition.transform.position.x;
   cubeMarkProximityZ = cubeMark.transform.position.z - currentCubePosition.transform.position.z;

   if(cubeMarkProximityX > cubeMarkProximityZ)
   {
     PushX();
   }

   if(cubeMarkProximityX < cubeMarkProximityZ)
   {
     PushZ();
   }

}

void PositionChanging () {

  Finding = true;
  Vector3 positionA = this.transform.position;
  Vector3 positionB = cubeMesh.transform.position;
  this.transform.position = Vector3.Lerp(positionA, positionB, Time.deltaTime * speed);
}

بعد إضافة أحدث الإجراءات إلى الرمز ، يجب على الشخصية أن تتعلم تحديد هدفه ، والعثور على المكعب ودفعه إلى الموضع المطلوب حتى يتمكن اللاعب من المرور وإنهاء المستوى. في هذا المثال ، ركزنا على كيفية حساب المسافات بين كائنات المشهد والشخصيات. سيساعدنا ذلك على إنشاء أنواع مماثلة من التفاعلات التي نحتاج فيها إلى وضع كائن اللعبة في موضع معين.

يوضح المثال شخصية منظمة العفو الدولية ودية تساعد اللاعب ، ولكن يمكن تطبيق نفس المبادئ إذا كنا بحاجة إلى التأثير المعاكس (إذا كانت الشخصية عدوًا) ، حيث تحتاج الشخصية للعثور على المكعب في أقرب وقت ممكن لإيقاف اللاعب.

عقبات الكائنات في البيئات باستخدام مثال Age من الامبراطوريات


كما رأينا سابقًا ، يمكنك استخدام أو تحريك الأشياء في اللعبة لتحقيق الأهداف ، ولكن ماذا يحدث إذا كان هناك شيء ما يعيق مسار الشخصية؟ يمكن وضع الكائن بواسطة اللاعب أو ببساطة يقع من قبل المصمم في هذا الموضع من الخريطة. على أي حال ، يجب أن تكون شخصية الذكاء الاصطناعي قادرة على تحديد ما يجب القيام به في هذه الحالة.

يمكننا ملاحظة هذا السلوك ، على سبيل المثال ، في استراتيجية تسمى Age of Empires II التي طورتها Ensemble Studios. في كل مرة لا يمكن لشخصية اللعبة الوصول إلى أراضي العدو نظرًا لكونها محاطة بجدران محصنة ، يتحول الذكاء الاصطناعي إلى تدمير جزء من الجدار للمتابعة.

هذا النوع من التفاعل هو أيضًا ذكي جدًا ومهم ، لأنه بخلاف ذلك فإن الشخصيات سوف تتجول على طول الجدار بحثًا عن مدخل ، وهذا لن يبدو سلوكًا معقولًا. نظرًا لأنه يتم إنشاء الجدار المقوى بواسطة اللاعب ، يمكن وضعه في أي مكان وله أي شكل. لذلك ، تحتاج إلى التفكير في هذا عند تطوير عدو AI.


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


في مثالنا ، يجب أن تدخل شخصية AI إلى المنزل ، ولكن عندما يقترب ، يدرك أنه محاط بسور خشبي ، لا يمكنك من خلاله المرور. نريد أن يختار الشخص هدفًا في هذه المرحلة ويبدأ في الهجوم حتى يتم تدمير هذا الجزء من السياج ويمكنه دخول المنزل.

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


نريد أن نضع الحي حول الشخصية ، حيث تقوم أقرب الأسوار بنقل معلوماتهم إلى الذكاء الاصطناعي بحيث يمكنها تحديد أيهما أسهل في التدمير. يمكن تنفيذ ذلك بطرق مختلفة ، إما باستخدام التعرف على تصادم الأسوار مع اللاعب ، أو إجبارهم على حساب المسافة بين الأسوار / الأشياء واللاعب ؛ نحدد قيمة المسافة التي يبدأ فيها اللاعب في إدراك حالة السياج. في مثالنا ، سنقوم بحساب المسافة واستخدامها لإخطار الشخصية حول أسوار HP.

لنبدأ بإنشاء الكود الذي سيتم تطبيقه على كائن السور ؛ جميعهم سيحصلون على نفس النص البرمجي:

public float HP;
public float distanceValue;
private Transform characterPosition;
private GameObject characterMesh;

private float proximityValueX;
private float proximityValueY;
private float nearValue;

// Use this for initialization
void Start () {

  HP = 100f;
  distanceValue = 1.5f;

  // Find the Character Mesh
  characterMesh = GameObject.Find("AICharacter");
}

// Update is called once per frame
void Update () {

  // Obtain the Character Mesh Position
  characterPosition = characterMesh.transform;

  //Calculate the distance between this object and the AI Character
  proximityValueX = characterPosition.transform.position.x - this.transform.position.x;
  proximityValueY = characterPosition.transform.position.y - this.transform.position.y;

  nearValue = proximityValueX + proximityValueY;
}

في هذا البرنامج النصي ، أضفنا معلومات أساسية حول HP والمسافات ، والتي سيتم استخدامها للاتصال بشخصية الذكاء الاصطناعي. هذه المرة نضيف البرنامج النصي لحساب المسافة ليس إلى الحرف ، ولكن إلى كائنات البيئة ؛ هذا يعطي الكائن ديناميكية أكبر ويتيح لنا خلق المزيد من الفرص.

على سبيل المثال ، إذا كانت شخصيات اللعبة منخرطة أيضًا في إنشاء الأسوار ، فستكون لها حالات مختلفة ، على سبيل المثال ، "قيد الإنشاء" أو "مكتملة" أو "تالفة" ؛ عندها ستكون الشخصية قادرة على تلقي هذه المعلومات واستخدامها لأغراضهم الخاصة.

لنقم بتعيين الشخصية التي تتفاعل مع كائن البيئة. سيكون هدفه الرئيسي هو الوصول إلى المنزل ، ولكن عندما يقترب منه ، يدرك أنه لا يستطيع الدخول بسبب حقيقة أنه محاط بأسوار خشبية. نريد ، بعد تحليل الوضع ، أن تدمر شخصيتنا السياج لتحقيق هدفه والدخول إلى المنزل.

في نص الحرف ، سنضيف وظيفة ثابتة ، لإدخال الأسوار التي ستتمكن من نقل المعلومات حول "صحتهم" الحالية ؛ هذا سوف يساعد الشخصية على اختيار أنسب السور للتدمير.

public static float fenceHP;
public static float lowerFenceHP;
public static float fencesAnalyzed;
public static GameObject bestFence;

private Transform House;

private float timeWasted;
public float speed;



void Start () {

        fenceHP = 100f;
        lowerFenceHP = fenceHP;
        fencesAnalyzed = 0;
        speed = 0.8;

        Vector3 House = new Vector3(300.2f, 83.3f, -13.3f);

}

void Update () {

        timeWasted += Time.deltaTime;

        if(fenceHP > lowerFenceHP)
        {
            lowerFenceHP = fenceHP;
        }

        if(timeWasted > 30f)
        {
            GoToFence();  
        }
}

void GoToFence() {

        Vector3 positionA = this.transform.position;
        Vector3 positionB = bestFence.transform.position;
        this.transform.position = Vector3.Lerp(positionA, positionB, Time.deltaTime * speed);
}


لقد قمنا بالفعل بإضافة المعلومات الأساسية إلى الشخصية. fenceHPسيكون متغيرًا ثابتًا يسجل فيه كل سور يقع داخل دائرة نصف قطر حي الشخصية معلومات حول HP الحالي. ثم تقوم شخصية الذكاء الاصطناعي بتحليل المعلومات الواردة ومقارنتها مع السياج مع أقل نقاط HP المقدمة lowerFenceHP.

يحتوي الحرف على متغير timeWastedيمثل عدد الثواني التي قضاها بالفعل في البحث عن سياج مناسب لتدميره. fencesAnalyzedسيتم استخدامه لمعرفة ما إذا كان هناك بالفعل سور في الرمز ، وإذا لم يكن كذلك ، فسيتم إضافة السياج الأول الذي وجده الحرف ؛ إذا كانت الأسوار لها نفس قيمة HP ، فإن الشخصية تهاجمها أولاً. الآن دعنا نضيف رمز الأسوار حتى يتمكنوا من الوصول إلى البرنامج النصي للشخصية وإدخال معلومات مفيدة.

public float HP;
public float distanceValue;
private Transform characterPosition;
private GameObject characterMesh;

private float proximityValueX;
private float proximityValueY;
private float nearValue;
void Start () {

        HP = 100f;
        distanceValue = 1.5f;

        // Find the Character Mesh
        characterMesh = GameObject.Find("AICharacter");
}

void Update () {

        // Obtain the Character Mesh Position
        characterPosition = characterMesh.transform;

        //Calculate the distance between this object and the AI Character
        proximityValueX = characterPosition.transform.position.x - this.transform.position.x;
        proximityValueY = characterPosition.transform.position.y - this.transform.position.y;

        nearValue = proximityValueX + proximityValueY;

        if(nearValue <= distanceValue){
            if(AICharacter.fencesAnalyzed == 0){
                AICharacter.fencesAnalyzed = 1;
                AICharacter.bestFence = this.gameObject;
            }

            AICharacter.fenceHP = HP;

            if(HP < AICharacter.lowerFenceHP){
                AICharacter.bestFence = this.gameObject;
            }
        }
}

أكملنا هذا المثال أخيرًا. يقارن السور الآن HP الحالي ببيانات الشخصية ( lowerFenceHP) ، وإذا كانت HP أقل من أقل قيمة لدى الشخصية ، فسيتم النظر في هذا السور bestFence.

يوضح هذا المثال كيفية تكييف شخصية AI مع كائنات ديناميكية مختلفة في اللعبة ؛ يمكن توسيع المبدأ نفسه واستخدامه للتفاعل مع أي شيء تقريبًا. كما أنها قابلة للتطبيق ومفيدة عند استخدام الكائنات للتفاعل مع شخصية ، وربط المعلومات بينها.

في هذا المنشور ، اكتشفنا طرقًا مختلفة للتفاعل مع البيئة. يمكن توسيع التقنيات الموضحة في هذا الفصل لتشمل العديد من أنواع الألعاب المختلفة واستخدامها لأداء تفاعلات بسيطة ومعقدة بين شخصيات الذكاء الاصطناعي والبيئة.

All Articles