我在使用距离计算正确检测对象邻近度时遇到问题,希望你们中的一个能帮助我。
我想要的东西: 我的场景中有几个具有相同标签的实例化游戏对象,如果它们在x和z轴上的距离小于“ 1”,我想更改其材质颜色。为此,我遍历了所有对象的列表,并将它们的位置与当前游戏对象的位置进行比较。
问题: 碰撞对象上的材质颜色会随机变化,并且一旦碰撞结束,有时不会变回原来的颜色。
到目前为止,我的代码:
public class DistanceTester : MonoBehaviour
{
void Start()
{
}
void Update()
{
var menschen = GameObject.FindGameObjectsWithTag("Mensch");
float positionX = transform.position.x;
float positionZ = transform.position.z;
foreach (GameObject mensch in menschen)
{
float distanceX = Mathf.Abs(mensch.transform.position.x - positionX);
float distanceZ = Mathf.Abs(mensch.transform.position.z - positionZ);
if (gameObject != mensch) //Making sure the object is not the same
{
if (distanceX <= 1 && distanceZ <= 1)
{
GetComponent<Renderer>().material.color = Color.red;
mensch.GetComponent<Renderer>().material.color = Color.red;
}
else
{
GetComponent<Renderer>().material.color = Color.green;
mensch.GetComponent<Renderer>().material.color = Color.green;
}
}
}
}
}
我已经尝试使用触发器进行碰撞检测,但希望使用一种更有效的方式,如上面的示例中那样。
答案 0 :(得分:2)
主要问题是您也可能设置了
GetComponent<Renderer>().material.color = ...;
那么如果您靠近menschen[0]
但又远离menschen[1]
怎么办?
→您总是使用menschen
中最后一项的结果来重置颜色!
听起来好像您应该只处理自己的对象,因为所有其他对象都做同样的事情吗?
using Sytsem.Linq;
public class DistanceTester : MonoBehaviour
{
// reference this via the Inspector already
[SerializeField] private Renderer _renderer;
private void Awake()
{
// As fallback get it ONCE
if(!_renderer) _renderer = GetComponent<Renderer>();
}
private void Update()
{
// If possible you should also store this ONCE
var menschen = GameObject.FindGameObjectsWithTag("Mensch");
// This checks if ANY of the objects that is not this object is clsoe enough
if(menschen.Where(m => m != gameObject).Any(m => (transform.position - m.transform.position).sqrMagnitude < 1))
{
_renderer.material.color = Color.red;
}
else
{
_renderer.material.color = Color.green;
}
}
}
menschen.Where(m => m!= gameObject).Any(m => (transform.position - m.transform.position).sqrMagnitude < 1)
基本上等于做类似的事情
var isClose = false;
foreach(var m in menschen)
{
if(m == gameObject) continue;
if((transform.position - m.transform.position).sqrMagnitude < 1)
{
isClose = true;
break;
}
}
if(isClose)
{
...
请注意,如果您可以将FindGameObjectsWithTag
一次的结果存储起来,而不是每帧都获取一次,那么它仍然会更加有效。
假设您的任何Mensch
对象都具有组件DistanceTester
,则您甚至可以通过使用类似模式来实现某种“自动检测”功能
public class DistanceTester : MonoBehaviour
{
private static HashSet<DistanceTester> _instances = new HashSet<DistanceTester>();
private void Awake()
{
_instances.Add(this);
...
}
private void OnDestroy()
{
_instances.Remove(this);
}
...
}
然后,您可以相当高效地遍历_instances
。
更有效的方法实际上是从全局控制器中仅迭代一次,而不是在DistanceTester
的每个实例中都这样做!