2658 lines
89 KiB
C#
2658 lines
89 KiB
C#
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using BehaviorDesigner.Runtime;
|
||
using BestHTTP;
|
||
using BestHTTP.JSON.LitJson;
|
||
using DarkTonic.MasterAudio;
|
||
using DG.Tweening;
|
||
using DragonLi.Core;
|
||
using DragonLi.Frame;
|
||
using JetBrains.Annotations;
|
||
using Mirror;
|
||
using NaughtyAttributes;
|
||
using Unity.Mathematics;
|
||
using Unity.XR.PXR;
|
||
using UnityEngine;
|
||
using UnityEngine.Rendering.Universal;
|
||
using UnityEngine.XR.Interaction.Toolkit;
|
||
using XPlugin.Data.JsonLiteDB;
|
||
using XUI;
|
||
using static XPlugin.Data.JsonLiteDB.JsonLiteDB;
|
||
using Random = System.Random;
|
||
|
||
namespace Valheim
|
||
{
|
||
public class GameManager : NetworkBehaviour
|
||
{
|
||
public static GameManager Ins { get; private set; }
|
||
|
||
#region 预制体
|
||
|
||
// 小动物预制集合
|
||
public List<GameObject> PetPres = new List<GameObject>();
|
||
|
||
// 怪物预制集合
|
||
public List<GameObject> EnemyPres = new List<GameObject>();
|
||
|
||
public List<GameObject> skillPres = new List<GameObject>();
|
||
|
||
public List<GameObject> bulletPres = new List<GameObject>();
|
||
|
||
public List<GameObject> itemPres = new List<GameObject>();
|
||
|
||
public List<GameObject> badgePres = new List<GameObject>();
|
||
|
||
public GameObject BattleArePre;
|
||
|
||
public GameObject reviePre;
|
||
|
||
public GameObject hitEffectPre;
|
||
|
||
public GameObject upgradEffectPre;
|
||
|
||
public GameObject spwanBallPointPre;
|
||
|
||
public GameObject EnergyBallPre;
|
||
|
||
public GameObject CagePre;
|
||
|
||
public GameObject EnemyUIPre;
|
||
|
||
public GameObject PetUIPre;
|
||
|
||
public GameObject AudioManagerPre;
|
||
|
||
public GameObject DoorColliderPre;
|
||
|
||
public GameObject InitDoorPre;
|
||
|
||
public GameObject aiDrPre;
|
||
|
||
public GameObject itemBoxPre;
|
||
|
||
#endregion
|
||
|
||
public int selectCardId = -1;
|
||
|
||
public Pet userPet;
|
||
public bool isGetPet = false;
|
||
|
||
public bool isPlayPetWorld;
|
||
|
||
public bool isGuide;
|
||
|
||
public SkillManager skillManager;
|
||
|
||
[NonSerialized]
|
||
public string HttpServerUrl = "";
|
||
//public string HttpServerUrl = "http://120.27.202.237:8888";
|
||
// http验证
|
||
[NonSerialized]
|
||
public readonly string Author = "";
|
||
// 验证信息
|
||
private AuthInfo authInfo = new AuthInfo();
|
||
|
||
// 游玩结束时间
|
||
#if UNITY_EDITOR
|
||
[UnityEngine.DisplayOnly]
|
||
#endif
|
||
[SyncVar]
|
||
public long vistEnd = 0;
|
||
// 总游玩时长
|
||
public int vistAllTime = (int)(60 * 15F);
|
||
|
||
public float curGameTime = 0;
|
||
// 游戏是否结束
|
||
[NonSerialized]
|
||
[SyncVar]
|
||
public bool GameOver = true;
|
||
/// <summary>
|
||
/// 游戏是否通关
|
||
/// </summary>
|
||
#if UNITY_EDITOR
|
||
[UnityEngine.DisplayOnly]
|
||
#endif
|
||
[SyncVar]
|
||
public bool IsWin = false;
|
||
|
||
// json数据库
|
||
private JsonLiteDB DB;
|
||
|
||
#region 配置表
|
||
|
||
// 当前关卡宠物信息集合
|
||
public Dictionary<int, EnemyData> PetDic = new Dictionary<int, EnemyData>();
|
||
// 当前关卡怪物信息集合
|
||
public Dictionary<int, EnemyData> EnemyDic = new Dictionary<int, EnemyData>();
|
||
// 关卡表2
|
||
public Dictionary<int, List<EditObjInfo>> GameLevelInfos2 = new Dictionary<int, List<EditObjInfo>>();
|
||
|
||
public List<EnemyData> EnemyDataList = new List<EnemyData>();
|
||
|
||
public Dictionary<int, SkillData> SkillDataList = new Dictionary<int, SkillData>();
|
||
|
||
public List<List<List<int>>> LevelEnemyList = new List<List<List<int>>>();
|
||
|
||
#endregion
|
||
|
||
// 宠物自增
|
||
private int petIndex = 0;
|
||
|
||
/// <summary>
|
||
/// 敌人自增
|
||
/// </summary>
|
||
private int enemyIndex = 0;
|
||
|
||
// 编队信息
|
||
public Dictionary<int, TeamInfo> Teams = new Dictionary<int, TeamInfo>();
|
||
|
||
/// <summary>
|
||
/// 跟随行为树
|
||
/// </summary>
|
||
public ExternalBehavior FollowBehavior;
|
||
|
||
// 跟随行为树
|
||
public Dictionary<int, BehaviorTree> FollowBehaviors = new Dictionary<int, BehaviorTree>();
|
||
|
||
/// <summary>
|
||
/// 所有敌人
|
||
/// </summary>
|
||
public List<Enemy> EnemyList = new List<Enemy>();
|
||
|
||
public Dictionary<int, List<Enemy>> BattleAreaEnemyDic = new Dictionary<int, List<Enemy>>();
|
||
|
||
/// <summary>
|
||
/// 巨型鱼人
|
||
/// </summary>
|
||
[NonSerialized]
|
||
public FishGiant fishGiant;
|
||
|
||
/// <summary>
|
||
/// 博士
|
||
/// </summary>
|
||
public AiDr aiDr;
|
||
|
||
/// <summary>
|
||
/// 所有动物
|
||
/// </summary>
|
||
public Dictionary<int, Pet> PetList = new Dictionary<int, Pet>();
|
||
|
||
/// <summary>
|
||
/// 所有复活点
|
||
/// </summary>
|
||
[NonSerialized]
|
||
public List<Transform> RevivePointList = new List<Transform>();
|
||
|
||
/// <summary>
|
||
/// 所有区域
|
||
/// </summary>
|
||
public Dictionary<int, BattleArea> AreaList = new Dictionary<int, BattleArea>();
|
||
|
||
/// <summary>
|
||
/// 所有笼子
|
||
/// </summary>
|
||
public Dictionary<int, List<Cage>> CageList = new Dictionary<int, List<Cage>>();
|
||
|
||
/// <summary>
|
||
/// 分配宠物给谁
|
||
/// </summary>
|
||
[NonSerialized]
|
||
[SyncVar]
|
||
public int curretAssignIndex = 0;
|
||
|
||
// [NonSerialized]
|
||
[SyncVar]
|
||
public float EnergyValue = 0;
|
||
|
||
public int curBattleAreaIndex = 0;
|
||
|
||
public int curEnemyLevel = 1;
|
||
|
||
public int curMapId;
|
||
public int curUpLevelCount;
|
||
public Vector3 lastAreaPos;
|
||
|
||
|
||
[SoundGroup] public string selectCardSound;
|
||
|
||
//添加AI相关字段
|
||
[Header("AI")]
|
||
public GameObject aiControllerPrefab;
|
||
public Transform aiSpawnPosition;
|
||
private AIController currentAI;
|
||
public Player player;
|
||
|
||
public Place place;
|
||
[Header("指引系统")]
|
||
public GameObject GuideArrowPre; // 指引箭头预制体
|
||
private GameObject guideArrowInstance; // 指引箭头实例
|
||
private DoorGuideArrowPath guideArrowComponent; // 指引箭头组件
|
||
private bool isGuideArrowActive = false;
|
||
private Vector3 lastPlayerPosition; // 记录玩家上一次的位置
|
||
private float updatePathThreshold = 0.5f; // 更新路径的阈值(玩家移动超过这个距离才更新路径)
|
||
private float updatePathCooldown = 0.3f; // 更新路径的冷却时间
|
||
private float lastPathUpdateTime = 0f;
|
||
private Vector3[] lastPathPoints; // 上一次的路径点
|
||
private bool isPathSmoothed = false;
|
||
private List<Vector3> smoothedPath = new List<Vector3>();
|
||
#region 生命周期
|
||
void Awake()
|
||
{
|
||
Ins = this;
|
||
}
|
||
|
||
void Start()
|
||
{
|
||
if (isClient)
|
||
{
|
||
AuthorPanel.Show();
|
||
}
|
||
// MonoSingleton<CoroutineTaskManager>.Instance.WaitSecondTodo(() =>
|
||
// {
|
||
// RpcRequestNotifyStart();
|
||
// }, 60f);
|
||
// 新增:初始化指引系统
|
||
InitializeGuideArrow();
|
||
}
|
||
|
||
void Destroy()
|
||
{
|
||
#if !UNITY_EDITOR && UNITY_ANDROID && PICO
|
||
PXR_Enterprise.UnBindEnterpriseService();
|
||
#endif
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 创建
|
||
/// <summary>
|
||
/// 创建战斗区域
|
||
/// </summary>
|
||
[Server]
|
||
public void CreateBattleArea(int id, Vector3 pos, Vector3 scale, Vector3 angle)
|
||
{
|
||
GameObject battleArea = Instantiate(BattleArePre);
|
||
NetworkServer.Spawn(battleArea);
|
||
battleArea.transform.position = pos;
|
||
battleArea.transform.localScale = scale;
|
||
battleArea.transform.eulerAngles = angle;
|
||
BattleArea script = battleArea.GetComponent<BattleArea>();
|
||
script.Init(id);
|
||
AreaList.Add(id, script);
|
||
battleArea.SetActive(false);
|
||
}
|
||
|
||
public int GetNowTime()
|
||
{
|
||
return Mathf.RoundToInt(curGameTime);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建复活点
|
||
/// </summary>
|
||
[Server]
|
||
public void CreateRevivePoint(Vector3 pos)
|
||
{
|
||
GameObject reviveArea = Instantiate(reviePre);
|
||
NetworkServer.Spawn(reviveArea);
|
||
reviveArea.transform.position = pos;
|
||
RevivePointList.Add(reviveArea.transform);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建笼子(牢笼)
|
||
/// </summary>
|
||
[Server]
|
||
public void CreateCage(int areaId, int cageId, Vector3 pos, float angleY, float scale)
|
||
{
|
||
GameObject cage = Instantiate(CagePre);
|
||
NetworkServer.Spawn(cage);
|
||
cage.transform.position = pos;
|
||
cage.transform.eulerAngles = new Vector3(0, angleY, 0);
|
||
cage.transform.localScale = new Vector3(scale, scale, scale);
|
||
Cage script = cage.GetComponent<Cage>();
|
||
script.Init(cageId);
|
||
CageList.TryGetValue(areaId, out List<Cage> list);
|
||
if (list == null)
|
||
{
|
||
list = new List<Cage>();
|
||
CageList.Add(areaId, list);
|
||
}
|
||
list.Add(script);
|
||
}
|
||
|
||
public void CreateHitEffect(Vector3 pos)
|
||
{
|
||
GameObject hitEffect = Instantiate(hitEffectPre);
|
||
NetworkServer.Spawn(hitEffect);
|
||
hitEffect.transform.position = pos;
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
NetworkServer.Destroy(hitEffect);
|
||
}, 1);
|
||
}
|
||
|
||
public void CreateUpgradEffect(Vector3 pos)
|
||
{
|
||
GameObject upgradEffect = Instantiate(upgradEffectPre);
|
||
NetworkServer.Spawn(upgradEffect);
|
||
upgradEffect.transform.position = pos;
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
NetworkServer.Destroy(upgradEffect);
|
||
}, 1);
|
||
}
|
||
|
||
[Server]
|
||
public GameObject CreateSpawnBallPoint(Vector3 pos)
|
||
{
|
||
// GameObject spwanBallPoint = Instantiate(spwanBallPointPre);
|
||
// NetworkServer.Spawn(spwanBallPoint);
|
||
// spwanBallPoint.transform.position = pos;
|
||
// return spwanBallPoint;
|
||
int max = UnityEngine.Random.Range(1, 101);
|
||
if (max <= 19)
|
||
{
|
||
//CreateItemBox(pos);
|
||
}
|
||
return null;
|
||
}
|
||
|
||
public GameObject CreateEnergyBall(Vector3 pos)
|
||
{
|
||
GameObject energyBall = Instantiate(EnergyBallPre);
|
||
NetworkServer.Spawn(energyBall);
|
||
energyBall.transform.position = pos;
|
||
return energyBall;
|
||
}
|
||
|
||
public GameObject CreateDoorCoiider(Vector3 pos, Vector3 angle)
|
||
{
|
||
isShowPetWorld = false;
|
||
GameObject doorCoiider = Instantiate(DoorColliderPre);
|
||
NetworkServer.Spawn(doorCoiider);
|
||
doorCoiider.transform.position = pos;
|
||
|
||
doorCoiider.transform.localEulerAngles = angle;
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
StartGuide();
|
||
}, 0.5f);
|
||
return doorCoiider;
|
||
|
||
}
|
||
|
||
public bool isShowPetWorld;
|
||
public void ShowPetWorld(GameObject door = null)
|
||
{
|
||
if (isShowPetWorld)
|
||
return;
|
||
isShowPetWorld = true;
|
||
CleanupGuideArrow();
|
||
// 游戏开始
|
||
TransitionPanel.Ins.WhiteFadeOut(() =>
|
||
{
|
||
if (curUpLevelCount >= 3)
|
||
{
|
||
ClosePet();
|
||
GameInit.Ins.StartGame(() =>
|
||
{
|
||
StartCoroutine(GameManager.Ins.PlayAudio("NPC24", transform, true));
|
||
MonoSingleton<CoroutineTaskManager>.Instance.WaitSecondTodo(() =>
|
||
{
|
||
StartCoroutine(GameInit.Ins.PlayEndAnimation());
|
||
}, 5f);
|
||
});
|
||
}
|
||
else
|
||
{
|
||
ClosePet();
|
||
GameInit.Ins.StartGame(() =>
|
||
{
|
||
GameStart(() =>
|
||
{
|
||
GameInit.Ins.self.ShowPathGuide();
|
||
});
|
||
});
|
||
UserJoinPet();
|
||
}
|
||
if (door != null)
|
||
NetworkServer.Destroy(door);
|
||
});
|
||
}
|
||
|
||
public void CreateInitDoor()
|
||
{
|
||
GameObject door = Instantiate(InitDoorPre);
|
||
NetworkServer.Spawn(door);
|
||
door.transform.position = new Vector3(0, 0, 2);
|
||
if (place == Place.Guangxi_Guilin_Gongcheng_Shijixincheng)
|
||
{
|
||
InitDoorPre.transform.position = new Vector3(-1.5f, 0, -1.5f);
|
||
}
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
if (isPlayGame)
|
||
return;
|
||
CreateMap();
|
||
StartGame();
|
||
NetworkServer.Destroy(door.gameObject);
|
||
}, 5);
|
||
}
|
||
|
||
public void CreateBadge(Vector3 pos, bool isRotate)
|
||
{
|
||
isShowPetWorld = false;
|
||
GameObject obj = Instantiate(badgePres[curMapId]);
|
||
NetworkServer.Spawn(obj);
|
||
obj.transform.position = pos + new Vector3(0, 1, 0);
|
||
obj.GetComponent<Badge>().Init(isRotate);
|
||
}
|
||
|
||
public bool isPlayGame;
|
||
public void StartGame()
|
||
{
|
||
CreateAIController();
|
||
//isPlayGame = true;
|
||
//GameInit.Ins.laboratory.Init();
|
||
////MasterAudio.StopAllSoundsOfTransform(GameInit.Ins.self.transform);
|
||
//GameInit.Ins.MRBgm.StateChangeBgm(-1);
|
||
//foreach (var obj in GameInit.Ins.worldPres)
|
||
//{
|
||
// obj.SetActive(false);
|
||
//}
|
||
//vistEnd = (long)(DateTime.Now.Subtract(new DateTime(1970, 1, 1))).TotalSeconds + vistAllTime;
|
||
//CreateHUD();
|
||
//GameInit.Ins.Close();
|
||
//GameOver = false;
|
||
//isPlayPetWorld = false;
|
||
//TransitionPanel.Ins.WhiteFadeOut(CreateAiDr);
|
||
//GetPetList();
|
||
}
|
||
|
||
//添加创建AI角色的方法
|
||
[Server]
|
||
public void CreateAIController()
|
||
{
|
||
//检查是否已经存在AI角色
|
||
if (currentAI != null)
|
||
{
|
||
Debug.Log("AI角色已经存在,不再创建新的");
|
||
return;
|
||
}
|
||
|
||
if (aiControllerPrefab != null)
|
||
{
|
||
Debug.Log("创建AI角色");
|
||
|
||
//在玩家前方创建AI角色
|
||
Vector3 spawnPosition = player.transform.position + player.transform.forward * 3f;
|
||
aiControllerPrefab = Instantiate(aiControllerPrefab, spawnPosition, Quaternion.identity);
|
||
|
||
//获取AIController并启动开场白
|
||
AIController aiController = aiControllerPrefab.GetComponent<AIController>();
|
||
GameInit.Ins.MRBgm.StateChangeBgm(-1);
|
||
if (aiController != null)
|
||
{
|
||
//注册AI介绍完成回调
|
||
aiController.OnIntroductionComplete += HandleAIIntroductionComplete;
|
||
|
||
//添加延迟,确保所有组件已经完成初始化
|
||
StartCoroutine(DelayedStartIntroduction(aiController));
|
||
}
|
||
else
|
||
{
|
||
Debug.LogError("AI预制体中的AIController组件丢失");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Debug.LogError("AI预制体没有在GameManager分配!");
|
||
}
|
||
}
|
||
|
||
private IEnumerator DelayedStartIntroduction(AIController aiController)
|
||
{
|
||
yield return new WaitForSeconds(0.1f); // 短暂延迟
|
||
aiController.StartIntroduction();
|
||
}
|
||
|
||
// 添加处理 AI 介绍完成
|
||
private void HandleAIIntroductionComplete()
|
||
{
|
||
Debug.Log("AI introduction completed!");
|
||
|
||
if (currentAI != null)
|
||
{
|
||
currentAI.OnIntroductionComplete -= HandleAIIntroductionComplete;
|
||
}
|
||
|
||
// 游戏正式开始的逻辑
|
||
StartCoroutine(StartMainGame());
|
||
}
|
||
|
||
//添加
|
||
private IEnumerator StartMainGame()
|
||
{
|
||
// 等待一下确保过渡平滑
|
||
yield return new WaitForSeconds(1f);
|
||
|
||
// 创建博士并让他开始说话
|
||
isPlayGame = true;
|
||
GameInit.Ins.laboratory.Init();
|
||
//MasterAudio.StopAllSoundsOfTransform(GameInit.Ins.self.transform);
|
||
foreach (var obj in GameInit.Ins.worldPres)
|
||
{
|
||
obj.SetActive(false);
|
||
}
|
||
vistEnd = (long)(DateTime.Now.Subtract(new DateTime(1970, 1, 1))).TotalSeconds + vistAllTime;
|
||
CreateHUD();
|
||
GameInit.Ins.Close();
|
||
GameOver = false;
|
||
isPlayPetWorld = false;
|
||
TransitionPanel.Ins.WhiteFadeOut(CreateAiDr);
|
||
}
|
||
|
||
public void CreateAiDr()
|
||
{
|
||
Debug.Log("创建博士");
|
||
GameObject aiDrObj = Instantiate(aiDrPre, GameInit.Ins.laboratory.transform);
|
||
NetworkServer.Spawn(aiDrObj);
|
||
aiDr = aiDrObj.GetComponent<AiDr>();
|
||
aiDr.transform.position = GameInit.Ins.aiDrPos.position;
|
||
aiDr.Init();
|
||
|
||
}
|
||
/// <summary>
|
||
/// 创建地图
|
||
/// </summary>
|
||
[Server]
|
||
public void CreateMap()
|
||
{
|
||
EditObjInfos infos = JsonMapper.ToObject<EditObjInfos>(Resources.Load<TextAsset>("Maps/" + GameInit.Ins.place).text);
|
||
GameLevelInfos2.Clear();
|
||
foreach (EditObjInfo info in infos.Data)
|
||
{
|
||
GameLevelInfos2.TryGetValue(info.ObjType, out List<EditObjInfo> infoList);
|
||
if (infoList == null)
|
||
{
|
||
List<EditObjInfo> list = new List<EditObjInfo>();
|
||
list.Add(info);
|
||
GameLevelInfos2.Add(info.ObjType, list);
|
||
}
|
||
else
|
||
{
|
||
infoList.Add(info);
|
||
}
|
||
}
|
||
// EditObjInfo doorInfo = GameLevelInfos2[(int)ObjTypes.door][0];
|
||
// CreateDoorCoiider(new Vector3(doorInfo.x, doorInfo.y, doorInfo.z), new Vector3(doorInfo.angleX, doorInfo.angleY, doorInfo.angleZ));
|
||
|
||
GameObject audioManager = Instantiate(AudioManagerPre);
|
||
NetworkServer.Spawn(audioManager);
|
||
}
|
||
|
||
public void CreateEnemyUI(Enemy enemy)
|
||
{
|
||
GameObject enemyUI = Instantiate(EnemyUIPre, enemy.uiPos.transform);
|
||
NetworkServer.Spawn(enemyUI);
|
||
enemyUI.GetComponent<EnemyUI>().Init(enemy);
|
||
}
|
||
|
||
public void CreatePetUI(Pet pet)
|
||
{
|
||
GameObject petUi = Instantiate(PetUIPre, pet.transform);
|
||
NetworkServer.Spawn(petUi);
|
||
petUi.GetComponent<PetUI>().Init(pet);
|
||
}
|
||
|
||
public IEnumerator CreateGameObjs(Action cb)
|
||
{
|
||
yield return isGuide;
|
||
Debug.Log("创建gameObjs");
|
||
AreaList.Clear();
|
||
// 生成战斗区域
|
||
List<EditObjInfo> battleAreaInfos = GameLevelInfos2[(int)ObjTypes.area];
|
||
List<EditObjInfo> curBattleAreaInfos = new List<EditObjInfo>();
|
||
foreach (EditObjInfo info in battleAreaInfos)
|
||
{
|
||
if (info.mapId == curMapId)
|
||
{
|
||
curBattleAreaInfos.Add(info);
|
||
}
|
||
}
|
||
foreach (EditObjInfo battleAreaInfo in curBattleAreaInfos)
|
||
{
|
||
CreateBattleArea(
|
||
battleAreaInfo.areaId,
|
||
new Vector3(battleAreaInfo.x, battleAreaInfo.y, battleAreaInfo.z),
|
||
new Vector3(battleAreaInfo.scaleX, battleAreaInfo.scaleY, battleAreaInfo.scaleZ),
|
||
new Vector3(battleAreaInfo.angleX, battleAreaInfo.angleY, battleAreaInfo.angleZ)
|
||
);
|
||
yield return null;
|
||
}
|
||
|
||
if (curMapId <= 0)
|
||
{
|
||
// // 生成复活点
|
||
// List<EditObjInfo> reviveInfos = GameLevelInfos2[(int)ObjTypes.revive];
|
||
// foreach (EditObjInfo reviveInfo in reviveInfos)
|
||
// {
|
||
// CreateRevivePoint(new Vector3(reviveInfo.x, reviveInfo.y, reviveInfo.z));
|
||
// yield return null;
|
||
// }
|
||
}
|
||
// // 生成怪物
|
||
// List<EditObjInfo> enemyInfos = GameLevelInfos2[(int)ObjTypes.enemy];
|
||
// foreach (EditObjInfo enemyInfo in enemyInfos)
|
||
// {
|
||
// CreateEnemy(
|
||
// (EnemyType)enemyInfo.id,
|
||
// new Vector3(enemyInfo.x, enemyInfo.y, enemyInfo.z),
|
||
// enemyInfo.angleY,
|
||
// enemyInfo.areaId,
|
||
// enemyInfo.scaleX,
|
||
// enemyInfo.lvl,
|
||
// (EnemyState)enemyInfo.state
|
||
// );
|
||
// yield return null;
|
||
// }
|
||
//
|
||
//
|
||
// // 生成宠物
|
||
// List<EditObjInfo> petInfos = GameLevelInfos2[(int)ObjTypes.pet];
|
||
// foreach (EditObjInfo petInfo in petInfos)
|
||
// {
|
||
// CreatePet(
|
||
// (PetType)petInfo.id,
|
||
// new Vector3(petInfo.x, petInfo.y, petInfo.z),
|
||
// petInfo.scaleX,
|
||
// petInfo.angleY,
|
||
// (int)petInfo.lvl,
|
||
// (PetState)petInfo.state,
|
||
// petInfo.cageId
|
||
// );
|
||
// yield return null;
|
||
// }
|
||
//
|
||
// // 生成笼子
|
||
// List<EditObjInfo> cageInfos = GameLevelInfos2[(int)ObjTypes.cage];
|
||
// foreach (EditObjInfo cageInfo in cageInfos)
|
||
// {
|
||
// CreateCage(cageInfo.areaId, cageInfo.cageId, new Vector3(cageInfo.x, cageInfo.y, cageInfo.z), cageInfo.angleY, cageInfo.scaleY);
|
||
// yield return null;
|
||
// }
|
||
//
|
||
// // 生成boss
|
||
// List<EditObjInfo> bossInfos = GameLevelInfos2[(int)ObjTypes.boss];
|
||
// foreach (EditObjInfo bossInfo in bossInfos)
|
||
// {
|
||
// CreateFishGiant(
|
||
// new Vector3(bossInfo.x, bossInfo.y, bossInfo.z),
|
||
// bossInfo.angleY,
|
||
// bossInfo.scaleX,
|
||
// bossInfo.lvl,
|
||
// (BossState)bossInfo.state,
|
||
// new Vector3(bossInfo.pos1X, 0, bossInfo.pos1Z)
|
||
// );
|
||
// yield return null;
|
||
// }
|
||
|
||
cb.Invoke();
|
||
}
|
||
|
||
public void UserJoinPet()
|
||
{
|
||
if (curMapId > 0)
|
||
return;
|
||
if (userPet != null && !isGetPet)
|
||
{
|
||
PetList.Add(petIndex, userPet);
|
||
AssignPetIndex();
|
||
PetPlace(petIndex);
|
||
isGetPet = true;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建触发区域的怪物
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public IEnumerator CreateBattleAreaEnemy()
|
||
{
|
||
EnemyList.Clear();
|
||
// 生成怪物
|
||
List<EditObjInfo> enemyInfos = GameLevelInfos2[(int)ObjTypes.enemy];
|
||
List<EditObjInfo> petInfos = GameLevelInfos2[(int)ObjTypes.pet];
|
||
List<EditObjInfo> battleObjInfos = new List<EditObjInfo>();
|
||
List<EditObjInfo> battlePetInfos = new List<EditObjInfo>();
|
||
foreach (var enemyInfo in enemyInfos)
|
||
{
|
||
if (enemyInfo.areaId == curBattleAreaIndex && enemyInfo.mapId == curMapId)
|
||
battleObjInfos.Add(enemyInfo);
|
||
}
|
||
foreach (var petInfo in petInfos)
|
||
{
|
||
if (petInfo.cageId == curBattleAreaIndex && petInfo.mapId == curMapId)
|
||
battlePetInfos.Add(petInfo);
|
||
}
|
||
if (battleObjInfos.Count > 0)
|
||
{
|
||
int index = 0;
|
||
if (curEnemyLevel % 6 == 0)
|
||
{
|
||
ChangeGameBGM(Bgm.Fight);
|
||
var enemyInfo = battleObjInfos[^1];
|
||
var curId = EnemyDataList.Where(item => item.EnemyType == 2).ToList()[curMapId].EnemyId;
|
||
CreateEnemyBoss(
|
||
curId,
|
||
new Vector3(enemyInfo.x, enemyInfo.y, enemyInfo.z),
|
||
enemyInfo.angleY,
|
||
curBattleAreaIndex,
|
||
enemyInfo.scaleX,
|
||
curEnemyLevel,
|
||
EnemyState.GroundIdle
|
||
);
|
||
}
|
||
else
|
||
{
|
||
foreach (var enemyInfo in battleObjInfos)
|
||
{
|
||
if (index >= LevelEnemyList[curMapId][(curEnemyLevel - 1) % 5].Count)
|
||
break;
|
||
int curId = LevelEnemyList[curMapId][(curEnemyLevel - 1) % 5][index];
|
||
CreateEnemy(
|
||
curId,
|
||
new Vector3(enemyInfo.x, enemyInfo.y, enemyInfo.z),
|
||
enemyInfo.angleY,
|
||
curBattleAreaIndex,
|
||
enemyInfo.scaleX,
|
||
curEnemyLevel,
|
||
(EnemyState)enemyInfo.state
|
||
);
|
||
//battleObjInfos.Remove(battleObjInfos[0]);
|
||
index++;
|
||
}
|
||
}
|
||
}
|
||
//生成需要解救的宠物
|
||
if (battlePetInfos.Count > 0 && curEnemyLevel % 5 != 0)
|
||
{
|
||
var petInfo = battlePetInfos[0];
|
||
//int curId=UnityEngine.Random.Range(0, PetDic.Count-1);
|
||
int curId = UnityEngine.Random.Range(4 + curMapId * 3, 7 + curMapId * 3);
|
||
CreatePet(
|
||
curId,
|
||
new Vector3(petInfo.x, petInfo.y, petInfo.z),
|
||
petInfo.angleY,
|
||
(PetState)petInfo.state,
|
||
curEnemyLevel
|
||
);
|
||
CreateCage(
|
||
curBattleAreaIndex,
|
||
curEnemyLevel,
|
||
new Vector3(petInfo.x, petInfo.y, petInfo.z),
|
||
petInfo.angleY,
|
||
1
|
||
);
|
||
battlePetInfos.Remove(petInfo);
|
||
}
|
||
curEnemyLevel++;
|
||
yield return null;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 宠物编队
|
||
|
||
/// <summary>
|
||
/// 申请创建一只宠物编队
|
||
/// </summary>
|
||
[Command(requiresAuthority = false)]
|
||
public void AddTeamCmd(int teamId)
|
||
{
|
||
Debug.Log(teamId + "玩家申请创建宠物编队");
|
||
BehaviorTree behaviorTree = gameObject.AddComponent<BehaviorTree>();
|
||
behaviorTree.ExternalBehavior = FollowBehavior;
|
||
behaviorTree.RestartWhenComplete = true;
|
||
FollowBehaviors.Add(teamId, behaviorTree);
|
||
TeamInfo teamInfo = new TeamInfo();
|
||
teamInfo.id = teamId;
|
||
Teams.Add(teamId, teamInfo);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取编队xx所有宠物
|
||
/// </summary>
|
||
/// <param name="teamId"></param>
|
||
/// <returns></returns>
|
||
public List<GameObject> GetTeamMembers(int teamId)
|
||
{
|
||
List<GameObject> resMembers = new List<GameObject>();
|
||
TeamInfo teamInfo = Teams[teamId];
|
||
foreach (int petId in teamInfo.membersId)
|
||
{
|
||
resMembers.Add(PetList[petId].gameObject);
|
||
}
|
||
return resMembers;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 重置编队行为
|
||
/// </summary>
|
||
public void ResetTeamBehavior(int teamId)
|
||
{
|
||
if (FollowBehaviors[teamId] == null) return;
|
||
FollowBehaviors[teamId].SetVariable("leader", (SharedGameObject)MRNetworkManager.Ins.roomSlots[teamId].gameObject);
|
||
FollowBehaviors[teamId].SetVariable("agents", (SharedGameObjectList)GetTeamMembers(teamId));
|
||
FollowBehaviors[teamId].SetVariable("hasInit", (SharedBool)false);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 加入编队
|
||
/// </summary>
|
||
public void JoinTeam(int teamId, int petId)
|
||
{
|
||
Debug.Log(petId + "号宠物加入" + teamId + "编队");
|
||
Teams.TryGetValue(teamId, out TeamInfo info);
|
||
if (info != null)
|
||
{
|
||
Teams[teamId].membersId.Add(petId);
|
||
Teams[teamId].joinId.Add(petId);
|
||
ResetTeamBehavior(teamId);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 暂离编队(Server)
|
||
/// </summary>
|
||
[Server]
|
||
public bool SetOutTeam(int teamId, int petId)
|
||
{
|
||
bool res = false;
|
||
Teams.TryGetValue(teamId, out TeamInfo info);
|
||
if (info != null)
|
||
{
|
||
if (info.membersId.Remove(petId))
|
||
{
|
||
info.setoutMembersId.Add(petId);
|
||
}
|
||
ResetTeamBehavior(teamId);
|
||
res = true;
|
||
Debug.Log(petId + "号宠物暂时离开" + teamId + "编队");
|
||
}
|
||
return res;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 暂离归队(Server)
|
||
/// </summary>
|
||
/// <param name="teamId"></param>
|
||
/// <param name="petId"></param>
|
||
[Server]
|
||
public bool Return2Team(int teamId, int petId)
|
||
{
|
||
bool res = false;
|
||
Teams.TryGetValue(teamId, out TeamInfo info);
|
||
if (info != null)
|
||
{
|
||
if (info.setoutMembersId.Remove(petId))
|
||
{
|
||
info.membersId.Add(petId);
|
||
}
|
||
ResetTeamBehavior(teamId);
|
||
res = true;
|
||
Debug.Log(string.Format("{0}号宠物回归{1}编队", petId, teamId));
|
||
}
|
||
return res;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清空队伍中除了第一个宠物的信息
|
||
/// </summary>
|
||
public void ClearTeam()
|
||
{
|
||
foreach (var item in Teams.Values)
|
||
{
|
||
var fistId = item.joinId.First();
|
||
item.membersId = item.membersId.Contains(fistId) ? new HashSet<int> { fistId } : new HashSet<int>();
|
||
item.setoutMembersId = item.setoutMembersId.Contains(fistId) ? new HashSet<int> { fistId } : new HashSet<int>();
|
||
item.joinId = item.joinId.Contains(fistId) ? new HashSet<int> { fistId } : new HashSet<int>();
|
||
ResetTeamBehavior(item.id);
|
||
}
|
||
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 宠物
|
||
|
||
/// <summary>
|
||
/// 创建宠物
|
||
/// </summary>
|
||
/// <param name="type"></param>
|
||
/// <param name="pos"></param>
|
||
/// <returns></returns>
|
||
[Server]
|
||
public Pet CreatePet(int curId, Vector3 pos, float angleY, PetState state, int cageId)
|
||
{
|
||
GameObject pet = Instantiate(GetPetPre(curId));
|
||
NetworkServer.Spawn(pet);
|
||
pet.transform.position = pos;
|
||
pet.transform.eulerAngles = new Vector3(0, angleY, 0);
|
||
Pet script = pet.GetComponent<Pet>();
|
||
petIndex++;
|
||
script.OnSpawn(PetDic[curId], curEnemyLevel + 1, state, cageId, petIndex);
|
||
PetList.Add(petIndex, script);
|
||
return script;
|
||
}
|
||
|
||
public GameObject GetPetPre(int curId)
|
||
{
|
||
foreach (var item in PetPres)
|
||
{
|
||
if (item.GetComponent<Pet>().id == curId)
|
||
return item;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
|
||
public void GetPet(int petId, Vector3 pos, Vector3 angles)
|
||
{
|
||
if (userPet != null)
|
||
NetworkServer.Destroy(userPet.gameObject);
|
||
GameObject pet = Instantiate(PetPres[petId]);
|
||
NetworkServer.Spawn(pet);
|
||
pet.transform.position = pos;
|
||
pet.transform.eulerAngles = angles;
|
||
userPet = pet.GetComponent<Pet>();
|
||
petIndex = 1;
|
||
EnemyData data = null;
|
||
foreach (var item in EnemyDataList)
|
||
{
|
||
if (item.EnemyId == petId + 1)
|
||
data = item;
|
||
}
|
||
userPet.OnSpawn(data, 1, PetState.Birth, -1, petIndex);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 尝试捕捉宠物
|
||
/// </summary>
|
||
[Server]
|
||
public void Try2CapturePet(int playerId, int petId)
|
||
{
|
||
Debug.Log("尝试捕捉宠物" + petId);
|
||
Pet pet = null;
|
||
foreach (var item in PetList)
|
||
{
|
||
if (item.Value.id == petId)
|
||
pet = item.Value;
|
||
}
|
||
|
||
if (pet != null)
|
||
{
|
||
if ((pet.state == PetState.Wild) && curretAssignIndex == playerId)
|
||
{
|
||
pet.Catched(playerId);
|
||
// 宠物加入编队
|
||
JoinTeam(playerId, petId);
|
||
// 统计捕获宠物数量
|
||
// StatisticsManager.Ins.SetPlayerStatistics(playerId, "GetPetCount", Teams[playerId].membersId.Count);
|
||
}
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// set all pet out line
|
||
/// </summary>
|
||
[Server]
|
||
public void SetAllPetOutLineToZero()
|
||
{
|
||
foreach (Pet pet in PetList.Values)
|
||
{
|
||
pet.SetOutLine(0);
|
||
}
|
||
}
|
||
|
||
public void PetJump()
|
||
{
|
||
foreach (Pet pet in PetList.Values)
|
||
{
|
||
pet.PlayJump();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 分配宠物
|
||
/// </summary>
|
||
[Server]
|
||
public void PetPlace(int petId)
|
||
{
|
||
PetList.TryGetValue(petId, out Pet pet);
|
||
if (pet != null)
|
||
{
|
||
if (pet.state == PetState.NeedAssigned)
|
||
{
|
||
pet.Catched(curretAssignIndex);
|
||
JoinTeam(curretAssignIndex, petId);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 打开笼子
|
||
/// </summary>
|
||
public void OpenCage(int cageId)
|
||
{
|
||
foreach (Pet pet in PetList.Values)
|
||
{
|
||
if (pet.cageId == cageId)
|
||
{
|
||
pet.Change2State(PetState.NeedAssigned);
|
||
AssignPetIndex();
|
||
PetPlace(pet.index);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
[Server]
|
||
/// <summary>
|
||
/// 回血
|
||
/// </summary>
|
||
public void RegenerationHealth(float checkRange, int count, int repliesVolume, GameObject gameObject)
|
||
{
|
||
foreach (Pet pet in PetList.Values)
|
||
{
|
||
if (Vector3.Distance(pet.transform.position, gameObject.transform.position) <= checkRange)
|
||
{
|
||
pet.AddBlood(count, repliesVolume);
|
||
}
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 怪物
|
||
|
||
/// <summary>
|
||
/// 创建怪物
|
||
/// </summary>
|
||
[Server]
|
||
public GameObject CreateEnemy(int curId, Vector3 Pos, float angleY, int areaId, float scale, int lvl, EnemyState enemyState)
|
||
{
|
||
GameObject enemy = Instantiate(GetEnemyPre(curId));
|
||
NetworkServer.Spawn(enemy);
|
||
|
||
enemy.transform.position = Pos;
|
||
enemy.transform.eulerAngles = new Vector3(0, angleY, 0);
|
||
Enemy enemyScript = enemy.GetComponent<Enemy>();
|
||
enemyScript.OnSpawn(EnemyDic[curId], areaId, lvl, enemyState);
|
||
EnemyList.Add(enemyScript);
|
||
enemyIndex++;
|
||
return enemy;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建巨鱼人
|
||
/// </summary>
|
||
[Server]
|
||
public GameObject CreateFishGiant(Vector3 Pos, float angleY, float scale, int lvl, BossState state, Vector3 wakeUpPos)
|
||
{
|
||
GameObject boss = Instantiate(EnemyPres[(int)EnemyType.FishGiant]);
|
||
NetworkServer.Spawn(boss);
|
||
boss.transform.position = Pos;
|
||
boss.transform.eulerAngles = new Vector3(0, angleY, 0);
|
||
FishGiant fishGiant = boss.GetComponent<FishGiant>();
|
||
fishGiant.OnSpawn(9999, GameManager.Ins.curEnemyLevel, state, wakeUpPos);
|
||
EnemyList.Add(fishGiant);
|
||
this.fishGiant = fishGiant;
|
||
return boss;
|
||
}
|
||
|
||
[Server]
|
||
public GameObject CreateEnemyBoss(int curId, Vector3 Pos, float angleY, int areaId, float scale, int lvl, EnemyState enemyState)
|
||
{
|
||
GameObject boss = Instantiate(GetEnemyPre(curId));
|
||
NetworkServer.Spawn(boss);
|
||
boss.transform.position = Pos;
|
||
boss.transform.eulerAngles = new Vector3(0, angleY, 0);
|
||
EnemyBoss enemyBoss = boss.GetComponent<EnemyBoss>();
|
||
enemyBoss.OnSpawn(EnemyDic[curId], areaId, lvl, enemyState, Pos);
|
||
EnemyList.Add(enemyBoss);
|
||
enemyIndex++;
|
||
return boss;
|
||
}
|
||
|
||
public GameObject GetEnemyPre(int curId)
|
||
{
|
||
foreach (var item in EnemyPres)
|
||
{
|
||
if (item.GetComponent<Enemy>().id == curId)
|
||
return item;
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取区域可攻击怪物
|
||
/// </summary>
|
||
[Server]
|
||
public List<Enemy> GetEnemysByAreaId(int areaId)
|
||
{
|
||
List<Enemy> list = new List<Enemy>();
|
||
foreach (Enemy enemy in EnemyList)
|
||
{
|
||
if (enemy.areaId == areaId && enemy.state != EnemyState.Ghost)
|
||
{
|
||
list.Add(enemy);
|
||
}
|
||
}
|
||
return list;
|
||
}
|
||
|
||
public void SetOutLine(int wit)
|
||
{
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检测区域是否清空怪物
|
||
/// </summary>
|
||
public void CheckAreaSettle(int areaId)
|
||
{
|
||
if (GetEnemysByAreaId(areaId).Count <= 0)
|
||
{
|
||
Debug.Log($"结算{areaId}区域奖励");
|
||
//打开区域内所有笼子
|
||
CageList.TryGetValue(areaId, out List<Cage> cages);
|
||
if (cages != null)
|
||
{
|
||
foreach (Cage cage in cages)
|
||
{
|
||
cage.OpenCage();
|
||
}
|
||
}
|
||
AreaList[areaId].isWin = true;
|
||
EnergyValue += 1F / AreaList.Count;
|
||
if (EnergyValue >= 1) EnergyValue = 1;
|
||
for (int i = 0; i < MRNetworkManager.Ins.roomSlots.Count; i++)
|
||
{
|
||
MRNetworkManager.Ins.roomSlots[i].GetComponent<Player>().ExitArea();
|
||
}
|
||
foreach (var item in PetList.Values)
|
||
{
|
||
if (item.state == PetState.Trained)
|
||
{
|
||
item.AddExp();
|
||
}
|
||
}
|
||
NetworkServer.Destroy(AreaList[areaId].gameObject);
|
||
AreaList.Remove(areaId);
|
||
// foreach (var pet in PetList.Values)
|
||
// {
|
||
// pet.Change2State(PetState.CurWin);
|
||
// }
|
||
//每次结算奖励时判断是否进入下一段剧情
|
||
// if (AreaList.Count == 0)
|
||
// {
|
||
// Debug.Log("进入下一段剧情");
|
||
// if (fishGiant != null) fishGiant.WakeUp();
|
||
// ChangeGameBGM(Bgm.Fight);
|
||
// }
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
#region 玩家
|
||
/// <summary>
|
||
/// 命令宠物攻击
|
||
/// </summary>
|
||
[Server]
|
||
public void OrderPetAttack(int petId, int enemyId)
|
||
{
|
||
//Debug.Log(string.Format("命令宠物{0}攻击怪物{1}", petId, enemyId));
|
||
PetList.TryGetValue(petId, out Pet pet);
|
||
|
||
|
||
// 找到最近的敌人
|
||
GameObject nearestEnemy = null;
|
||
float minDistance = float.MaxValue;
|
||
Vector3 petPos = pet.transform.position;
|
||
foreach (var enemy in EnemyList)
|
||
{
|
||
if (enemy == null)
|
||
continue;
|
||
// 计算宠物和敌人之间的距离,要求敌人 GameObject 必须有有效 transform
|
||
float distance = Vector3.Distance(petPos, enemy.transform.position);
|
||
if (distance < minDistance)
|
||
{
|
||
minDistance = distance;
|
||
nearestEnemy = enemy.gameObject;
|
||
}
|
||
}
|
||
|
||
if (nearestEnemy != null)
|
||
{
|
||
// 假设每个敌人 GameObject 上都有 Enemy 组件,其中有 enemyId 属性
|
||
Enemy enemyComponent = nearestEnemy.GetComponent<Enemy>();
|
||
if (enemyComponent != null)
|
||
{
|
||
// 通知宠物攻击敌人
|
||
pet.AttackOrder(enemyComponent);
|
||
//Debug.Log($"宠物 {petId} 正在攻击离它最近的敌人 {enemyComponent.id},距离:{minDistance}");
|
||
}
|
||
else
|
||
{
|
||
//Debug.LogWarning("最近的敌人没有 Enemy 组件,无法获取 enemyId!");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Debug.LogWarning("无法找到最近的敌人!");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 命令宠物撤退
|
||
/// </summary>
|
||
public void OrderPetRetreat(int petId)
|
||
{
|
||
// Debug.Log(string.Format("命令宠物{0}撤退", petId));
|
||
PetList.TryGetValue(petId, out Pet pet);
|
||
if (pet != null)
|
||
{
|
||
pet.RetreatOrder();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 督战宠物
|
||
/// </summary>
|
||
public void OverseerPetInArea(int teamId)
|
||
{
|
||
// if(isGuide)
|
||
// return;
|
||
// Debug.Log("区域内督战");
|
||
Teams.TryGetValue(teamId, out TeamInfo teamInfo);
|
||
Player player = MRNetworkManager.Ins.roomSlots[teamId].GetComponent<Player>();
|
||
if (teamInfo != null)
|
||
{
|
||
HashSet<int> membersId = teamInfo.membersId;
|
||
HashSet<int> setoutMembersId = teamInfo.setoutMembersId;
|
||
|
||
if (membersId.Count > 0)
|
||
{
|
||
List<Enemy> enemys = GetEnemysByAreaId(player.InAreaId);
|
||
if (enemys.Count > 0)
|
||
{
|
||
int i = 0;
|
||
foreach (int petId in membersId)
|
||
{
|
||
Enemy enemy = enemys[i % enemys.Count];
|
||
PetList.TryGetValue(petId, out Pet pet);
|
||
if (pet.state != PetState.Terminal)
|
||
{
|
||
// 给宠物分配攻击对象
|
||
OrderPetAttack(petId, enemy.id);
|
||
i++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (setoutMembersId.Count > 0)
|
||
{
|
||
List<Enemy> enemys2 = GetEnemysByAreaId(player.InAreaId);
|
||
if (enemys2.Count > 0)
|
||
{
|
||
int j = 0;
|
||
foreach (int petId in setoutMembersId)
|
||
{
|
||
Enemy enemy = enemys2[j % enemys2.Count];
|
||
PetList.TryGetValue(petId, out Pet pet);
|
||
if (pet.state != PetState.Terminal)
|
||
{
|
||
// 给宠物分配攻击对象
|
||
OrderPetAttack(petId, enemy.id);
|
||
j++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 督战宠物攻击boss
|
||
/// </summary>
|
||
public void OverseerPet2Boss(int teamId)
|
||
{
|
||
|
||
Teams.TryGetValue(teamId, out TeamInfo teamInfo);
|
||
if (teamInfo != null)
|
||
{
|
||
HashSet<int> membersId = teamInfo.membersId;
|
||
HashSet<int> setoutMembersId = teamInfo.setoutMembersId;
|
||
|
||
if (membersId.Count > 0)
|
||
{
|
||
foreach (int petId in membersId)
|
||
{
|
||
PetList.TryGetValue(petId, out Pet pet);
|
||
if (pet.state != PetState.Terminal)
|
||
{
|
||
OrderPetAttack(petId, fishGiant.id);
|
||
}
|
||
}
|
||
}
|
||
if (setoutMembersId.Count > 0)
|
||
{
|
||
foreach (int petId in membersId)
|
||
{
|
||
PetList.TryGetValue(petId, out Pet pet);
|
||
if (pet.state != PetState.Terminal)
|
||
{
|
||
OrderPetAttack(petId, fishGiant.id);
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 组织撤退
|
||
/// </summary>
|
||
public void OriginRetreat(int playerId)
|
||
{
|
||
Teams.TryGetValue(playerId, out TeamInfo teamInfo);
|
||
if (teamInfo != null)
|
||
{
|
||
if (Teams[playerId].joinId.Count > 0)
|
||
{
|
||
int[] membersId = Teams[playerId].joinId.ToArray();
|
||
foreach (int petId in membersId)
|
||
{
|
||
OrderPetRetreat(petId);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 分配宠物给玩家
|
||
[Server]
|
||
public void AssignPetIndex()
|
||
{
|
||
// 使用局部变量存储roomSlots的Count属性,避免多次访问。
|
||
int slotCount = MRNetworkManager.Ins.roomSlots.Count;
|
||
|
||
// 获取并返回当前分配的索引。
|
||
// int index = MRNetworkManager.Ins.roomSlots[curretAssignIndex].index;
|
||
|
||
int tempVale = curretAssignIndex + 1;
|
||
|
||
// 更新当前分配索引,使用取模运算确保索引不会超出范围。
|
||
curretAssignIndex = tempVale % slotCount;
|
||
|
||
// 输出日志,便于调试。
|
||
Debug.Log($"Current Assign Index: {curretAssignIndex}");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 玩家选择卡片
|
||
/// </summary>
|
||
public void SelectCard()
|
||
{
|
||
if (selectCardId == -1 || isPlayPetWorld)
|
||
return;
|
||
LaboratoryManager.Ins.isGetPet = true;
|
||
var selectedCard = selectCardId;
|
||
MasterAudio.PlaySound3DFollowTransform(selectCardSound, GameInit.Ins.MRCamera.transform);
|
||
TransitionPanel.Ins.WhiteFadeOut(() =>
|
||
{
|
||
aiDr.ChangeState(1);
|
||
GetPet(selectedCard, GameInit.Ins.petPos.position, GameInit.Ins.petPos.rotation.eulerAngles);
|
||
});
|
||
GameInit.Ins.laboratory.CloseCards();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 技能
|
||
|
||
public void CreateSkill(int skillId, Vector3 pos, float time, Transform target)
|
||
{
|
||
//Debug.LogError("技能ID"+skillId);
|
||
if (GetSkill(skillId) == null)
|
||
return;
|
||
GameObject obj = Instantiate(GetSkill(skillId), pos, Quaternion.identity);
|
||
NetworkServer.Spawn(obj);
|
||
var skill = obj.GetComponent<Skill>();
|
||
skill.Init();
|
||
if (skill.isFinger && target != null)
|
||
{
|
||
obj.transform.position = target.position;
|
||
}
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
NetworkServer.Destroy(obj);
|
||
}, time);
|
||
}
|
||
|
||
public GameObject GetSkill(int skillId)
|
||
{
|
||
foreach (var obj in skillPres)
|
||
{
|
||
var skill = obj.GetComponent<Skill>();
|
||
if (skill.skillID == skillId)
|
||
return obj;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
public void CreateBullet(int bulletId, Vector3 pos, Transform tran, int campId, float atk, GameObject target)
|
||
{
|
||
GameObject obj = Instantiate(GetBullet(bulletId), pos, tran.rotation);
|
||
NetworkServer.Spawn(obj);
|
||
RemoteButtlet bullet = obj.GetComponent<RemoteButtlet>();
|
||
if (bullet != null)
|
||
{
|
||
bullet.Init(campId == 2, atk, target);
|
||
}
|
||
}
|
||
|
||
public GameObject GetBullet(int bulletId)
|
||
{
|
||
foreach (var obj in bulletPres)
|
||
{
|
||
var bullet = obj.GetComponent<RemoteButtlet>();
|
||
if (bullet != null && bullet.id == bulletId)
|
||
{
|
||
return obj;
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 道具
|
||
|
||
public void CreateItemBox(Vector3 pos)
|
||
{
|
||
GameObject obj = Instantiate(itemBoxPre, pos, Quaternion.identity);
|
||
NetworkServer.Spawn(obj);
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
NetworkServer.Destroy(obj);
|
||
}, 30);
|
||
var objData = obj.GetComponent<ItemBox>();
|
||
objData.Init();
|
||
}
|
||
|
||
public PropItem CreateItem(int itemId, Vector3 pos, bool isReduce)
|
||
{
|
||
GameObject obj = Instantiate(GetItem(itemId), pos, Quaternion.identity);
|
||
NetworkServer.Spawn(obj);
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
NetworkServer.Destroy(obj);
|
||
}, 30);
|
||
var itemData = obj.GetComponent<PropItem>();
|
||
itemData.Init((WeaponType)itemId);
|
||
itemData.Amplify();
|
||
if (isReduce)
|
||
itemData.Reduce();
|
||
return itemData;
|
||
}
|
||
|
||
public GameObject GetItem(int itemId)
|
||
{
|
||
foreach (var obj in itemPres)
|
||
{
|
||
var item = obj.GetComponent<PropItem>();
|
||
if (item != null && item.id == itemId)
|
||
{
|
||
return obj;
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
public void DelItem(int playerId)
|
||
{
|
||
var player = MRNetworkManager.Ins.roomSlots[playerId].GetComponent<Player>();
|
||
player.DelWeapon();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 计费
|
||
|
||
/// <summary>
|
||
/// 鉴权
|
||
/// </summary>
|
||
public void RequestAuth(Action<HTTPRequest, HTTPResponse> cb = null)
|
||
{
|
||
string url = "http://www.pineappletech.cn/startcount";
|
||
HTTPRequest request = new HTTPRequest(new Uri(url), HTTPMethods.Post, (req, response) =>
|
||
{
|
||
if (response != null)
|
||
{
|
||
Debug.Log("收到数据 ->" + response.DataAsText);
|
||
}
|
||
cb?.Invoke(req, response);
|
||
});
|
||
request.AddHeader("Authorization", Author);
|
||
authInfo.deviceSn = GetSn();
|
||
authInfo.startAt = ConvertTimestampToDateTime(GetTimestamp()) + "";
|
||
authInfo.shop = 0;
|
||
|
||
#if !UNITY_EDITOR && UNITY_ANDROID && PICO
|
||
authInfo.shop = (int)GameInit.Ins.place;
|
||
if (GameInit.Ins.place == Place.Liaoning_Anshan_Lishan_Dayuecheng)
|
||
authInfo.shop = 1;
|
||
if (GameInit.Ins.place == Place.Zhejiang_Jinhua_KeJiGuan)
|
||
authInfo.shop = 5;
|
||
if (GameInit.Ins.place == Place.Shandong_Jining_Shangchang_nei)
|
||
authInfo.shop = 9;
|
||
if (GameInit.Ins.place == Place.Shandong_Jinan_Huaiyin_ShengfutongShangmao_wai)
|
||
authInfo.shop = 15;
|
||
if (GameInit.Ins.place == Place.Nanjing_Qixia_Yaohuamen_Jindiguangchang_nei)
|
||
authInfo.shop = 17;
|
||
if (GameInit.Ins.place == Place.Anhui_Suzhou_Yueshan_Guchengshangyejie_2)
|
||
authInfo.shop = 18;
|
||
if (GameInit.Ins.place == Place.Wulanhaote_Wanda_Shangchang)
|
||
authInfo.shop = 21;
|
||
if (GameInit.Ins.place == Place.Hunan_Hengyang_Zhuhui_Dongzhoudao_nei)
|
||
authInfo.shop = 24;
|
||
if (GameInit.Ins.place == Place.Yunnan_Lincang_Linxiang_Hengji_Dixia)
|
||
authInfo.shop = 25;
|
||
if (GameInit.Ins.place == Place.Gansu_Jinchang_Jinchuan_Shijiguangchang_Shiwai )
|
||
authInfo.shop = 28;
|
||
if (GameInit.Ins.place == Place.Guangdong_Guangzhou_Yanghaiyan_Lihu )
|
||
authInfo.shop = 31;
|
||
if (GameInit.Ins.place == Place.Zhejiang_Hangzhou_Linping_Yintaicheng_Shinei)
|
||
authInfo.shop = 32;
|
||
if (GameInit.Ins.place == Place.Henan_Xinxiang_Wandaguangchang_Shinei)
|
||
authInfo.shop = 33;
|
||
if (GameInit.Ins.place == Place.Jiangsu_Xvzhou_Guolou_Oulebao_2)
|
||
authInfo.shop = 36;
|
||
if (GameInit.Ins.place == Place.Jiangsu_Xvzhou_Suning_Guangchang_1)
|
||
authInfo.shop = 37;
|
||
if (GameInit.Ins.place == Place.Chongqing_Yuzhong_Hongyadong_Xiakexing_shiwan)
|
||
authInfo.shop = 42;
|
||
if (GameInit.Ins.place == Place.Hebei_Hengshui_Taocheng_WandaGuangchang)
|
||
authInfo.shop = 44;
|
||
if (GameInit.Ins.place == Place.GongSi1LouShiwai)
|
||
authInfo.shop = 999;
|
||
#endif
|
||
authInfo.gameId = (int)GameInit.Ins.gameId;
|
||
string authJson = JsonUtility.ToJson(authInfo);
|
||
Debug.Log("发送数据 -> " + authJson);
|
||
request.RawData = System.Text.Encoding.UTF8.GetBytes(authJson);
|
||
request.AddHeader("Content-Type", "application/json");
|
||
request.Send();
|
||
}
|
||
|
||
[ClientRpc]
|
||
public void RpcRequestNotifyStart()
|
||
{
|
||
//RequestNotifyStart();
|
||
}
|
||
|
||
[ClientRpc]
|
||
public void RpcRequestNotifyEnd()
|
||
{
|
||
//RequestNotifyEnd();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通知服务器已开始游戏
|
||
/// </summary>
|
||
// public void RequestNotifyStart(Action<HTTPRequest, HTTPResponse> cb = null)
|
||
// {
|
||
// string url = HttpServerUrl + "/api/record";
|
||
// HTTPRequest request = new HTTPRequest(new Uri(url), HTTPMethods.Put, (req, response) =>
|
||
// {
|
||
// if (response != null)
|
||
// {
|
||
// Debug.Log("收到数据 ->" + response.DataAsText);
|
||
// cb?.Invoke(req, response);
|
||
// }
|
||
// });
|
||
// request.AddHeader("Authorization", Author);
|
||
// authInfo.paid = 1;
|
||
// string authJson = JsonUtility.ToJson(authInfo);
|
||
// Debug.Log("发送数据 -> " + authJson);
|
||
// request.RawData = System.Text.Encoding.UTF8.GetBytes(authJson);
|
||
// request.AddHeader("Content-Type", "application/json");
|
||
// request.Send();
|
||
// }
|
||
//
|
||
// /// <summary>
|
||
// /// 通知服务器游戏结束
|
||
// /// </summary>
|
||
// public void RequestNotifyEnd(Action<HTTPRequest, HTTPResponse> cb = null)
|
||
// {
|
||
// string url = HttpServerUrl + "/api/record";
|
||
// HTTPRequest request = new HTTPRequest(new Uri(url), HTTPMethods.Put, (req, response) =>
|
||
// {
|
||
// if (response != null)
|
||
// {
|
||
// Debug.Log("收到数据 ->" + response.DataAsText);
|
||
// cb?.Invoke(req, response);
|
||
// }
|
||
// });
|
||
// request.AddHeader("Authorization", Author);
|
||
// authInfo.endAt = ConvertTimestampToDateTime(GetTimestamp()) + "";
|
||
// authInfo.dur = (int)(((long)(DateTime.Now.Subtract(new DateTime(1970, 1, 1))).TotalSeconds) - (vistEnd - vistAllTime));
|
||
// string authJson = JsonUtility.ToJson(authInfo);
|
||
// Debug.Log("发送数据 -> " + authJson);
|
||
// request.RawData = System.Text.Encoding.UTF8.GetBytes(authJson);
|
||
// request.AddHeader("Content-Type", "application/json");
|
||
// request.Send();
|
||
// }
|
||
|
||
[Command(requiresAuthority = false)]
|
||
public void KillAllEnemy()
|
||
{
|
||
var enemies = new List<Enemy>(EnemyList);
|
||
foreach (var enemy in enemies)
|
||
{
|
||
if (enemy.id != 9999)
|
||
{
|
||
enemy.transform.GetComponent<IDamagable>().ApplyDamage(100000000000, true, null);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 能量球飞到世界树中
|
||
/// </summary>
|
||
public IEnumerator BallFlyToTree(NetworkRoomPlayer roomPlayer, int amount, float delay, Vector3 treePos)
|
||
{
|
||
PetJump();
|
||
List<GameObject> energyBalls = new List<GameObject>();
|
||
for (int j = 0; j < amount; j++)
|
||
{
|
||
GameObject energyBall = Instantiate(EnergyBallPre);
|
||
energyBalls.Add(energyBall);
|
||
NetworkServer.Spawn(energyBall);
|
||
energyBall.transform.position = roomPlayer.transform.position;
|
||
energyBall.GetComponent<Rigidbody>().useGravity = false;
|
||
energyBall.transform.DOMove(treePos, 5F).OnComplete(() =>
|
||
{
|
||
// Math.Clamp();
|
||
EnergyValue -= 1F / (MRNetworkManager.Ins.roomSlots.Count * amount);
|
||
EnergyValue = Math.Clamp(EnergyValue, 0F, 1F);
|
||
energyBalls.Remove(energyBall);
|
||
NetworkServer.Destroy(energyBall);
|
||
if (energyBalls.Count == 0)
|
||
{
|
||
//GameEnd();
|
||
}
|
||
});
|
||
yield return new WaitForSeconds(delay);
|
||
}
|
||
}
|
||
|
||
[ClientRpc]
|
||
public void ChangeGameBGM(Bgm bgm)
|
||
{
|
||
GameInit.Ins.MRBgm.StateChangeBgm((int)bgm);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新配置表
|
||
/// </summary>
|
||
public void UpdateConf()
|
||
{
|
||
string text = Resources.Load<TextAsset>("Data").text;
|
||
if (text != null)
|
||
{
|
||
ParseGameJson(text);
|
||
}
|
||
|
||
var str = "Data/" + GameInit.Ins.place + "Data";
|
||
string data = Resources.Load<TextAsset>(str).text;
|
||
if (data != null)
|
||
{
|
||
ParseGameDataJson(data);
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 解析游戏json
|
||
/// <summary>
|
||
/// 解析游戏使用的json
|
||
/// </summary>
|
||
public void ParseGameJson(string text)
|
||
{
|
||
// DB = new JsonLiteDB();
|
||
// DB.Load(text);
|
||
// // 关卡表
|
||
// TableReader infoReader = DB["EnemysInfo"].GetReader();
|
||
// while (infoReader.Read())
|
||
// {
|
||
// EnemyInfo info = new EnemyInfo(infoReader);
|
||
//
|
||
// EnemyInfos.TryGetValue((EnemyType)info.EnemyType, out Dictionary<int, EnemyInfo> infoList);
|
||
// if (infoList == null)
|
||
// {
|
||
// Dictionary<int, EnemyInfo> list = new Dictionary<int, EnemyInfo>();
|
||
// list.Add(info.Lvl, info);
|
||
// EnemyInfos.Add((EnemyType)info.EnemyType, list);
|
||
// }
|
||
// else
|
||
// {
|
||
// infoList.Add(info.Lvl, info);
|
||
// }
|
||
// }
|
||
//
|
||
// infoReader = DB["PetsInfo"].GetReader();
|
||
// while (infoReader.Read())
|
||
// {
|
||
// PetInfo info = new PetInfo(infoReader);
|
||
// PetInfos.TryGetValue((PetType)info.ID, out Dictionary<int, PetInfo> infoList);
|
||
// if (infoList == null)
|
||
// {
|
||
// Dictionary<int, PetInfo> list = new Dictionary<int, PetInfo>();
|
||
// list.Add(info.Lvl, info);
|
||
// PetInfos.Add((PetType)info.ID, list);
|
||
// }
|
||
// else
|
||
// {
|
||
// infoList.Add(info.Lvl, info);
|
||
//
|
||
// }
|
||
// }
|
||
//Debug.Log("游戏数值更新 -> complete" + EnemyInfos);
|
||
}
|
||
|
||
public void ParseGameDataJson(string text)
|
||
{
|
||
DB = new JsonLiteDB();
|
||
DB.Load(text);
|
||
TableReader enemyDataReader = DB["EnemyData"].GetReader();
|
||
EnemyDataList.Clear();
|
||
while (enemyDataReader.Read())
|
||
{
|
||
EnemyData data = new EnemyData(enemyDataReader);
|
||
EnemyDataList.Add(data);
|
||
}
|
||
|
||
TableReader skillDataReader = DB["SkillData"].GetReader();
|
||
SkillDataList.Clear();
|
||
while (skillDataReader.Read())
|
||
{
|
||
SkillData data = new SkillData(skillDataReader);
|
||
SkillDataList.Add(data.SkillId, data);
|
||
}
|
||
skillManager.Init();
|
||
TableReader levelDataReader = DB["LevelData"].GetReader();
|
||
while (levelDataReader.Read())
|
||
{
|
||
LevelData data = new LevelData(levelDataReader);
|
||
LevelEnemyList.Add(data.LevelMonsters);
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
public void ClosePet()
|
||
{
|
||
List<int> petIds = new List<int>();
|
||
foreach (var item in PetList)
|
||
{
|
||
if (item.Key == 1)
|
||
continue;
|
||
petIds.Add(item.Key);
|
||
NetworkServer.Destroy(item.Value.gameObject);
|
||
}
|
||
foreach (var item in petIds)
|
||
{
|
||
PetList.Remove(item);
|
||
}
|
||
|
||
foreach (var pet in PetList)
|
||
{
|
||
pet.Value.Change2State(PetState.Trained);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 游戏开始
|
||
/// </summary>
|
||
[Server]
|
||
public void GameStart(Action cb)
|
||
{
|
||
isPlayPetWorld = true;
|
||
GetEnemyList();
|
||
GetPetList();
|
||
MasterAudio.StopAllSoundsOfTransform(aiDr.transform);
|
||
|
||
foreach (var item in AreaList)
|
||
{
|
||
item.Value.isWin = false;
|
||
}
|
||
var str = "新手教程1";
|
||
switch (curMapId)
|
||
{
|
||
case 0:
|
||
str = "新手教程2";
|
||
break;
|
||
case 1:
|
||
str = "迷雾丛林提示音";
|
||
break;
|
||
case 2:
|
||
str = "熔岩火山提示音";
|
||
break;
|
||
case 3:
|
||
str = "NPC24";
|
||
break;
|
||
}
|
||
|
||
if (curMapId == 0)
|
||
{
|
||
hud[0].Instance.GetComponent<HUD>().ShoGuide(0);
|
||
}
|
||
StartCoroutine(PlayAudio(str, GameInit.Ins.self.transform, true, () =>
|
||
{
|
||
if (curMapId == 0)
|
||
{
|
||
isGuide = true;
|
||
hud[0].Instance.GetComponent<HUD>().ShoGuide(1);
|
||
StartCoroutine(PlayAudio("新手教程1", GameInit.Ins.self.transform, true, () =>
|
||
{
|
||
isGuide = false;
|
||
}));
|
||
}
|
||
|
||
}));
|
||
StartCoroutine(CreateGameObjs(() =>
|
||
{
|
||
cb?.Invoke();
|
||
ShowBattleArea();
|
||
}));
|
||
ChangeGameBGM((Bgm)curMapId + 4);
|
||
}
|
||
public void Update()
|
||
{
|
||
// 更新指引箭头位置
|
||
UpdateGuideArrowPosition();
|
||
if (!GameOver && GetCountDownSecond() <= 0)
|
||
{
|
||
GameEnd();
|
||
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
Debug.Log("正在退出游戏...");
|
||
Application.Quit();
|
||
}, 75f);
|
||
|
||
}
|
||
|
||
if (isPlayGame)
|
||
{
|
||
curGameTime += Time.deltaTime;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 游戏结束
|
||
/// </summary>
|
||
[Server]
|
||
public void GameEnd()
|
||
{
|
||
GameOver = true;
|
||
|
||
//统计双方的宠物总数
|
||
// int allPetNum = 0;
|
||
// StatisticsDate date = new StatisticsDate();
|
||
// List<int> ints = new List<int>();
|
||
// Debug.Log(Teams);
|
||
// for (int i = 0; i < Teams.Count; i++)
|
||
// {
|
||
// for (int j = 0; j < Teams[i].joinId.Count; j++)
|
||
// {
|
||
// int id = Teams[i].joinId.ElementAt(j);
|
||
// allPetNum++;
|
||
// ints.Add(PetList[id].id);
|
||
// }
|
||
// }
|
||
// date.GetPetCount = allPetNum;
|
||
// date.numberIds = ints.ToArray();
|
||
// string strJson = JsonUtility.ToJson(date);
|
||
// StatisticsManager.Ins.StatisticsDate = strJson;
|
||
//所有怪物消失
|
||
foreach (Enemy Enemy in EnemyList)
|
||
{
|
||
Enemy.TrueDie();
|
||
}
|
||
if (IsWin)
|
||
{
|
||
//所有小动物原地跳舞
|
||
//世界树恢复生长
|
||
//RpcShowWorkTree();
|
||
}
|
||
else
|
||
{
|
||
ChangeGameBGM(Bgm.Fail);
|
||
}
|
||
//所有玩家展示结算页面
|
||
RpcShowResult();
|
||
RpcRequestNotifyEnd();
|
||
|
||
}
|
||
|
||
public void OpenEndScenes()
|
||
{
|
||
|
||
}
|
||
|
||
public IEnumerator PlayAudio(string audioName, Transform tran, bool isAllStop, Action cb = null)
|
||
{
|
||
if (isAllStop)
|
||
MasterAudio.StopAllSoundsOfTransform(tran);
|
||
if (audioName != "")
|
||
{
|
||
MasterAudio.PlaySound3DAtTransform(audioName, tran);
|
||
MasterAudioGroup audioGroup = MasterAudio.GrabGroup(audioName);
|
||
if (cb != null)
|
||
{
|
||
while (audioGroup.ActiveVoices > 0)
|
||
{
|
||
yield return new WaitForSeconds(1f);
|
||
}
|
||
cb?.Invoke();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通过一个区域
|
||
/// </summary>
|
||
[Server]
|
||
public void WinArea(Vector3 pos)
|
||
{
|
||
curUpLevelCount++;
|
||
// if (curUpLevelCount >= 3)
|
||
// {
|
||
// //GameEnd();
|
||
// return;
|
||
// }
|
||
MonoSingleton<CoroutineTaskManager>.Instance.WaitSecondTodo(() =>
|
||
{
|
||
ChangeGameBGM(Bgm.Win);
|
||
CreateBadge(pos, true);
|
||
WinAreaPanel.Show(PetList.Count - 1);
|
||
TransitionPanel.Ins.WhiteFadeOut();
|
||
curMapId++;
|
||
}, 5f);
|
||
ClearTeam();
|
||
//后续改为多个区域中随机一个
|
||
foreach (var pet in PetList)
|
||
{
|
||
pet.Value.Upgrad();
|
||
pet.Value.Change2State(PetState.AreaWin);
|
||
}
|
||
foreach (Enemy Enemy in EnemyList)
|
||
{
|
||
Enemy.TrueDie();
|
||
}
|
||
EnemyList.Clear();
|
||
CageList.Clear();
|
||
enemyIndex = 0;
|
||
}
|
||
|
||
[ClientRpc]
|
||
public void RpcShowWorkTree()
|
||
{
|
||
for (int i = 0; i < GameInit.Ins.WorkTree.Length; i++)
|
||
{
|
||
GameInit.Ins.WorkTree[0].gameObject.SetActive(false);
|
||
GameInit.Ins.WorkTree[1].gameObject.SetActive(true);
|
||
}
|
||
}
|
||
[ClientRpc]
|
||
public void RpcShowResult()
|
||
{
|
||
OverlayUIManager.Ins.Cover("UI/ResultPanel", false);
|
||
}
|
||
|
||
public UIGroup hud;
|
||
[ClientRpc]
|
||
public void CreateHUD()
|
||
{
|
||
hud = HUD.Show();
|
||
//OverlayUIManager.Ins.Cover("UI/HUD", false);
|
||
}
|
||
|
||
public bool isShowBattleArea;
|
||
|
||
/// <summary>
|
||
/// 展示战斗区域
|
||
/// </summary>
|
||
public void ShowBattleArea()
|
||
{
|
||
isShowBattleArea = false;
|
||
foreach (var area in AreaList.Values)
|
||
{
|
||
area.gameObject.SetActive(false);
|
||
}
|
||
|
||
if (curBattleAreaIndex != -1)
|
||
{
|
||
var area = AreaList[curBattleAreaIndex];
|
||
GameInit.Ins.self.InAreaId = area.AreaId;
|
||
area.gameObject.SetActive(true);
|
||
if (curMapId == 0 && curEnemyLevel == 1)
|
||
{
|
||
//触发区域怪物
|
||
GameInit.Ins.self.ClosePathGuide();
|
||
StartCoroutine(CreateBattleAreaEnemy());
|
||
area.gameObject.SetActive(false);
|
||
}
|
||
else
|
||
{
|
||
MonoSingleton<CoroutineTaskManager>.Instance.WaitSecondTodo(() =>
|
||
{
|
||
if (isShowBattleArea || area == null)
|
||
return;
|
||
isShowBattleArea = true;
|
||
//触发区域怪物
|
||
GameInit.Ins.self.ClosePathGuide();
|
||
StartCoroutine(CreateBattleAreaEnemy());
|
||
area.gameObject.SetActive(false);
|
||
}, 10f);
|
||
}
|
||
|
||
}
|
||
else
|
||
{
|
||
foreach (var item in AreaList.Values)
|
||
{
|
||
if (item.isWin)
|
||
continue;
|
||
//item.gameObject.SetActive(true);
|
||
curBattleAreaIndex = item.AreaId;
|
||
var area = AreaList[curBattleAreaIndex];
|
||
GameInit.Ins.self.InAreaId = area.AreaId;
|
||
area.gameObject.SetActive(true);
|
||
if (curMapId == 0 && curEnemyLevel == 1)
|
||
{
|
||
//触发区域怪物
|
||
GameInit.Ins.self.ClosePathGuide();
|
||
StartCoroutine(CreateBattleAreaEnemy());
|
||
area.gameObject.SetActive(false);
|
||
}
|
||
else
|
||
{
|
||
MonoSingleton<CoroutineTaskManager>.Instance.WaitSecondTodo(() =>
|
||
{
|
||
if (isShowBattleArea)
|
||
return;
|
||
isShowBattleArea = true;
|
||
//触发区域怪物
|
||
GameInit.Ins.self.ClosePathGuide();
|
||
StartCoroutine(CreateBattleAreaEnemy());
|
||
area.gameObject.SetActive(false);
|
||
}, 10f);
|
||
}
|
||
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取当前关卡的宠物列表
|
||
/// </summary>
|
||
public void GetPetList()
|
||
{
|
||
PetDic.Clear();
|
||
int index = 0;
|
||
foreach (var data in EnemyDataList)
|
||
{
|
||
if (data.Camp == 1 && data.LevelId == curMapId)
|
||
{
|
||
PetDic.Add(data.EnemyId, data);
|
||
index++;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取当前关卡的怪物列表
|
||
/// </summary>
|
||
public void GetEnemyList()
|
||
{
|
||
EnemyDic.Clear();
|
||
int index = 0;
|
||
foreach (var data in EnemyDataList)
|
||
{
|
||
if (data.Camp == 2 && data.LevelId == curMapId)
|
||
{
|
||
EnemyDic.Add(data.EnemyId, data);
|
||
index++;
|
||
}
|
||
}
|
||
}
|
||
#region 区域
|
||
|
||
public List<Transform> GetRangeEnemy(Vector3 Pos, float radius, string tag)
|
||
{
|
||
Collider[] colliders;
|
||
colliders = new Collider[30];
|
||
int colliderCount = Physics.OverlapSphereNonAlloc(Pos, radius, colliders);
|
||
List<Transform> animals = new List<Transform>();
|
||
for (int i = 0; i < colliderCount; i++)
|
||
{
|
||
if (colliders[i].CompareTag(tag))
|
||
{
|
||
if (colliders[i].GetComponent<Agent>().IsAlive)
|
||
{
|
||
animals.Add(colliders[i].transform);
|
||
}
|
||
}
|
||
}
|
||
return animals;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取范围内宠物
|
||
/// </summary>
|
||
public List<int> GetRangePetId(Vector3 pos, float radius)
|
||
{
|
||
List<int> res = new List<int>();
|
||
foreach (Pet pet in PetList.Values)
|
||
{
|
||
float dis = Vector3.Distance(pet.transform.position, pos);
|
||
if (dis <= radius)
|
||
{
|
||
res.Add(pet.id);
|
||
}
|
||
}
|
||
return res;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取范围内敌人
|
||
/// </summary>
|
||
public List<int> GetRangeEnemyId(Vector3 pos, float radius)
|
||
{
|
||
List<int> res = new List<int>();
|
||
foreach (Enemy enemy in EnemyList)
|
||
{
|
||
float dis = Vector3.Distance(enemy.transform.position, pos);
|
||
if (dis <= radius)
|
||
{
|
||
res.Add(enemy.id);
|
||
}
|
||
}
|
||
return res;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检测一个点是否在区域内
|
||
/// </summary>
|
||
public bool CheckPointInArea(int areaId, Vector3 point)
|
||
{
|
||
AreaList.TryGetValue(areaId, out BattleArea area);
|
||
if (area == null) return false;
|
||
Bounds bounds = area.boxCollider.bounds;
|
||
point.y = 0;
|
||
if (!bounds.Contains(point)) return false;
|
||
return true;
|
||
}
|
||
#endregion
|
||
|
||
#region 工具
|
||
/// <summary>
|
||
/// 获取sn号
|
||
/// </summary>
|
||
public string GetSn()
|
||
{
|
||
string res = "UnityEditor";
|
||
// string res = "PA8E10MGH7210380D";
|
||
#if !UNITY_EDITOR && UNITY_ANDROID && PICO
|
||
res = PXR_Enterprise.StateGetDeviceInfo(SystemInfoEnum.EQUIPMENT_SN);
|
||
#endif
|
||
return res;
|
||
}
|
||
|
||
public long GetTimestamp()
|
||
{
|
||
return (long)DateTime.Now.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
|
||
}
|
||
|
||
public static string ConvertTimestampToDateTime(long timestamp)
|
||
{
|
||
// Unix时间戳是从1970年1月1日00:00:00开始的秒数或毫秒数
|
||
// 这里以秒为单位,如果时间戳是毫秒则除以1000
|
||
DateTime dateTime = DateTimeOffset.FromUnixTimeSeconds(timestamp).DateTime;
|
||
return dateTime.ToString("yyyy-MM-dd HH:mm:ss");
|
||
}
|
||
public void LogPosition(Vector3 pos)
|
||
{
|
||
Debug.Log("x:" + pos.x + " y:" + pos.y + " z:" + pos.z);
|
||
}
|
||
public string GetLessTimeStr()
|
||
{
|
||
string res = "";
|
||
if (!GameOver)
|
||
{
|
||
res = FormatTime((int)(vistEnd - DateTime.Now.Subtract(new DateTime(1970, 1, 1)).TotalSeconds));
|
||
}
|
||
return res;
|
||
}
|
||
public string GetLessTimeStr2()
|
||
{
|
||
string res = "";
|
||
if (!GameOver)
|
||
{
|
||
res = FormatTime2((int)(vistEnd - DateTime.Now.Subtract(new DateTime(1970, 1, 1)).TotalSeconds));
|
||
}
|
||
return res;
|
||
}
|
||
public string GetEndTime()
|
||
{
|
||
string res = "";
|
||
if (GameOver)
|
||
{
|
||
res = FormatTime2((int)(((long)(DateTime.Now.Subtract(new DateTime(1970, 1, 1))).TotalSeconds) - (vistEnd - vistAllTime)));
|
||
}
|
||
return res;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取当前剩余多少秒
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public int GetCountDownSecond()
|
||
{
|
||
return (int)(vistEnd - DateTime.Now.Subtract(new DateTime(1970, 1, 1)).TotalSeconds);
|
||
}
|
||
// 时分秒
|
||
public string FormatTime(int totalSeconds)
|
||
{
|
||
int hours = totalSeconds / 3600;
|
||
// string hh = hours < 10 ? "0" + hours : hours.ToString();
|
||
int minutes = (totalSeconds - hours * 3600) / 60;
|
||
string mm = minutes < 10f ? "0" + minutes : minutes.ToString();
|
||
int seconds = totalSeconds - hours * 3600 - minutes * 60;
|
||
string ss = seconds < 10 ? "0" + seconds : seconds.ToString();
|
||
return string.Format("{0}:{1}", mm, ss);
|
||
}
|
||
|
||
public string FormatTime2(int totalSeconds)
|
||
{
|
||
int hours = totalSeconds / 3600;
|
||
// string hh = hours < 10 ? "0" + hours : hours.ToString();
|
||
int minutes = (totalSeconds - hours * 3600) / 60;
|
||
string mm = minutes < 10f ? "0" + minutes : minutes.ToString();
|
||
int seconds = totalSeconds - hours * 3600 - minutes * 60;
|
||
string ss = seconds < 10 ? "0" + seconds : seconds.ToString();
|
||
return string.Format("{0}分{1}秒", mm, ss);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region NPC引导
|
||
|
||
|
||
public void Guide1()
|
||
{
|
||
ChangeGameBGM(Bgm.Fight);
|
||
//播放第一关引导语音:这是第一关,你们只需要击败这些小家伙和大家伙就够了。不用担心,他们都是数据模拟出来的,放心大胆的动手吧!
|
||
}
|
||
|
||
public void Guide2()
|
||
{
|
||
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 指引系统
|
||
|
||
/// <summary>
|
||
/// 初始化指引箭头
|
||
/// </summary>
|
||
|
||
private void InitializeGuideArrow()
|
||
{
|
||
// 检查预制体是否存在
|
||
if (GuideArrowPre == null)
|
||
{
|
||
Debug.LogError("GuideArrowPre 预制体未分配!");
|
||
return;
|
||
}
|
||
|
||
// 实例化指引箭头预制体
|
||
guideArrowInstance = Instantiate(GuideArrowPre);
|
||
guideArrowInstance.name = "GuideArrow";
|
||
|
||
// 获取指引箭头组件
|
||
guideArrowComponent = guideArrowInstance.GetComponent<DoorGuideArrowPath>();
|
||
if (guideArrowComponent == null)
|
||
{
|
||
Debug.LogError("GuideArrowPre 预制体上没有找到 GuideArrowPath 组件!");
|
||
Destroy(guideArrowInstance);
|
||
guideArrowInstance = null;
|
||
return;
|
||
}
|
||
|
||
// 设置指引箭头的层级和高度
|
||
guideArrowComponent.obstacleMask = LayerMask.GetMask("Default"); // 根据实际障碍物层级设置
|
||
guideArrowComponent.pathHeight = 0.5f; // 设置路径显示高度
|
||
|
||
// 初始隐藏指引
|
||
guideArrowComponent.ClosePath();
|
||
|
||
// 可选:设置父物体,保持场景整洁
|
||
guideArrowInstance.transform.SetParent(this.transform);
|
||
|
||
// 初始化玩家位置
|
||
if (GameInit.Ins.self != null)
|
||
{
|
||
lastPlayerPosition = GameInit.Ins.self.transform.position;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新指引箭头位置(实时跟随玩家移动)
|
||
/// </summary>
|
||
|
||
// 修改 UpdateGuideArrowPosition 方法
|
||
private void UpdateGuideArrowPosition()
|
||
{
|
||
if (!isGuideArrowActive || GameInit.Ins.doorPos == null || GameInit.Ins.self == null)
|
||
return;
|
||
|
||
// 获取玩家当前位置
|
||
Vector3 currentPlayerPosition = GameInit.Ins.self.transform.position;
|
||
|
||
// 检查冷却时间
|
||
if (Time.time - lastPathUpdateTime < updatePathCooldown)
|
||
return;
|
||
|
||
// 检查玩家是否移动了足够远的距离
|
||
float distanceMoved = Vector3.Distance(currentPlayerPosition, lastPlayerPosition);
|
||
|
||
if (distanceMoved > updatePathThreshold)
|
||
{
|
||
// 获取门的位置
|
||
Vector3 doorPosition = GameInit.Ins.doorPos.transform.position;
|
||
|
||
// 使用曲线检测和路径平滑
|
||
UpdatePathWithCurveDetection(currentPlayerPosition, doorPosition);
|
||
|
||
// 更新记录的位置和时间
|
||
lastPlayerPosition = currentPlayerPosition;
|
||
lastPathUpdateTime = Time.time;
|
||
}
|
||
}
|
||
|
||
// 新增:使用曲线检测和路径平滑的方法
|
||
private void UpdatePathWithCurveDetection(Vector3 start, Vector3 end)
|
||
{
|
||
if (guideArrowComponent == null)
|
||
return;
|
||
|
||
// 1. 检测是否为直接可见路径
|
||
if (IsDirectPathClear(start, end))
|
||
{
|
||
// 直接路径,使用简单的贝塞尔曲线
|
||
smoothedPath = GenerateBezierCurve(start, end, 0.2f);
|
||
guideArrowComponent.SetPath(smoothedPath); // 这里使用 List<Vector3> 参数
|
||
isPathSmoothed = true;
|
||
return;
|
||
}
|
||
|
||
// 2. 间接路径,使用优化的绕路算法
|
||
List<Vector3> newPath = CalculateObstacleAvoidancePath(start, end);
|
||
|
||
if (newPath != null && newPath.Count > 1)
|
||
{
|
||
// 应用路径平滑
|
||
smoothedPath = SmoothPath(newPath);
|
||
guideArrowComponent.SetPath(smoothedPath); // 这里使用 List<Vector3> 参数
|
||
isPathSmoothed = true;
|
||
lastPathPoints = smoothedPath.ToArray();
|
||
}
|
||
}
|
||
|
||
// 新增:检查直接路径是否畅通
|
||
private bool IsDirectPathClear(Vector3 start, Vector3 end)
|
||
{
|
||
Vector3 direction = (end - start).normalized;
|
||
float distance = Vector3.Distance(start, end);
|
||
|
||
// 使用射线检测,同时检查多个点
|
||
int checkPoints = Mathf.CeilToInt(distance / 0.5f);
|
||
for (int i = 0; i <= checkPoints; i++)
|
||
{
|
||
float t = (float)i / checkPoints;
|
||
Vector3 checkPoint = Vector3.Lerp(start, end, t);
|
||
|
||
// 检查周围小范围的碰撞
|
||
if (Physics.CheckSphere(checkPoint, 0.3f, guideArrowComponent.obstacleMask))
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
// 新增:生成贝塞尔曲线路径
|
||
private List<Vector3> GenerateBezierCurve(Vector3 start, Vector3 end, float curveHeight)
|
||
{
|
||
List<Vector3> curvePoints = new List<Vector3>();
|
||
int segments = 20; // 曲线分段数
|
||
|
||
// 计算控制点(在中间稍微抬起形成曲线)
|
||
Vector3 controlPoint = (start + end) * 0.5f + Vector3.up * curveHeight;
|
||
|
||
for (int i = 0; i <= segments; i++)
|
||
{
|
||
float t = (float)i / segments;
|
||
|
||
// 二次贝塞尔曲线公式
|
||
Vector3 point = (1 - t) * (1 - t) * start +
|
||
2 * (1 - t) * t * controlPoint +
|
||
t * t * end;
|
||
|
||
curvePoints.Add(point);
|
||
}
|
||
|
||
return curvePoints;
|
||
}
|
||
|
||
// 新增:优化后的绕障碍物路径计算
|
||
private List<Vector3> CalculateObstacleAvoidancePath(Vector3 start, Vector3 end)
|
||
{
|
||
List<Vector3> path = new List<Vector3>();
|
||
path.Add(start);
|
||
|
||
// 尝试寻找最佳绕行点
|
||
Vector3 bypassPoint = FindOptimalBypassPoint(start, end);
|
||
|
||
if (bypassPoint != start)
|
||
{
|
||
// 如果有绕行点,构建曲线路径
|
||
List<Vector3> curve1 = GenerateBezierCurve(start, bypassPoint, 0.3f);
|
||
List<Vector3> curve2 = GenerateBezierCurve(bypassPoint, end, 0.3f);
|
||
|
||
path.AddRange(curve1.Skip(1));
|
||
path.AddRange(curve2.Skip(1));
|
||
}
|
||
else
|
||
{
|
||
// 没有找到绕行点,使用简单的曲线
|
||
path = GenerateBezierCurve(start, end, 0.2f);
|
||
}
|
||
|
||
return path;
|
||
}
|
||
|
||
// 新增:寻找最优绕行点
|
||
private Vector3 FindOptimalBypassPoint(Vector3 from, Vector3 to)
|
||
{
|
||
Vector3 direction = (to - from).normalized;
|
||
float distance = Vector3.Distance(from, to);
|
||
|
||
// 定义多个探测方向
|
||
Vector3[] probeDirections = new Vector3[]
|
||
{
|
||
Vector3.Cross(direction, Vector3.up).normalized, // 右侧
|
||
-Vector3.Cross(direction, Vector3.up).normalized, // 左侧
|
||
(Vector3.Cross(direction, Vector3.up).normalized + Vector3.up * 0.3f).normalized, // 右上
|
||
(-Vector3.Cross(direction, Vector3.up).normalized + Vector3.up * 0.3f).normalized // 左上
|
||
};
|
||
|
||
float[] probeDistances = new float[] { 2f, 3f, 4f, 5f };
|
||
|
||
Vector3 bestBypassPoint = from;
|
||
float bestScore = float.MaxValue;
|
||
|
||
foreach (Vector3 probeDir in probeDirections)
|
||
{
|
||
foreach (float probeDist in probeDistances)
|
||
{
|
||
Vector3 probePoint = from + probeDir * probeDist;
|
||
|
||
// 检查探测点是否可行
|
||
if (!Physics.CheckSphere(probePoint, 0.5f, guideArrowComponent.obstacleMask))
|
||
{
|
||
// 计算路径分数(距离 + 转向角度)
|
||
float pathLength = Vector3.Distance(from, probePoint) +
|
||
Vector3.Distance(probePoint, to);
|
||
float angleCost = Vector3.Angle(probePoint - from, to - probePoint) * 0.1f;
|
||
float score = pathLength + angleCost;
|
||
|
||
if (score < bestScore)
|
||
{
|
||
bestScore = score;
|
||
bestBypassPoint = probePoint;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return bestBypassPoint;
|
||
}
|
||
|
||
// 新增:路径平滑算法
|
||
private List<Vector3> SmoothPath(List<Vector3> rawPath)
|
||
{
|
||
if (rawPath.Count < 3)
|
||
return rawPath;
|
||
|
||
List<Vector3> smoothed = new List<Vector3>();
|
||
smoothed.Add(rawPath[0]);
|
||
|
||
// 使用简单的平均平滑
|
||
for (int i = 1; i < rawPath.Count - 1; i++)
|
||
{
|
||
Vector3 smoothedPoint = (rawPath[i - 1] + rawPath[i] + rawPath[i + 1]) / 3f;
|
||
smoothed.Add(smoothedPoint);
|
||
}
|
||
|
||
smoothed.Add(rawPath[rawPath.Count - 1]);
|
||
|
||
return smoothed;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 显示指引箭头
|
||
/// </summary>
|
||
|
||
public void ShowGuideArrow()
|
||
{
|
||
if (guideArrowComponent != null && GameInit.Ins.doorPos != null && GameInit.Ins.self != null)
|
||
{
|
||
guideArrowComponent.ShowPath();
|
||
isGuideArrowActive = true;
|
||
|
||
// 初始化路径
|
||
Vector3 playerPosition = GameInit.Ins.self.transform.position;
|
||
Vector3 doorPosition = GameInit.Ins.doorPos.transform.position;
|
||
UpdatePathWithCurveDetection(playerPosition, doorPosition);
|
||
|
||
// 记录初始位置
|
||
lastPlayerPosition = playerPosition;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 隐藏指引箭头
|
||
/// </summary>
|
||
|
||
public void HideGuideArrow()
|
||
{
|
||
if (guideArrowComponent != null)
|
||
{
|
||
guideArrowComponent.ClosePath();
|
||
isGuideArrowActive = false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 开始指引(在创建门后调用)
|
||
/// </summary>
|
||
|
||
public void StartGuide()
|
||
{
|
||
if (GameInit.Ins.doorPos != null && GameInit.Ins.self != null)
|
||
{
|
||
ShowGuideArrow();
|
||
|
||
// 初始化路径
|
||
Vector3 playerPosition = GameInit.Ins.self.transform.position;
|
||
Vector3 doorPosition = GameInit.Ins.doorPos.transform.position;
|
||
|
||
// 使用新的路径计算方法
|
||
UpdatePathWithCurveDetection(playerPosition, doorPosition);
|
||
|
||
// 记录初始位置
|
||
lastPlayerPosition = playerPosition;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 停止指引(在游戏开始或删除门时调用)
|
||
/// </summary>
|
||
|
||
public void StopGuide()
|
||
{
|
||
HideGuideArrow();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清理指引箭头实例
|
||
/// </summary>
|
||
|
||
public void CleanupGuideArrow()
|
||
{
|
||
if (guideArrowInstance != null)
|
||
{
|
||
Destroy(guideArrowInstance);
|
||
guideArrowInstance = null;
|
||
guideArrowComponent = null;
|
||
isGuideArrowActive = false;
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
} |