结构大修改,改成朴实无华的结构,不过度架构。能跑就行

This commit is contained in:
2025-12-23 00:09:39 +08:00
parent 384f11f620
commit 3d14085920
2837 changed files with 149714 additions and 1100 deletions

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0eb35ab0b70344b4a2b6054f7a7ecd1b
timeCreated: 1756822717

View File

@@ -0,0 +1,98 @@
using Fantasy.Async;
using NBC;
using Fantasy.Entitas;
using Fantasy.Entitas.Interface;
using Fantasy.Event;
using UnityEngine;
namespace NBF.Fishing2
{
public enum CameraShowMode
{
None = 0,
FPP,
TPP,
}
public class CameraComponent : Entity
{
public CameraShowMode Mode = CameraShowMode.None;
private CameraAsset _cameraAsset;
private CameraShowMode _lastMode = CameraShowMode.None;
public class CameraComponentAwakeSystem : AwakeSystem<CameraComponent>
{
protected override void Awake(CameraComponent self)
{
self._cameraAsset = Game.Instance.gameObject.GetComponentInChildren<CameraAsset>();
}
}
public class CameraComponentUpdateSystem : UpdateSystem<CameraComponent>
{
protected override void Update(CameraComponent self)
{
self.UpdateCamera();
}
}
public class CameraComponentDestroySystem : DestroySystem<CameraComponent>
{
protected override void Destroy(CameraComponent self)
{
self._cameraAsset = null;
self._lastMode = CameraShowMode.None;
self.Mode = CameraShowMode.None;
}
}
private void UpdateCamera()
{
if (_lastMode == Mode) return;
if (Mode == CameraShowMode.TPP)
{
//第三人称视角
SetTPPCam();
}
else if (Mode == CameraShowMode.FPP)
{
//第一人称视角
SetFPPCam();
}
}
private void SetTPPCam()
{
_cameraAsset.fppVCam.Priority = 0;
_cameraAsset.tppVCam.Priority = 10;
}
private void SetFPPCam()
{
var map = App.Main.GetComponent<Map>();
var unityComponent = map.SelfMapUnit.GetComponent<UnitUnityComponent>();
if (unityComponent != null)
{
_cameraAsset.fppVCam.LookAt = unityComponent.RootAsset.FppLook;
_cameraAsset.fppVCam.Follow = unityComponent.ModelAsset.NeckTransform;
unityComponent.ModelAsset.LookIk.solver.target = unityComponent.RootAsset.FppLook;
}
_cameraAsset.fppVCam.Priority = 10;
_cameraAsset.tppVCam.Priority = 0;
}
public void SetFppLook(Transform fppCamLook)
{
_cameraAsset.fppVCam.LookAt = fppCamLook;
}
public void SetFppFollow(Transform fppCamFollow)
{
_cameraAsset.fppVCam.Follow = fppCamFollow;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: aee3947bbf944ecb9e955d2ac1d9e3a5
timeCreated: 1756822741

View File

@@ -0,0 +1,104 @@
// using Fantasy.Async;
// using Fantasy.Entitas;
// using Fantasy.Entitas.Interface;
// using Fantasy.Event;
// using NBC;
// using UnityEngine;
//
// namespace NBF.Fishing2
// {
// public class CursorUIShowEvent : AsyncEventSystem<UIShowEvent>
// {
// protected override async FTask Handler(UIShowEvent self)
// {
// var cursorComponent = App.Main.GetComponent<CursorComponent>();
// cursorComponent.UpdateCursor();
// }
// // protected override FTask Handler(UIShowEvent self)
// // {
// // throw new System.NotImplementedException();
// // }
// }
//
// public class CursorUIHideEvent : AsyncEventSystem<UIHideEvent>
// {
// protected override async FTask Handler(UIHideEvent self)
// {
// var cursorComponent = App.Main.GetComponent<CursorComponent>();
// cursorComponent.UpdateCursor();
// }
// }
//
// public class CursorComponent : Entity
// {
// #region System
//
//
//
// // public class CursorComponentAwakeSystem : AwakeSystem<CursorComponent>
// // {
// // protected override void Awake(CursorComponent self)
// // {
// //
// // }
// // }
// //
// // public class CursorComponentUpdateSystem : UpdateSystem<CursorComponent>
// // {
// // protected override void Update(CursorComponent self)
// // {
// // }
// // }
// //
// // public class CursorComponentDestroySystem : DestroySystem<CursorComponent>
// // {
// // protected override void Destroy(CursorComponent self)
// // {
// // }
// // }
//
// #endregion
//
// public void UpdateCursor()
// {
// bool showCursor = false;
// var uis = App.UI.GetAllUI();
// foreach (var ui in uis)
// {
// if (ui.IsShowing && ui.IsShowCursor)
// {
// showCursor = true;
// break;
// }
// }
//
// SetMouseCursor(showCursor);
// }
//
// public ControllerType controllerType = ControllerType.GamePad;
//
// public void SetMouseCursor(bool val)
// {
// Log.Info($"设置鼠标光标==={val}");
// if (val)
// {
// if (controllerType == ControllerType.KeyboardMouse)
// {
// Cursor.visible = true;
// }
//
// Cursor.lockState = CursorLockMode.None;
// }
// else if (controllerType == ControllerType.KeyboardMouse)
// {
// Cursor.visible = false;
// }
//
// Cursor.visible = val;
// if (!val)
// {
// Cursor.lockState = CursorLockMode.Confined;
// }
// }
// }
// }

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a04f3272f2604244b8cd9d9923bb35b0
timeCreated: 1765374579

View File

@@ -0,0 +1,222 @@
using System;
using Fantasy.Entitas;
using Fantasy.Entitas.Interface;
using UnityEngine;
using UnityEngine.InputSystem;
namespace NBF.Fishing2
{
public enum ControllerType
{
KeyboardMouse = 0,
GamePad = 1
}
public class InputComponent : Entity
{
public PlayerInputControl PlayerInputControl { get; set; }
/// <summary>
/// 执行输入事件
/// </summary>
public event Action<string> OnUIPerformed;
/// <summary>
/// 执行输入事件完毕
/// </summary>
public event Action<string> OnUICanceled;
/// <summary>
/// 执行输入事件
/// </summary>
public event Action<string> OnPlayerPerformed;
/// <summary>
/// 执行输入事件完毕
/// </summary>
public event Action<string> OnPlayerCanceled;
/// <summary>
/// 执行输入事件
/// </summary>
public event Action<InputAction.CallbackContext> OnPlayerValuePerformed;
/// <summary>
/// 执行输入事件完毕
/// </summary>
public event Action<InputAction.CallbackContext> OnPlayerValueCanceled;
/// <summary>
/// 触发交互游戏对象
/// </summary>
public event Action<InteractiveObject> OnInteractiveObjectAction;
/// <summary>
/// 手柄输入
/// </summary>
public static bool IsControllerInput;
/// <summary>
/// ui阻止游戏输入
/// </summary>
public static bool IsUIStopInput;
#region Event
public class InputComponentAwakeSystem : AwakeSystem<InputComponent>
{
protected override void Awake(InputComponent self)
{
self.PlayerInputControl = new PlayerInputControl();
self.PlayerInputControl.Enable();
foreach (var actionMap in self.PlayerInputControl.asset.actionMaps)
{
actionMap.Enable();
if (actionMap.name == "UI")
{
foreach (var action in actionMap.actions)
{
if (action.type == InputActionType.Button)
{
action.performed += self.OnUIButtonPerformed;
action.canceled += self.OnUIButtonCanceled;
}
}
}
else if (actionMap.name == "Player")
{
foreach (var action in actionMap.actions)
{
if (action.type == InputActionType.Button)
{
action.performed += self.OnPlayerButtonPerformed;
action.canceled += self.OnPlayerButtonCanceled;
}
else if (action.type == InputActionType.Value)
{
action.performed += self.OnInputPlayerValuePerformed;
action.canceled += self.OnInputPlayerValueCanceled;
}
}
}
}
}
}
public class InputComponentDestroySystem : DestroySystem<InputComponent>
{
protected override void Destroy(InputComponent self)
{
foreach (var actionMap in self.PlayerInputControl.asset.actionMaps)
{
actionMap.Enable();
if (actionMap.name == "UI")
{
foreach (var action in actionMap.actions)
{
if (action.type == InputActionType.Button)
{
action.performed -= self.OnUIButtonPerformed;
action.canceled -= self.OnUIButtonCanceled;
}
}
}
else if (actionMap.name == "Player")
{
foreach (var action in actionMap.actions)
{
if (action.type == InputActionType.Button)
{
action.performed -= self.OnPlayerButtonPerformed;
action.canceled -= self.OnPlayerButtonCanceled;
}
else if (action.type == InputActionType.Value)
{
action.performed -= self.OnInputPlayerValuePerformed;
action.canceled -= self.OnInputPlayerValueCanceled;
}
}
}
}
}
}
public void OnUIButtonPerformed(InputAction.CallbackContext context)
{
OnUIPerformed?.Invoke(context.action.name);
}
private void OnUIButtonCanceled(InputAction.CallbackContext context)
{
OnUICanceled?.Invoke(context.action.name);
}
private void OnPlayerButtonPerformed(InputAction.CallbackContext context)
{
if (IsUIStopInput) return;
var actionName = context.action.name;
// if (actionName == "Op1")
// {
// OnOp1Action?.Invoke(true);
// }
// else if (actionName == "Op2")
// {
// OnOp2Action?.Invoke(true);
// }
OnPlayerPerformed?.Invoke(actionName);
}
private void OnPlayerButtonCanceled(InputAction.CallbackContext context)
{
if (IsUIStopInput) return;
var actionName = context.action.name;
// if (actionName == "Op1")
// {
// OnOp1Action?.Invoke(false);
// }
// else if (actionName == "Op2")
// {
// OnOp2Action?.Invoke(false);
// }
//
OnPlayerCanceled?.Invoke(actionName);
}
private void OnInputPlayerValuePerformed(InputAction.CallbackContext context)
{
if (IsUIStopInput) return;
OnPlayerValuePerformed?.Invoke(context);
}
private void OnInputPlayerValueCanceled(InputAction.CallbackContext context)
{
if (IsUIStopInput) return;
OnPlayerValueCanceled?.Invoke(context);
}
#endregion
public Vector2 GetMovementInput()
{
if (IsUIStopInput) return Vector2.zero;
return PlayerInputControl.Player.Move?.ReadValue<Vector2>() ?? Vector2.zero;
}
public Vector2 GetLookInput()
{
if (IsUIStopInput) return Vector2.zero;
return PlayerInputControl.Player.Look?.ReadValue<Vector2>() ?? Vector2.zero;
}
public void SendUIInput(string actionName)
{
OnUIPerformed?.Invoke(actionName);
OnUICanceled?.Invoke(actionName);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 09132878c89a444a88421b7434394235
timeCreated: 1756826439

View File

@@ -0,0 +1,9 @@
using Fantasy.Entitas;
namespace NBF.Fishing2
{
public class SettingComponent : Entity
{
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7c6adcf67ef545f99c590d1078a76eea
timeCreated: 1756826460

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4c1174e9753b43ac9dd5fa664e92021b
timeCreated: 1756450590

View File

@@ -0,0 +1,25 @@
using System.Collections.Generic;
using Fantasy.Async;
using NBC;
using Unity.Mathematics;
namespace NBF.Fishing2
{
public static class MoveHelper
{
/// <summary>
/// 可以多次调用,多次调用的话会取消上一次的协程
/// </summary>
/// <param name="unit"></param>
/// <param name="targetPos"></param>
/// <returns></returns>
public static async FTask<int> MoveToAsync(this MapUnit unit, float3 targetPos)
{
return 0;
}
public static async FTask MoveToAsync(this MapUnit unit, List<float3> path)
{
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2ce11e50e0d749bfa5915208b1ce1a44
timeCreated: 1756822516

View File

@@ -0,0 +1,13 @@
using System.IO;
namespace NBF
{
public static class PathHelper
{
public static string GetFullPath(string path)
{
return Path.Combine("gfx", path);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 774fd7a393874949863a694a79823e1c
timeCreated: 1761145384

View File

@@ -0,0 +1,83 @@
using System.Linq;
using Fantasy;
using NBC;
using Unity.Mathematics;
using UnityEngine;
namespace NBF.Fishing2
{
public static class ProtoHelper
{
public static MapUnitInfo ToMapUnitInfo(this RoleInfo self)
{
MapUnitInfo mapUnit = new MapUnitInfo();
mapUnit.Id = self.RoleId;
mapUnit.RoleInfo = self.ToSimpleInfo();
// mapUnit.Gears = self.Gears;
return mapUnit;
}
public static RoleSimpleInfo ToSimpleInfo(this RoleInfo self)
{
var ret = new RoleSimpleInfo();
ret.NickName = self.BaseInfo.NickName;
ret.RoleId = self.RoleId;
ret.Country = self.BaseInfo.Country;
ret.Head = self.BaseInfo.Head;
ret.Level = self.BaseInfo.Level;
// ret.Vip = self.BaseInfo.Vip;
return ret;
}
#region Vector
public static Vector3Info ToVector3Info(this Vector3 self)
{
var ret = new Vector3Info();
ret.x = self.x;
ret.y = self.y;
ret.z = self.z;
return ret;
}
public static QuaternionInfo ToQuaternionInfo(this Quaternion self)
{
var ret = new QuaternionInfo();
ret.x = self.x;
ret.y = self.y;
ret.z = self.z;
ret.w = self.w;
return ret;
}
public static Vector3 ToVector3(this Vector3Info self)
{
var ret = new Vector3
{
x = self.x,
y = self.y,
z = self.z
};
return ret;
}
public static Quaternion ToQuaternion(this QuaternionInfo self)
{
var ret = new Quaternion
{
x = self.x,
y = self.y,
z = self.z,
w = self.w
};
return ret;
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 850c683faae3419abd3693f7e87accae
timeCreated: 1756738767

View File

@@ -0,0 +1,25 @@
using Fantasy.Async;
using NBC;
using Fantasy.Entitas;
namespace NBF.Fishing2
{
public static class UnitHelper
{
public static async FTask InitMapUnit(this MapUnit self)
{
await FTask.CompletedTask;
}
public static bool IsSelf(this MapUnit self)
{
if (self.Id == Game.SelfId)
{
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 82c91df89554417c87a3658709ef406d
timeCreated: 1756450600

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b9626380655a42298daf90e7333172ae
timeCreated: 1756363915

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9720afaa3bc94081b63a7c0571e4c86a
timeCreated: 1757251153

View File

@@ -0,0 +1,20 @@
using Fantasy;
using Fantasy.Async;
using Fantasy.Network;
using Fantasy.Network.Interface;
using NBF.Fishing2;
using Log = NBC.Log;
namespace NBF.Fishing2
{
public class Map2C_ChangeMapHandler : Message<Map2C_ChangeMap>
{
protected override async FTask Run(Session session, Map2C_ChangeMap message)
{
Log.Info($"收到地图切换消息=={message.MapId}");
// await MapHelper.ChangeMap(message.MapId);
// await MapHelper.CreateRoomTest(message.MapId);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9aca13592484450582e818dd128a23c2
timeCreated: 1756301493

View File

@@ -0,0 +1,32 @@
using Fantasy;
using Fantasy.Async;
using Fantasy.Network;
using Fantasy.Network.Interface;
using NBC;
using Log = NBC.Log;
namespace NBF.Fishing2
{
public class Map2C_RoleEnterMapNotifyHandler : Message<Map2C_RoleEnterRoomNotify>
{
protected override async FTask Run(Session session, Map2C_RoleEnterRoomNotify message)
{
Log.Info($"收到进入房间推送 id={message.Info.Id} ");
var map = App.Main.GetComponent<Map>();
if (map == null || !map.IsRoomMap)
{
Log.Info("房间不是好友房间,不处理进入请求");
return;
}
var info = message.Info;
var unit = map.GetUnit(info.Id);
if (unit == null)
{
unit = map.CreateMapUnit(info);
}
await unit.CreateView();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b0934eeab5b8445b824f1337f774379e
timeCreated: 1757251141

View File

@@ -0,0 +1,27 @@
using Fantasy;
using Fantasy.Async;
using Fantasy.Network;
using Fantasy.Network.Interface;
using NBC;
using Log = NBC.Log;
namespace NBF.Fishing2
{
public class Map2C_RoleExitMapNotifyHandler : Message<Map2C_RoleExitRoomNotify>
{
protected override async FTask Run(Session session, Map2C_RoleExitRoomNotify message)
{
Log.Info($"收到离开房间推送 id={message.Id} ");
var map = App.Main.GetComponent<Map>();
if (map == null)
{
Log.Info("地图不存在,不处理退出请求");
return;
}
if (map.Units.Remove(message.Id, out var unit))
{
unit.Dispose();
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 18ae467167c44db1873fee88067d2f9a
timeCreated: 1757251193

View File

@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using Fantasy;
using NBC;
using Fantasy.Entitas;
using Fantasy.Entitas.Interface;
namespace NBF.Fishing2
{
public class Map : Entity
{
public int MapId;
public string RoomCode;
/// <summary>
/// 自己的实体id
/// </summary>
public long SelfId;
/// <summary>
/// 好友房地图
/// </summary>
public bool IsRoomMap => !string.IsNullOrEmpty(RoomCode);
/// <summary>
/// 地图中的单位
/// </summary>
public Dictionary<long, MapUnit> Units = new Dictionary<long, MapUnit>();
/// <summary>
/// 自己的实体
/// </summary>
public MapUnit SelfMapUnit => GetUnit(SelfId);
#region System
public class MapDestroySystem : DestroySystem<Map>
{
protected override void Destroy(Map self)
{
self.MapId = 0;
self.SelfId = 0;
self.RoomCode = string.Empty;
self.Units.Clear();
}
}
#endregion
public MapUnit CreateMapUnit(MapUnitInfo unitInfo)
{
var mapUnit = Create<MapUnit>(Scene, unitInfo.Id, true, true);
mapUnit.SetUnitInfo(unitInfo);
Add(mapUnit);
return mapUnit;
}
/// <summary>
/// 获取一个单位
/// </summary>
/// <param name="self"></param>
/// <param name="id"></param>
/// <returns></returns>
public MapUnit GetUnit(long id)
{
return Units.GetValueOrDefault(id);
}
/// <summary>
/// 进入地图
/// </summary>
/// <param name="map"></param>
/// <param name="unit"></param>
/// <returns></returns>
public bool Add(MapUnit unit)
{
Units.Add(unit.Id, unit);
return true;
}
/// <summary>
/// 离开地图
/// </summary>
/// <param name="self"></param>
/// <param name="id"></param>
/// <returns></returns>
public bool Remove(long id)
{
return Units.Remove(id);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2acb8a2309ee4443a812939b0e02c18f
timeCreated: 1756049289

View File

@@ -0,0 +1,11 @@
using Fantasy.Entitas;
namespace NBF.Fishing2
{
/// <summary>
/// 地图管理组件
/// </summary>
public class MapManageComponent : Entity
{
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 226c840e80f840ae8a4ff54bc7c6645a
timeCreated: 1756304063

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b35630cbcbbb4792a821de847fabbd69
timeCreated: 1757820526

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c197c410c838437996d832515a62026e
timeCreated: 1757835465

View File

@@ -0,0 +1,35 @@
// using System.Collections.Generic;
// using Fantasy;
// using Fantasy.Event;
//
// namespace NBF.Fishing2
// {
// public class NumericChangeEvent : EventSystem<NumericChange>
// {
// protected override void Handler(NumericChange self)
// {
// if (self.Old == self.New) return;
// if (self.NumericType == NumericType.Flashlight)
// {
// var flashlight = self.MapUnit.GetComponent<FlashlightComponent>();
// flashlight.Change(self.New);
// if (self.MapUnit.IsSelf())
// {
// var list = new List<KeyValueInt64>
// {
// new KeyValueInt64()
// {
// Key = self.NumericType,
// Value = self.New
// }
// };
// //如果是自己的,则同步给其他玩家
// Net.Send(new C2Map_RolePropertyChange()
// {
// Propertys = list
// });
// }
// }
// }
// }
// }

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2dae2fd757bc46b7b47a7b548b36ed54
timeCreated: 1757835696

View File

@@ -0,0 +1,33 @@
using Fantasy;
using Fantasy.Async;
using Fantasy.Network;
using Fantasy.Network.Interface;
using NBC;
using Log = NBC.Log;
namespace NBF.Fishing2
{
public class Map2C_LookNotifyHandler : Message<Map2C_LookeNotify>
{
protected override async FTask Run(Session session, Map2C_LookeNotify message)
{
Log.Info($"收到朝向推送 id={message.Id} ");
var map = App.Main.GetComponent<Map>();
var unit = map.Units[message.Id];
if (unit.IsSelf())
{
Log.Info("自己的旋转消息,不处理");
}
else
{
var moveComponent = unit.GetComponent<CharacterControllerComponent>();
if (moveComponent != null)
{
moveComponent.OnServerLook(message.Rotation.ToVector3(), message.Timestamp);
}
}
await FTask.CompletedTask;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f1f00b074c7f48248773361036d3bfcf
timeCreated: 1757238435

View File

@@ -0,0 +1,36 @@
using Fantasy;
using Fantasy.Async;
using Fantasy.Network;
using Fantasy.Network.Interface;
using NBC;
using Log = NBC.Log;
namespace NBF.Fishing2
{
public class Map2C_MoveNotifyHandler : Message<Map2C_MoveNotify>
{
protected override async FTask Run(Session session, Map2C_MoveNotify message)
{
Log.Info($"收到移动推送 id={message.Id} stop={message.IsStop}");
// session.Scene
// session.Scene.GetComponent<MapUnitInfo>(message.Id),
var map = App.Main.GetComponent<Map>();
var unit = map.Units[message.Id];
var moveComponent = unit.GetComponent<CharacterControllerComponent>();
if (moveComponent != null)
{
if (message.IsStop)
{
moveComponent.OnServerStopMove(message.Position.ToVector3(), message.Timestamp);
}
else
{
moveComponent.OnServerStartMove(message.Position.ToVector3(),
message.Direction.ToVector3(), 3, message.Timestamp);
}
}
await FTask.CompletedTask;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2306a332c3f842e78fd8d70c9ef1f8ed
timeCreated: 1757148423

View File

@@ -0,0 +1,26 @@
using Fantasy;
using Fantasy.Async;
using Fantasy.Network;
using Fantasy.Network.Interface;
using NBC;
using Log = NBC.Log;
namespace NBF.Fishing2
{
public class Map2C_RolePropertyChangeNotifyHandler : Message<Map2C_RolePropertyChangeNotify>
{
protected override async FTask Run(Session session, Map2C_RolePropertyChangeNotify message)
{
Log.Info($"收到角色属性推送 id={message.Id}");
var map = App.Main.GetComponent<Map>();
var unit = map.Units[message.Id];
var numericComponent = unit.GetComponent<NumericComponent>();
foreach (var property in message.Propertys)
{
numericComponent.Set(property.Key, property.Value);
}
await FTask.CompletedTask;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b507863390534ecca584e3a787180493
timeCreated: 1757820797

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 53262d3faa5141deb0c8809a4354daa0
timeCreated: 1756820602

View File

@@ -0,0 +1,13 @@
using Cinemachine;
using UnityEngine;
namespace NBF.Fishing2
{
public class CameraAsset : MonoBehaviour
{
public CinemachineVirtualCamera fppVCam;
public CinemachineVirtualCamera tppVCam;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5dd3e6b2217c463e94e32f15c4ea3c5c
timeCreated: 1765306413

View File

@@ -0,0 +1,58 @@
using RootMotion.FinalIK;
using UnityEngine;
namespace NBF
{
public class PlayerArm : MonoBehaviour
{
public bool IsLeft;
public LimbIK IK;
public Transform RodContainer;
public Transform LeftRigMagnet;
public FingerRig FingerRig;
public PlayerShoulder Shoulder;//PlayerShoulder
[HideInInspector] public float interactionTargetWeight;
public void SetReelHandle(ReelAsset asset)
{
IK.solver.target = asset.handle;
IK.enabled = true;
// var fingers = FingerRig.fingers;
// foreach (var finger in fingers)
// {
// finger.target = asset.handleEnd;
// }
// // 启用整体控制
// FingerRig.weight = 1f;
//
// // 绑定大拇指和食指的目标
// FingerRig.fingers[0].target = asset.handleEnd; // Thumb
// FingerRig.fingers[1].target = asset.handleEnd; // Index
//
// FingerRig.fingers[0].weight = 1f;
// FingerRig.fingers[1].weight = 1f;
// 其余手指握拳(不绑定 target
for (int i = 2; i < 5; i++)
{
FingerRig.fingers[i].target = null;
FingerRig.fingers[i].weight = 1f;
}
}
public void MoveTowardsInteraction()
{
if (!IK)
{
return;
}
IK.solver.SetIKPositionWeight(Mathf.MoveTowards(IK.solver.IKPositionWeight,
interactionTargetWeight, Time.deltaTime * 2f));
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ed33e261a2784ee0814ceaa6c88aefdf
timeCreated: 1756821001

View File

@@ -0,0 +1,37 @@
using System;
using UnityEngine;
namespace NBF
{
public class PlayerShoulder : MonoBehaviour
{
private Vector3 startEulerAngles;
private const int MaxAngle = 30;
private const int MinAngle = -30;
public float TestZ;
private void Awake()
{
startEulerAngles = transform.localEulerAngles;
}
public void SetCameraEulerAngleX(float value)
{
value = (value > 180f) ? value - 360f : value;
Debug.Log($"value={value}");
var addValue = value * -1;
if (addValue > MaxAngle)
{
addValue = MaxAngle;
}
else if (addValue < MinAngle)
{
addValue = MinAngle;
}
transform.localEulerAngles =
new Vector3(addValue + startEulerAngles.x, startEulerAngles.y, TestZ);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f85286904d2d45738c4b415f3503d4ab
timeCreated: 1756820965

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1fb0ee12d9cf40408478e8f9ad9aafdd
timeCreated: 1755915944

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 35bf130c632b4a31b064a6d0706aba65
timeCreated: 1757835845

View File

@@ -0,0 +1,69 @@
using Fantasy.Entitas;
using Fantasy.Entitas.Interface;
using UnityEngine;
namespace NBF.Fishing2
{
/// <summary>
/// 手电筒组件
/// </summary>
public class FlashlightComponent : Entity
{
private GameObject _fishingLight;
public class FlashlightComponentAwakeSystem : AwakeSystem<FlashlightComponent>
{
protected override void Awake(FlashlightComponent self)
{
var numericComponent = self.Parent.GetComponent<NumericComponent>();
var unityComponent = self.Parent.GetComponent<UnitUnityComponent>();
// self._fishingLight = unityComponent.Asset.FishingLight;
// self.Change(numericComponent[NumericType.Flashlight]);
var mapUnit = self.Parent as MapUnit;
if (mapUnit.IsSelf())
{
var inputComponent = self.Scene.GetComponent<InputComponent>();
inputComponent.OnPlayerPerformed += self.OnPlayerCanceled;
}
}
}
public class FlashlightComponentDestroySystem : DestroySystem<FlashlightComponent>
{
protected override void Destroy(FlashlightComponent self)
{
self._fishingLight = null;
var mapUnit = self.Parent as MapUnit;
if (mapUnit.IsSelf())
{
var inputComponent = self.Scene.GetComponent<InputComponent>();
if (inputComponent != null)
{
inputComponent.OnPlayerPerformed -= self.OnPlayerCanceled;
}
}
}
}
private void OnPlayerCanceled(string action)
{
if (action == InputDef.Player.UseTorch)
{
var numericComponent = Parent.GetComponent<NumericComponent>();
if (numericComponent != null)
{
var oldValue = numericComponent[NumericType.Flashlight];
numericComponent[NumericType.Flashlight] = oldValue > 0 ? 0 : 1;
}
}
}
public void Change(long value)
{
_fishingLight.SetActive(value > 0);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b498c6d3db5b4d44a1dc99b547416d59
timeCreated: 1757836076

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1c61b32e7992466f9771eac80763078e
timeCreated: 1765523393

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 70bbe8d6e0c04cdaa553cacaee37fe59
timeCreated: 1755921259

View File

@@ -0,0 +1,16 @@
using System.Collections.Generic;
using Fantasy.Entitas;
namespace NBF.Fishing2
{
/// <summary>
/// 玩家组件
/// </summary>
public class MapUnitGear : Entity
{
/// <summary>
/// 绑定的子组件
/// </summary>
public List<MapUnitGearPart> Binding = new List<MapUnitGearPart>();
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 01c5cf0e015042fbae5000cff14bb419
timeCreated: 1766325287

View File

@@ -0,0 +1,12 @@
using Fantasy.Entitas;
namespace NBF.Fishing2
{
public class MapUnitGearPart : Entity
{
/// <summary>
/// 配置表id
/// </summary>
public int ConfigId { get; set; }
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a83db5681be745a3b692da5c82496a40
timeCreated: 1766325663

View File

@@ -0,0 +1,120 @@
using System.Collections.Generic;
using Fantasy;
using Fantasy.Async;
using NBC;
using Fantasy.Entitas;
using Fantasy.Entitas.Interface;
using Unity.Mathematics;
using UnityEngine;
namespace NBF.Fishing2
{
/// <summary>
/// 单位
/// </summary>
public class MapUnit : Entity
{
public int ConfigId { get; set; } //配置表id
/// <summary>
/// 钓组信息
/// </summary>
public List<MapUnitGear> Gears = new List<MapUnitGear>();
/// <summary>
/// 是否在地面
/// </summary>
public bool IsGrounded { get; set; }
/// <summary>
/// 是否在水里
/// </summary>
public bool IsInWater { get; set; }
public float Speed { get; set; }
public float RotationSpeed { get; set; }
private Vector3 position; //坐标
public Vector3 Position
{
get => position;
set
{
// Vector3 oldPos = position;
position = value;
// Scene.EventComponent.Publish(new ChangePosition() { MapUnit = this, OldPos = oldPos });
}
}
public Vector3 Forward
{
get => math.mul(Rotation, math.forward());
set => Rotation = Quaternion.LookRotation(value, math.up());
}
private Quaternion rotation;
public Quaternion Rotation
{
get => rotation;
set
{
rotation = value;
// Scene.EventComponent.Publish(new ChangeRotation() { MapUnit = this });
}
}
public MapUnitState State { get; set; }
public string StateArgs { get; set; }
#region System
public class MapUnitDestroySystem : DestroySystem<MapUnit>
{
protected override void Destroy(MapUnit self)
{
}
}
#endregion
public void ChangeState(MapUnitState state, string args)
{
Scene.EventComponent.Publish(new ChangeState() { MapUnit = this, State = state, Args = args });
}
public void SetUnitInfo(MapUnitInfo unitInfo)
{
GetOrAddComponent<ObjectWait>();
var unitBasic = GetOrAddComponent<MapUnitBasic>();
unitBasic.UpdateInfo(unitInfo);
// unitInfo.Gears
var numericComponent = GetOrAddComponent<NumericComponent>();
foreach (var kv in unitInfo.Propertys)
{
numericComponent.Set(kv.Key, kv.Value);
}
}
#region View
public async FTask CreateView()
{
var unitUnity = GetComponent<UnitUnityComponent>();
if (unitUnity != null)
{
unitUnity.Dispose();
}
unitUnity = AddComponent<UnitUnityComponent>();
await unitUnity.InitUnityObject();
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ff176fc098254fe2a1b48ea26eaf8857
timeCreated: 1755915448

View File

@@ -0,0 +1,39 @@
using Fantasy;
using NBC;
using Fantasy.Entitas;
namespace NBF.Fishing2
{
public class MapUnitBasic : Entity
{
/// <summary>
/// 昵称
/// </summary>
public string NickName;
/// <summary>
/// 头像
/// </summary>
public string Head;
/// <summary>
/// 国家
/// </summary>
public string Country;
/// <summary>
/// 等级
/// </summary>
public int Level;
public void UpdateInfo(MapUnitInfo mapUnitInfo)
{
if (mapUnitInfo.RoleInfo == null) return;
NickName = mapUnitInfo.RoleInfo.NickName;
Head = mapUnitInfo.RoleInfo.Head;
Country = mapUnitInfo.RoleInfo.Country;
Level = mapUnitInfo.RoleInfo.Level;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: fac7cf28f53b4a929d2584c9a95fd242
timeCreated: 1756881253

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 309507c5427f4a95bb64f526ce60ded0
timeCreated: 1757820516

View File

@@ -0,0 +1,427 @@
using System.Collections.Generic;
using Fantasy;
using Fantasy.Entitas;
using Fantasy.Entitas.Interface;
using Fantasy.Helper;
using UnityEngine;
using UnityEngine.InputSystem;
using Log = NBC.Log;
namespace NBF.Fishing2
{
[System.Serializable]
public struct MoveState
{
public Vector3 startPosition; // 开始移动时的位置
public Vector3 moveDirection; // 移动方向(标准化向量)
public float moveSpeed; // 移动速度
public bool isMoving; // 是否正在移动
public double serverTimestamp; // 服务器时间戳
}
public class CharacterControllerComponent : Entity
{
public bool IsSelf;
public bool Run;
public CharacterController characterController;
public PlayerModelAsset PlayerModelAsset;
public readonly Queue<MoveState> MoveStateQueue = new Queue<MoveState>();
public Transform transform => characterController.transform;
private MoveState currentMoveState;
// private Vector3 networkFacingDirection;
// 添加目标位置和旋转用于插值
private Vector3 targetPosition;
private Quaternion targetRotation;
// 插值平滑参数
public float positionLerpSpeed = 10f;
public float rotationLerpSpeed = 10f;
private float currentSpeed = 0f;
private float acceleration = 10f; // 加速度
/// <summary>
/// 重力加速度
/// </summary>
private float gravity = 9.81f;
private Vector3 currentVelocity = Vector3.zero;
private float verticalVelocity = 0f;
private float groundedGravity = -0.5f; // 小的向下力确保角色保持在地面
private float airControl = 0.5f; // 空中控制系数
#region System
public class MoveComponentDestroySystem : DestroySystem<CharacterControllerComponent>
{
protected override void Destroy(CharacterControllerComponent self)
{
self.characterController = null;
self.IsSelf = false;
self.Run = false;
var mapUnit = self.Parent as MapUnit;
if (mapUnit.IsSelf())
{
var inputComponent = self.Scene.GetComponent<InputComponent>();
if (inputComponent != null)
{
inputComponent.OnPlayerPerformed -= self.OnPlayerCanceled;
inputComponent.OnPlayerPerformed -= self.OnPlayerPerformed;
inputComponent.OnPlayerValueCanceled -= self.OnPlayerValueCanceled;
inputComponent.OnPlayerValuePerformed -= self.OnPlayerValuePerformed;
}
}
self.PlayerModelAsset = null;
}
}
public class MoveComponentAwakeSystem : AwakeSystem<CharacterControllerComponent>
{
protected override void Awake(CharacterControllerComponent self)
{
var unitUnityComponent = self.Parent.GetComponent<UnitUnityComponent>();
self.PlayerModelAsset = unitUnityComponent.ModelAsset;
self.characterController = unitUnityComponent.GameObject.GetComponent<CharacterController>();
self.lastSyncedFacing = self.characterController.transform.forward;
// 初始化目标位置和旋转
self.targetPosition = self.characterController.transform.position;
self.targetRotation = self.characterController.transform.rotation;
self.characterController.enabled = true;
var mapUnit = self.Parent as MapUnit;
if (mapUnit.IsSelf())
{
self.IsSelf = true;
var inputComponent = self.Scene.GetComponent<InputComponent>();
inputComponent.OnPlayerPerformed += self.OnPlayerCanceled;
inputComponent.OnPlayerPerformed += self.OnPlayerPerformed;
inputComponent.OnPlayerValueCanceled += self.OnPlayerValueCanceled;
inputComponent.OnPlayerValuePerformed += self.OnPlayerValuePerformed;
}
}
}
public class MoveComponentUpdateSystem : UpdateSystem<CharacterControllerComponent>
{
protected override void Update(CharacterControllerComponent self)
{
self.ProcessMoveStates();
self.CheckRotationSync();
// 插值更新位置和旋转
self.InterpolatePositionAndRotation();
var mapUnit = self.Parent as MapUnit;
mapUnit.Position = self.characterController.transform.position;
mapUnit.Rotation = self.characterController.transform.rotation;
var f = mapUnit.Forward;
}
}
#endregion
#region Input
private void OnPlayerPerformed(string action)
{
if (action == InputDef.Player.Run)
{
Run = true;
}
}
private void OnPlayerCanceled(string action)
{
if (action == InputDef.Player.Run)
{
Run = false;
}
}
private void OnPlayerValueCanceled(InputAction.CallbackContext context)
{
var name = context.action.name;
if (name == InputDef.Player.Move)
{
var v2 = context.ReadValue<Vector2>();
SendMoveMessage(v2, true);
}
}
private void OnPlayerValuePerformed(InputAction.CallbackContext context)
{
// var mapUnit = Parent as MapUnit;
// Log.Info($"OnPlayerValuePerformed IsSelf={mapUnit.IsSelf()} id={mapUnit.Id}");
var name = context.action.name;
if (name == InputDef.Player.Move)
{
var v2 = context.ReadValue<Vector2>();
SendMoveMessage(v2, false);
}
else if (name == InputDef.Player.Look)
{
var v2 = context.ReadValue<Vector2>();
UpdatePlayerRotation(v2);
}
}
#endregion
#region Message
private void SendMoveMessage(Vector3 movementInput, bool isStop = false)
{
var mapUnit = Parent as MapUnit;
Vector3 movementDirection = Vector3.zero;
// 发送本地相对坐标而不是世界坐标
if (!isStop)
{
movementDirection = new Vector3(movementInput.x, 0, movementInput.y);
}
Net.Send(new C2Map_Move()
{
Direction = movementDirection.ToVector3Info(),
IsStop = isStop,
IsRun = Run,
Timestamp = TimeHelper.Now,
Position = mapUnit.Position.ToVector3Info(),
Rotation = mapUnit.Forward.ToVector3Info(),
});
}
private void SendLookMessage()
{
Log.Info("发送朝向同步消息");
Net.Send(new C2Map_Look()
{
Rotation = characterController.transform.forward.ToVector3Info(),
Timestamp = TimeHelper.Now
});
}
/// <summary>
/// 接收服务器移动开始通知
/// </summary>
/// <param name="startPosition"></param>
/// <param name="moveDirection"></param>
/// <param name="speed"></param>
/// <param name="timestamp"></param>
public void OnServerStartMove(Vector3 startPosition, Vector3 moveDirection, float speed, double timestamp)
{
MoveState moveState = new MoveState
{
startPosition = startPosition,
moveDirection = moveDirection.normalized,
moveSpeed = speed,
isMoving = true,
serverTimestamp = timestamp
};
MoveStateQueue.Enqueue(moveState);
Log.Info($"MoveStateQueue Count={MoveStateQueue.Count}");
}
/// <summary>
/// 接收服务器移动停止通知
/// </summary>
/// <param name="finalPosition"></param>
/// <param name="timestamp"></param>
public void OnServerStopMove(Vector3 finalPosition, double timestamp)
{
MoveState moveState = new MoveState
{
startPosition = finalPosition,
moveDirection = Vector3.zero,
moveSpeed = 0f,
isMoving = false,
serverTimestamp = timestamp
};
MoveStateQueue.Enqueue(moveState);
Log.Info($"MoveStateQueue Count={MoveStateQueue.Count}");
}
public void OnServerLook(Vector3 rotation, double timestamp)
{
// 设置目标旋转用于插值
targetRotation = Quaternion.LookRotation(rotation);
}
#endregion
#region Move
private void ProcessMoveStates()
{
// 只有在当前状态不是移动状态时,才处理下一个状态
if (MoveStateQueue.Count > 0)
{
currentMoveState = MoveStateQueue.Dequeue();
if (currentMoveState.isMoving)
{
StartMovement(currentMoveState);
}
else
{
StopMovement(currentMoveState);
}
}
// 如果正在移动,持续更新
if (currentMoveState.isMoving)
{
UpdateMovement();
}
}
private void StartMovement(MoveState moveState)
{
targetPosition = moveState.startPosition;
Debug.Log($"开始移动 - 位置: {moveState.startPosition}");
}
private void StopMovement(MoveState moveState)
{
targetPosition = moveState.startPosition;
Debug.Log($"停止移动 - 最终位置: {moveState.startPosition}");
}
private void UpdateMovement()
{
// 将本地相对方向转换为世界方向
Vector3 localDirection = currentMoveState.moveDirection;
Vector3 characterRight = Vector3.ProjectOnPlane(characterController.transform.right, Vector3.up).normalized;
Vector3 characterForward = Vector3.ProjectOnPlane(characterController.transform.forward, Vector3.up).normalized;
Vector3 movementDirection = characterForward * localDirection.z + characterRight * localDirection.x;
float targetSpeed = currentMoveState.moveSpeed;
// 平滑加速
if (movementDirection.magnitude > 0.1f)
{
currentSpeed = Mathf.Lerp(currentSpeed, targetSpeed, acceleration * Time.deltaTime);
}
else
{
currentSpeed = Mathf.Lerp(currentSpeed, 0f, acceleration * 2f * Time.deltaTime);
}
// 处理重力
if (characterController.isGrounded)
{
verticalVelocity = groundedGravity;
// 地面移动 - 完全控制
currentVelocity = Vector3.Lerp(currentVelocity, movementDirection.normalized * currentSpeed,
acceleration * Time.deltaTime);
}
else
{
verticalVelocity -= gravity * Time.deltaTime;
// 空中移动 - 有限控制
Vector3 targetAirVelocity = movementDirection.normalized * currentSpeed * airControl;
currentVelocity = Vector3.Lerp(currentVelocity,
new Vector3(targetAirVelocity.x, currentVelocity.y, targetAirVelocity.z),
acceleration * Time.deltaTime);
}
// 组合移动
Vector3 totalMovement = currentVelocity * Time.deltaTime;
totalMovement.y = verticalVelocity * Time.deltaTime;
Log.Info($"移动=== Id={Parent.Id} 位置: {characterController.transform.position} 移动量: {totalMovement}");
characterController.Move(totalMovement);
}
// 添加位置和旋转插值方法
private void InterpolatePositionAndRotation()
{
// 只对非本地玩家进行插值
if (!IsSelf)
{
// 插值位置
// characterController.transform.position = Vector3.Lerp(
// characterController.transform.position,
// targetPosition,
// positionLerpSpeed * Time.deltaTime);
// 插值旋转 - 使用更平滑的插值方法
characterController.transform.rotation = Quaternion.Slerp(
characterController.transform.rotation,
targetRotation,
rotationLerpSpeed * Time.deltaTime);
}
}
#endregion
#region Look
public float rotationSyncInterval = 0.15f;
public float minRotationChange = 10f;
private Vector3 _rotationInput = Vector3.zero;
private float rotationSyncTimer;
private Vector3 lastSyncedFacing;
private bool isRotating = false;
[Tooltip("视角旋转敏感度")] public Vector2 sensitivity = new Vector2(0.015f, 0.015f);
private void UpdatePlayerRotation(Vector2 lookValue)
{
// Look
Vector2 lookInput = lookValue * sensitivity;
// 处理水平旋转 (Yaw)
if (lookInput.x != 0.0f)
{
_rotationInput.y += lookInput.x;
isRotating = true;
}
// 应用旋转到角色和相机
if (_rotationInput != Vector3.zero)
{
characterController.transform.rotation *= Quaternion.Euler(0, _rotationInput.y, 0);
_rotationInput = Vector3.zero;
}
}
// 检查朝向同步
private void CheckRotationSync()
{
if (!IsSelf) return;
rotationSyncTimer += Time.deltaTime;
if (rotationSyncTimer >= rotationSyncInterval)
{
float angleChange = Vector3.Angle(transform.forward, lastSyncedFacing);
// 修改:即使在旋转中也定期同步朝向,避免累积误差
if (angleChange >= minRotationChange || isRotating)
{
SendLookMessage();
lastSyncedFacing = transform.forward;
rotationSyncTimer = 0f;
isRotating = false;
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 36fb267f0f5149caa23ac1b6cf005067
timeCreated: 1757164955

View File

@@ -0,0 +1,108 @@
using ECM2.Examples.FirstPerson;
using Fantasy.Entitas;
using Fantasy.Entitas.Interface;
using UnityEngine;
using UnityEngine.InputSystem;
namespace NBF.Fishing2
{
public class CharacterLookComponent : Entity
{
// private UnitUnityComponent _UnitUnityComponent;
public FirstPersonCharacter FirstPerson { get; set; }
private float lookXRot;
private float lookYRot;
private Vector2 _moveInput;
public float MouseSensitivity = 0.1f;
[Space(15f)] public bool invertLook = true;
public float minPitch = -60f;
public float maxPitch = 60f;
private InputComponent _inputComponent;
private Quaternion lastRotation;
public MapUnit MapUnit;
#region System
public class LookComponentDestroySystem : DestroySystem<CharacterLookComponent>
{
protected override void Destroy(CharacterLookComponent self)
{
self.FirstPerson = null;
// var mapUnit = self.Parent as MapUnit;
self._inputComponent = null;
}
}
public class LookComponentAwakeSystem : AwakeSystem<CharacterLookComponent>
{
protected override void Awake(CharacterLookComponent self)
{
var mapUnit = self.Parent as MapUnit;
self.MapUnit = mapUnit;
var unitUnityComponent = self.Parent.GetComponent<UnitUnityComponent>();
self.FirstPerson = unitUnityComponent.FirstPerson;
self._inputComponent = self.Scene.GetComponent<InputComponent>();
}
}
public class LookComponentUpdateSystem : UpdateSystem<CharacterLookComponent>
{
protected override void Update(CharacterLookComponent self)
{
self.UpdateLookInput();
}
}
// public class LookComponentLateUpdateSystem : LateUpdateSystem<CharacterLookComponent>
// {
// protected override void LateUpdate(CharacterLookComponent self)
// {
// self.UpdateLookInput();
// }
// }
#endregion
private void UpdateLookInput()
{
// TPPLookTarget.position = base.transform.position;
// if (CameraView.Value == CameraViewType.TPP)
// {
// lookXRot -= MouseInput.Value.y;
// lookXRot = Mathf.Clamp(lookXRot, -25f, 55f);
// lookYRot += MouseInput.Value.x;
// lookYRot = Mathf.Repeat(lookYRot, 360f);
// TPPLookTarget.localEulerAngles = new Vector3(lookXRot, lookYRot, 0f);
// }
// else if (CameraView.Value == CameraViewType.FPP)
{
// if (_IsInVehicle && PlayerState.Value == State.vehicle)
// {
// lookXRot -= MouseInput.Value.y;
// lookXRot = Mathf.Clamp(lookXRot, VehicleLookXMinMax.x, VehicleLookXMinMax.y);
// lookYRot += MouseInput.Value.x;
// lookYRot = Mathf.Clamp(lookYRot, VehicleLookYMinMax.x, VehicleLookYMinMax.y);
// VehicleLookTargetParent.localEulerAngles = new Vector3(lookXRot, lookYRot, 0f);
// _character.CameraPitch = 0f;
// }
// else
{
Vector2 value = _inputComponent.GetLookInput();
FirstPerson.AddControlYawInput(value.x * (float)MouseSensitivity);
FirstPerson.AddControlPitchInput((invertLook ? (0f - value.y) : value.y) * (float)MouseSensitivity,
minPitch, maxPitch);
// lookXRot = base.transform.eulerAngles.x;
// lookYRot = base.transform.eulerAngles.y;
}
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 316d2e71f8b3473e961ac86ce4568704
timeCreated: 1765283815

View File

@@ -0,0 +1,214 @@
using ECM2;
using ECM2.Examples.FirstPerson;
using Fantasy.Entitas;
using Fantasy.Entitas.Interface;
using UnityEngine;
using UnityEngine.InputSystem;
namespace NBF.Fishing2
{
public class CharacterMovementComponent : Entity
{
public bool IsSelf;
public bool Run;
private Vector2 _moveInput;
public MapUnit MapUnit;
private FirstPersonCharacter _Character;
private Quaternion lastRotation;
#region System
public class MovementComponentDestroySystem : DestroySystem<CharacterMovementComponent>
{
protected override void Destroy(CharacterMovementComponent self)
{
// self.characterController = null;
self.IsSelf = false;
self.Run = false;
var mapUnit = self.Parent as MapUnit;
if (mapUnit.IsSelf())
{
var inputComponent = self.Scene.GetComponent<InputComponent>();
if (inputComponent != null)
{
inputComponent.OnPlayerPerformed -= self.OnPlayerCanceled;
inputComponent.OnPlayerPerformed -= self.OnPlayerPerformed;
inputComponent.OnPlayerValueCanceled -= self.OnPlayerValueCanceled;
inputComponent.OnPlayerValuePerformed -= self.OnPlayerValuePerformed;
}
}
// self.PlayerAsset = null;
}
}
public class MovementComponentAwakeSystem : AwakeSystem<CharacterMovementComponent>
{
protected override void Awake(CharacterMovementComponent self)
{
var unitUnityComponent = self.Parent.GetComponent<UnitUnityComponent>();
self._Character = unitUnityComponent.FirstPerson;
var mapUnit = self.Parent as MapUnit;
self.MapUnit = mapUnit;
if (mapUnit.IsSelf())
{
self.IsSelf = true;
var inputComponent = self.Scene.GetComponent<InputComponent>();
inputComponent.OnPlayerPerformed += self.OnPlayerCanceled;
inputComponent.OnPlayerPerformed += self.OnPlayerPerformed;
inputComponent.OnPlayerValueCanceled += self.OnPlayerValueCanceled;
inputComponent.OnPlayerValuePerformed += self.OnPlayerValuePerformed;
}
}
}
public class MovementComponentUpdateSystem : UpdateSystem<CharacterMovementComponent>
{
protected override void Update(CharacterMovementComponent self)
{
self.UpdateGrounded();
self.UpdateWater();
self.ProcessMoveStates();
}
}
#endregion
#region Input
private void OnPlayerPerformed(string action)
{
if (action == InputDef.Player.Run)
{
Run = true;
}
}
private void OnPlayerCanceled(string action)
{
if (action == InputDef.Player.Run)
{
Run = false;
}
}
private void OnPlayerValueCanceled(InputAction.CallbackContext context)
{
var name = context.action.name;
if (name == InputDef.Player.Move)
{
// var v2 = context.ReadValue<Vector2>();
_moveInput = Vector2.zero;
// SendMoveMessage(v2, true);
}
}
private void OnPlayerValuePerformed(InputAction.CallbackContext context)
{
// var mapUnit = Parent as MapUnit;
// Log.Info($"OnPlayerValuePerformed IsSelf={mapUnit.IsSelf()} id={mapUnit.Id}");
var name = context.action.name;
if (name == InputDef.Player.Move)
{
var v2 = context.ReadValue<Vector2>();
_moveInput = v2;
// SendMoveMessage(v2, false);
}
else if (name == InputDef.Player.Look)
{
var v2 = context.ReadValue<Vector2>();
// UpdatePlayerRotation(v2);
}
}
#endregion
#region Move
private void UpdateGrounded()
{
MapUnit.IsGrounded = _Character.IsGrounded();
MapUnit.Speed = _Character.velocity.magnitude;
Quaternion rotation = _Character.transform.rotation;
// 计算当前帧与上一帧的旋转差异
Quaternion rotationDelta = rotation * Quaternion.Inverse(lastRotation);
// 将四元数转换为角度轴表示
rotationDelta.ToAngleAxis(out float angle, out Vector3 axis);
// 确保角度在0-360范围内
if (angle > 180f) angle -= 360f;
// 获取Y轴旋转分量归一化处理
float yRotation = 0f;
if (Mathf.Abs(angle) > 0.001f && Mathf.Abs(axis.y) > 0.1f)
{
// 计算Y轴方向的旋转角度考虑旋转轴方向
yRotation = angle * Mathf.Sign(axis.y);
}
float maxTurnSpeed = 180f; // 度/秒
// 转换为角速度并归一化到[-1, 1]
float angularSpeed = yRotation / Time.deltaTime;
float turnValue = Mathf.Clamp(angularSpeed / maxTurnSpeed, -1f, 1f);
MapUnit.RotationSpeed = turnValue;
lastRotation = rotation;
}
private void UpdateWater()
{
// SceneSettings.Instance.Water.w
}
private void ProcessMoveStates()
{
// if (CameraView.Value == CameraViewType.TPP)
// {
// float num = (IsRunPressed.Value ? MovementSpeed.Value : (MovementSpeed.Value * 0.5f));
// num = (IsFlyModeEnabled ? (num * (float)FlySpeed) : num);
// Vector3 zero = Vector3.zero;
// zero += Vector3.right * MovementDirection.Value.x;
// zero += Vector3.forward * MovementDirection.Value.y;
// zero = zero.relativeTo(_CameraTPPTarget, _Character.GetUpVector());
// _Character.RotateTowards(zero, Time.deltaTime * _RotateTPPSpeed);
// float value = Vector3.Dot(_Character.GetForwardVector(), zero);
// Vector3 vector = _Character.GetForwardVector() * Mathf.Clamp01(value) * num;
// if (checkWaterBound)
// {
// SetMovementDirectionWithRaycastCheck(vector);
// }
// else
// {
// _Character.SetMovementDirection(vector);
// }
// }
// else
{
float num2 = Run ? 7 : 5; //(IsRunPressed.Value ? MovementSpeed.Value : (MovementSpeed.Value * 0.5f));
// num2 = (IsFlyModeEnabled ? (num2 * (float)FlySpeed) : num2);
Vector3 vector2 = _Character.GetRightVector() * _moveInput.x * num2;
vector2 += _Character.GetForwardVector() * _moveInput.y * num2;
// if (checkWaterBound)
// {
// SetMovementDirectionWithRaycastCheck(vector2);
// }
// else
{
_Character.SetMovementDirection(vector2);
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f032bbea4a2a4ab099d2f4800670ad48
timeCreated: 1765282951

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f63b5a4df9be4d1c839c3c1cc56c1275
timeCreated: 1756048419

View File

@@ -0,0 +1,15 @@
using Fantasy.Entitas;
namespace NBF.Fishing2
{
/// <summary>
/// 手电筒组件
/// </summary>
public class UnitFlashlightComponent : Entity
{
/// <summary>
/// 打开手电筒
/// </summary>
public bool OpenLight { get; set; }
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5f151cee0d5f43ff90c3aa013214b1ea
timeCreated: 1756048476

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0f655e37e9dd4b5885e127f44e01100d
timeCreated: 1756048586

View File

@@ -0,0 +1,11 @@
using Fantasy.Entitas;
namespace NBF.Fishing2
{
/// <summary>
/// Unity皮肤组件
/// </summary>
public class UnitSkinComponent : Entity
{
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 40c5cce71c8443aa82ea4108e72c887b
timeCreated: 1756048599

View File

@@ -0,0 +1,22 @@
using Unity.Mathematics;
namespace NBF.Fishing2
{
public struct ChangePosition
{
public MapUnit MapUnit;
public float3 OldPos;
}
public struct ChangeRotation
{
public MapUnit MapUnit;
}
public struct ChangeState
{
public MapUnit MapUnit;
public MapUnitState State;
public string Args;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cd2dd8a7207544b19be4b51b2a6ef215
timeCreated: 1755915609

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b2120457449841468649709d6b193c35
timeCreated: 1756821388

View File

@@ -0,0 +1,113 @@
using Fantasy.Entitas;
using Fantasy.Entitas.Interface;
using NBC;
using UnityEngine;
namespace NBF.Fishing2
{
public class CharacterAnimatorComponent : Entity
{
#region
public static readonly int IsSwiming = Animator.StringToHash("Swim");
public static readonly int ThrowFar = Animator.StringToHash("ThrowFar");
public static readonly int BoatDriving = Animator.StringToHash("BoatDriving");
public static readonly int BaitInWater = Animator.StringToHash("BaitInWater");
public static readonly int HeldRod = Animator.StringToHash("HeldRod");
public static readonly int RodArming = Animator.StringToHash("RodArming");
public static readonly int Forward = Animator.StringToHash("Forward");
public static readonly int Turn = Animator.StringToHash("Turn");
public static readonly int OnGround = Animator.StringToHash("OnGround");
public static readonly int RodRight = Animator.StringToHash("rod right");
public static readonly int RodForward = Animator.StringToHash("rod forward");
public static readonly int PreciseCast = Animator.StringToHash("Precise Cast");
public static readonly int PreciseIdle = Animator.StringToHash("Precise Idle");
public static readonly string Torso = "Torso";
#endregion
public Animator Animator { get; private set; }
public MapUnit MapUnit;
private bool _isTorsoLayerEnabled;
#region System
public class CharacterAnimatorComponentDestroySystem : DestroySystem<CharacterAnimatorComponent>
{
protected override void Destroy(CharacterAnimatorComponent self)
{
}
}
public class CharacterAnimatorComponentAwakeSystem : AwakeSystem<CharacterAnimatorComponent>
{
protected override void Awake(CharacterAnimatorComponent self)
{
self.MapUnit = self.Parent as MapUnit;
var unitUnityComponent = self.Parent.GetComponent<UnitUnityComponent>();
self.Animator = unitUnityComponent.ModelAsset.Animator;
}
}
// public class CharacterAnimatorComponentUpdateSystem : UpdateSystem<CharacterAnimatorComponent>
// {
// protected override void Update(CharacterAnimatorComponent self)
// {
// // self.UpdateAnimator();
// }
// }
public class CharacterAnimatorComponentLateUpdateSystem : LateUpdateSystem<CharacterAnimatorComponent>
{
protected override void LateUpdate(CharacterAnimatorComponent self)
{
self.UpdateAnimator();
}
}
#endregion
private void UpdateAnimator()
{
Animator.SetBool(OnGround, MapUnit.IsGrounded);
float value3 = Mathf.Lerp(Animator.GetFloat(Forward), MapUnit.Speed / 5f, Time.deltaTime * 20f);
Animator.SetFloat(Forward, value3);
// 平滑处理
// float smoothedTurn = Mathf.SmoothDamp(Animator.GetFloat(Turn),
// MapUnit.RotationSpeed,
// ref turnSmoothVelocity,
// smoothingTime
// );
float smoothedTurn = Mathf.Lerp(Animator.GetFloat(Turn), MapUnit.RotationSpeed, Time.deltaTime * 10f);
Animator.SetFloat(Turn, smoothedTurn);
float layerWeight = Animator.GetLayerWeight(Animator.GetLayerIndex(Torso));
SetLayerWeight(Torso,
Mathf.MoveTowards(layerWeight, _isTorsoLayerEnabled ? 1f : 0f, Time.deltaTime * 3f));
}
public void SetLayerWeight(string layer, float weight)
{
Animator.SetLayerWeight(Animator.GetLayerIndex(layer), weight);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8c8042507191477295dbdac2c7dd7c59
timeCreated: 1765353895

View File

@@ -0,0 +1,74 @@
using ECM2;
using ECM2.Examples.FirstPerson;
using Fantasy.Async;
using NBC;
using Fantasy.Entitas;
using Fantasy.Entitas.Interface;
using RootMotion.FinalIK;
using UnityEngine;
namespace NBF.Fishing2
{
/// <summary>
/// Unit 对应的unity对象组件
/// </summary>
public class UnitUnityComponent : Entity
{
public GameObject GameObject { get; set; }
public GameObject ModelGameObject { get; set; }
public Transform Transform { get; set; }
public PlayerModelAsset ModelAsset { get; set; }
public CharacterMovement Character { get; set; }
public FirstPersonCharacter FirstPerson { get; set; }
public PlayerRootAsset RootAsset { get; set; }
#region System
public class UnitUnityComponentDestroySystem : DestroySystem<UnitUnityComponent>
{
protected override void Destroy(UnitUnityComponent self)
{
if (self.GameObject != null)
{
Object.Destroy(self.GameObject);
}
self.ModelAsset = null;
self.GameObject = null;
self.Transform = null;
self.Character = null;
self.FirstPerson = null;
self.RootAsset = null;
}
}
#endregion
public async FTask InitUnityObject()
{
var gameObject = PrefabsHelper.CreatePlayer(SceneSettings.Instance.Node);
GameObject = gameObject;
Transform = gameObject.transform;
Transform.localPosition = new Vector3(484, 1, 422);
Parent.GetOrAddComponent<FlashlightComponent>();
Character = gameObject.GetComponent<CharacterMovement>();
FirstPerson = gameObject.GetComponent<FirstPersonCharacter>();
RootAsset = gameObject.GetComponent<PlayerRootAsset>();
// Parent.GetOrAddComponent<CharacterControllerComponent>();
var modelObject = PrefabsHelper.CreatePlayer(RootAsset.Root, "Human_Male");
modelObject.transform.localPosition = Vector3.zero;
ModelGameObject = modelObject;
ModelAsset = modelObject.GetComponent<PlayerModelAsset>();
Parent.GetOrAddComponent<CharacterMovementComponent>();
Parent.GetOrAddComponent<CharacterLookComponent>();
Parent.GetOrAddComponent<CharacterAnimatorComponent>();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0d2c42a4bc1347cebc390147a1a95c54
timeCreated: 1755921030