الدوال (Methods) في C#: تنظيم شيفرات اللعبة لسهولة التعديل


الدوال (Methods) في C#: تنظيم شيفرات اللعبة لسهولة التعديل

ماذا سنتعلم اليوم؟ سنتعلم كيف تساعدنا الدوال (Methods) في C# على تنظيم شيفرات الألعاب، مما يجعلها أسهل في القراءة والتعديل والصيانة.

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

الخطوة 1: الأساسيات - تعريف واستدعاء دالة بسيطة

الدالة (Method) هي كتلة من الأوامر تقوم بمهمة محددة. لتعريف دالة، نحدد نوع الوصول (مثل public أو private)، ونوع القيمة التي تعيدها (void إذا لم تعد شيئاً)، واسم الدالة، وأقواس المعاملات ()، ثم أقواس المجموعة {} التي تحتوي على الأوامر.

ملاحظة تقنية: void تعني أن الدالة لا تُعيد أي قيمة بعد تنفيذها. هذا شائع للمهام التي تؤثر على حالة اللعبة مباشرة.

using UnityEngine;

public class GameController : MonoBehaviour
{
    // دالة Start يتم استدعاؤها مرة واحدة عند بدء تشغيل الكائن
    void Start()
    {
        Debug.Log("بدأت اللعبة!"); // طباعة رسالة عند بدء اللعبة
        GreetPlayer(); // استدعاء دالة GreetPlayer
    }

    // دالة مخصصة لترحيب اللاعب
    private void GreetPlayer()
    {
        Debug.Log("أهلاً بك أيها المغامر في عالمنا!"); // رسالة ترحيب باللاعب
    }
}

في هذا المثال، قمنا بتعريف دالة GreetPlayer واستدعيناها من داخل دالة Start. هذا يبدأ في تنظيم مهامنا.

الخطوة 2: تمرير المعاملات (Parameters) للدوال

لجعل الدوال أكثر مرونة وقابلية لإعادة الاستخدام، يمكننا تمرير المعلومات إليها على شكل معاملات (Parameters). هذه المعاملات تعمل كمتغيرات محلية داخل الدالة.

ملاحظة تقنية: تحديد نوع المعامل (مثلاً int damageAmount) يضمن أن الدالة تستقبل النوع الصحيح من البيانات، مما يمنع الأخطاء.

using UnityEngine;

public class PlayerHealth : MonoBehaviour
{
    public int currentHealth = 100; // صحة اللاعب الحالية

    void Start()
    {
        Debug.Log($"صحة اللاعب الأولية: {currentHealth}"); // طباعة الصحة الأولية
        TakeDamage(20); // استدعاء دالة TakeDamage لتلقي 20 نقطة ضرر
        TakeDamage(15); // تلقي 15 نقطة ضرر إضافية
    }

    // دالة لتلقي الضرر، تأخذ قيمة الضرر كمعامل
    public void TakeDamage(int damageAmount)
    {
        currentHealth -= damageAmount; // تقليل الصحة بمقدار الضرر
        Debug.Log($"تلقى اللاعب ضررًا بمقدار {damageAmount}. الصحة المتبقية: {currentHealth}"); // إبلاغ عن الضرر والصحة

        if (currentHealth <= 0)
        {
            Debug.Log("اللاعب هُزم!"); // رسالة عند هزيمة اللاعب
            // هنا يمكن إضافة منطق مثل إعادة تشغيل المستوى أو إظهار شاشة النهاية
        }
    }
}

هنا، الدالة TakeDamage يمكنها التعامل مع أي مقدار ضرر يتم تمريره إليها، مما يجعلها دالة قوية وقابلة لإعادة الاستخدام لأي هجوم في اللعبة.

الخطوة 3: الدوال التي تعيد قيمة (Return Values)

في بعض الأحيان، تحتاج الدالة إلى تنفيذ عملية ثم إرجاع نتيجة هذه العملية. هنا يأتي دور الدوال التي تعيد قيمة. بدلاً من void، نحدد نوع البيانات التي ستعيدها الدالة (مثل int، float، string، إلخ)، ونستخدم الكلمة المفتاحية return.

ملاحظة تقنية: يجب أن يتطابق نوع القيمة التي تعيدها الدالة مع النوع المحدد قبل اسمها. إذا كان النوع int، فيجب أن تُعيد الدالة قيمة من نوع int.

using UnityEngine;

public class ScoreManager : MonoBehaviour
{
    public int totalScore = 0; // إجمالي نقاط اللاعب

    void Start()
    {
        int scoreFromKills = CalculateScore(5, 100); // حساب نقاط من 5 عمليات قتل، كل منها 100 نقطة
        totalScore += scoreFromKills; // إضافة النقاط المكتسبة إلى الإجمالي
        Debug.Log($"النقاط من عمليات القتل: {scoreFromKills}");

        int bonusScore = CalculateBonus(true, 500); // حساب نقاط إضافية إذا كان هناك مكافأة
        totalScore += bonusScore; // إضافة النقاط الإضافية
        Debug.Log($"النقاط الإضافية: {bonusScore}");

        Debug.Log($"النقاط الإجمالية النهائية: {totalScore}"); // عرض النقاط النهائية
    }

