/* * @Author: 白哉 * @Description: 输入逻辑 * @Date: 2025年04月01日 星期二 11:04:30 * @Modify: */ using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; using RuntimeData; using TMPro; using Logic.Multilingual; using Logic.Action; using Logic.Skill; using NodeCanvas.Tasks.Actions; using TH1_Core.Events; using TH1_Core.Managers; using TH1_Logic.Core; using TH1_Logic.Net; using TH1_UI.Controller.Info; using TH1_UI.HintUI; using TH1_UI.View.Bottom; using UI; using UnityEngine.UI; namespace Logic { public class InputLogic { Main _main; MapData _mapData; public int highlightCurrentState = 0; //0无1unit2land private Vector3 mouseLastDownPosition; private Vector2Int lastSelectedTile = new Vector2Int(-1, -1); // 上次点击的land坐标 private Vector2Int lastSelectedUnit = new Vector2Int(-1, -1); // 上次点击的unit坐标 //避免打包的时候吧TooltipTrigger代码剥离删掉的临时变量 private TooltipTrigger onozukakomachi; bool inputLock = false; public bool WASDMapMover = false; public Vector3 WASDMapMoverVector = Vector3.zero; // Shenlan 连点检测:在自己的回合,同一个单位上 5 秒内点击 15 次,触发 ToggleShenlan private const int ShenlanComboNeed = 15; private const float ShenlanComboWindow = 5f; private uint _shenlanComboUnitId = 0; private readonly List _shenlanComboTimestamps = new List(); public InputLogic(Main main, MapData mapData) { _main = main; _mapData = mapData; onozukakomachi = null; } private bool ShouldIgnoreClick(GameObject clickedUI) { // 检查当前对象及其所有祖先对象 Transform currentTransform = clickedUI.transform; while (currentTransform != null) { if (currentTransform.name == "UICanvas" || currentTransform.name == "HintMap" ) { return true; } currentTransform = currentTransform.parent; } return false; } public void LockInput() { inputLock = true; } public void UnlockInput() { inputLock = false; } public void Update() { // 聊天输入框激活时,Enter发送/关闭,ESC/右键关闭,其余快捷键全部屏蔽 if (UIBottomNetChatAreaMono.IsInputFieldFocused) { if (Input.GetKeyDown(KeyCode.Return) || Input.GetKeyDown(KeyCode.KeypadEnter)) { UIBottomNetChatAreaMono.SendOrClose(); } else if (Input.GetKeyDown(KeyCode.Escape) || Input.GetMouseButtonDown(1)) { UIBottomNetChatAreaMono.HideInputArea(); } return; } //如果锁了input 但是DebugMode不会锁定input if (inputLock &&!DebugCenter.Instance.DebugMode) { //观战模式:非自己回合时允许查看地块/单位信息 //非自己回合时不需要判断PresentationManager.Busy,Presentation播放的是AI动作,不阻止玩家查看信息 //允许点击地块查看信息 if (UIBlockCameraDrag.DownUpEvent) { UIBlockCameraDrag.DownUpEvent = false; if (HeroHintPanel.IsPinned) { EventManager.Publish(new HideHeroHintPanelEvent { Force = true }); return; } Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition); Vector2Int cellPosition = Table.Instance.WorldToGrid(mousePosition); if (cellPosition.x >= Main.MapData.MapConfig.Width || cellPosition.x < 0 || cellPosition.y < 0 || cellPosition.y >= Main.MapData.MapConfig.Height) return; Main.MapData.GridMap.GetGridDataByPos(cellPosition.x, cellPosition.y, out var clickedTerrain); _main.MapInteractionLogic.OnTileClicked(Main.MapData, clickedTerrain); } //允许Esc/右键关闭已打开的信息面板 if (Input.GetKeyDown(KeyCode.Escape) || Input.GetMouseButtonDown(1)) { if (HeroHintPanel.IsPinned) { EventManager.Publish(new HideHeroHintPanelEvent { Force = true }); return; } if (UIManager.Instance?.UIInfoManager != null) { UIManager.Instance.UIInfoManager.TryCloseCurTaskByEsc(); } } return; } //如果PresentationManager正在播放,则只考虑相应UI Esc 和右键交互 if (PresentationManager.Busy) { if (Input.GetKeyDown(KeyCode.Escape) || Input.GetMouseButtonDown(1)) { if (PresentationManager.TryCloseCurrentByEsc()) { return; } } //Debug.Log($"BusyType is {PresentationManager.BusyType}"); return; } OnGridInfoAction(); if (UIBlockCameraDrag.DownUpEvent) // 检测鼠标点击 { UIBlockCameraDrag.DownUpEvent = false; if (HeroHintPanel.IsPinned) { EventManager.Publish(new HideHeroHintPanelEvent { Force = true }); return; } Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition); Vector2Int cellPosition = Table.Instance.WorldToGrid(mousePosition); if (cellPosition.x >= Main.MapData.MapConfig.Width || cellPosition.x < 0 || cellPosition.y < 0 || cellPosition.y >= Main.MapData.MapConfig.Height) return; // 获取点击的地块类型 Main.MapData.GridMap.GetGridDataByPos(cellPosition.x, cellPosition.y, out var clickedTerrain); // 连点 Shenlan 检测:在 OnTileClicked 改变选中状态前嗅探这次点击 TryShenlanCombo(clickedTerrain); // 根据点击的地形类型执行某些操作(例如,显示消息) _main.MapInteractionLogic.OnTileClicked(Main.MapData,clickedTerrain); } OnBottomBarNextButton(); if (Input.GetKeyDown(KeyCode.BackQuote)) { #if UNITY_EDITOR || USE_INPUT if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) { // Shift+~ 清零金币、文化值、科技点 var self = Main.MapData.PlayerMap.SelfPlayerData; self._playerCoin = 0; self.PlayerCultureInfo.PlayerCulture = 0; self._playerTechPoint = 0; EventManager.Publish(new UpdateUITopTopBar() { UpdateType = UpdateTopBarType.UpdateAllInstant }); } else { Main.MapData.PlayerMap.SelfPlayerData.AddCoin(1000); Main.MapData.PlayerMap.SelfPlayerData.AddCulturePoint(1000); } #endif } if (Input.GetKeyDown(KeyCode.F9)) { #if UNITY_EDITOR || USE_INPUT Main.PlayerLogic.GetAllSight(); #endif } if (Input.GetKeyDown(KeyCode.K)) { #if UNITY_EDITOR || USE_INPUT foreach (var player in Main.MapData.PlayerMap.PlayerDataList) { if (!Main.MapData.CheckIsAI(player.Id)) continue; player.Alive = false; } #endif } if (Input.GetKeyDown(KeyCode.F7)) { #if UNITY_EDITOR || USE_INPUT var selectUnit = TH1Renderer.MapRenderer.Instance?.SelectUnitData; if (selectUnit != null && selectUnit.IsAlive()) { if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) { //Shift+F7:调试用,强制让选中单位消失(绕开CheckCan归属校验、不返还金币) var map = Main.MapData; //播放Fog雾效(与ForceDisband视觉一致) if (map.GetGridDataByUnitId(selectUnit.Id, out var gridData)) gridData.Renderer(map)?.PlayVFXInSight(new TH1Renderer.GridVFXParams(TH1Renderer.GridVFXType.Fog)); //通知渲染器播放死亡 if (TH1Renderer.MapRenderer.Instance.ROUnitMap.TryGetValue(selectUnit.Id, out var unitRenderer)) unitRenderer.Die(); //单位彻底死亡 Main.UnitLogic.UnitUnnaturalDie(map, selectUnit); } else { selectUnit.Health = 1; selectUnit.Renderer(Main.MapData)?.InstantUpdateUnit(true); } } #endif } if (Input.GetKeyDown(KeyCode.F8)) { #if UNITY_EDITOR || USE_INPUT DebugCenter.Instance.DebugHideCenterMessage = !DebugCenter.Instance.DebugHideCenterMessage; #endif } OnTechTreeAction(); OnHeroAction(); /* if (Input.GetKeyDown(KeyCode.Q)) { if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) { foreach (WonderTypeEnum wonder in System.Enum.GetValues(typeof(WonderTypeEnum))) { _mapData.PlayerMap.SelfPlayerData.Wonder.SetWonderState(wonder,WonderState.FINISH_NOT_BUILD); } } }*/ OnTabAction(); //这里处理WASD移动 float horizontalInput = Input.GetAxisRaw("Horizontal"); // verticalInput 会在 -1 (S键) 到 +1 (W键) 之间变化 float verticalInput = Input.GetAxisRaw("Vertical"); // 2. 构建移动方向向量 // 我们用获取到的输入值来构建一个方向 Vector3 direction = new Vector3(horizontalInput, verticalInput, 0); // **重要优化**: 如果不进行归一化,斜向移动(同时按W和D)会比直线移动更快 // 因为 Vector3(1, 1, 0).magnitude ≈ 1.414. 归一化后长度始终为1。 // 我们只在有输入的时候进行移动,避免不必要的计算 if (direction.magnitude > 0.1f) // magnitude > 0.1f 是为了处理浮点数精度和摇杆的微小偏移 { // 归一化向量,使其长度为1 direction.Normalize(); // 3. 计算本帧的移动量 // 位移 = 方向 * 速度 * 时间 // 乘以 Time.deltaTime 可以保证移动速度在任何帧率的电脑上都保持一致 WASDMapMoverVector = direction * 30 * Time.deltaTime; WASDMapMover = true; // 4. 应用移动 // 使用 transform.Translate 在当前位置的基础上进行移动 } /* if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.A) ||Input.GetKey(KeyCode.D) ) { WASDMapMover = true; WASDMapMoverVector = Vector3.zero; if (Input.GetKey(KeyCode.W)) WASDMapMoverVector += new Vector3(0, 20 / (1f / _deltaTime), 0); if (Input.GetKey(KeyCode.S)) WASDMapMoverVector += new Vector3(0, -20 / (1f / _deltaTime), 0); if (Input.GetKey(KeyCode.A)) WASDMapMoverVector += new Vector3(-20 / (1f / _deltaTime), 0 , 0); if (Input.GetKey(KeyCode.D)) WASDMapMoverVector += new Vector3(20 / (1f / _deltaTime), 0 , 0); };*/ // Enter键 - 联机聊天快捷键 if ((Input.GetKeyDown(KeyCode.Return) || Input.GetKeyDown(KeyCode.KeypadEnter)) && Main.MapData?.Net != null && Main.MapData.Net.Mode == NetMode.Multi && UIBottomNetChatAreaMono.IsActive) { if (!UIBottomNetChatAreaMono.IsInputAreaVisible) { // 输入区未打开 → 打开并聚焦 UIBottomNetChatAreaMono.ShowInputArea(); } else { // 输入区已打开但未聚焦 → 聚焦 UIBottomNetChatAreaMono.FocusInputField(); } return; } if (Input.GetKeyDown(KeyCode.Escape) || Input.GetMouseButtonDown(1)) { // 优先关闭固定的HeroHintPanel if (HeroHintPanel.IsPinned) { EventManager.Publish(new HideHeroHintPanelEvent { Force = true }); return; } // 优先检查UIInfoManager是否有可关闭的界面 if (UIManager.Instance?.UIInfoManager != null) { if (UIManager.Instance.UIInfoManager.TryCloseCurTaskByEsc()) { return; // 成功关闭UI,不再执行其他Escape逻辑 } } } //HintWindowUIHandleHover(); } public void SimulateButtonClick(Button button) { var pointer = new PointerEventData(EventSystem.current); var go = button.gameObject; ExecuteEvents.Execute(go, pointer, ExecuteEvents.pointerDownHandler); ExecuteEvents.Execute(go, pointer, ExecuteEvents.pointerUpHandler); button.onClick.Invoke(); } private void OnTabAction() { var mapData = Main.MapData; if (mapData?.PlayerMap?.SelfPlayerData == null || mapData.CurPlayer == null) return; if (mapData.CurPlayer != mapData.PlayerMap.SelfPlayerData) return; if (Input.GetKeyDown(KeyCode.Tab) || Input.GetMouseButtonDown(2)) { UIManager.Instance?.UIBottomManager?.BottomBarController?.TryTabUnit(); } } private void OnGridInfoAction() { // 检查 Main.MapData 是否为 null if (Main.MapData == null) { Debug.LogError("OnGridInfoAction Error: Main.MapData is null"); return; } // 检查 PlayerMap 和 SelfPlayerData 是否为 null if (Main.MapData.PlayerMap?.SelfPlayerData == null) { Debug.LogError("OnGridInfoAction Error: Main.MapData.PlayerMap?.SelfPlayerData is null"); return; } if (Main.MapData.CurPlayer == null || Main.MapData.CurPlayer != Main.MapData.PlayerMap.SelfPlayerData) return; // 检查 UIManager.Instance 和 UIInfoManager 是否为 null if (UIManager.Instance?.UIInfoManager == null) { Debug.LogError("OnGridInfoAction Error: UIManager.Instance?.UIInfoManager is null"); return; } // 检测数字键1-9的按下,执行对应的操作 if (UIManager.Instance.UIInfoManager.GetCurTaskType() != typeof(UIInfoGridInfoController)) return; for (int i = 1; i <= 9; i++) { if (Input.GetKeyDown(KeyCode.Alpha1 + i - 1)) { EventManager.Publish(new ExecuteUIInfoGridInfo(){idx = (uint)(i - 1)}); //UIManager.Instance.BottomInfoUI.ExecuteActionButtonByIndex(i - 1); break; } } } private void OnBottomBarNextButton() { // 检测E的按下,执行对应的操作 if (Main.MapData?.PlayerMap?.SelfPlayerData == null || Main.MapData.CurPlayer == null) return; if (Main.MapData.CurPlayer != Main.MapData.PlayerMap.SelfPlayerData) return; if (Input.GetKeyDown(KeyCode.E)) { EventManager.Publish(new ExecuteUIBottomBottomBarNextButtonClick()); //SimulateButtonClick(UIManager.Instance.BottomBarUI.NextTurnButton); } } private void OnTechTreeAction() { if (Main.MapData?.PlayerMap?.SelfPlayerData == null || Main.MapData.CurPlayer == null) return; if (Main.MapData.CurPlayer != Main.MapData.PlayerMap.SelfPlayerData) return; if (Input.GetKeyDown(KeyCode.T)) { if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) { #if UNITY_EDITOR || USE_INPUT Main.MapData.PlayerMap.SelfPlayerData.AddCoin(1000); Main.MapData.PlayerMap.SelfPlayerData.AddCulturePoint(1000); Table.Instance.PlayerDataAssets.GetPlayerInfo(Main.MapData.PlayerMap.SelfPlayerData, out var info); if (info?.TechPool != null) { foreach (TechType techType in info.TechPool) Main.PlayerLogic.ResearchTech(Main.MapData, Main.MapData.PlayerMap.SelfPlayerData,techType,0); } #endif } else { if (UIManager.Instance?.UIInfoManager == null) return; if(UIManager.Instance.UIInfoManager.GetCurTaskType() == typeof(UIInfoTechTreeController)) EventManager.Publish(new HideUIInfoTechTree(){}); else EventManager.Publish(new ShowUIInfoTechTree(){}); /* if (UIManager.Instance.TechTreeUI.ROTechTreeUI.activeSelf) { UIManager.Instance.TechTreeUI.SetTechTreeShowHide(false); UIManager.Instance.BottomBarUI.SetBottomBarShowHide(true); } else { UIManager.Instance.TechTreeUI.SetTechTreeShowHide(true); UIManager.Instance.BottomBarUI.SetBottomBarShowHide(false); UIManager.Instance.BottomInfoUI.SetBottomInfoHide(); } */ } } } private void OnHeroAction() { if (Main.MapData?.PlayerMap?.SelfPlayerData == null || Main.MapData.CurPlayer == null) return; if (Main.MapData.CurPlayer != Main.MapData.PlayerMap.SelfPlayerData) return; if (Input.GetKeyDown(KeyCode.C)) { if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) { } else { if (UIManager.Instance?.UIInfoManager == null) return; if(UIManager.Instance.UIInfoManager.GetCurTaskType() == typeof(UIInfoHeroController)) EventManager.Publish(new HideUIInfoHero(){}); else EventManager.Publish(new ShowUIInfoHero(){}); } } } // Shenlan 连点检测:当前玩家回合内,同一个单位上 5 秒内点击 15 次 → 施加 Shenlan private void TryShenlanCombo(GridData clickedGrid) { if (clickedGrid == null) return; if (Main.MapData?.PlayerMap?.SelfPlayerData == null || Main.MapData.CurPlayer == null) return; // 必须是当前玩家的回合 if (Main.MapData.CurPlayer != Main.MapData.PlayerMap.SelfPlayerData) return; // 点击位置必须有当前玩家可见的单位 if (!clickedGrid.MainSelfPlayerVisibleUnit(out var unitData) || unitData == null) return; // 切换累计目标:如果点了另一个单位,重置计数 if (_shenlanComboUnitId != unitData.Id) { _shenlanComboUnitId = unitData.Id; _shenlanComboTimestamps.Clear(); } // 移除窗口外的时间戳 float now = Time.time; float threshold = now - ShenlanComboWindow; while (_shenlanComboTimestamps.Count > 0 && _shenlanComboTimestamps[0] < threshold) _shenlanComboTimestamps.RemoveAt(0); _shenlanComboTimestamps.Add(now); if (_shenlanComboTimestamps.Count < ShenlanComboNeed) return; // 达到阈值 → 触发 ToggleShenlan _shenlanComboTimestamps.Clear(); _shenlanComboUnitId = 0; // 必须属于自己(避免点击敌人单位连点意外触发) if (!Main.MapData.GetPlayerDataByUnitId(unitData.Id, out var ownerPlayer)) return; if (ownerPlayer != Main.MapData.PlayerMap.SelfPlayerData) return; var actionId = new CommonActionId { ActionType = CommonActionType.UnitAction, UnitActionType = UnitActionType.ToggleShenlan, }; var actionLogic = ActionLogicFactory.GetActionLogic(actionId); if (actionLogic == null) return; var param = new CommonActionParams( mapData: Main.MapData, playerData: Main.MapData.PlayerMap.SelfPlayerData, unitData: unitData, mainObjectType: MainObjectType.Unit ); param.OnParamChanged(); actionLogic.CompleteExecute(param); } } }