2026-05-25 21:59:14 +08:00

576 lines
24 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* @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 TH1_UI.View.Common;
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<float> _shenlanComboTimestamps = new List<float>();
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 (UIChatAreaMono.IsInputFieldFocused)
{
if (Input.GetKeyDown(KeyCode.Return) || Input.GetKeyDown(KeyCode.KeypadEnter))
{
UIChatAreaMono.SendOrClose();
}
else if (Input.GetKeyDown(KeyCode.Escape) || Input.GetMouseButtonDown(1))
{
UIChatAreaMono.HideInputArea();
}
return;
}
//如果锁了input 但是DebugMode不会锁定input
if (inputLock &&!DebugCenter.Instance.DebugMode)
{
//观战模式:非自己回合时允许查看地块/单位信息
//非自己回合时不需要判断PresentationManager.BusyPresentation播放的是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
}
if (Input.GetKeyDown(KeyCode.Alpha1))
{
#if UNITY_EDITOR
if ((Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
&& (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)))
{
//Ctrl+Shift+1调试用让当前选中的我方城市立即升1级仅编辑器下可用
var map = Main.MapData;
var selfPlayer = map?.PlayerMap?.SelfPlayerData;
var grid = MapRecordManager.Instance?.RecordGridData;
if (map != null && selfPlayer != null && grid != null
&& map.GetCityDataByGid(grid.Id, out var city)
&& map.GetPlayerDataByCityId(city.Id, out var owner)
&& owner == selfPlayer)
{
//恰好升1级所需的exp每级升级消耗等于当前 Level
int need = city.Level - city.LevelExp;
if (need < 1) need = 1;
Main.CityLogic.GridGiveCityExp_LogicView(map, owner, grid, city, need);
}
}
#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
&& UIChatAreaMono.IsActive)
{
if (!UIChatAreaMono.IsInputAreaVisible)
{
// 输入区未打开 → 打开并聚焦
UIChatAreaMono.ShowInputArea();
}
else
{
// 输入区已打开但未聚焦 → 聚焦
UIChatAreaMono.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;
//带 Ctrl 修饰的数字键留给作弊快捷键(如 Ctrl+Shift+1不在此处吃掉
if (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)) 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);
}
}
}