unity3d:保持V字型队形,按路径点移动
思路:
1.分为领导者,追随者,追随点。
2.先创建领导者。根据剩下人数的多少,再在左右创建追随者和追随点,成v字排列。追随点是领导者的子物体
3.领导者按照路径点移动
4.追随者追的追随点移动,如果距离过远,要提高速度
创建队形脚本
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SanJiao : MonoBehaviour { public GameObject m_tmp; public List<Transform> m_listPos; public Transform m_pointPar; public int m_tankCnt; public Dictionary<int, List<Vector3>> m_dicPos = new Dictionary<int, List<Vector3>>(); public List<Transform> m_listTank; // Use this for initialization void Start () { m_dicPos[0] = new List<Vector3>(); for (int i = 0; i < m_pointPar.childCount; i++) { m_listPos.Add(m_pointPar.GetChild(i)); } for (int i = 0; i < m_listPos.Count; i++) { m_dicPos[0].Add(m_listPos[i].transform.position); GameObject objPos = Instantiate(m_tmp); objPos.transform.position = m_listPos[i].transform.position; if (i < m_listPos.Count - 1) { Vector3 dir = m_listPos[i + 1].transform.position - m_listPos[i].transform.position; objPos.transform.rotation = Quaternion.LookRotation(dir.normalized); } if (i == m_listPos.Count - 1) { Vector3 dir = m_listPos[i].transform.position - m_listPos[i-1].transform.position; objPos.transform.rotation = Quaternion.LookRotation(dir.normalized); } if (m_tankCnt > 1) { Sector(objPos.transform, objPos.transform.position, 60, 5, m_tankCnt-1); } } CreateTank(); } // Update is called once per frame void Update () { } void CreateTank() { Transform par = null; Quaternion qua = Quaternion.identity; for (int i = 0; i < m_tankCnt; i++) { GameObject tank; //m_listTank.Add(tank.transform); if (i == 0) { tank = Instantiate(m_tmp); tank.transform.position = m_dicPos[i][0]; tank.transform.GetComponent<FollowPath>().SetLeader(m_dicPos[i]); Vector3 dir = m_dicPos[i][1] - m_dicPos[i][0]; tank.transform.rotation = Quaternion.LookRotation(dir.normalized); // 一开始就要确定leader 的方向 qua = tank.transform.rotation; par = tank.transform; } else { GameObject follow = new GameObject(); follow.transform.position = m_dicPos[i][0]; follow.transform.SetParent(par, true); tank = Instantiate(m_tmp); tank.transform.position = m_dicPos[i][0]; tank.transform.GetComponent<FollowPath>().SetFollow(follow.transform); tank.transform.rotation = qua; //tank.transform.SetParent(par, false); } } } public void Sector(Transform t, Vector3 center, float angle, float radius,int cnt) { Vector3 forward = -t.forward; int sign = -1; for (int i = 0; i < cnt; i++) { if (i % 2 == 0) { sign = -1; } else { sign = 1; } Vector3 pos = Quaternion.Euler(0f, sign * angle / 2, 0f) * forward * radius * (1 + i / 2) + center; //GameObject obj = Instantiate(m_tmp); //obj.transform.position = pos; if (m_dicPos.ContainsKey(i+1) == false) { m_dicPos[1 + i] = new List<Vector3>(); } m_dicPos[1 + i].Add(pos); } } void OnDrawGizmos() { Gizmos.color = Color.white; for (int i = 0; i < m_pointPar.transform.childCount; i++) { Vector3 position = m_pointPar.transform.GetChild(i).position; if (i > 0) { Vector3 previous = m_pointPar.transform.GetChild(i-1).position; Gizmos.DrawLine(previous, position); Gizmos.DrawWireSphere(position, 0.3f); } } } }
追随脚本
using System.Collections; using System.Collections.Generic; using UnityEngine; public class FollowPath : MonoBehaviour { public int CurrentWayPointID = 0; public float Speed;//移动速度 public float reachDistance = 0.01f;//里路径点的最大范围 public List<Vector3> m_listPos = new List<Vector3>(); public bool m_isCanFollow = false; public bool m_isLeader = false; public Transform m_followTrans; public Transform m_leaderTrans; void Start() { } public void SetLeader(List<Vector3> listPos) { m_isLeader = true; m_listPos = listPos; m_isCanFollow = true; CurrentWayPointID = 0; } public void SetFollow(Transform trans) { m_isLeader = false; m_followTrans = trans; m_isCanFollow = true; CurrentWayPointID = 0; } void Update() { if (!m_isCanFollow) return; if (m_isLeader == true) { if (CurrentWayPointID >= m_listPos.Count) { return; } float distance = Vector3.Distance(m_listPos[CurrentWayPointID], transform.position); transform.position = Vector3.MoveTowards(transform.position, m_listPos[CurrentWayPointID], Time.deltaTime * Speed); Vector3 LookDirection = m_listPos[CurrentWayPointID] - transform.position; Quaternion targetlook = Quaternion.LookRotation(LookDirection); if (distance <= reachDistance) { CurrentWayPointID++; if (CurrentWayPointID < m_listPos.Count) { playerRotate(m_listPos[CurrentWayPointID], gameObject/*transform.Find("Tank").gameObject*/); } } } else if (m_isLeader == false) { float distance = Vector3.Distance(m_followTrans.position, transform.position); if (distance > 3) { transform.position = Vector3.MoveTowards(transform.position, m_followTrans.position, Time.deltaTime * Speed * 1.25f); } else { transform.position = Vector3.MoveTowards(transform.position, m_followTrans.position, Time.deltaTime * Speed ); } //Vector3 LookDirection = m_listPos[CurrentWayPointID] - transform.position; //Quaternion targetlook = Quaternion.LookRotation(LookDirection); //playerRotate(m_followTrans.position, gameObject/*transform.Find("Tank").gameObject*/); transform.LookAt(m_followTrans); } } void playerRotate(Vector3 target, GameObject rot) { //向量的叉乘 if (Vector3.Cross(rot.transform.forward, target - this.transform.position).y > 0) { //计算角度 rot.transform.Rotate(Vector3.up * Vector3.Angle(rot.transform.forward, target - this.transform.position)); } else { rot.transform.Rotate(Vector3.down * Vector3.Angle(rot.transform.forward, target - this.transform.position)); } } }
效果
posted on 2023-05-28 12:22 luoyikun 阅读(51) 评论(0) 编辑 收藏 举报 来源
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!