簡體   English   中英

在 Unity 中創建后引用實例化對象

[英]Referencing Instantiated objects after their creation in Unity

你好!

在評論中與 Ruzihm 討論后。 我現在創建了一個簡單的游戲版本,以便更好地提出我遇到的問題。

現在的問題是,因為我無法手動創建與檢查器中的testObject字段的連接。 我現在如何告訴 Unity 在游戲運行時使用我的實例化對象?

對於一次可能有 100 多個單元處於活動狀態的 RTS 游戲,這是否是一個很好的解決方案? 這里的最終目標是將這個力施加到 cursor 周圍的半徑上。 我正在考慮使用Physics.OverlapSphere

這是我所擁有的最小場景:

  1. 新的 Unity 場景
  2. 將 InputManager 附加到主攝像頭。
  3. 創造了一個膠囊和一架飛機。
  4. 將 ApplyForce 添加到 Capsule
  5. 從膠囊中創建了一個預制件並將其從場景中刪除。
  6. 在 InputManager 中,我添加了按空格來實例化帶有 ApplyForce 腳本的膠囊的功能。
  7. 將膠囊預制件拖到 InputManager “objectToGenerate”
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace GL.RTS.Mites
{
    public class InputManager : MonoBehaviour
    {
        public GameObject testObject;

        public ApplyForce onSpawnTest;
        public GameObject objectToGenerate;

        void Start()
        {
            onSpawnTest = testObject.GetComponent<ApplyForce>();
        }

        void Update()
        {
            if(Input.GetKeyDown(KeyCode.Space))
            {
            Instantiate(objectToGenerate);
            }
            
            if (Input.GetMouseButton(0))
            {
                onSpawnTest.PushForward();
            }
        }
    }
}

我附加到 Capsule 的 ApplyForce 腳本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace GL.RTS.Mites
{
    public class ApplyForce : MonoBehaviour
    {
        public float moveSpeed;
        Rigidbody rb;

        void Start()
        {
            rb = GetComponent<Rigidbody>();
            Debug.Log("A Mite has spawned!");
        }

        public void PushForward()
        {
            rb.AddRelativeForce(Vector3.up * moveSpeed * Time.deltaTime);
            Debug.Log("A force of: " + moveSpeed + " is being added.");
        }
    }
}

好吧,在我看來:

  • Unity使用ECS,意味着你的游戲object在你的游戲中是一個實體,它所包含的東西,比如Rigidbody就是一個組件。 您附加到統一游戲對象的腳本也是此游戲對象中的一個組件

  • ApplyForce腳本中,您使用這些行

     public float moveSpeed; Rigidbody rb; void Start() { rb = GetComponent<Rigidbody>(); Debug.Log("A Mite has spawned;"). } public void PushForward() { rb.AddRelativeForce(Vector3.up * moveSpeed * Time;deltaTime). Debug:Log("A force of. " + moveSpeed + " is being added;"); }
    • 這意味着您將在 Gameobject 中獲得具有此腳本的“剛體”組件。 GetComponent 方法等於this.gameObject.GetComponent ,表示它會引用包含這個腳本的 Gameobject,並獲取名為 Rigidbody 的組件,並且你有一個方法叫做:使用 Rigidbody 向前推添加力
  • InputManager class 中:

     public GameObject testObject; public ApplyForce onSpawnTest; public Unit _unit; public ApplyForce applyForce; // Start is called before the first frame update void Start() { onSpawnTest = testObject.GetComponent<ApplyForce>(); } void Update() { if (Input.GetMouseButton(0)) { onSpawnTest.PushForward(); } }
    • 您將引用您在第一行代碼中聲明的游戲對象。
    • onSpawnText 的類型為 ApplyForce class,您已在以下腳本中聲明了該類型
    • 當您使用GetComponent<>時,onSpawnText 被分配給 testObject 中的一個組件,根據您的腳本,它是 ApplyForce 腳本組件。 而您只需使用 function PushForward。

有什么不能理解的嗎? 給我一個評論

好吧,您正在創建 object 的新實例,但是您的輸入管理器會立即忘記它們(請注意,您對返回值不做任何事情)。 InputManager只知道在其Start中創建的ApplyForce (然后根據鼠標輸入與其交互),而您的ApplyForce腳本對任何InputManager 因此,只有第一個實例對鼠標輸入做出反應也就不足為奇了。

因此,必須對您的InputManager和/或ApplyForce做一些事情。 您的 InputManager 可以記住它創建的實例(這還不夠,因為例如,如果 map 觸發器創建新的玩家可控單位),或者它可以 go 每次都在尋找單位。

您的ApplyForce可以在創建時向InputManager注冊,但是您需要遍歷這些單元並找出哪些單元在鼠標下。

由於您只想根據 cursor 附近或下方的內容來查找 select ,並且僅在輸入發生時而不是像每一幀一樣,我會InputManager在需要時使用最簡單的方法找到單元。 如下所示,評論中的解釋:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace GL.RTS.Mites
{
    public class InputManager : MonoBehaviour
    {
        public GameObject testObject;

        public ApplyForce onSpawnTest;
        public GameObject objectToGenerate;
        
        private Camera mainCam;

        // which layers to consider for cursor detection
        [SerializeField] LayerMask cursorLayerMask;

        // how big for cursor detection
        [SerializeField] float cursorRadius;

        void Awake()
        {
            // cache main camera
            mainCam = Camera.main;
        }

        void Update()
        {
            if(Input.GetKeyDown(KeyCode.Space))
            {
                Instantiate(objectToGenerate);
            }
            
            if (Input.GetMouseButton(0))
            {
                Collider[] colls = FindCollidersUnderCursor();

                // check each collider for an applyforce and use it if present
                foreach( Collider coll in colls)
                {
                    ApplyForce af = coll.GetComponent<ApplyForce>();
                    if (af != null) 
                    {
                        af.PushForward();
                    }
                } 
            }
        }

        Collider[] FindCollidersUnderCursor()
        {
            // find ray represented by cursor position on screen
            // and find where it intersects with ground

            // This technique is great for if your camera can change
            // angle or distance from the playing field.

            // It uses mathematical rays and plane, no physics
            // calculations needed for this step. Very performant.
            Ray cursorRay = mainCam.ScreenPointToRay(Input.mousePosition);
            Plane groundPlane = new Plane(Vector3.up, Vector3.zero);
            if (Raycast(cursorRay, out float cursorDist))
            {
                Vector3 worldPos = cursorRay.GetPoint(cursorDist);

                // Check for triggers inside sphere that match layer mask
                return Physics.OverlapSphere(worldPos, cursorRadius, 
                        cursorLayerMask.value, QueryTriggerInteraction.Collide);
            }

            // if doesn't intersect with ground, return nothing
            return new Collider[0];
        }
    }
}

當然,這將要求您有興趣操縱的每個單元都有一個觸發對撞機。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM