You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity:如何让玩家在程序化地形上生成且不穿透地面?

解决Unity程序化地形中玩家生成穿透地面的问题

原代码的核心问题

  1. 检测与生成位置不匹配:SpawnCheck里检测了一个随机位置,但SpawnPlayer又重新随机了另一个位置,等于之前的射线检测完全无效,生成的位置根本没经过碰撞校验,必然会出现穿透。
  2. Y坐标设置错误:生成玩家时Y轴用了Random.Range(35,300),完全没用到射线检测到的地面高度hit.point.y,要么悬浮过高,要么直接穿进地面。
  3. 旋转逻辑无效:Quaternion.Lerp的第三个参数是0,等于完全不插值,旋转代码起不到让玩家贴合地面法线的作用。
  4. 射线检测无过滤:没指定只检测地形层,可能误撞其他物体或漏检地形。

修复后的代码及说明

using System.Collections;
using UnityEngine;

public class PlayerSpawn : MonoBehaviour
{
    public GameObject player;
    // 在Inspector中指定地形所在的Layer
    public LayerMask terrainLayer;
    // 玩家胶囊体半高(根据实际Collider调整,比如胶囊体height为2则填1)
    public float playerHalfHeight = 1f;
    // 生成范围边界
    public float spawnRange = 350f;
    // 射线起始高度(需高于地形最高处)
    public float rayStartY = 150f;

    void Start()
    {
        StartCoroutine(TrySpawnPlayer());
    }

    // 重试生成玩家的协程
    IEnumerator TrySpawnPlayer()
    {
        while (true)
        {
            // 随机生成检测位置
            float randomX = Random.Range(-spawnRange, spawnRange);
            float randomZ = Random.Range(-spawnRange, spawnRange);
            Vector3 rayStart = new Vector3(randomX, rayStartY, randomZ);

            // 仅检测地形层,限制射线长度提升效率
            if (Physics.Raycast(rayStart, Vector3.down, out RaycastHit hit, rayStartY + 50f, terrainLayer))
            {
                // 生成玩家:地面点+半高,避免穿模
                GameObject spawnedPlayer = Instantiate(player, hit.point + Vector3.up * playerHalfHeight, Quaternion.identity);
                // 让玩家贴合地面法线,斜面也能正确站立
                spawnedPlayer.transform.rotation = Quaternion.FromToRotation(Vector3.up, hit.normal);
                // 随机Y轴旋转
                spawnedPlayer.transform.Rotate(Vector3.up, Random.Range(0f, 360f), Space.World);
                
                Debug.Log("玩家已生成在地面");
                break; // 生成成功则退出循环
            }
            // 未检测到地面,0.25秒后重试
            yield return new WaitForSeconds(0.25f);
        }
    }
}

关键修复点说明

  • 统一检测与生成流程:在同一个协程内完成随机位置、射线检测、生成操作,确保生成位置是经过校验的合法地面点。
  • 精准设置Y坐标:用hit.point.y + playerHalfHeight让玩家刚好站在地面上,既不穿模也不悬浮。
  • 层过滤射线检测:通过terrainLayer指定仅检测地形,避免误撞场景中其他物体导致错误生成。
  • 简化旋转逻辑:直接用Quaternion.FromToRotation让玩家up方向对齐地面法线,保证斜面站立姿态正确。
  • 优化重试逻辑:用while(true)循环重试直到生成成功,代码结构更简洁。

额外注意事项

  • 在Inspector面板中,把terrainLayer设置为地形所在的Layer(比如默认的Terrain层)。
  • 根据玩家Collider实际尺寸调整playerHalfHeight,胶囊体直接取CapsuleCollider.height / 2即可。
  • 确保rayStartY高于地形最高处,避免射线从地形内部出发导致检测失败。

内容的提问来源于stack exchange,提问作者Smoothbrick578

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 05:20:43