यूनिटी में एआई सपोर्ट के साथ एफपीएस कैसे बनाएं

प्रथम-व्यक्ति शूटर (एफपीएस) शूटर गेम की एक उप-शैली है जहां खिलाड़ी को प्रथम-व्यक्ति के दृष्टिकोण से नियंत्रित किया जाता है।

Unity में एक एफपीएस गेम बनाने के लिए हमें एक खिलाड़ी नियंत्रक, वस्तुओं की एक श्रृंखला (इस मामले में हथियार), और दुश्मनों की आवश्यकता होगी।

चरण 1: प्लेयर कंट्रोलर बनाएं

यहां हम एक नियंत्रक बनाएंगे जिसका उपयोग हमारे खिलाड़ी द्वारा किया जाएगा।

  • एक नया गेम ऑब्जेक्ट बनाएं (गेम ऑब्जेक्ट -> खाली बनाएं) और इसे नाम दें "Player"
  • एक नया कैप्सूल बनाएं (गेम ऑब्जेक्ट -> 3डी ऑब्जेक्ट -> कैप्सूल) और इसे "Player" ऑब्जेक्ट के अंदर ले जाएं
  • कैप्सूल से कैप्सूल कोलाइडर घटक निकालें और उसकी स्थिति को (0, 1, 0) में बदलें
  • मुख्य कैमरे को "Player" ऑब्जेक्ट के अंदर ले जाएं और उसकी स्थिति को (0, 1.64, 0) में बदलें
  • एक नई स्क्रिप्ट बनाएं, इसे "SC_CharacterController" नाम दें और नीचे दिए गए कोड को इसके अंदर पेस्ट करें:

SC_CharacterController.cs

using UnityEngine;

[RequireComponent(typeof(CharacterController))]

public class SC_CharacterController : MonoBehaviour
{
    public float speed = 7.5f;
    public float jumpSpeed = 8.0f;
    public float gravity = 20.0f;
    public Camera playerCamera;
    public float lookSpeed = 2.0f;
    public float lookXLimit = 45.0f;

    CharacterController characterController;
    Vector3 moveDirection = Vector3.zero;
    Vector2 rotation = Vector2.zero;

    [HideInInspector]
    public bool canMove = true;

    void Start()
    {
        characterController = GetComponent<CharacterController>();
        rotation.y = transform.eulerAngles.y;
    }

    void Update()
    {
        if (characterController.isGrounded)
        {
            // We are grounded, so recalculate move direction based on axes
            Vector3 forward = transform.TransformDirection(Vector3.forward);
            Vector3 right = transform.TransformDirection(Vector3.right);
            float curSpeedX = canMove ? speed * Input.GetAxis("Vertical") : 0;
            float curSpeedY = canMove ? speed * Input.GetAxis("Horizontal") : 0;
            moveDirection = (forward * curSpeedX) + (right * curSpeedY);

            if (Input.GetButton("Jump") && canMove)
            {
                moveDirection.y = jumpSpeed;
            }
        }

        // Apply gravity. Gravity is multiplied by deltaTime twice (once here, and once below
        // when the moveDirection is multiplied by deltaTime). This is because gravity should be applied
        // as an acceleration (ms^-2)
        moveDirection.y -= gravity * Time.deltaTime;

        // Move the controller
        characterController.Move(moveDirection * Time.deltaTime);

        // Player and Camera rotation
        if (canMove)
        {
            rotation.y += Input.GetAxis("Mouse X") * lookSpeed;
            rotation.x += -Input.GetAxis("Mouse Y") * lookSpeed;
            rotation.x = Mathf.Clamp(rotation.x, -lookXLimit, lookXLimit);
            playerCamera.transform.localRotation = Quaternion.Euler(rotation.x, 0, 0);
            transform.eulerAngles = new Vector2(0, rotation.y);
        }
    }
}
  • SC_CharacterController स्क्रिप्ट को "Player" ऑब्जेक्ट में संलग्न करें (आप देखेंगे कि इसमें कैरेक्टर कंट्रोलर नामक एक अन्य घटक भी जोड़ा गया है, इसके केंद्र मान को (0, 1, 0) में बदल दिया गया है)
  • SC_CharacterController में प्लेयर कैमरा वेरिएबल को मुख्य कैमरा असाइन करें

प्लेयर नियंत्रक अब तैयार है:

