unity3d-搞个场景漫游如何实现Alpha

要处理两个问题:

  1. 如何设置地面人不掉下去
    方法一、 游戏物体加刚体,将游戏物体和地面加collider。如果是地形,可以使用 Terrain Collider;如果是简单的平面,可以添加 Box Collider 或者 Mesh Collider(如果平面是复杂的网格形状)。
    方法二、在游戏物体上增加刚体,在刚体组件的 Constraints 选项中,可以限制物体在某些轴向上的运动。例如,如果不想让物体在 Y 轴(垂直方向)下落,可以勾选 “Freeze Position” 中的 Y 选项。这样,刚体在物理模拟过程中,其 Y 轴位置就不会因为重力而改变,从而不会掉下去。
    缺点:当冻住y的时候, 遇到地上有坑的时候,也不会按地势走
    方法三、使用navi ai,给人物挂上agent后,烘焙后任务就不会掉下去了
  2. 鼠标控制方向,可以参考
        // 鼠标控制镜头方向
        float rotLeftRight = Input.GetAxis("Mouse X") * mouseSensitivity;
        float horizontalRotationTarget = horizontalRotation + rotLeftRight;
        horizontalRotation = Mathf.SmoothDamp(horizontalRotation, horizontalRotationTarget, ref horizontalRotationVelocity, horizontalSmoothTime);
        horizontalRotation = Mathf.Clamp(horizontalRotation, -leftRightRange, leftRightRange);
        transform.localEulerAngles = new Vector3(transform.localEulerAngles.x, horizontalRotation, transform.localEulerAngles.z);

        float verticalRotationTarget = verticalRotation - Input.GetAxis("Mouse Y") * mouseSensitivity;
        verticalRotation = Mathf.SmoothDamp(verticalRotation, verticalRotationTarget, ref verticalRotationVelocity, smoothTime);
        verticalRotation = Mathf.Clamp(verticalRotation, -upDownRange, upDownRange);
        Camera.main.transform.localEulerAngles = new Vector3(verticalRotation, 0, 0);
  1. 如何漫游,代码实现如下

方向键控制方向,挂载到游戏物体player上

  • Rigidbody 模式(任选)
public Rigidbody rd;
// Start is called before the first frame update
void Start()
{
}

// Update is called once per frame
void Update()
{
    float f = Input.GetAxis("Horizontal");
    float v = Input.GetAxis("Vertical");
    rd.AddForce(new Vector3(f,0,v)*1);
}
  • transform模式(任选)

using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    // 角色的移动速度
    public float speed = 5.0f;

    void Update()
    {
        // 获取水平(左右)和垂直(前后)输入
        float horizontalInput = Input.GetAxis("Horizontal");
        float verticalInput = Input.GetAxis("Vertical");

        // 计算移动方向
        Vector3 moveDirection = new Vector3(horizontalInput, 0, verticalInput);

        // 应用移动
        transform.position += moveDirection * speed * Time.deltaTime;
    }
}

镜头跟随玩家,挂载到镜头上

public class FollowTarget : MonoBehaviour {
private Transform player;
private Vector3 offset;
private float smoothing = 3;
	void Start (){
		player = GameObject.FindGameObjectWithTag("Player”).transform;
		offset = transform.position - player.position;
	}
	void LateUpdate (){
		Vector3 targetPosition = player.position + player.TransformDirection( offset)
		transform.position = Vector3.Lerp(transform.position, targetPosition,Time.deltaTime*smoothing);
		transform.LookAt(player.position);
	}
}

七八

  1. 为地面增加ground标签,collider,取消Is Kinematic,
  2. 角色挂上rigidbody组件
  3. 有一些属性可以影响其与碰撞体的相互作用。例如,Mass(质量)和Drag(空气阻力)
using UnityEngine;

public class PlayerMovementWithJumpAndMouse : MonoBehaviour
{
    // 角色的移动速度
    public float speed = 5.0f;

    // 角色的跳跃力
    public float jumpForce = 10.0f;

    // 判断角色是否在地面上
    private bool isGrounded = true;

    // 地面的检测半径
    private float groundCheckDistance = 0.4f;

    // 地面检测层的层掩码
    private LayerMask groundLayerMask;

    // 用于存储鼠标的当前和上一个位置
    private Vector3 mouseCurrentPosition;
    private Vector3 mouseLastPosition;

    // 新增的变量,用于存储调整后的移动速度和斜坡的法线
    private float adjustedSpeed;
    private Vector3 slopeNormal;

    void Start()
    {
        // 设置地面检测层的层掩码
        groundLayerMask = LayerMask.GetMask("Ground");

        // 初始化鼠标位置
        mouseLastPosition = Input.mousePosition;
    }

    void Update()
    {
        // 获取鼠标输入
        mouseCurrentPosition = Input.mousePosition;
        Vector3 mouseDelta = mouseCurrentPosition - mouseLastPosition;

        // 将鼠标移动转换为旋转角度(这里假设每100像素移动对应1度旋转)
        float rotationX = mouseDelta.y * -1 * Time.deltaTime * 100f; // 乘以-1是因为我们希望向上移动鼠标时角色向下看(Y轴反转)
        float rotationY = mouseDelta.x * Time.deltaTime * 100f;

        // 限制旋转角度,防止角色倒立或过度旋转
        rotationX = Mathf.Clamp(rotationX, -30f, 30f); // 限制X轴旋转在-30到30度之间

        // 计算旋转后的方向
        Quaternion targetRotation = Quaternion.Euler(rotationX, transform.eulerAngles.y + rotationY, transform.eulerAngles.z);

        // 平滑过渡到目标旋转方向(可选)
        transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 5f);