    // دالة تحسب النقاط بناءً على عدد عمليات القتل وقيمة النقطة لكل قتل
    public int CalculateScore(int kills, int pointsPerKill)
    {
        int calculatedScore = kills * pointsPerKill; // حساب النقاط
        return calculatedScore; // إرجاع القيمة المحسوبة
    }

    // دالة تحسب نقاط مكافأة بناءً على شرط وقيمة مكافأة
    public int CalculateBonus(bool gotAchievement, int bonusValue)
    {
        if (gotAchievement)
        {
            return bonusValue; // إرجاع قيمة المكافأة إذا تحقق الشرط
        }
        return 0; // إرجاع صفر إذا لم يتحقق الشرط
    }
}

هنا، تُعيد الدالة CalculateScore قيمة عددية تمثل النقاط المحسوبة، وتستخدم الدالة CalculateBonus منطقًا شرطيًا لإرجاع قيمة مختلفة. هذا يجعل منطق حساب النقاط نظيفًا وسهل الفهم.

الكود النهائي الكامل

إليك سكربت C# كامل يجمع بين المفاهيم التي تعلمناها، يمكنك لصقه في ملف .cs داخل مشروع Unity وتعيينه لكائن لعب (GameObject).

using UnityEngine;

public class GameLogicManager : MonoBehaviour
{
    public int playerHealth = 100; // صحة اللاعب
    public int playerScore = 0; // نقاط اللاعب

    // دالة Start تُستدعى مرة واحدة عند بدء تشغيل السكربت
    void Start()
    {
        DisplayGameIntro(); // عرض مقدمة اللعبة
        ApplyInitialDamage(10); // تطبيق ضرر أولي على اللاعب

        int pointsFromEnemy = GetPointsForKill(50); // الحصول على نقاط من عدو
        AddScore(pointsFromEnemy); // إضافة النقاط إلى مجموع اللاعب

        Debug.Log($"الصحة الحالية: {playerHealth}"); // طباعة الصحة النهائية
        Debug.Log($"النقاط الحالية: {playerScore}"); // طباعة النقاط النهائية

        CheckGameOver(); // التحقق مما إذا كانت اللعبة انتهت
    }

    // دالة لعرض مقدمة اللعبة (لا تُعيد قيمة ولا تأخذ معاملات)
    private void DisplayGameIntro()
    {
        Debug.Log("مرحباً بك في مغامرة الأكواد!"); // رسالة ترحيب
        Debug.Log("استعد للتحدي..."); // رسالة تحفيزية
    }

    // دالة لتطبيق الضرر على اللاعب (تأخذ معامل ولا تُعيد قيمة)
    public void ApplyInitialDamage(int damageAmount)
    {
        playerHealth -= damageAmount; // تقليل صحة اللاعب
        Debug.Log($"تلقى اللاعب ضرراً أولياً بمقدار {damageAmount}."); // إبلاغ عن الضرر
    }

    // دالة لحساب النقاط المكتسبة من قتل عدو (تأخذ معامل وتُعيد قيمة)
    public int GetPointsForKill(int basePoints)
    {
        // يمكن إضافة منطق أكثر تعقيداً هنا مثل مضاعفات النقاط
        int finalPoints = basePoints + Random.Range(0, 10); // إضافة نقاط عشوائية كمكافأة
        Debug.Log($"اكتسبت {finalPoints} نقطة من قتل عدو."); // إبلاغ بالنقاط المكتسبة
        return finalPoints; // إرجاع النقاط النهائية
    }

    // دالة لإضافة النقاط إلى مجموع اللاعب
    private void AddScore(int pointsToAdd)
    {
        playerScore += pointsToAdd; // إضافة النقاط
        Debug.Log($"تمت إضافة {pointsToAdd} نقطة إلى مجموعك."); // إبلاغ عن إضافة النقاط
    }

    // دالة للتحقق من حالة نهاية اللعبة
    private void CheckGameOver()
    {
        if (playerHealth <= 0)
        {
            Debug.Log("انتهت اللعبة! اللاعب هُزم."); // رسالة نهاية اللعبة
            // هنا يمكن استدعاء دالة أخرى لإظهار شاشة النهاية أو إعادة التشغيل
        } else {
            Debug.Log("اللعبة مستمرة... ما زلت على قيد الحياة!"); // رسالة استمرار اللعبة
        }
    }
}

النتيجة المتوقعة

عند تشغيل هذا السكربت في Unity، ستلاحظ ظهور الرسائل التالية في نافذة Console (قد تختلف قيمة النقاط العشوائية قليلاً):

  • مرحباً بك في مغامرة الأكواد!
  • استعد للتحدي...
  • تلقى اللاعب ضرراً أولياً بمقدار 10.
  • اكتسبت 5X نقطة من قتل عدو. (حيث X هو رقم عشوائي بين 0 و 9)
  • تمت إضافة 5X نقطة إلى مجموعك.
  • الصحة الحالية: 90
  • النقاط الحالية: 5X
  • اللعبة مستمرة... ما زلت على قيد الحياة!

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