चरण 2: हथियार प्रणाली बनाएं

खिलाड़ी हथियार प्रणाली में 3 घटक शामिल होंगे: एक हथियार प्रबंधक, एक हथियार स्क्रिप्ट और एक बुलेट स्क्रिप्ट।

  • एक नई स्क्रिप्ट बनाएं, इसे "SC_WeaponManager" नाम दें और नीचे दिए गए कोड को इसके अंदर पेस्ट करें:

SC_WeaponManager.cs

using UnityEngine;

public class SC_WeaponManager : MonoBehaviour
{
    public Camera playerCamera;
    public SC_Weapon primaryWeapon;
    public SC_Weapon secondaryWeapon;

    [HideInInspector]
    public SC_Weapon selectedWeapon;

    // Start is called before the first frame update
    void Start()
    {
        //At the start we enable the primary weapon and disable the secondary
        primaryWeapon.ActivateWeapon(true);
        secondaryWeapon.ActivateWeapon(false);
        selectedWeapon = primaryWeapon;
        primaryWeapon.manager = this;
        secondaryWeapon.manager = this;
    }

    // Update is called once per frame
    void Update()
    {
        //Select secondary weapon when pressing 1
        if (Input.GetKeyDown(KeyCode.Alpha1))
        {
            primaryWeapon.ActivateWeapon(false);
            secondaryWeapon.ActivateWeapon(true);
            selectedWeapon = secondaryWeapon;
        }

        //Select primary weapon when pressing 2
        if (Input.GetKeyDown(KeyCode.Alpha2))
        {
            primaryWeapon.ActivateWeapon(true);
            secondaryWeapon.ActivateWeapon(false);
            selectedWeapon = primaryWeapon;
        }
    }
}
  • एक नई स्क्रिप्ट बनाएं, इसे "SC_Weapon" नाम दें और इसके अंदर नीचे दिया गया कोड पेस्ट करें:

SC_Weapon.cs

using System.Collections;
using UnityEngine;

[RequireComponent(typeof(AudioSource))]

public class SC_Weapon : MonoBehaviour
{
    public bool singleFire = false;
    public float fireRate = 0.1f;
    public GameObject bulletPrefab;
    public Transform firePoint;
    public int bulletsPerMagazine = 30;
    public float timeToReload = 1.5f;
    public float weaponDamage = 15; //How much damage should this weapon deal
    public AudioClip fireAudio;
    public AudioClip reloadAudio;

    [HideInInspector]
    public SC_WeaponManager manager;

    float nextFireTime = 0;
    bool canFire = true;
    int bulletsPerMagazineDefault = 0;
    AudioSource audioSource;

    // Start is called before the first frame update
    void Start()
    {
        bulletsPerMagazineDefault = bulletsPerMagazine;
        audioSource = GetComponent<AudioSource>();
        audioSource.playOnAwake = false;
        //Make sound 3D
        audioSource.spatialBlend = 1f;
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(0) && singleFire)
        {
            Fire();
        }
        if (Input.GetMouseButton(0) && !singleFire)
        {
            Fire();
        }
        if (Input.GetKeyDown(KeyCode.R) && canFire)
        {
            StartCoroutine(Reload());
        }
    }

    void Fire()
    {
        if (canFire)
        {
            if (Time.time > nextFireTime)
            {
                nextFireTime = Time.time + fireRate;

                if (bulletsPerMagazine > 0)
                {
                    //Point fire point at the current center of Camera
                    Vector3 firePointPointerPosition = manager.playerCamera.transform.position + manager.playerCamera.transform.forward * 100;
                    RaycastHit hit;
                    if (Physics.Raycast(manager.playerCamera.transform.position, manager.playerCamera.transform.forward, out hit, 100))
                    {
                        firePointPointerPosition = hit.point;
                    }
                    firePoint.LookAt(firePointPointerPosition);
                    //Fire
                    GameObject bulletObject = Instantiate(bulletPrefab, firePoint.position, firePoint.rotation);
                    SC_Bullet bullet = bulletObject.GetComponent<SC_Bullet>();
                    //Set bullet damage according to weapon damage value
                    bullet.SetDamage(weaponDamage);

                    bulletsPerMagazine--;
                    audioSource.clip = fireAudio;
                    audioSource.Play();
                }
                else
                {
                    StartCoroutine(Reload());
                }
            }
        }
    }

    IEnumerator Reload()
    {
        canFire = false;

        audioSource.clip = reloadAudio;
        audioSource.Play();

        yield return new WaitForSeconds(timeToReload);

        bulletsPerMagazine = bulletsPerMagazineDefault;

        canFire = true;
    }

    //Called from SC_WeaponManager
    public void ActivateWeapon(bool activate)
    {
        StopAllCoroutines();
        canFire = true;
        gameObject.SetActive(activate);
    }
}
  • एक नई स्क्रिप्ट बनाएं, इसे "SC_Bullet" नाम दें और इसके अंदर नीचे दिया गया कोड पेस्ट करें:

