Unity具有出色的功能Terrain.sampleHeight(point)
,它可以立即为您提供脚下地形的高度,而不必进行投射。
但是,任何不重要的项目都具有多个Terrain。 (实际上,任何物理上很大的场景都不可避免地具有地形拼接,一种或另一种方式。)
Unity具有功能Terrain.activeTerrain
,它-不弥补这一点-为您提供“第一个加载的”功能,因此没有用。
事实上,有没有一种快速的方法可以使地形“处于您的控制之下”-然后使用快速功能.sampleHeight
?
{当然,请注意,您可以...投下自己的地形!但是您将拥有自己的高度,因此无需担心.sampleHeight
!}
简而言之,有一个与sampleHeight
配合使用的匹配函数,该函数让该函数知道要在给定xyz中使用哪个Terrain?
(或者确实sampleHeight
只是一个相当无用的演示功能,仅可用于具有一个Terrain的演示中吗?)
答案 0 :(得分:1)
事实上,有没有一种快速的方法可以使地形“处于您的控制之下”-从而 然后使用快速功能.sampleHeight?
是的,可以做到的。
(或者实际上,sampleHeight只是一个相当无用的演示函数, 只能在具有一个地形的演示中使用吗?)
否
有Terrain.activeTerrain
会返回场景中的主要地形。还有Terrain.activeTerrains
(在末尾请注意“ s”)可返回场景中的活动地形。
使用Terrain.activeTerrains
获取地形,该地形返回Terrain
数组,然后使用Terrain.GetPosition
函数获取其位置。通过找到距玩家位置最近的地形来获取当前地形。您可以使用Vector3.Distance
或Vector3.sqrMagnitude
(更快)对地形位置进行排序来实现此目的。
Terrain GetClosestCurrentTerrain(Vector3 playerPos)
{
//Get all terrain
Terrain[] terrains = Terrain.activeTerrains;
//Make sure that terrains length is ok
if (terrains.Length == 0)
return null;
//If just one, return that one terrain
if (terrains.Length == 1)
return terrains[0];
//Get the closest one to the player
float lowDist = (terrains[0].GetPosition() - playerPos).sqrMagnitude;
var terrainIndex = 0;
for (int i = 1; i < terrains.Length; i++)
{
Terrain terrain = terrains[i];
Vector3 terrainPos = terrain.GetPosition();
//Find the distance and check if it is lower than the last one then store it
var dist = (terrainPos - playerPos).sqrMagnitude;
if (dist < lowDist)
{
lowDist = dist;
terrainIndex = i;
}
}
return terrains[terrainIndex];
}
用法:
假设玩家的位置是transform.position
:
//Get the current terrain
Terrain terrain = GetClosestCurrentTerrain(transform.position);
Vector3 point = new Vector3(0, 0, 0);
//Can now use SampleHeight
float yHeight = terrain.SampleHeight(point);
虽然可以使用Terrain.SampleHeight
进行操作,但可以通过从玩家位置到地形的简单射线广播来简化此操作。
Vector3 SampleHeightWithRaycast(Vector3 playerPos)
{
float groundDistOffset = 2f;
RaycastHit hit;
//Raycast down to terrain
if (Physics.Raycast(playerPos, -Vector3.up, out hit))
{
//Get y position
playerPos.y = (hit.point + Vector3.up * groundDistOffset).y;
}
return playerPos;
}
答案 1 :(得分:1)
事实证明答案是肯定的,Unity不提供这样的功能。
答案 2 :(得分:1)
Terrain.GetPosition()= Terrain.transform.position =在世界上的位置
工作方法:
Terrain[] _terrains = Terrain.activeTerrains;
int GetClosestCurrentTerrain(Vector3 playerPos)
{
//Get the closest one to the player
var center = new Vector3(_terrains[0].transform.position.x + _terrains[0].terrainData.size.x / 2, playerPos.y, _terrains[0].transform.position.z + _terrains[0].terrainData.size.z / 2);
float lowDist = (center - playerPos).sqrMagnitude;
var terrainIndex = 0;
for (int i = 0; i < _terrains.Length; i++)
{
center = new Vector3(_terrains[i].transform.position.x + _terrains[i].terrainData.size.x / 2, playerPos.y, _terrains[i].transform.position.z + _terrains[i].terrainData.size.z / 2);
//Find the distance and check if it is lower than the last one then store it
var dist = (center - playerPos).sqrMagnitude;
if (dist < lowDist)
{
lowDist = dist;
terrainIndex = i;
}
}
return terrainIndex;
}
答案 3 :(得分:0)
您可以使用此功能将最近的地形获取到您的当前位置:
int GetClosestTerrain(Vector3 CheckPos)
{
int terrainIndex = 0;
float lowDist = float.MaxValue;
for (int i = 0; i < _terrains.Length; i++)
{
var center = new Vector3(_terrains[i].transform.position.x + _terrains[i].terrainData.size.x / 2, CheckPos.y, _terrains[i].transform.position.z + _terrains[i].terrainData.size.z / 2);
float dist = Vector3.Distance(center, CheckPos);
if (dist < lowDist)
{
lowDist = dist;
terrainIndex = i;
}
}
return terrainIndex;
}
然后您可以使用如下功能:
private Terrain[] _terrains;
void Start()
{
_terrains = Terrain.activeTerrains;
Vector3 start_pos = Vector3.zero;
start_pos.y = _terrains[GetClosestTerrain(start_pos)].SampleHeight(start_pos);
}
答案 4 :(得分:0)
public static Terrain GetClosestTerrain(Vector3 position)
{
return Terrain.activeTerrains.OrderBy(x =>
{
var terrainPosition = x.transform.position;
var terrainSize = x.terrainData.size * 0.5f;
var terrainCenter = new Vector3(terrainPosition.x + terrainSize.x, position.y, terrainPosition.z + terrainSize.z);
return Vector3.Distance(terrainCenter, position);
}).First();
}