using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using UnityEngine; using asap.core; using Cinemachine; using DataCenter; using EventPartnerGather; using EventPartnerGather.Mining; using game; using UniRx; using UnityEngine.Serialization; using Random = UnityEngine.Random; public class EnterTrophyEvent { } namespace UI.PartnerGather.Mining { /// /// 事件合作伙伴挖矿场景控制器 /// 负责管理整个挖矿场景的逻辑,包括角色移动、挖矿动画、相机跟随等 /// 建议挂载在:挖矿场景的根对象上 /// public class EventPartnerMiningSceneController : MonoBehaviour { private const bool EnableTraceLogs = false; private const int FlowLogSampleInterval = 5; #region 组件引用配置 [FormerlySerializedAs("character")] [Header("=== 核心组件引用 ===")] [Tooltip("角色控制器 - 建议挂载在角色GameObject上")] public EventPartnerMiningCharacterController character1; [Header("第二主角")] public EventPartnerMiningCharacterController character2; // 好友的 [Header("第二主角的偏移")] public Vector3 secondOffsetVector3 = Vector3.zero; [Header("奖杯摄像机")] public CinemachineVirtualCamera vcamArea; [Tooltip("挖矿点管理器 - 建议挂载在MiningPoints容器对象上")] public EventPartnerMiningPointManager miningPoints; [Tooltip("火车控制器 - 建议挂载在Train容器对象上")] public EventPartnerTrainController trainController; [Header("=== 资源配置 ===")] [Tooltip("矿石资源预制体数组 - 从Project窗口拖拽矿石Prefab到这里")] public GameObject[] miningFlyResourcePrefabs; // 每一组矿石 [Tooltip("矿石资源预制体数组")] public GameObject[] miningResourcePrefabs; [Tooltip("挖矿几次算一个周期")] public int gatherNumPerDuration = 3; [Header("=== 动画与移动配置 ===")] [Range(0.5f, 10f)] [Tooltip("角色移动速度")] public float characterMoveSpeed = 2f; [Tooltip("用户落点偏移")] [Range(-10f, 10f)] public List userPointDelta = new(); [Range(0.5f, 5f)] [Tooltip("挖矿动画持续时间")] public float miningDuration = 2f; [Range(0.01f, 1f)] [Tooltip("矿石生成间隔")] public float oreGenerateDelay = 0.5f; [Tooltip("矿石飞行周期")] public float oreFlightDuration = 1.0f; // [SerializeField] // [Tooltip("矿石距离")] private float _columnDistance = 1.12f; #endregion private IConfig _config; #region 运行时数据 private CinemachineVirtualCameraBase _vCamSwitch; // 用户摄像机,负责跟随用户 private CinemachineVirtualCamera _vCamCharacter; // public int activePriority = 20; // 低级 private int areaBasePriority = 5; private int zeroPriority = 0; private int chaBasePriority = 10; // 动态生成的矿石对象缓存 private readonly List _activeMiningResources = new(); // 数据管理与事件订阅 private EventPartnerGatherManager _manager; // private CompositeDisposable _disposables = new(); // UI面板引用 private EventPartnerDrawMiningPanel _drawMiningPanel; // 数据同步缓存(用于检测变化) private int _lastMiningProgress = -1; private int _lastPoints = -1; // private int _lastPartnerPoint = -1; // 当前step 剩余的点数 private int _lastLeftPoint = -1; private int _usedPoints = 0; // 当前已经挖去的矿石数 // 当前移动了的Column private int _moveColumn = 0; // 当前组需要挖掉的矿石 private readonly List _miningOres = new(); // 可能剩多出的哪一个 private Transform _lastOre; private int _miningPoint = 0; private int _flowLogCounter = 0; //- private bool _isStageRewardLogic = false; // private bool _isFinalRewardLogic = false; private readonly IUserService _userService = GContext.container.Resolve(); // 当前建造过程 private BuildPartner _buildPartner; // private EventPartnerMiningCharacterController mainCharacter; private EventPartnerMiningCharacterController otherCharacter; // private Vector3 _bornPos1; private Vector3 _bornPos2; private Vector3 _trainBornPos; #endregion private void Awake() { _config = GContext.container.Resolve(); // 获取数据管理器 _manager = GContext.container.Resolve(); // 自动查找子组件 InitializeComponents(); Trace("SceneControllerInitialized"); // 第二主角 // Log(Character2); GContext.OnEvent().Subscribe(OnAddScore).AddTo(_disposables); GContext.OnEvent().Subscribe(_ => OnPointsUpdate()).AddTo(_disposables); GContext.OnEvent().Subscribe(evt => OnMiningProgressUpdate(evt)).AddTo(_disposables); GContext.OnEvent().Subscribe(evt => OnTrainProgressUpdate(evt)).AddTo(_disposables); GContext.OnEvent().Subscribe(OnMiningOre).AddTo(_disposables);; GContext.OnEvent().Subscribe(OnStageLogicContinue).AddTo(_disposables); GContext.OnEvent().Subscribe(OnEnterTrophyRegion).AddTo(_disposables); GContext.OnEvent().Subscribe(OnMiningStart).AddTo(_disposables); } private void OnEnable() { // var outplaySound = GetComponent(); // if(outplaySound) // outplaySound.enabled = true; if (_vCamSwitch) { _vCamSwitch.Priority = zeroPriority; } if (_vCamCharacter) { _vCamCharacter.Priority = chaBasePriority; } if (vcamArea) { vcamArea.Priority = areaBasePriority; } } private void Start() { _columnDistance = miningPoints.cubeWidthZ; _buildPartner = _manager.CurrentBuildPartner; Physics.IgnoreCollision(character1.GetComponent(), character2.GetComponent(), true); } // #if UNITY_EDITOR private void Update() { // UpdateBonus() // UpdateCameraFollow(); // PollDataChanges(); if (_config != null && _config.Get("GM", "0") == "1") { OnGM(); } } bool isShow; private string _spinIdStr; private string _startTime; private string _deltaTime; // private bool isChecked = false; private void OnGM() { if (Input.GetKeyDown(KeyCode.K)) { isShow = !isShow; } // if(Input.GetTouch()) } private void OnGUI() { if (!isShow) { return; } float buttonWidth = 300; // Replace with your desired width float buttonHeight = 70; // Replace with your desired height var fontSize = 40; // Replace with your desired font size GUI.skin.textField.fontSize = fontSize; GUI.skin.button.fontSize = fontSize; GUI.skin.label.fontSize = fontSize; GUI.skin.toggle.fontSize = fontSize; // GUILayout.Label($"当前阶段: {_lastMiningProgress}"); GUILayout.Label("SpinId:"); _spinIdStr = GUILayout.TextField(_spinIdStr, GUILayout.Width(buttonWidth), GUILayout.Height(buttonHeight)); int.TryParse(_spinIdStr, out var spinId); _manager.GmSetSpinId(spinId); if(GUILayout.Button("关闭作弊",GUILayout.Width(buttonWidth), GUILayout.Height(buttonHeight))) { _manager.CloseGM(); _spinIdStr = ""; } if (GUILayout.Button("清理挖矿数字", GUILayout.Width(buttonWidth), GUILayout.Height(buttonHeight))) { // var ret = await _manager.BuildWorks(score * _multipleValue,cost); CleanMyScore(); } GUILayout.Label("作弊时间"); _startTime = GUILayout.TextField(_startTime, GUILayout.Width(buttonWidth), GUILayout.Height(buttonHeight)); int.TryParse(_startTime, out var timeSeconds); _deltaTime = GUILayout.TextField(_deltaTime, GUILayout.Width(buttonWidth), GUILayout.Height(buttonHeight)); _manager.GMRobotStartTIme(timeSeconds); int.TryParse(_deltaTime, out var deltaSeconds); _manager.GMRobotDelta(deltaSeconds); } public async void CleanMyScore() { await _manager.BuildWorks( _buildPartner.ScoreSelfActual * -1 ,0); } // #endif public void ShowDebugView() { if (_config.Get("GM", "0") == "1") { isShow = !isShow; } } /// /// 自动查找和初始化子组件 /// 如果Inspector中未手动分配组件,会尝试在子对象中查找 /// private void InitializeComponents() { Trace("InitSceneComponentsStart"); // 查找挖矿点管理器 if (!miningPoints) { miningPoints = GetComponentInChildren(); if (miningPoints) Trace($"ComponentAutoFound component=MiningPointManager name={miningPoints.name}"); else LogWarning("MissingComponent component=EventPartnerMiningPointManager"); } // 查找角色控制器 if (!character1) { character1 = GetComponentInChildren(); if (character1) Trace($"ComponentAutoFound component=MiningCharacterController name={character1.name}"); else LogWarning("MissingComponent component=EventPartnerMiningCharacterController"); } if (character1) { character1.GatherNumPerDuration = gatherNumPerDuration; _bornPos1 = character1.transform.position; } if (!character2) { character2 = transform.Find("playerNode/player2").GetComponent(); } if (character2) { character2.GatherNumPerDuration = gatherNumPerDuration; _bornPos2 = character2.transform.position; } // 查找火车控制器 if (!trainController) { trainController = GetComponentInChildren(); if (trainController) Trace($"ComponentAutoFound component=TrainController name={trainController.name}"); else LogWarning("MissingComponent component=EventPartnerTrainController"); _trainBornPos = trainController.transform.position; } _vCamSwitch = transform.Find("CameraRoot/CameraSwitch").GetComponent(); _vCamCharacter = transform.Find("CameraRoot/Camera").GetComponent(); // 验证矿石资源预制体 if (miningFlyResourcePrefabs == null || miningFlyResourcePrefabs.Length == 0) { LogWarning("MissingConfig key=MiningResourcePrefabs impact=OreGenerationUnavailable"); } else { Trace($"MiningResourcePrefabCount count={miningFlyResourcePrefabs.Length}"); } Trace("InitSceneComponentsComplete"); } #region 数据同步监听 (来自EventPartnerMiningController) // rock1 rock2 rock3 // private void MiningOreProgress(Transform ore, int progress) // { // // Log($"MiningOreProgress-> {ore} {progress}"); // foreach (var child in ore.Cast()) // { // var childName = child.gameObject.name; // child.gameObject.SetActive(childName.EndsWith(progress.ToString())); // } // } private void OnMiningOre(EventMiningOre evt) { // Log($"OnMiningOre -> {evt.Num} {_miningOres.Count}"); // var index = evt.Num + 1; var index = evt.Num; if (_miningOres is { Count: > 0 }) { foreach (var ore in _miningOres) { // MiningOreProgress(ore, index); MiningOreWithScore(ore, index); } } if (_lastOre) { MiningOreWithScore(_lastOre,index); } // var (leftScore,oreLast,progress) = _lastFinalOre; // if (leftScore > 0 && oreLast) // { // MiningOreWithScore(oreLast,progress); // } // // var (first, oreFirst) = _firstBrokenOre; // if (first > 0 && oreFirst) // { // MiningOreWithScore(oreFirst, index, first); // } } // private int private void MiningOreWithScore(Transform ore, int progress) { var oreController = ore.GetComponent(); oreController?.OnMining(progress); } //- public async void OnAddScore(EventPartnerGatherPartnerAddScore evt) { Trace($"PartnerScoreAdd partnerId={evt.partnerId} score={evt.score}"); // _lastPartnerPoint += evt.score; // // _manager.AddPoints(evt.score); // // character2.SetSpinPointText(_lastPartnerPoint); // SetupMainCharacter(true); // await StartMining(evt.score); } private async void OnMiningStart(EventPartnerGatherSceneStart evt) { Trace($"SceneStartEventReceived event={evt?.GetType().Name}"); await RunPartnerMining(); await CheckForStepCompletion(); // _manager.SyncFromPartnerInfo(_buildPartner.SlotId); Log("SceneEnterNormalFlow"); _drawMiningPanel.SetInteractable(true); } private void OnEnterTrophyRegion(EnterTrophyEvent evt) { Trace("EnterTrophyRegion"); if (vcamArea) vcamArea.Priority = activePriority; } private void OnStageLogicContinue(FishingChallengeContinueEvent evt) { Trace("StageLogicContinue"); _isStageRewardLogic = false; // _isFinalRewardLogic = false; } private void OnPointsUpdate() { Trace("PointsUpdate"); UpdateUIPanel(); } private void OnMiningProgressUpdate(EventPartnerGatherMiningProgressUpdate evt) { Trace($"MiningProgressUpdate progress={evt.Progress}"); // 触发自动挖矿动画(如果进度增加) // int delta = evt.Progress - _lastMiningProgress; // if (delta > 0) // { // _lastMiningProgress = evt.Progress; // for (int i = 0; i < delta; i++) // { // DoAutoMiningStep(); // } // } // UpdateUIPanel(); } private void OnTrainProgressUpdate(EventPartnerGatherTrainProgressUpdate evt) { // Log($"接收到火车进度更新事件: {evt.Progress}/{evt.MaxNodes}"); // _lastTrainProgress = evt.Progress; // UpdateUIPanel(); } public void OnEnter() { Trace("OnEnter"); // if (true) // 作弊 // { // _manager.GatherData.CurrentPoints = 2100; // _manager.GatherData.CurrentMiningProgress = 4; // _manager.GatherData.CompletedNodes.Clear(); // } ResetScene(); SyncAllData(); UpdateTrainData(); SyncSceneElement(); // 同步,后续优化 _drawMiningPanel.OnEnter(); } public void OnLeave() { Trace("OnLeave"); _vCamCharacter.Priority = chaBasePriority; vcamArea.Priority = areaBasePriority; ResetScene(); } private void SyncAllData() { Trace("SyncAllData"); if (_manager?.GatherData == null) return; _buildPartner = _manager.CurrentBuildPartner; // // if (true) // { // var slotId = _manager.CurrentBuildPartner.SlotId; // var completedNodes = _manager.GatherData.CompletedNodesList[slotId]; // completedNodes.Remove(4); // completedNodes.Remove(3); // _manager.SaveData(); // _buildPartner.ScoreSelfActual = 962; // _buildPartner.ScorePartnerDisplay = 1998; // } _lastPoints = _buildPartner.ScoreSelfActual; _usedPoints = _lastPoints + _buildPartner.ScorePartnerDisplay; _lastMiningProgress = _manager.CalcMiningProgressOld(_usedPoints); _lastLeftPoint = _manager.GetLeftPoint(_usedPoints,_lastMiningProgress); if (_manager.IsStepFinished(_buildPartner.SlotId,_lastMiningProgress) && _lastLeftPoint == 0) // 结束,进入下一阶段 { _lastMiningProgress = _manager.CalcMiningProgressNew(_usedPoints); _lastLeftPoint = _manager.GetLeftPoint(_usedPoints,_lastMiningProgress); } CheckCompleteNodes(_lastLeftPoint <= 0 && _lastMiningProgress == _manager.MaxSteps) ; } private void CheckCompleteNodes(bool hasLast) { int finalIdx;// = _lastMiningProgress; if (hasLast) finalIdx = _lastMiningProgress + 1; else finalIdx = _lastMiningProgress; for (var i = 0; i < finalIdx; ++i) { if (!_manager.IsStepFinished(_buildPartner.SlotId, i)) { _manager.CompleteStage(i); } } } private void SyncSceneElement() { Trace($"SyncSceneElement lastPoints={_lastPoints} lastMiningProgress={_lastMiningProgress}"); // 设置用户的位置 var nameSelf = _userService.DisplayName; var partnerName = _buildPartner.DisplayName; // var info = _userService.GetPlayInfo(_buildPartner.PartnerId); // Log($"info.name = {info.name} partnerName = {partnerName}"); character1.SetHeadImage(_userService.AvatarUrl); character1.SetPlayerName(nameSelf); character1.SetSpinPointText(_buildPartner.ScoreSelfActual); character2.SetPlayerName(partnerName); character2.SetSpinPointText(_buildPartner.ScorePartnerActual); character2.SetHeadImage(_buildPartner.AvatarUrl); SetupMainCharacter(); if (_usedPoints > 0) { var step = _lastMiningProgress; var waPoint = _usedPoints - _manager.GetCumulativeStepPoint(step - 1); _moveColumn = _manager.GetGoColumn(waPoint,step); Log($"CalcWaPoint waPoint={waPoint}"); if (step == _manager.MaxSteps && _moveColumn > 24) { _moveColumn = 24; } SetPlayerPos(step, _moveColumn); SetTrainPos(step, _moveColumn); // 破坏的数据 for(var i = 0;i < step;i++) { DestroyOres(i,-1); trainController.SetTrainCarCollectPoints(i); } DestroyOres(step,waPoint); trainController.SetTrainCarCollectPoints(step,waPoint); // } UpdateUIPanel(); } // 执行 好友挖矿流程 private async Task RunPartnerMining() { ELog($"RunPartnerMining moveColumn={_moveColumn}"); if (_buildPartner.ScorePartnerActual > _buildPartner.ScorePartnerDisplay) { SetupMainCharacter(true); await Awaiters.Seconds(1.0f); var curStep = _manager.CalcMiningProgressNew(_usedPoints); var slotId = _manager.CurrentBuildPartner.SlotId; var completedNodes = _manager.GatherData.CompletedNodesList[slotId]; ELog(completedNodes.Count); completedNodes.RemoveAll(x => x >= curStep); var score = (_buildPartner.ScorePartnerActual - _buildPartner.ScorePartnerDisplay); if (character2.IsMainCharacter) { ELog($"CharacterPositionSnapshot character1={character1.transform.position} character2={character2.transform.position}"); // Physics.IgnoreCollision(character1.GetComponent(), character2.GetComponent(), true); var character1Pos = character1.body.position; var character2Pos = character2.body.position; var tasks = new List(); async Task ExecuteCharacter1Movement() { await character1.MoveToPosition(character2Pos, characterMoveSpeed); character1.FinishMove(); } async Task ExecuteCharacter2Movement() { await character2.MoveToPosition(character1Pos, characterMoveSpeed); character2.FinishMove(); } tasks.Add(ExecuteCharacter1Movement()); tasks.Add(ExecuteCharacter2Movement()); await Task.WhenAll(tasks); await Awaiters.NextFrame; // character1.SetSpinPointText(_buildPartner.ScoreSelfActual); character2.SetSpinPointText(_buildPartner.ScorePartnerActual); } _drawMiningPanel.SetInteractable(false); await StartMining(score); _manager.SavePartnerInfo(slotId); } } private void SetTrainPos(int step, int col) { ELog($"SetTrainPos step={step} col={col}"); var train = trainController.transform; var targetPoint = miningPoints.GetPoint(step); var trainPoint = targetPoint.Find("train_point"); var targetPosition = new Vector3(trainPoint.position.x + col * _columnDistance, train.position.y, train.position.z); train.position = targetPosition; } public Vector3 GetPlayerBasePos(EventPartnerMiningCharacterController character, bool isSecondary = false) { var step = character.step; var col = character.col; var animType = character.GetAnimatorShowType(); return GetPlayerBasePos(step, col, animType,isSecondary); } public Vector3 GetPlayerBasePos (int step,int col,int animType, bool isSecondary = false) { // if (step == -1) { return isSecondary ?_bornPos2 :_bornPos1; } var targetPoint = miningPoints.GetPoint(step); var userPoint = targetPoint.Find("user_point"); var position = userPoint.position; var newDelta = userPointDelta?[animType] ?? 0; var userPosX = position.x + col * _columnDistance; userPosX += newDelta; var playerPos = new Vector3(userPosX, position.y, position.z); if (isSecondary) { playerPos += secondOffsetVector3; } ELog($"GetPlayerPos step={step} col={col} isSecondary={isSecondary} playerPos={playerPos}"); // return new Vector3(userPosX, position.y, position.z); return playerPos; } // 获取偏移 private float GetPositionDelta(int animType) { var newDelta = userPointDelta?[animType] ?? 0; return newDelta; } private void SetPlayerPos(int step, int col) { ELog($"SetPlayerPos step={step} col={col}"); var targetPoint = miningPoints.GetPoint(step); var userPoint = targetPoint.Find("user_point"); // var position = GetUserPoint(character1, userPoint.position); // Log($"position- >{position} : userPoint.position: {userPoint.position}"); // var userPosX = position.x + col * _columnDistance; SetPlayerStepAndCol(step, col); var position = this.GetPlayerBasePos(step, col,0); character1.transform.position = position; // character1.transform.position = new Vector3(userPosX, character1.transform.position.y, userPoint.position.z); // character1.LastTargetPosition = position; var playerPos1 = character1.transform.position; character2.transform.position = playerPos1 + secondOffsetVector3; } private void UpdateTrainData() { trainController.OreFlightDuration = oreFlightDuration; trainController?.UpdateData(_manager); } private void UpdateUIPanel() { if (!_drawMiningPanel || _manager?.GatherData == null) return; _drawMiningPanel.SetMiningProgress(_lastMiningProgress); _drawMiningPanel.SetMiningPoints(_usedPoints); } public void SetUIPanel(EventPartnerDrawMiningPanel panel) { _drawMiningPanel = panel; } #endregion // private Transform _transPoint; #region 手动采集流程 (原MiningSceneController功能) public async Task StartMining(int point ,string showType = "Basic") { ELog($"StartMining point={point}"); if (mainCharacter) { await MoveNext(point,showType); } ELog($"StartMiningFinished point={point}"); } // private async Task MoveNextProgress() private async Task MoveNext(int point,string showType) { ELog($"MoveNextStart point={point}"); if (point < 0) { return; } var leftPoint = _lastLeftPoint; var curStep = _lastMiningProgress; var stepPoints = _manager.GetStepPoints(curStep); FlowELog($"MoveNextState curStep={curStep} leftPoint={leftPoint} stepPoints={stepPoints}"); if (leftPoint > 0) { if (stepPoints == leftPoint) // 还没挖过矿,移动到当前 { _moveColumn = 0; SetPlayerStepAndCol(curStep,_moveColumn); await UpdatePlayerShowType(showType); await MoveToMiningPoint(curStep); if (point <= 0) { await FinishMiningStep(); return; } } else { FlowELog($"MoveNextBranch111 curStep={curStep} leftPoint={leftPoint} stepPoints={stepPoints}"); if (point <= 0) { await FinishMiningStep(); return; } var consumePoints = stepPoints - leftPoint; var column = _manager.GetGoColumn(consumePoints,curStep); // TODO:LF 逻辑再修改,先挖矿再移动还是直接移动,以及移动的 范围 FlowELog($"MoveNextBranch122 consumePoints={consumePoints} column={column} moveColumn={_moveColumn}"); SetPlayerStepAndCol(curStep,column); if (consumePoints > 0) { await MoveToPlayerMiningPos(showType); await UpdatePlayerShowType(showType); } if (_moveColumn != column) { // var disColumn = column - _moveColumn; // await MoveCol(disColumn); _moveColumn = column; // await UpdatePlayerShowType(showType); await MoveToCol(curStep,_moveColumn); } } int consumePoint; (point,leftPoint,consumePoint )= await ConsumePoint(point, leftPoint); FlowELog($"MoveNextBranch133 consumePoint={consumePoint} point={point}"); _lastLeftPoint = leftPoint; } else { var hasNextStep = OnNextMiningStep(); if (!hasNextStep) { ELog($"MoveNextFinished curStep={curStep}"); await FinishMiningStep(); return; } } await MoveNext(point,showType); } private async Task MoveToPlayerMiningPos(string newShowType) { var step = mainCharacter.step; var col = mainCharacter.col; var oldAnimType = mainCharacter.GetAnimatorShowType(); var newAnimType = GetAniIndexByShowType(newShowType); if (oldAnimType == newAnimType) { return; } var pos = GetPlayerBasePos(step,col,newAnimType); await mainCharacter.MoveToPosition(pos,characterMoveSpeed); mainCharacter.FinishMove(); } private void SetPlayerStepAndCol(int step,int col) { character1.step = step; character1.col = col; character2.step = step; character2.step = col; } // private async Task CompleteStepFinished(int step) // { // Log($"CompleteStepFinished -> {step}"); // if (step > -1) // { // if (_manager.CompleteStage(step)) // { // await Awaiters.Seconds(1.0f); // } // } // } private async Task FinishMiningStep() { Log($"FinishMiningStep miningProgress={_lastMiningProgress}"); mainCharacter.FinishMove(); await Awaiters.NextFrame; // var pos = GetPlayerBasePos(mainCharacter); await mainCharacter.WaitIdleSpecialFinish(); } private bool OnNextMiningStep() { Log($"NextMiningStep from={_lastMiningProgress} to={_lastMiningProgress + 1}"); _moveColumn = 0; if (_lastMiningProgress <= _manager.MaxSteps) { // GContext.Publish(new EventUISound("audio_ui_partnermining_target_finish")); _manager.CompleteStage(_lastMiningProgress); _lastMiningProgress += 1; _lastLeftPoint = _manager.GetStepPoints(_lastMiningProgress); if (_drawMiningPanel) { // _drawMiningPanel.SetMiningProgress(_lastMiningProgress); _drawMiningPanel.FinishStep(_lastMiningProgress); } return true; } return false; } // private async Task MoveCol(int column) // { // Log($"MoveCol->{column}"); // if (column > 0) // { // var step = _lastMiningProgress; // var targetPoint = miningPoints.GetPoint(step); // var userPoint = targetPoint.Find("user_point"); // // 传入变身后的 userPoint 点,根据自身的位置,再次移动 // var currentPoint = GetUserPoint(mainCharacter, userPoint.position); // await mainCharacter.MoveCol(column ,currentPoint,_columnDistance,characterMoveSpeed); // var train = trainController.transform; // // _ = character2.FollowCol(column,GetUserPoint(character2, userPoint.position,true),_columnDistance); // var characterPos = GetUserPoint(otherCharacter,mainCharacter.transform.position, true); // _ = otherCharacter.FollowToPosition(characterPos); // var targetPosition = new Vector3(train.position.x + column * _columnDistance, train.position.y, train.position.z); // trainController.StartMoveTo(targetPosition); // } // } private async Task MoveToCol(int step, int column) { var targetPoint = miningPoints.GetPoint(step); var trainPoint = targetPoint.Find("train_point"); var animType = mainCharacter.GetAnimatorShowType(); var userPosition = GetPlayerBasePos(step,column,animType); var otherUserPosition = GetPlayerBasePos(step, column,animType,true); await mainCharacter.MoveToPosition(userPosition, characterMoveSpeed); _ = otherCharacter.FollowToPosition(otherUserPosition,characterMoveSpeed); var trainPos = trainPoint.position.x + column * _columnDistance; trainController.StartMoveTo(new Vector3(trainPos,trainController.transform.position.y,trainController.transform.position.z)); // var targetPosition = new Vector3(train.position.x + column * _columnDistance, train.position.y, train.position.z); // trainController.StartMoveTo(targetPosition); // trainController.StartMoveTo(new Vector3(trainPoint.position.x,trainController.transform.position.y,trainController.transform.position.z)); } private async Task MoveToMiningPoint(int miningProgress) { ELog($"MoveToMiningPoint miningProgress={miningProgress}"); var targetPoint = miningPoints.GetPoint(miningProgress); var trainPoint = targetPoint.Find("train_point"); // var userPoint = targetPoint.Find("user_point"); // Log($"MoveToMiningPoint -> {miningProgress} {userPoint.position}"); // await mainCharacter.MoveToPosition(GetUserPoint(mainCharacter,userPoint.position), characterMoveSpeed); // _ = otherCharacter.FollowToPosition(GetUserPoint(otherCharacter, userPoint.position,true )); // trainController.StartMoveTo(new Vector3(trainPoint.position.x,trainController.transform.position.y,trainController.transform.position.z)); var animType = mainCharacter.GetAnimatorShowType(); // var deltaPos = GetPositionDelta(animType); var userPosition = GetPlayerBasePos(miningProgress,0,animType); // 修正 userPosition = new Vector3(userPosition.x, userPosition.y,userPosition.z); var otherUserPosition = GetPlayerBasePos(miningProgress, 0,animType,true); otherUserPosition = new Vector3(otherUserPosition.x, otherUserPosition.y, otherUserPosition.z); ELog($"MoveToMiningPointResolved userPosition={userPosition}"); await mainCharacter.MoveToPosition(userPosition, characterMoveSpeed); _ = otherCharacter.FollowToPosition(otherUserPosition,characterMoveSpeed); trainController.StartMoveTo(new Vector3(trainPoint.position.x,trainController.transform.position.y,trainController.transform.position.z)); } // private Vector3 GetUserPoint(EventPartnerMiningCharacterController characterController, Vector3 position,bool isSecondary = false) // { // var idx = characterController.GetAnimatorShowType(); // var delta = userPointDelta?[idx] ?? 0; // Log($"GetUserPoint -> {idx}"); // position.x += delta; // position.y = characterController.transform.position.y; // if (isSecondary) // { // position += secondOffsetVector3; // } // return position; // } // 消耗之后还剩余多少 private async Task<(int myPoints,int levelPoints,int counsumePoint)> ConsumePoint(int waPoints, int leftPoint) { if (waPoints <= 0) { return (0, leftPoint,0); } var consumePoints = _manager.GetConsumePoint(_lastMiningProgress); var realConsumePoint = Mathf.Min(consumePoints, waPoints,leftPoint); FlowELog($"ConsumePointPhase11 waPoints={waPoints} leftPoint={leftPoint} consumePoints={consumePoints} realConsumePoint={realConsumePoint}"); UpdateUsedPoints(realConsumePoint); GetMiningOres(realConsumePoint); var gatherNum = gatherNumPerDuration; if (_miningOres.Count <= 0) { gatherNum = GetGatherNum(realConsumePoint); } FlowELog($"GatherNumResolved gatherNum={gatherNum}"); await PlayMining(gatherNum); await GenerateAndCollectOres(realConsumePoint); leftPoint -= realConsumePoint; waPoints -= realConsumePoint; FlowELog($"ConsumePointPhase12 waPoints={waPoints} leftPoint={leftPoint}"); return (waPoints,leftPoint,realConsumePoint); } private void UpdateUsedPoints(int realConsumePoint) { _usedPoints += realConsumePoint; // 更新 挖了的数值 } private async Task PlayMining(int gatherNum = 3) { mainCharacter.GatherNumPerDuration = gatherNum; await mainCharacter.PlayMining(); } private int GetGatherNum(int point) { var num = gatherNumPerDuration; // if (_miningOres is { Count: > 0 }) // return num; var perPoint = _manager.EventPartnerMineMainData.MinePoint / num; if (point < _manager.EventPartnerMineMainData.MinePoint) { for (var i = 1; i <= num; ++i) { if (point <= perPoint * i) { return i; } } } return num; } private void GetMiningOres(int consumePoint) { var step = _lastMiningProgress; var collectedPointsTo = _manager.CollectPointAndCalcValid(step,_usedPoints); var num = _manager.CalcWaNum(collectedPointsTo,out var leftPoint); FlowELog($"CollectPointCalc step={step} collectTo={collectedPointsTo} num={num} lastPoints={_lastPoints} usedPoints={_usedPoints}"); var pointTrans = miningPoints.GetPoint(step); var oresRoot = pointTrans.Find("ores"); var allChildren = oresRoot.Cast().ToList(); num = Mathf.Min(num, allChildren.Count); _miningOres.Clear(); for (var i = 0; i < num; ++i) { var child = allChildren[i]; if (child.gameObject.activeSelf) { _miningOres.Add(child); // 记录生成的石头 } var saver = child.gameObject.GetComponent(); if (!saver) { saver = child.gameObject.AddComponent(); } if (saver) { saver.InQueue = true; saver.validTimes = gatherNumPerDuration; } } // 只有一个的时候,放入单独处理中 if(_miningOres.Count == 1 && leftPoint <= 0) { _miningOres.Clear(); leftPoint = _manager.EventPartnerMineMainData.MinePoint; num -= 1; } if (leftPoint > 0) { if (num < allChildren.Count) { var trans = allChildren[num]; var saver = trans.gameObject.GetComponent(); if (!saver) { saver = trans.gameObject.AddComponent(); saver.miningTimes = 0; } saver.InQueue = false; saver.maxTimes = gatherNumPerDuration; saver.validTimes = gatherNumPerDuration; _lastOre = trans; if (_miningOres.Count > 0) { saver.validTimes = GetGatherNum(leftPoint); } } } else { _lastOre = null; } // if (num == 0) // { // SetFirstOre(allChildren[num],leftPoint); // } // // if (num > 0) // { // SetLastOre(allChildren[num],leftPoint); // } // } } private async Task GenerateAndCollectOres(int realPoints) { ELog($"GenerateAndCollectOresStart realPoints={realPoints}"); var step = _lastMiningProgress; var collectedPointsTo = _manager.CollectPointAndCalcValid(step,_usedPoints); // 根据点数销毁对应数量的矿石 DestroyOres(); var oreCount = CalculateOreCount(realPoints); await CollectOreAnimation(step,oreCount); _drawMiningPanel.RunCollectOreAnimation(step, oreCount); await trainController.RunOreIncreaseAnimation(step,collectedPointsTo - realPoints,collectedPointsTo); ELog("GenerateAndCollectOresFinish"); } // [SerializeField] private float baseValue = 0.1f; [SerializeField] private float fluctuation = 0.01f; // 浮动范围 ±0.01 private async Task CollectOreAnimation(int step, int oreCount) { var tasks = new List(); var iCount = _miningOres.Count; if (_lastOre) { iCount += 1; } FlowELog($"CollectOreAnimation step={step} oreCount={oreCount} oreGroups={iCount}"); if (iCount <= 0) return; var listOrePos = _miningOres.Select(ore => ore.position).ToList(); if (_lastOre) { listOrePos.Add(_lastOre.position); } var num = oreCount / iCount; // 共20个,每组 10个 for (var i = 0; i < iCount ; i++) { tasks.Add(CollectOreGroups(i,num )); } await Task.WhenAll(tasks); return; // async Task CollectOreGroups(int index ,int num ) { // var posStart = Mathf.Max(0,index * (num - 1)); // Log($"CollectOreGroups-> {index} {num} {posStart}"); // var childTasks = new List(); for (var i = 0; i < num; ++i) { var random2 = Random.Range(baseValue - fluctuation, baseValue + fluctuation); await Awaiters.Seconds(oreGenerateDelay + random2); var ore = CreateFlyOre(index , listOrePos); if (ore) { childTasks.Add(trainController.CollectOre(step, ore)); } } // await Task.WhenAll(childTasks); await Task.WhenAny(childTasks); } } private int DestroyOres() { var num = 0; if (_miningOres is { Count: > 0 }) { foreach (var child in _miningOres) { // var oreController = child.gameObject.GetComponent(); // if (oreController) // { // // oreController.ResetValues(); // Destroy(oreController); // } child.gameObject.SetActive(false); } num += _miningOres.Count; } if (_lastOre) { // MiningOreProgress(_lastOre,1) num += 1; } return num; } // 隐藏矿石的数量 private int DestroyOres(int step ,int points) { if (points == -1) { points = _manager.GetStepPoints(step); } var num = _manager.CalcWaNum(points,out var leftPoint); ELog($"DestroyOres step={step} num={num}"); var pointTrans = miningPoints.GetPoint(step); var oresRoot = pointTrans.Find("ores"); var allChildren = oresRoot.Cast().ToList(); num = Mathf.Min(num, allChildren.Count); for (var i = 0; i < num; ++i) { var child = allChildren[i]; // var oreController = child.gameObject.GetComponent(); // if (oreController) // { // // oreController.ResetValues(); // // Destroy(oreController); // } child.gameObject.SetActive(false); } if (leftPoint > 0) { if (num < allChildren.Count) { var trans = allChildren[num]; var oreController = trans.gameObject.GetComponent(); if (!oreController) { oreController = trans.gameObject.AddComponent(); } // oreController.ResetValues(); oreController.UpdateMiningTimes(GetGatherNum(leftPoint)); // oreController.miningTimes = 0; // oreController.InQueue = false; // oreController.Score = leftPoint; // oreController.maxTimes = gatherNumPerDuration; // oreController.validTimes = gatherNumPerDuration; // // _lastOre = trans; // if (_miningOres.Count > 0) // { // saver.validTimes = GetGatherNum(leftPoint); // } // oreController.UpdateOre(); } } // else // { // _lastOre = null; // } // if (_lastOre) // { // var oreController = _lastOre.GetComponent(); // if (oreController) // { // oreController.UpdateOre(); // } // } return num; } private int CalculateOreCount(int points) { // return points switch // { // // return points; // // 根据点数计算矿石数量 // // if (points >= 50) return 5; // // if (points >= 30) return 3; // // if (points >= 20) return 2; // // return 1; // < 100 => 8, // < 200 => 16, // _ => 1 // }; //return _manager.CalcWaNum(points); return points; } private GameObject CreateFlyOre(int index, List list) { var idx = index % list.Count ; // Log($"CreateOre -> {index} {list.Count} {idx}"); return CreateFlyOre(list[idx]); } private GameObject CreateFlyOre(Vector3 position) { // Log($"CreateOre -> {position}"); if (miningFlyResourcePrefabs == null || miningFlyResourcePrefabs.Length == 0) return null; // 随机选择一个矿石预制体 var orePos = new Vector3(position.x, position.y + 1, position.z); // var idx = _manager.GatherData.CurrentMiningProgress; // var prefab = miningResourcePrefabs[Random.Range(0, miningResourcePrefabs.Length)]; var idx = _lastMiningProgress; var prefab = miningFlyResourcePrefabs[idx]; // var ore = Instantiate(prefab, orePos, Quaternion.identity,transform); var ore = Instantiate(prefab, orePos,prefab.transform.rotation,transform); // ore.transform.position = orePos; ore.SetActive(true); _activeMiningResources.Add(ore); return ore; } #endregion public void ResetScene() { // 重置 位置 character1.transform.position = _bornPos1; character1.step = -1; character1.col = -1; character2.transform.position = _bornPos2; character1.step = -1; character2.col = -1; // 重置 trainController.transform.position = _trainBornPos; // 重置奖杯 var trophyPoint = miningPoints.GetTrophyPoint(); var fxCelebrate = trophyPoint.Find("fx_partnermining_celebrate"); if (fxCelebrate) { fxCelebrate.gameObject.SetActive(false); } // 声音 var audioFinished = trophyPoint.Find("audio_finished"); if (audioFinished) { audioFinished.gameObject.SetActive(false); } // 清理场景中的矿石 foreach (var ore in _activeMiningResources) { if (ore) DestroyImmediate(ore); } _activeMiningResources.Clear(); // 重置挖矿点 miningPoints?.ResetPoints(); // 重置火车状态 trainController?.ResetTrain(); // vcamArea.Priority = areaBasePriority; _vCamCharacter.Priority = chaBasePriority; // _vCamSwitch.Priority = zeroPriority; _drawMiningPanel.Reset(); _miningOres.Clear(); } private void OnDisable() { if (!_vCamSwitch) return; // 方法1:将该相机移动到当前优先级子队列顶部,通常会成为Live或在混合后成为Live _vCamSwitch.MoveToTopOfPrioritySubqueue(); } private void OnDestroy() { _disposables?.Dispose(); _disposables = null; } public void SetupMainCharacter(bool isFriend = false) { mainCharacter = character1; otherCharacter = character2; if (isFriend) { mainCharacter = character2; otherCharacter= character1; } mainCharacter.IsMainCharacter = true; otherCharacter.IsMainCharacter = false; _vCamCharacter.Follow = mainCharacter.transform.Find("lookatPoint"); } public int GetAniIndexByShowType(string showType) { var typeList = new List { "Basic", "Advanced", "Master", }; var idx = typeList.IndexOf(showType); return idx; } public async Task UpdatePlayerShowType(string showType) { // var typeList = new List // { // "Basic", // "Advanced", // "Master", // }; // var idx = typeList.IndexOf(showType); var animType = GetAniIndexByShowType(showType); if (animType != mainCharacter.GetAnimatorShowType()) { await mainCharacter.UpdateShowType(animType); } } private bool _isShowingSettlement = false; public async Task CheckForStepCompletion() { Log($"CheckNodeCompletion miningProgress={_lastMiningProgress}"); if (_manager?.GatherData == null) return; var currentMiningProgress = _lastMiningProgress; var maxSteps = _manager.MaxSteps; Log($"NodeCompletionRange maxSteps={maxSteps} currentProgress={currentMiningProgress}"); _isStageRewardLogic = _manager.PlayGetStageReward(); if (_isStageRewardLogic) { await CheckStageRewardFinished(); } Log($"PlayStageReward miningProgress={_lastMiningProgress}"); if (_manager.IsStepFinished(_manager.CurrentBuildPartner.SlotId, maxSteps) && !_isShowingSettlement) { await ShowNodeCompletionSequence(); } } private async Task CheckStageRewardFinished() { if (!_isStageRewardLogic) return; while (true) { if (!_isStageRewardLogic) return; await Awaiters.Seconds(1f); } } // private async Task CheckFinalRewardFinished() // { // if (!_isFinalRewardLogic) return; // while (true) // { // if (!_isFinalRewardLogic) // return; // await Awaiters.Seconds(1f); // } // } private async Task ShowNodeCompletionSequence() { Log("ShowNodeCompletionSequence"); if (_isShowingSettlement) return; _isShowingSettlement = true; try { Log("NodeSettlementTransitionStart"); // // 1. 禁用交互 // SetInteractable(false); // EnableAutoScroll(false); _drawMiningPanel.SetInteractable(false); _drawMiningPanel.EnableAutoScroll(false); // // _drawMiningPanel.gameObject.SetActive(false); _drawMiningPanel.HideUI(); // // await WaitPlayerRunToWinPosition(); // // // 4. 显示奖杯(如果获得) await WaitForRunTrophyAni(); // 最终奖励 // await WaitForFinalReward(); _manager.FinishMining(); // FinishAllMining(); } finally { _isShowingSettlement = false; } } // private async Task WaitForFinalReward() // { // Log("WaitForFinalReward"); // // _isFinalRewardLogic = true; // _manager.PlayGetFinalReward(); // // return Task.CompletedTask; // await CheckFinalRewardFinished(); // } private async Task WaitForRunTrophyAni() { Log("WaitForRunTrophyAnimation"); GContext.Publish(new EventPartnerGatherPlayTrophy()); var trophyPoint = miningPoints.GetTrophyPoint(); // 特效 var fxCelebrate = trophyPoint.Find("fx_partnermining_celebrate"); if (fxCelebrate) { fxCelebrate.gameObject.SetActive(true); } var anim = trophyPoint.GetComponent(); if (anim) { anim.Play(); } var list = new List { character1.WaitForIdleFinished(), character2.WaitForIdleFinished(), }; await Task.WhenAll(list); character1.SetAnimationState("celebrate"); character2.SetAnimationState("celebrate"); await character2.WaitForCelebrateFinished(); } // private async Task WaitForCelebrateFinished() // { // await character.WaitForCelebrateFinished(); // } private async Task WaitPlayerRunToWinPosition() { Log("WaitPlayerRunToWinPosition"); // character.SetIdle(); // await character.StartIdleSpecial(); // var targetPoint = miningPoints.GetTrophyPoint(); var targetPoint = transform.Find("trophy_region"); var userPoint1 = targetPoint.Find("user_point1"); var userPoint2 = targetPoint.Find("user_point2"); // 注意是一个组合,等待全部完成 var tasks = new List() { ExecuteCharacter1Movement(), ExecuteCharacter2Movement() }; // tasks.Add(character.MoveToPosition(userPoint1.position, characterMoveSpeed)); // tasks.Add(character2.MoveToPosition(userPoint2.position, characterMoveSpeed)); await Task.WhenAll(tasks); await Awaiters.NextFrame; return; async Task ExecuteCharacter1Movement() { await character1.MoveToPosition(userPoint1.position, characterMoveSpeed); character1.FinishMove(); } async Task ExecuteCharacter2Movement() { await character2.MoveToPosition(userPoint2.position, characterMoveSpeed); character2.FinishMove(); } } private static void ELog(object message) { #if UNITY_EDITOR Debug.Log($" EventPartnerMiningSceneController {message} "); #endif } private void FlowELog(object message) { #if UNITY_EDITOR _flowLogCounter++; if (_flowLogCounter % FlowLogSampleInterval != 0) return; Log(message); #endif } private void Log(object t) { Debug.Log($" EventPartnerMiningSceneController {t} "); } private void LogWarning(object t) { Debug.LogWarning($" EventPartnerMiningSceneController {t} "); } [System.Diagnostics.Conditional("UNITY_EDITOR")] private void Trace(object t) { if (!EnableTraceLogs) return; ELog(t); } public void AddPlayerScore(int normalPoints, bool isFriend) { Log($"AddPlayerScore normalPoints={normalPoints}"); if (!isFriend) { _lastPoints += normalPoints; character1.SetSpinPointText(_lastPoints); } // else // { // _lastPartnerPoint += normalPoints; // character2.SetSpinPointText(_lastPartnerPoint); // } } public async Task MainPlayerMining(int normalPoints,string showType) { AddPlayerScore(normalPoints, false); // await Awaiters.Seconds(1.0f); // var score = _buildPartner.ScorePartnerActual - _buildPartner.ScorePartnerDisplay; if (character2.IsMainCharacter) { SetupMainCharacter(false); Log($"CharacterPositionSnapshot character1={character1.transform.position} character2={character2.transform.position}"); var character1Pos = character1.body.position; var character2Pos = character2.body.position; var tasks = new List(); async Task ExecuteCharacter1Movement() { await character1.MoveToPosition(character2Pos, characterMoveSpeed); character1.FinishMove(); // character1.LastTargetPosition = Vector3.zero; } async Task ExecuteCharacter2Movement() { await character2.MoveToPosition(character1Pos, characterMoveSpeed); character2.FinishMove(); // character2.LastTargetPosition = Vector3.zero; } tasks.Add(ExecuteCharacter1Movement()); tasks.Add(ExecuteCharacter2Movement()); await Task.WhenAll(tasks); await Awaiters.NextFrame; } // await UpdatePlayerPos(); // await UpdatePlayerShowType(showType); await StartMining(normalPoints,showType); } // 测试函数 public async void Test() { OnEnterTrophyRegion(null); await Awaiters.Seconds(2f); await WaitForRunTrophyAni(); // SetPlayerStepAndCol(1,1); // // Log($"start: mainCharacter.position - >{mainCharacter.transform.position}"); // await UpdatePlayerShowType("Advanced"); // // mainCharacter.SetAnimationState("moving"); // await Awaiters.Seconds(1f); // // mainCharacter.FinishMove(); // await FinishMiningStep(); // // // await UpdateShowType(2); // // UpdateShowType // // await mainCharacter.WaitIdleSpecialFinish(GetPlayerBasePos(mainCharacter)); // // // await Awaiters.Seconds(1f); // await UpdatePlayerShowType("Master"); // await Awaiters.Seconds(1f); // mainCharacter.SetAnimationState("moving"); // await Awaiters.Seconds(1f); // await FinishMiningStep(); // Log($"end: mainCharacter.position - >{mainCharacter.transform.position}"); // // // mainCharacter.FinishMove(); // // await mainCharacter.WaitIdleSpecialFinish(GetPlayerBasePos(mainCharacter)); // // // await Awaiters.Seconds(1f); // await UpdatePlayerShowType("Basic"); // mainCharacter.SetAnimationState("moving"); // await Awaiters.Seconds(1f); // await FinishMiningStep(); } } }