SC_बुलेट.cs

using System.Collections;
using UnityEngine;

public class SC_Bullet : MonoBehaviour
{
    public float bulletSpeed = 345;
    public float hitForce = 50f;
    public float destroyAfter = 3.5f;

    float currentTime = 0;
    Vector3 newPos;
    Vector3 oldPos;
    bool hasHit = false;

    float damagePoints;

    // Start is called before the first frame update
    IEnumerator Start()
    {
        newPos = transform.position;
        oldPos = newPos;

        while (currentTime < destroyAfter && !hasHit)
        {
            Vector3 velocity = transform.forward * bulletSpeed;
            newPos += velocity * Time.deltaTime;
            Vector3 direction = newPos - oldPos;
            float distance = direction.magnitude;
            RaycastHit hit;

            // Check if we hit anything on the way
            if (Physics.Raycast(oldPos, direction, out hit, distance))
            {
                if (hit.rigidbody != null)
                {
                    hit.rigidbody.AddForce(direction * hitForce);

                    IEntity npc = hit.transform.GetComponent<IEntity>();
                    if (npc != null)
                    {
                        //Apply damage to NPC
                        npc.ApplyDamage(damagePoints);
                    }
                }

                newPos = hit.point; //Adjust new position
                StartCoroutine(DestroyBullet());
            }

            currentTime += Time.deltaTime;
            yield return new WaitForFixedUpdate();

            transform.position = newPos;
            oldPos = newPos;
        }

        if (!hasHit)
        {
            StartCoroutine(DestroyBullet());
        }
    }

    IEnumerator DestroyBullet()
    {
        hasHit = true;
        yield return new WaitForSeconds(0.5f);
        Destroy(gameObject);
    }

    //Set how much damage this bullet will deal
    public void SetDamage(float points)
    {
        damagePoints = points;
    }
}

अब, आप देखेंगे कि SC_Bullet स्क्रिप्ट में कुछ त्रुटियाँ हैं। ऐसा इसलिए है क्योंकि हमें एक आखिरी काम करना है, जो कि IEntity इंटरफ़ेस को परिभाषित करना है।

C# में इंटरफ़ेस तब उपयोगी होते हैं जब आपको यह सुनिश्चित करने की आवश्यकता होती है कि जो स्क्रिप्ट इसका उपयोग करती है, उसमें कुछ विधियां लागू की गई हैं।

IEntity इंटरफ़ेस में एक विधि होगी जो ApplyDamage है, जिसका उपयोग बाद में दुश्मनों और हमारे खिलाड़ी को नुकसान पहुंचाने के लिए किया जाएगा।

  • एक नई स्क्रिप्ट बनाएं, इसे "SC_InterfaceManager" नाम दें और इसके अंदर नीचे दिया गया कोड पेस्ट करें:

SC_InterfaceManager.cs

//Entity interafce
interface IEntity
{ 
    void ApplyDamage(float points);
}

एक हथियार प्रबंधक की स्थापना

एक हथियार प्रबंधक एक ऑब्जेक्ट है जो मुख्य कैमरा ऑब्जेक्ट के नीचे रहेगा और इसमें सभी हथियार होंगे।

  • एक नया गेमऑब्जेक्ट बनाएं और उसे नाम दें "WeaponManager"
  • हथियार प्रबंधक को प्लेयर मुख्य कैमरे के अंदर ले जाएँ और उसकी स्थिति को (0, 0, 0) में बदलें
  • इसमें SC_WeaponManager स्क्रिप्ट संलग्न करें "WeaponManager"
  • SC_WeaponManager में प्लेयर कैमरा वेरिएबल को मुख्य कैमरा असाइन करें

