Unity,获取“实际”当前地形?

时间:2018-09-15 14:14:04

标签: c# unity3d unity3d-terrain

Unity具有出色的功能Terrain.sampleHeight(point),它可以立即为您提供脚下地形的高度,而不必进行投射。

但是,任何不重要的项目都具有多个Terrain。 (实际上,任何物理上很大的场景都不可避免地具有地形拼接,一种或另一种方式。)

Unity具有功能Terrain.activeTerrain,它-不弥补这一点-为您提供“第一个加载的”功能,因此没有用。

事实上,有没有一种快速的方法可以使地形“处于您的控制之下”-然后使用快速功能.sampleHeight

{当然,请注意,您可以...投下自己的地形!但是您将拥有自己的高度,因此无需担心.sampleHeight!}

简而言之,有一个与sampleHeight配合使用的匹配函数,该函数让该函数知道要在给定xyz中使用哪个Terrain?

(或者确实sampleHeight只是一个相当无用的演示功能,仅可用于具有一个Terrain的演示中吗?)

5 个答案:

答案 0 :(得分:1)

  

事实上,有没有一种快速的方法可以使地形“处于您的控制之下”-从而   然后使用快速功能.sampleHeight?

是的,可以做到的。

  

(或者实际上,sampleHeight只是一个相当无用的演示函数,   只能在具有一个地形的演示中使用吗?)


Terrain.activeTerrain会返回场景中的主要地形。还有Terrain.activeTerrains(在末尾请注意“ s”)可返回场景中的活动地形

使用Terrain.activeTerrains获取地形,该地形返回Terrain数组,然后使用Terrain.GetPosition函数获取其位置。通过找到距玩家位置最近的地形来获取当前地形。您可以使用Vector3.DistanceVector3.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();
}