9.阵型布局优化
9.1 知识点
定义士兵类型枚举。注意前排英雄枚举值越小,后排英雄枚举值越大。
public enum SoldierType
{
Hero, //英雄
Warrior, //战士
Archer, //猎人
Magician, //魔法师
Loong, //龙
}
在士兵对象脚本定义士兵类型变量,在外部修改并覆盖到预制体
public class SoldierObj : MonoBehaviour
{
//士兵的类型
public SoldierType type;
// ...
}
在SelSoldiers选择士兵方法中抬起鼠标时对士兵列表进行排序。枚举值越小就越前面。因为前面的返回的是阵型前排的位置
/// <summary>
/// 选择士兵方法
/// </summary>
private void SelSoldiers()
{
if (Input.GetMouseButtonDown(0))
{
// ...
}
else if(Input.GetMouseButtonUp(0))
{
// ...
//我们根据兵种的类型进行排序
//对应类型值晓得 放到前面 否则 放到后面
soldierObjs.Sort((a, b)=> {
if (a.type < b.type)
return -1;
else if (a.type == b.type)
return 0;
else
return 1;
});
}
// ...
}
9.2 知识点代码
SoldierObj
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public enum SoldierType
{
Hero, //英雄
Warrior, //战士
Archer, //猎人
Magician, //魔法师
Loong, //龙
}
public class SoldierObj : MonoBehaviour
{
//动画的切换
private Animator animator;
//移动方法
private NavMeshAgent agent;
//设置是否处于选中状态
private GameObject footEffect;
//士兵的类型
public SoldierType type;
void Start()
{
animator = this.GetComponentInChildren<Animator>();
agent = this.GetComponent<NavMeshAgent>();
footEffect = this.transform.Find("FootEffect").gameObject;
SetSelSelf(false);
}
void Update()
{
//根据当前的移动速度 决定动画时 待机 还是移动
animator.SetBool("IsMove", agent.velocity.magnitude > 0);
}
//移动方法 传入目标点即可
public void Move(Vector3 pos)
{
agent.SetDestination(pos);
}
/// <summary>
/// 设置自己是否被选中 决定光圈是否显示
/// </summary>
/// <param name="isSel"></param>
public void SetSelSelf(bool isSel)
{
footEffect.SetActive(isSel);
}
}
Controller
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Controller : MonoBehaviour
{
//鼠标左键是否按下
private bool isMouseDown = false;
//获取LineRenderer组件 用于绘制线段
private LineRenderer line;
//屏幕上的四个点 用于绘制矩形
//鼠标按下时 记录的当前鼠标位置
private Vector3 leftUpPoint;
private Vector3 rightUpPoint;
private Vector3 leftDownPoint;
private Vector3 rightDownPoint;
//射线检测获取到的信息
private RaycastHit hitInfo;
private Vector3 beginWorldPos;
//选择到的士兵对象 存储在该容器
private List<SoldierObj> soldierObjs = new List<SoldierObj>();
//上一次鼠标点击的位置
private Vector3 frontPos = Vector3.zero;
//士兵之间的间隔距离
private float soldierOffset = 3;
void Start()
{
line = this.GetComponent<LineRenderer>();
}
void Update()
{
//选择士兵逻辑处理
SelSoldiers();
//控制士兵移动
ControlSoldiersMove();
}
/// <summary>
/// 选择士兵方法
/// </summary>
private void SelSoldiers()
{
if (Input.GetMouseButtonDown(0))
{
//记录鼠标当前位置
leftUpPoint = Input.mousePosition;
isMouseDown = true;
//通过射线检测 得到地面上的点 之后 用于 范围检测
if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hitInfo, 1000, 1 << LayerMask.NameToLayer("Ground")))
beginWorldPos = hitInfo.point;
}
else if(Input.GetMouseButtonUp(0))
{
isMouseDown = false;
//将线段的点设置为0个 就不会去绘制
line.positionCount = 0;
//每一次重新选择士兵时 我们都把记录的上一个位置清空
frontPos = Vector3.zero;
//清空选择
for (int i = 0; i < soldierObjs.Count; i++)
soldierObjs[i].SetSelSelf(false);
soldierObjs.Clear();
//选择当前的对象
//通过射线检测 得到地面上的另一个点 用于 范围检测
if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hitInfo, 1000, 1 << LayerMask.NameToLayer("Ground")))
{
//范围检测用的中心点 (由于 摄像机 朝向 是世界坐标系正方向 没有旋转 所以我们可以这样做)
Vector3 center = new Vector3((hitInfo.point.x + beginWorldPos.x) / 2, 1, (hitInfo.point.z + beginWorldPos.z) / 2);
//范围检测 盒装的 长宽高的一半
Vector3 halfExtents = new Vector3(Mathf.Abs(hitInfo.point.x - beginWorldPos.x) / 2, 1, Mathf.Abs(hitInfo.point.z - beginWorldPos.z) / 2);
//得到 这个盒装范围内的 所有碰撞器
Collider[] colliders = Physics.OverlapBox(center, halfExtents);
//soldierObjs.Count < 12 是 设置的 选择上限 最多只能选择12个士兵
for (int i = 0; i < colliders.Length && soldierObjs.Count < 12; i++)
{
SoldierObj obj = colliders[i].GetComponent<SoldierObj>();
if (obj != null)
{
obj.SetSelSelf(true);
soldierObjs.Add(obj);
}
}
//我们根据兵种的类型进行排序
//对应类型值晓得 放到前面 否则 放到后面
soldierObjs.Sort((a, b)=> {
if (a.type < b.type)
return -1;
else if (a.type == b.type)
return 0;
else
return 1;
});
}
}
//当鼠标左键处于按下状态时
//就在这里面去处理 线段绘制的逻辑
if( isMouseDown)
{
//注意:目前我们获取的位置 是屏幕坐标系的位置
//设置屏幕上的4个点
leftUpPoint.z = 5;
rightDownPoint = Input.mousePosition;
rightDownPoint.z = 5;
rightUpPoint.x = rightDownPoint.x;
rightUpPoint.y = leftUpPoint.y;
rightUpPoint.z = 5;
leftDownPoint.x = leftUpPoint.x;
leftDownPoint.y = rightDownPoint.y;
leftDownPoint.z = 5;
//设置线段画线的世界坐标系的点
line.positionCount = 4;
line.SetPosition(0, Camera.main.ScreenToWorldPoint(leftUpPoint));
line.SetPosition(1, Camera.main.ScreenToWorldPoint(rightUpPoint));
line.SetPosition(2, Camera.main.ScreenToWorldPoint(rightDownPoint));
line.SetPosition(3, Camera.main.ScreenToWorldPoint(leftDownPoint));
}
}
private void ControlSoldiersMove()
{
if(Input.GetMouseButtonDown(1))
{
//没有士兵不移动
if (soldierObjs.Count == 0)
return;
//获取目标点 通过射线检测
if( Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hitInfo, 1000, 1 << LayerMask.NameToLayer("Ground")) )
{
//通过目标点 计算出 真正的 阵型目标点
//计算目标点
List<Vector3> targetsPos = GetTargetPos(hitInfo.point);
//命令士兵朝向各自的目标点 移动
for (int i = 0; i < soldierObjs.Count; i++)
soldierObjs[i].Move(targetsPos[i]);
}
}
}
/// <summary>
/// 根据鼠标点击的目标点 计算出 阵型的其它点位
/// </summary>
/// <param name="targetPos"></param>
/// <returns></returns>
private List<Vector3> GetTargetPos(Vector3 targetPos)
{
//需要计算目标点 的 面朝向和 右朝向
Vector3 nowForward = Vector3.zero;
Vector3 nowRigth = Vector3.zero;
//是一批士兵 上一次已经移动过一次了 有上一次的位置
if(frontPos != Vector3.zero)
nowForward = (targetPos - frontPos).normalized;//有上一次的点 就直接计算
else//没有上一次的点 就用第一个士兵的位置 作为上一次的点来计算
nowForward = (targetPos - soldierObjs[0].transform.position).normalized;
//根据面朝向 得到右朝向 旋转y轴 90度
nowRigth = Quaternion.Euler(0, 90, 0) * nowForward;
List<Vector3> targetsPos = new List<Vector3>();
switch (soldierObjs.Count)
{
case 1:
targetsPos.Add(targetPos);
break;
case 2:
targetsPos.Add(targetPos + nowRigth * soldierOffset / 2);
targetsPos.Add(targetPos - nowRigth * soldierOffset / 2);
break;
case 3:
targetsPos.Add(targetPos);
targetsPos.Add(targetPos + nowRigth * soldierOffset);
targetsPos.Add(targetPos - nowRigth * soldierOffset);
break;
case 4:
targetsPos.Add(targetPos + nowForward * soldierOffset / 2 - nowRigth * soldierOffset / 2);
targetsPos.Add(targetPos + nowForward * soldierOffset / 2 + nowRigth * soldierOffset / 2);
targetsPos.Add(targetPos - nowForward * soldierOffset / 2 - nowRigth * soldierOffset / 2);
targetsPos.Add(targetPos - nowForward * soldierOffset / 2 + nowRigth * soldierOffset / 2);
break;
case 5:
targetsPos.Add(targetPos + nowForward * soldierOffset / 2);
targetsPos.Add(targetPos + nowForward * soldierOffset / 2 - nowRigth * soldierOffset);
targetsPos.Add(targetPos + nowForward * soldierOffset / 2 + nowRigth * soldierOffset);
targetsPos.Add(targetPos - nowForward * soldierOffset / 2 - nowRigth * soldierOffset);
targetsPos.Add(targetPos - nowForward * soldierOffset / 2 + nowRigth * soldierOffset);
break;
case 6:
targetsPos.Add(targetPos + nowForward * soldierOffset / 2);
targetsPos.Add(targetPos + nowForward * soldierOffset / 2 - nowRigth * soldierOffset);
targetsPos.Add(targetPos + nowForward * soldierOffset / 2 + nowRigth * soldierOffset);
targetsPos.Add(targetPos - nowForward * soldierOffset / 2 - nowRigth * soldierOffset);
targetsPos.Add(targetPos - nowForward * soldierOffset / 2 + nowRigth * soldierOffset);
targetsPos.Add(targetPos - nowForward * soldierOffset / 2);
break;
case 7:
targetsPos.Add(targetPos + nowForward * soldierOffset);
targetsPos.Add(targetPos + nowForward * soldierOffset - nowRigth * soldierOffset);
targetsPos.Add(targetPos + nowForward * soldierOffset + nowRigth * soldierOffset);
targetsPos.Add(targetPos - nowRigth * soldierOffset);
targetsPos.Add(targetPos + nowRigth * soldierOffset);
targetsPos.Add(targetPos);
targetsPos.Add(targetPos - nowForward * soldierOffset);
break;
case 8:
targetsPos.Add(targetPos + nowForward * soldierOffset);
targetsPos.Add(targetPos + nowForward * soldierOffset - nowRigth * soldierOffset);
targetsPos.Add(targetPos + nowForward * soldierOffset + nowRigth * soldierOffset);
targetsPos.Add(targetPos - nowRigth * soldierOffset);
targetsPos.Add(targetPos + nowRigth * soldierOffset);
targetsPos.Add(targetPos);
targetsPos.Add(targetPos - nowForward * soldierOffset - nowRigth * soldierOffset);
targetsPos.Add(targetPos - nowForward * soldierOffset + nowRigth * soldierOffset);
break;
case 9:
targetsPos.Add(targetPos + nowForward * soldierOffset);
targetsPos.Add(targetPos + nowForward * soldierOffset - nowRigth * soldierOffset);
targetsPos.Add(targetPos + nowForward * soldierOffset + nowRigth * soldierOffset);
targetsPos.Add(targetPos - nowRigth * soldierOffset);
targetsPos.Add(targetPos + nowRigth * soldierOffset);
targetsPos.Add(targetPos);
targetsPos.Add(targetPos - nowForward * soldierOffset - nowRigth * soldierOffset);
targetsPos.Add(targetPos - nowForward * soldierOffset + nowRigth * soldierOffset);
targetsPos.Add(targetPos - nowForward * soldierOffset);
break;
case 10:
targetsPos.Add(targetPos + nowForward * soldierOffset - nowRigth * soldierOffset / 2);
targetsPos.Add(targetPos + nowForward * soldierOffset + nowRigth * soldierOffset / 2);
targetsPos.Add(targetPos + nowForward * soldierOffset - nowRigth * soldierOffset * 1.5f);
targetsPos.Add(targetPos + nowForward * soldierOffset + nowRigth * soldierOffset * 1.5f);
targetsPos.Add(targetPos - nowRigth * soldierOffset * 1.5f);
targetsPos.Add(targetPos + nowRigth * soldierOffset * 1.5f);
targetsPos.Add(targetPos - nowRigth * soldierOffset / 2);
targetsPos.Add(targetPos + nowRigth * soldierOffset / 2);
targetsPos.Add(targetPos - nowForward * soldierOffset - nowRigth * soldierOffset * 1.5f);
targetsPos.Add(targetPos - nowForward * soldierOffset + nowRigth * soldierOffset * 1.5f);
break;
case 11:
targetsPos.Add(targetPos + nowForward * soldierOffset - nowRigth * soldierOffset / 2);
targetsPos.Add(targetPos + nowForward * soldierOffset + nowRigth * soldierOffset / 2);
targetsPos.Add(targetPos + nowForward * soldierOffset - nowRigth * soldierOffset * 1.5f);
targetsPos.Add(targetPos + nowForward * soldierOffset + nowRigth * soldierOffset * 1.5f);
targetsPos.Add(targetPos - nowRigth * soldierOffset * 1.5f);
targetsPos.Add(targetPos + nowRigth * soldierOffset * 1.5f);
targetsPos.Add(targetPos - nowRigth * soldierOffset / 2);
targetsPos.Add(targetPos + nowRigth * soldierOffset / 2);
targetsPos.Add(targetPos - nowForward * soldierOffset - nowRigth * soldierOffset * 1.5f);
targetsPos.Add(targetPos - nowForward * soldierOffset + nowRigth * soldierOffset * 1.5f);
targetsPos.Add(targetPos - nowForward * soldierOffset);
break;
case 12:
targetsPos.Add(targetPos + nowForward * soldierOffset - nowRigth * soldierOffset / 2);
targetsPos.Add(targetPos + nowForward * soldierOffset + nowRigth * soldierOffset / 2);
targetsPos.Add(targetPos + nowForward * soldierOffset - nowRigth * soldierOffset * 1.5f);
targetsPos.Add(targetPos + nowForward * soldierOffset + nowRigth * soldierOffset * 1.5f);
targetsPos.Add(targetPos - nowRigth * soldierOffset * 1.5f);
targetsPos.Add(targetPos + nowRigth * soldierOffset * 1.5f);
targetsPos.Add(targetPos - nowRigth * soldierOffset / 2);
targetsPos.Add(targetPos + nowRigth * soldierOffset / 2);
targetsPos.Add(targetPos - nowForward * soldierOffset - nowRigth * soldierOffset * 1.5f);
targetsPos.Add(targetPos - nowForward * soldierOffset + nowRigth * soldierOffset * 1.5f);
targetsPos.Add(targetPos - nowForward * soldierOffset - nowRigth * soldierOffset / 2);
targetsPos.Add(targetPos - nowForward * soldierOffset + nowRigth * soldierOffset / 2);
break;
}
//计算完毕后 记录当前次的位置
frontPos = targetPos;
return targetsPos;
}
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com