एक राइफल की स्थापना

  • अपने बंदूक मॉडल को दृश्य में खींचें और छोड़ें (या यदि आपके पास अभी तक कोई मॉडल नहीं है तो बस एक क्यूब बनाएं और इसे खींचें)।
  • मॉडल को स्केल करें ताकि उसका आकार प्लेयर कैप्सूल के सापेक्ष हो

मेरे मामले में, मैं एक कस्टम-निर्मित राइफल मॉडल (बर्गारा BA13) का उपयोग करूंगा:

बर्गारा BA13

  • एक नया गेमऑब्जेक्ट बनाएं और इसे "Rifle" नाम दें, फिर राइफल मॉडल को इसके अंदर ले जाएं
  • "Rifle" ऑब्जेक्ट को "WeaponManager" ऑब्जेक्ट के अंदर ले जाएं और कैमरे के सामने इस तरह रखें:

यूनिटी में कैमरा क्लिपिंग समस्या को ठीक करें।

ऑब्जेक्ट क्लिपिंग को ठीक करने के लिए, बस कैमरे के निकट क्लिपिंग प्लेन को कुछ छोटे में बदलें (मेरे मामले में मैंने इसे 0.15 पर सेट किया है):

बर्गारा BA13

काफी बेहतर।

  • राइफल ऑब्जेक्ट में SC_Weapon स्क्रिप्ट संलग्न करें (आप देखेंगे कि इसमें एक ऑडियो स्रोत घटक भी जोड़ा गया है, यह फायर चलाने और ऑडियो को फिर से लोड करने के लिए आवश्यक है)।

जैसा कि आप देख सकते हैं, SC_Weapon में असाइन करने के लिए 4 वेरिएबल हैं। यदि आपके प्रोजेक्ट में उपयुक्त ऑडियो क्लिप हैं तो आप तुरंत फायर ऑडियो और रीलोड ऑडियो वेरिएबल असाइन कर सकते हैं।

बुलेट प्रीफ़ैब वैरिएबल को इस ट्यूटोरियल में बाद में समझाया जाएगा।

अभी के लिए, हम केवल फायर पॉइंट वेरिएबल निर्दिष्ट करेंगे:

  • एक नया गेमऑब्जेक्ट बनाएं, इसका नाम बदलकर "FirePoint" रखें और इसे राइफल ऑब्जेक्ट के अंदर ले जाएं। इसे बैरल के ठीक सामने या थोड़ा अंदर रखें, इस तरह:

  • SC_Weapon पर फ़ायरपॉइंट वेरिएबल को फ़ायरपॉइंट ट्रांसफ़ॉर्म असाइन करें
  • SC_WeaponManager स्क्रिप्ट में एक सेकेंडरी वेपन वेरिएबल में राइफल असाइन करें

एक सबमशीनगन स्थापित करना

  • राइफल ऑब्जेक्ट को डुप्लिकेट करें और इसका नाम बदलकर सबमशीनगन कर दें
  • इसके अंदर बंदूक मॉडल को एक अलग मॉडल से बदलें (मेरे मामले में मैं TAVOR X95 के कस्टम-निर्मित मॉडल का उपयोग करूंगा)

टैवोर X95

  • फायर प्वाइंट ट्रांसफॉर्म को तब तक हिलाएं जब तक यह नए मॉडल में फिट न हो जाए

यूनिटी में हथियार फायर पॉइंट ऑब्जेक्ट सेटअप।

  • SC_WeaponManager स्क्रिप्ट में प्राथमिक हथियार चर के लिए सबमशीनगन असाइन करें

बुलेट प्रीफैब की स्थापना

