MMO_1_准备阶段_3_预设、射线的搜索

一、创建箱子

1.首先创建脚本:ScenesCtrl.cs,并且将脚本挂载到主摄像机上。
在这里插入图片描述

2.ScenesCtrl.cs脚本的内容如下:

public class SceneCtrl : MonoBehaviour 
{
    /// <summary>
    /// 箱子的预设
    /// </summary>
    [SerializeField]
    private GameObject m_BoxPrefab;

    /// <summary>
    /// 当前箱子的数量
    /// </summary>
    private int m_CurrBoxCount = 0;

    /// <summary>
    /// 创建箱子最大数量
    /// </summary>
    private int m_MaxBoxCount = 10;

    /// <summary>
    /// 下次创建箱子的时间
    /// </summary>
    private float m_CreateBoxTime = 0.0f;

    /// <summary>
    /// 箱子的父节点
    /// </summary>
    private Transform m_BoxParent;

    /// <summary>
    /// 箱子的创建区域
    /// </summary>
    private Transform m_CreateBoxArea;

    private void Start()
    {
        m_BoxParent = GameObject.Find("BoxParent").transform;
        m_CreateBoxArea = GameObject.Find("BoxCreationArea").transform;
        m_BoxPrefab = Resources.Load<GameObject>("ItemPrefab/Box");
    }

    private void Update()
    {
        //当前箱子数量 < 箱子的最大数量
        if (m_CurrBoxCount < m_MaxBoxCount)
        {
            //当前时间 > 下一次创建箱子的时间
            if (Time.time > m_CreateBoxTime)
            {
                m_CreateBoxTime += 0.5f;

                //克隆
                GameObject boxObj = Instantiate(m_BoxPrefab);
                boxObj.transform.parent = m_BoxParent;

                //GameObjectXXX.TransformPoint():
                //将GameObjectXXX下的本地坐标转换为世界坐标
                //而-0.5f 和 0.5f 就是GameObjectXXX上的边界坐标极限
                //这个我们可以自己来创建试试,请注意,这里的GameObjectXXX必须是Cube单位(您可以放大或缩小,千万别为了方便用Plane)
                boxObj.transform.position = m_CreateBoxArea.TransformPoint(new Vector3(Random.Range(-0.5f, 0.5f), 1.0f, Random.Range(-0.5f, 0.5f)));
                m_CurrBoxCount += 1;
            }
        }
    }
}

这里特别提一下下面代码:

boxObj.transform.position = m_CreateBoxArea.TransformPoint(new Vector3(Random.Range(-0.5f, 0.5f), 1.0f, Random.Range(-0.5f, 0.5f)));

这是将m_CreateBoxArea坐标系下的本地坐标转换为世界坐标并赋值给boxObj。为什么是-0.5f和0.5f呢,这里我们可以在Unity中去试一试,-0.5f和0.5f其实就是m_CreateBoxArea物体的极限边界,注意这里的m_CreateBoxArea是由Cube物体缩放做成的,如果换成Plane的话就会出问题。

实际效果图:
在这里插入图片描述
在这里插入图片描述

二、点击箱子,销毁箱子

1.首先,我们在Box上挂载上BoxCtrl.cs脚本,并且应用一下预制物,BoxCtrl.cs的内容如下:

public class BoxCtrl : MonoBehaviour 
{
    /// <summary>
    /// 委托
    /// </summary>
    public Action<GameObject> OnHit;


    public void Hit()
    {
        if (OnHit != null)
        {
            OnHit.Invoke(gameObject);
        }
    }
}

2.接着我们需要修改角色控制器上的脚本,修改后的脚本如下:

public class RoleCtrl : MonoBehaviour 
{
    /// <summary>
    /// 角色移动速度
    /// </summary>
    [SerializeField]
    private float m_Speed = 10.0f;

    /// <summary>
    /// 角色目标移动位置
    /// </summary>
    private Vector3 m_TargetPos = Vector3.zero;

    /// <summary>
    /// 角色的转向(四元数)
    /// </summary>
    private Quaternion m_DirectionQua;

    /// <summary>
    /// 角色的转身速度
    /// </summary>
    private float m_RotationSpeed = 0.0f;

    /// <summary>
    /// 转身完成
    /// </summary>
    private bool m_RotationOver = false;

    /// <summary>
    /// 角色控制器
    /// </summary>
    private CharacterController m_CharacterController;

    private void Start()
    {
        m_CharacterController = GetComponent<CharacterController>();
    }

    private void Update()
    {
        if (m_CharacterController == null)
        {
            return;
        }

        //使角色紧贴地面
        if (!m_CharacterController.isGrounded)
        {
            m_CharacterController.Move((transform.position + new Vector3(0.0f, -1000.0f, 0.0f)) - transform.position);
        }

        //如果按下了鼠标右键
        if (Input.GetMouseButtonUp(1))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hitInfo;
            if (Physics.Raycast(ray, out hitInfo, 1 << LayerMask.NameToLayer("B")))
            {
                BoxCtrl boxCtrl = hitInfo.transform.gameObject.GetComponent<BoxCtrl>();
                if (boxCtrl != null)
                {
                    boxCtrl.Hit();
                }
            }
        }

        #region 控制角色移动转向

        //如果点击了鼠标左键
        if (Input.GetMouseButtonUp(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hitInfo;

            if (Physics.Raycast(ray, out hitInfo, Mathf.Infinity, 1 << LayerMask.NameToLayer("Ground")))
            {
                m_TargetPos = hitInfo.point;
                m_RotationOver = false;
                m_RotationSpeed = 0.0f;
            }
        }

        //开始设置角色的移动和转向
        if (m_TargetPos != Vector3.zero)
        {
            //当目标位置和角色之间的距离大于0.1f的时候
            //进行移动和旋转
            if (Vector3.Distance(m_TargetPos, transform.position) > 0.1f)
            {
                //1.确定方向
                Vector3 direction = m_TargetPos - transform.position;
                direction = direction.normalized;
                direction.y = 0.0f;

                //2.开始转向
                if (!m_RotationOver)
                {
                    m_RotationSpeed += 5.0f;
                    m_DirectionQua = Quaternion.LookRotation(direction);
                    transform.rotation = Quaternion.Lerp(transform.rotation, m_DirectionQua, m_RotationSpeed * Time.deltaTime);
                    if (Quaternion.Angle(transform.rotation, m_DirectionQua) < 0.1f)
                    {
                        m_RotationSpeed = 1.0f;
                        m_RotationOver = true;
                    }
                }

                //3.移动
                m_CharacterController.Move(direction * m_Speed * Time.deltaTime);
            }
        }
        #endregion

    }
}

3.最后,我们需要再修改一下SceneCtrl.cs脚本,脚本内容如下:

public class SceneCtrl : MonoBehaviour 
{
    /// <summary>
    /// 箱子的预设
    /// </summary>
    [SerializeField]
    private GameObject m_BoxPrefab;

    /// <summary>
    /// 当前箱子的数量
    /// </summary>
    private int m_CurrBoxCount = 0;

    /// <summary>
    /// 创建箱子最大数量
    /// </summary>
    private int m_MaxBoxCount = 10;

    /// <summary>
    /// 下次创建箱子的时间
    /// </summary>
    private float m_CreateBoxTime = 0.0f;

    /// <summary>
    /// 箱子的父节点
    /// </summary>
    private Transform m_BoxParent;

    /// <summary>
    /// 箱子的创建区域
    /// </summary>
    private Transform m_CreateBoxArea;

    private void Start()
    {
        m_BoxParent = GameObject.Find("BoxParent").transform;
        m_CreateBoxArea = GameObject.Find("BoxCreationArea").transform;
        m_BoxPrefab = Resources.Load<GameObject>("ItemPrefab/Box");
    }

    private void Update()
    {
        //当前箱子数量 < 箱子的最大数量
        if (m_CurrBoxCount < m_MaxBoxCount)
        {
            //当前时间 > 下一次创建箱子的时间
            if (Time.time > m_CreateBoxTime)
            {
                m_CreateBoxTime += 0.5f;

                //克隆
                GameObject boxObj = Instantiate(m_BoxPrefab);
                boxObj.transform.parent = m_BoxParent;

                //GameObjectXXX.TransformPoint():
                //将GameObjectXXX下的本地坐标转换为世界坐标
                //而-0.5f 和 0.5f 就是GameObjectXXX上的边界坐标极限
                //这个我们可以自己来创建试试,请注意,这里的GameObjectXXX必须是Cube单位(您可以放大或缩小,千万别为了方便用Plane)
                boxObj.transform.position = m_CreateBoxArea.TransformPoint(new Vector3(UnityEngine.Random.Range(-0.5f, 0.5f), 1.0f, UnityEngine.Random.Range(-0.5f, 0.5f)));

                BoxCtrl boxCtrl = boxObj.GetComponent<BoxCtrl>();
                if (boxCtrl != null)
                {
                    m_CurrBoxCount += 1;
                    boxCtrl.OnHit += BoxHit;
                }

                
            }
        }
    }

    private void BoxHit(GameObject obj)
    {
        m_CurrBoxCount -= 1;
        GameObject.Destroy(obj);
    }
}

这里就实现了,角色点击鼠标右键并且击中箱子的时候,销毁掉了箱子。

三、搜索角色附近的箱子,并销毁

1.首先需要修改角色的脚本,点击键盘R,搜索附近的Box,并且销毁掉,代码如下:

public class RoleCtrl : MonoBehaviour 
{
    /// <summary>
    /// 角色移动速度
    /// </summary>
    [SerializeField]
    private float m_Speed = 10.0f;

    /// <summary>
    /// 角色目标移动位置
    /// </summary>
    private Vector3 m_TargetPos = Vector3.zero;

    /// <summary>
    /// 角色的转向(四元数)
    /// </summary>
    private Quaternion m_DirectionQua;

    /// <summary>
    /// 角色的转身速度
    /// </summary>
    private float m_RotationSpeed = 0.0f;

    /// <summary>
    /// 转身完成
    /// </summary>
    private bool m_RotationOver = false;

    /// <summary>
    /// 角色控制器
    /// </summary>
    private CharacterController m_CharacterController;

    private void Start()
    {
        m_CharacterController = GetComponent<CharacterController>();
    }

    private void Update()
    {
        if (m_CharacterController == null)
        {
            return;
        }

        //使角色紧贴地面
        if (!m_CharacterController.isGrounded)
        {
            m_CharacterController.Move((transform.position + new Vector3(0.0f, -1000.0f, 0.0f)) - transform.position);
        }

        //如果按下了鼠标右键
        if (Input.GetMouseButtonUp(1))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hitInfo;
            if (Physics.Raycast(ray, out hitInfo, 1 << LayerMask.NameToLayer("B")))
            {
                BoxCtrl boxCtrl = hitInfo.transform.gameObject.GetComponent<BoxCtrl>();
                if (boxCtrl != null)
                {
                    boxCtrl.Hit();
                }
            }
        }

        //如果按下了键盘R
        if (Input.GetKeyUp(KeyCode.R))
        {
            Collider[] col = Physics.OverlapSphere(transform.position, 3.5f, 1 << LayerMask.NameToLayer("B"));
            if (col != null && col.Length > 0)
            {
                for (int i = 0; i < col.Length; ++i)
                {
                    BoxCtrl boxCtrl = col[i].gameObject.GetComponent<BoxCtrl>();
                    if (boxCtrl != null)
                    {
                        boxCtrl.Hit();
                    }
                }
            }
        }

        #region 控制角色移动转向

        //如果点击了鼠标左键
        if (Input.GetMouseButtonUp(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hitInfo;

            if (Physics.Raycast(ray, out hitInfo, Mathf.Infinity, 1 << LayerMask.NameToLayer("Ground")))
            {
                m_TargetPos = hitInfo.point;
                m_RotationOver = false;
                m_RotationSpeed = 0.0f;
            }
        }

        //开始设置角色的移动和转向
        if (m_TargetPos != Vector3.zero)
        {
            //当目标位置和角色之间的距离大于0.1f的时候
            //进行移动和旋转
            if (Vector3.Distance(m_TargetPos, transform.position) > 0.1f)
            {
                //1.确定方向
                Vector3 direction = m_TargetPos - transform.position;
                direction = direction.normalized;
                direction.y = 0.0f;

                //2.开始转向
                if (!m_RotationOver)
                {
                    m_RotationSpeed += 5.0f;
                    m_DirectionQua = Quaternion.LookRotation(direction);
                    transform.rotation = Quaternion.Lerp(transform.rotation, m_DirectionQua, m_RotationSpeed * Time.deltaTime);
                    if (Quaternion.Angle(transform.rotation, m_DirectionQua) < 0.1f)
                    {
                        m_RotationSpeed = 1.0f;
                        m_RotationOver = true;
                    }
                }

                //3.移动
                m_CharacterController.Move(direction * m_Speed * Time.deltaTime);
            }
        }
        #endregion

    }

    void OnDrawGizmos()
    {
        Gizmos.color = Color.blue;
        Gizmos.DrawWireSphere(transform.position, 3.5f);
    }
}

以上就是今天的全部内容

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值