        // 重置鼠标位置为当前位置,以便下一次计算移动量
        mouseLastPosition = mouseCurrentPosition;

        // 获取水平(左右)和垂直(前后)输入(这里仍然保留键盘输入,以便可以同时使用)
        float horizontalInput = Input.GetAxis("Horizontal");
        float verticalInput = Input.GetAxis("Vertical");

        // 计算移动方向
        Vector3 moveDirection = new Vector3(horizontalInput, 0, verticalInput);

        // 检测斜坡并获取其法线
        RaycastHit slopeHit;
        if (Physics.Raycast(transform.position, transform.forward, out slopeHit, 100f, groundLayerMask))
        {
            // 获取斜坡的法线
            slopeNormal = slopeHit.normal;

            // 根据斜坡倾斜程度调整移动速度
            float slopeAngle = Vector3.Angle(Vector3.up, slopeNormal);
            AdjustMovementBySlope(slopeAngle);

            // 应用移动
            transform.position += moveDirection * adjustedSpeed * Time.deltaTime;

            // 根据斜坡法线调整角色方向
            AdjustCharacterDirection(slopeNormal);
        }
        else
        {
            // 如果没有检测到斜坡,则使用默认速度,并重置斜坡法线
            adjustedSpeed = speed;
            slopeNormal = Vector3.up; // 或者你可以设置为其他默认方向
        }

        // 检测跳跃输入
        if (Input.GetButtonDown("Jump") && isGrounded)
        {
            // 给角色一个向上的力
            Vector3 jump = new Vector3(0, jumpForce, 0);
            rigidbody.velocity = Vector3.zero; // 重置垂直速度,防止跳跃时受其他力影响
            rigidbody.AddForce(jump, ForceMode.Impulse);
            isGrounded = false; // 标记角色已经起跳
        }
    }

    // 用于检测角色是否在地面上
    private void OnCollisionStay(Collision collision)
    {
        // 检查是否与地面层的对象接触
        if ((groundLayerMask & (1 << collision.gameObject.layer)) != 0)
        {
            // 检查是否在地面检测半径内
            if (Mathf.Abs(collision.contacts[0].point.y - transform.position.y) <= groundCheckDistance)
            {
                isGrounded = true; // 标记角色在地面上
            }
        }
    }

    // 如果没有地面碰撞,则重置isGrounded,防止角色在空中时误判为已落地
    private void OnCollisionExit(Collision collision)
    {
        if ((groundLayerMask & (1 << collision.gameObject.layer)) != 0)
        {
            isGrounded = false;
        }
    }

    // 检测斜坡的倾斜角度,并调整移动速度(此方法已被整合到Update中,但保留此方法签名以便理解)
    /*private float DetectSlopeAngle()
    {
        // ...(原代码已整合到Update中)
    }*/

    // 根据斜坡倾斜程度调整移动速度或方向
    private void AdjustMovementBySlope(float slopeAngle)
    {
        // 设置一个最大斜坡角度阈值,超过此角度则减少速度
        float maxSlopeAngle = 45f;

        // 根据斜坡角度调整速度
        if (slopeAngle > maxSlopeAngle)
        {
            // 计算速度调整因子(0到1之间)
            float speedReductionFactor = 1f - (slopeAngle - maxSlopeAngle) / (90f - maxSlopeAngle);
            speedReductionFactor = Mathf.Clamp01(speedReductionFactor); // 确保因子在0到1之间

            // 应用速度调整因子
            adjustedSpeed = speed * speedReductionFactor;
        }
        else
        {
            // 没有超过最大斜坡角度,使用正常速度
            adjustedSpeed = speed;
        }
    }

    // 根据斜坡法线调整角色方向
    private void AdjustCharacterDirection(Vector3 slopeNormal)
    {
        // 计算角色应该面向的方向,即斜坡法线的水平分量(忽略Y轴)
        Vector3 targetDirection = new Vector3(slopeNormal.x, 0, slopeNormal.z).normalized;

        // 如果角色当前面向的方向与目标方向差异较大,则平滑过渡到目标方向
        // 这里我们使用Quaternion.Slerp来实现平滑过渡
        Quaternion targetRotation = Quaternion.LookRotation(targetDirection);
        transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 5f);

        // 注意:上面的平滑过渡可能会导致角色在陡峭的斜坡上时旋转过快。
        // 为了解决这个问题,你可以根据斜坡角度来限制旋转速度,或者完全禁用平滑过渡,直接设置旋转。
        // 例如:
        // float maxRotationSpeed = 30f; // 最大旋转速度(度/秒)
        // float rotationAngle = Vector3.Angle(transform.forward, targetDirection);
        // float rotationSpeed = Mathf.Min(maxRotationSpeed, rotationAngle / Time.deltaTime);
        // transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
    }
}

参考

https://www.jianshu.com/p/0e8d4dd55c2c

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值