बुलेट प्रीफ़ैब को हथियार की अग्नि दर के अनुसार तैयार किया जाएगा और रेकास्ट का उपयोग यह पता लगाने के लिए किया जाएगा कि क्या यह किसी चीज़ से टकराता है और क्षति पहुँचाता है।

  • एक नया गेमऑब्जेक्ट बनाएं और उसे नाम दें "Bullet"
  • इसमें ट्रेल रेंडरर घटक जोड़ें और इसके टाइम वेरिएबल को 0.1 में बदलें।
  • चौड़ाई वक्र को कम मान पर सेट करें (उदा. प्रारंभ 0.1 अंत 0), एक नुकीला रूप जोड़ने के लिए
  • नई सामग्री बनाएं और इसे बुलेट_ट्रेल_मटेरियल नाम दें और इसके शेडर को पार्टिकल्स/एडिटिव में बदलें
  • एक नव निर्मित सामग्री को ट्रेल रेंडरर को सौंपें
  • ट्रेल रेंडरर का रंग बदलकर कुछ अलग करें (उदा. प्रारंभ: चमकीला नारंगी अंत: गहरा नारंगी)

  • बुलेट ऑब्जेक्ट को Prefab में सहेजें और इसे दृश्य से हटा दें।
  • राइफल और सबमशीनगन बुलेट प्रीफैब वैरिएबल के लिए एक नव निर्मित प्रीफैब (प्रोजेक्ट व्यू से खींचें और छोड़ें) असाइन करें

सबमशीन गन:

राइफल:

हथियार अब तैयार हैं.

चरण 3: शत्रु एआई बनाएं

दुश्मन साधारण क्यूब्स होंगे जो खिलाड़ी का अनुसरण करते हैं और काफी करीब आने पर हमला करते हैं। वे लहरों में हमला करेंगे, प्रत्येक लहर में खत्म करने के लिए अधिक दुश्मन होंगे।

शत्रु एआई की स्थापना

नीचे मैंने क्यूब के 2 रूप बनाए हैं (बायां वाला जीवित उदाहरण के लिए है और दायां वाला दुश्मन के मारे जाने के बाद उत्पन्न होगा):

  • मृत और जीवित दोनों उदाहरणों में एक रिगिडबॉडी घटक जोड़ें
  • डेड इंस्टेंस को प्रीफ़ैब में सेव करें और इसे सीन से हटा दें।

अब, जीवित उदाहरण को खेल के स्तर को नेविगेट करने और खिलाड़ी को नुकसान पहुंचाने में सक्षम होने के लिए कुछ और घटकों की आवश्यकता होगी।

  • एक नई स्क्रिप्ट बनाएं और इसे "SC_NPCEnemy" नाम दें, फिर नीचे दिए गए कोड को इसके अंदर पेस्ट करें:

SC_NPCEnemy.cs

using UnityEngine;
using UnityEngine.AI;

[RequireComponent(typeof(NavMeshAgent))]

public class SC_NPCEnemy : MonoBehaviour, IEntity
{
    public float attackDistance = 3f;
    public float movementSpeed = 4f;
    public float npcHP = 100;
    //How much damage will npc deal to the player
    public float npcDamage = 5;
    public float attackRate = 0.5f;
    public Transform firePoint;
    public GameObject npcDeadPrefab;

    [HideInInspector]
    public Transform playerTransform;
    [HideInInspector]
    public SC_EnemySpawner es;
    NavMeshAgent agent;
    float nextAttackTime = 0;

    // Start is called before the first frame update
    void Start()
    {
        agent = GetComponent<NavMeshAgent>();
        agent.stoppingDistance = attackDistance;
        agent.speed = movementSpeed;

        //Set Rigidbody to Kinematic to prevent hit register bug
        if (GetComponent<Rigidbody>())
        {
            GetComponent<Rigidbody>().isKinematic = true;
        }
    }

    // Update is called once per frame
    void Update()
    {
        if (agent.remainingDistance - attackDistance < 0.01f)
        {
            if(Time.time > nextAttackTime)
            {
                nextAttackTime = Time.time + attackRate;

                //Attack
                RaycastHit hit;
                if(Physics.Raycast(firePoint.position, firePoint.forward, out hit, attackDistance))
                {
                    if (hit.transform.CompareTag("Player"))
                    {
                        Debug.DrawLine(firePoint.position, firePoint.position + firePoint.forward * attackDistance, Color.cyan);

                        IEntity player = hit.transform.GetComponent<IEntity>();
                        player.ApplyDamage(npcDamage);
                    }
                }
            }
        }
        //Move towardst he player
        agent.destination = playerTransform.position;
        //Always look at player
        transform.LookAt(new Vector3(playerTransform.transform.position.x, transform.position.y, playerTransform.position.z));
    }

