我在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功能。它找到了每个立方体的距离,但它只选择了目标列表中的最后一个元素。
它仍然显示控制台中每个立方体的距离。
答案 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个相等距离的球体。