在Unity中找到最接近我的目标

时间:2013-10-17 14:12:11

标签: c# unity3d button

我在Unity中有一个玩家类,除了我的ClosestTarget函数之外,它都可以正常工作。该功能按我想要的方式运行,但现在它只选择Cube 2(列表中的最后一个元素),即使我更接近另一个立方体。

课程如下所示:

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

public class Player : MonoBehaviour
{

    public int health; //Current health
    public int stamina; //Current stamina
    public int maxHealth = 100; //Constant for max health
    public int maxStamina = 500; //Constant for max stamina
    protected CharacterController chCtrl; //Reference to the character controller
    protected CharacterMotor chMotor; //Reference to the character motor
    public float walkSpeed = 3; //Speed at which the player walks
    public float runSpeed = 20; //Speed at which the player runs
    public bool isWalking = false; //Check for whether the player is walking
    public bool isRunning = false; //Check for whether the player is running
    public bool isFatigued = false; //Check for whether the player is fatigued
    public List<Transform> targets; //Create a list of transforms
    public Transform currentTarget;
    float distance = Mathf.Infinity;

    // Use this for initialization
    void Start ()
    {
        //Get the character controller assigned to the current game object
        chCtrl = GetComponent<CharacterController> ();
        //Get the character motor assigned to the current game object
        chMotor = GetComponent<CharacterMotor> ();
        //Set the stamina to the max stamina
        stamina = maxStamina;
        //Set the health to the max health
        health = maxHealth;
        //Initialise the targets list
        targets = new List<Transform>();
        //Call the function to retrieve all buttons in the scene
        AddAllButtons();
    }

    // Update is called once per frame
    void Update ()
    {
        //Call the function to set the speed of the player
        SetSpeed ();

        ClosestTarget();
    }

    public void SetSpeed ()
    {
        //Set the player to walking speed by default
        float speed = walkSpeed;

        //If the stamina is less than or equal to 0
        if (stamina <= 0) 
        {
            //Set the player as fatigued
            isFatigued = true;
            //Set the player to walking
            speed = walkSpeed;
            //Set stamina to 0
            stamina = 0;
        }
        //If the stamina is greater than or equal to max stamina
        if(stamina >= maxStamina)
        {
            //Set the stamina to the max stamina
            stamina = maxStamina;
            //Set the player as not fatigued
            isFatigued = false;
        }
        //If the player is moving along either the x or y axis
        if (Input.GetAxis("Horizontal") !=0 || Input.GetAxis("Vertical") !=0)
         {
        //If the player is fatigued
        if(isFatigued == true)
        {
                //Set the player to walking speed
                speed = walkSpeed;
                //Player is not running
                isRunning = false;
                //Player is walking
                isWalking = true;
                //Start increasing stamina
                stamina++;
        }
        //If the player is touching the ground and the user is either pressing left shift or right shift
        else if (chCtrl.isGrounded && Input.GetKey ("left shift") || Input.GetKey ("right shift") && isFatigued == false ) 
            {
                //Set the player to running speed
                speed = runSpeed;
                //Player is running
                isRunning = true;
                //Player is not walking
                isWalking = false;
                //Start reducting stamina
                stamina--;
            }
            else
            {
                //Set the player to walking speed
                speed = walkSpeed;
                //Player is not running
                isRunning = false;
                //Player is walking
                isWalking = true;
                //Start increasing stamina
                stamina++;
            }
        }
        else
        {
            //Player is not running
            isRunning = false;
            //Player is not walking
            isWalking = false;
            //Start increasing stamina
            stamina++;
        }
        //Set the players speed to either walkSpeed or runSpeed
        chMotor.movement.maxForwardSpeed = speed;
    }

    void AddAllButtons()
    {
        //Create an array that contains all game objects tagged with 'button'
        GameObject[] buttons = GameObject.FindGameObjectsWithTag("Button"); 
        //For each of the game objects in the array
        foreach(GameObject button in buttons)
        {
            //Add the transform of the button
            AddButton(button.transform);
        }
    }

    void AddButton(Transform button)
    {
        //Add the transform of the button into the targets list
        targets.Add(button);
    }

    void ButtonCheck(Transform button)
    {   
        Vector3 dir = (button.position - transform.position).normalized;
        float direction = Vector3.Dot(dir, transform.forward);
        Debug.Log(direction);

        if(Input.GetKeyDown(KeyCode.E))
        if(direction > 0.7F && Vector3.Distance(currentTarget.position, transform.position) < 2.0F)
        {   
            print("Button has been clicked");
        }
    }

    void ClosestTarget()
    {
        foreach (Transform button in targets) 
        { 
        Vector3 diff = (button.position - transform.position); 
        float curDistance = Vector3.Distance(transform.position, button.position );
        Debug.Log(curDistance);
        if (curDistance < distance ) 
        { 
          currentTarget = button;
          distance = curDistance;
        } 
        }
    }
}

如前所述,问题在于ClosestTargets功能。它找到了每个立方体的距离,但它只选择了目标列表中的最后一个元素。

http://puu.sh/4Sh9U.png

它仍然显示控制台中每个立方体的距离。

http://puu.sh/4Shbk.png

2 个答案:

答案 0 :(得分:1)

我的猜测:distance是类成员并正确初始化为Mathf.Infinity,但它永远不会重置。因此,在第一次调用ClosestTarget ()时,Cube2可能是最接近玩家的,因为Player.Update可能会稍后调用。所以distance包含的值太小(0?),其他对象有机会。

答案 1 :(得分:0)

我使用此扩展方法来查找最接近的gameObject(警告它使用linq):

public static GameObject ReturnClosestObject(this GameObject go, float radius, LayerMask layerMask)
{               
    Collider[] closeObjects = Physics.OverlapSphere(go.transform.position, radius, layerMask);

    closeObjects = closeObjects.OrderBy((collider) => Vector3.Distance(collider.gameObject.transform.position, go.transform.position)).ToArray();

    GameObject returnedObject = null;

    if(closeObjects.FirstOrDefault().Exist())
    {
        returnedObject = closeObjects.FirstOrDefault().gameObject;
    }

    return returnedObject;              
}

此方法的缺点是它只会检测与投影球体重叠的对象,并完全错过其内部的对象。因此,我会经常用这种递归函数来赞美它,该函数在不同的距离投射出有限数量的球体。

注意,虽然它们具有相似的名称,但上面是扩展方法,下面是实例方法。他们携手合作。

public GameObject FindClosestGameObject(int startingLookUpDistance, int maxLookUpDistance, int numberOfSteps)
{
    GameObject closestGameObject = gameObject.ReturnClosestObject(startingLookUpDistance, LayerMasks.gameObjects);      

    bool gameObjectNotFound = (closestGameObject.Equals(null));

    if(gameObjectNotFound)
    {
        if(startingLookUpDistance <= maxLookUpDistance)
        {
            float stepDistance = maxLookUpDistance / numberOfSteps;
            return FindClosestBuildingObject((int)(startingLookUpDistance + stepDistance), maxLookUpDistance, numberOfSteps);
        }           

        return null;
    }
    else
    {
        return closestGameObject;       
    }
}

此顶级方法通过指定起始距离和最大距离来工作,然后指定要执行的函数的迭代次数。根据迭代次数,它将在开始和结束界限之间投射n个相等距离的球体。