    public void ApplyDamage(float points)
    {
        npcHP -= points;
        if(npcHP <= 0)
        {
            //Destroy the NPC
            GameObject npcDead = Instantiate(npcDeadPrefab, transform.position, transform.rotation);
            //Slightly bounce the npc dead prefab up
            npcDead.GetComponent<Rigidbody>().velocity = (-(playerTransform.position - transform.position).normalized * 8) + new Vector3(0, 5, 0);
            Destroy(npcDead, 10);
            es.EnemyEliminated(this);
            Destroy(gameObject);
        }
    }
}
  • एक नई स्क्रिप्ट बनाएं, इसे "SC_EnemySpawner" नाम दें, फिर नीचे दिए गए कोड को इसके अंदर पेस्ट करें:

SC_EnemySpawner.cs

using UnityEngine;
using UnityEngine.SceneManagement;

public class SC_EnemySpawner : MonoBehaviour
{
    public GameObject enemyPrefab;
    public SC_DamageReceiver player;
    public Texture crosshairTexture;
    public float spawnInterval = 2; //Spawn new enemy each n seconds
    public int enemiesPerWave = 5; //How many enemies per wave
    public Transform[] spawnPoints;

    float nextSpawnTime = 0;
    int waveNumber = 1;
    bool waitingForWave = true;
    float newWaveTimer = 0;
    int enemiesToEliminate;
    //How many enemies we already eliminated in the current wave
    int enemiesEliminated = 0;
    int totalEnemiesSpawned = 0;

    // Start is called before the first frame update
    void Start()
    {
        //Lock cursor
        Cursor.lockState = CursorLockMode.Locked;
        Cursor.visible = false;

        //Wait 10 seconds for new wave to start
        newWaveTimer = 10;
        waitingForWave = true;
    }

    // Update is called once per frame
    void Update()
    {
        if (waitingForWave)
        {
            if(newWaveTimer >= 0)
            {
                newWaveTimer -= Time.deltaTime;
            }
            else
            {
                //Initialize new wave
                enemiesToEliminate = waveNumber * enemiesPerWave;
                enemiesEliminated = 0;
                totalEnemiesSpawned = 0;
                waitingForWave = false;
            }
        }
        else
        {
            if(Time.time > nextSpawnTime)
            {
                nextSpawnTime = Time.time + spawnInterval;

                //Spawn enemy 
                if(totalEnemiesSpawned < enemiesToEliminate)
                {
                    Transform randomPoint = spawnPoints[Random.Range(0, spawnPoints.Length - 1)];

                    GameObject enemy = Instantiate(enemyPrefab, randomPoint.position, Quaternion.identity);
                    SC_NPCEnemy npc = enemy.GetComponent<SC_NPCEnemy>();
                    npc.playerTransform = player.transform;
                    npc.es = this;
                    totalEnemiesSpawned++;
                }
            }
        }

        if (player.playerHP <= 0)
        {
            if (Input.GetKeyDown(KeyCode.Space))
            {
                Scene scene = SceneManager.GetActiveScene();
                SceneManager.LoadScene(scene.name);
            }
        }
    }

    void OnGUI()
    {
        GUI.Box(new Rect(10, Screen.height - 35, 100, 25), ((int)player.playerHP).ToString() + " HP");
        GUI.Box(new Rect(Screen.width / 2 - 35, Screen.height - 35, 70, 25), player.weaponManager.selectedWeapon.bulletsPerMagazine.ToString());

        if(player.playerHP <= 0)
        {
            GUI.Box(new Rect(Screen.width / 2 - 85, Screen.height / 2 - 20, 170, 40), "Game Over\n(Press 'Space' to Restart)");
        }
        else
        {
            GUI.DrawTexture(new Rect(Screen.width / 2 - 3, Screen.height / 2 - 3, 6, 6), crosshairTexture);
        }

        GUI.Box(new Rect(Screen.width / 2 - 50, 10, 100, 25), (enemiesToEliminate - enemiesEliminated).ToString());

        if (waitingForWave)
        {
            GUI.Box(new Rect(Screen.width / 2 - 125, Screen.height / 4 - 12, 250, 25), "Waiting for Wave " + waveNumber.ToString() + " (" + ((int)newWaveTimer).ToString() + " seconds left...)");
        }
    }

    public void EnemyEliminated(SC_NPCEnemy enemy)
    {
        enemiesEliminated++;

        if(enemiesToEliminate - enemiesEliminated <= 0)
        {
            //Start next wave
            newWaveTimer = 10;
            waitingForWave = true;
            waveNumber++;
        }
    }
}
  • एक नई स्क्रिप्ट बनाएं, इसे "SC_DamageReceiver" नाम दें, फिर नीचे दिए गए कोड को इसके अंदर पेस्ट करें:

SC_DamageReceiver.cs

using UnityEngine;

public class SC_DamageReceiver : MonoBehaviour, IEntity
{
    //This script will keep track of player HP
    public float playerHP = 100;
    public SC_CharacterController playerController;
    public SC_WeaponManager weaponManager;

    public void ApplyDamage(float points)
    {
        playerHP -= points;

        if(playerHP <= 0)
        {
            //Player is dead
            playerController.canMove = false;
            playerHP = 0;
        }
    }
}
  • जीवित शत्रु उदाहरण के लिए SC_NPCEnemy स्क्रिप्ट संलग्न करें (आप देखेंगे कि इसमें NavMesh एजेंट नामक एक अन्य घटक जोड़ा गया है, जो NavMesh को नेविगेट करने के लिए आवश्यक है)
  • हाल ही में बनाए गए डेड इंस्टेंस प्रीफ़ैब को एनपीसी डेड प्रीफ़ैब वैरिएबल में असाइन करें
  • फायर प्वाइंट के लिए, एक नया गेमऑब्जेक्ट बनाएं, इसे जीवित दुश्मन इंस्टेंस के अंदर ले जाएं और इसे इंस्टेंस के थोड़ा सामने रखें, फिर इसे फायर प्वाइंट वेरिएबल पर असाइन करें:

  • अंत में, जीवित उदाहरण को प्रीफ़ैब में सहेजें और इसे दृश्य से हटा दें।

शत्रु प्रवर्तक की स्थापना

अब SC_EnemySpawner की ओर चलते हैं। यह स्क्रिप्ट दुश्मनों को तरंगों में पैदा करेगी और स्क्रीन पर कुछ यूआई जानकारी भी दिखाएगी, जैसे प्लेयर एचपी, वर्तमान बारूद, वर्तमान लहर में कितने दुश्मन बचे हैं, आदि।

  • एक नया गेमऑब्जेक्ट बनाएं और उसे नाम दें "_EnemySpawner"
  • इसमें SC_EnemySpawner स्क्रिप्ट संलग्न करें
  • नव निर्मित शत्रु AI ​​को शत्रु प्रीफ़ैब वैरिएबल में असाइन करें
  • नीचे दिए गए टेक्सचर को क्रॉसहेयर टेक्सचर वेरिएबल पर असाइन करें

  • कुछ नए गेमऑब्जेक्ट बनाएं और उन्हें दृश्य के चारों ओर रखें और फिर उन्हें स्पॉन पॉइंट्स सरणी में असाइन करें

आप देखेंगे कि असाइन करने के लिए एक अंतिम वेरिएबल बचा है जो कि प्लेयर वेरिएबल है।

  • प्लेयर इंस्टेंस में SC_DamageReceiver स्क्रिप्ट संलग्न करें
  • प्लेयर इंस्टेंस टैग को इसमें बदलें "Player"
  • SC_DamageReceiver में प्लेयर कंट्रोलर और वेपन मैनेजर वेरिएबल असाइन करें

  • SC_EnemySpawner में प्लेयर वेरिएबल को प्लेयर इंस्टेंस असाइन करें

और अंत में, हमें अपने दृश्य में NavMesh को बेक करना होगा ताकि दुश्मन AI नेविगेट करने में सक्षम हो सके।

इसके अलावा, NavMesh को बेक करने से पहले दृश्य में प्रत्येक स्थिर वस्तु को नेविगेशन स्टेटिक के रूप में चिह्नित करना न भूलें:

  • NavMesh विंडो (विंडो -> AI -> नेविगेशन) पर जाएं, बेक टैब पर क्लिक करें और फिर बेक बटन पर क्लिक करें। NavMesh बेक होने के बाद इसे कुछ इस तरह दिखना चाहिए:

अब प्ले को दबाने और इसका परीक्षण करने का समय आ गया है:

Sharp Coder वीडियो प्लेयर

सब कुछ उम्मीद के मुताबिक काम करता है!

स्रोत
SimpleFPS.unitypackage4.61 MB
लिंक
Unity 6