一、准备阶段-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);
}
}
以上就是今天的全部内容