导入角色动画,和增加角色控制

This commit is contained in:
2025-12-11 19:30:20 +08:00
parent a60a92e7ba
commit 7775fa30bb
1452 changed files with 592217 additions and 42573 deletions

View File

@@ -0,0 +1,123 @@
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public class BobberBuoyancy : MonoBehaviour
{
[Header("Water")]
public float waterLevel = 0f; // 水面是 0
public Vector3 waterFlow = Vector3.zero;
[Header("Bobber Size (origin at bottom)")]
public float bobberHeight = 0.18f; // 浮漂总高度(底部原点 → 顶部)
[Header("Buoyancy")]
public float maxBuoyancy = 12f; // 完全浸没浮力
public float buoyancyMultiplier = 1.0f;
public float waterDrag = 0.7f;
public float waterAngularDrag = 0.4f;
[Header("Vertical Damping控制“慢慢上浮”避免弹跳")]
public float verticalDamping = 4.0f; // 数值越大,上浮越慢、越不弹
[Header("Upright")]
public float uprightStrength = 8f; // 站漂恢复力
public float uprightDamping = 1.2f;
[Header("Lay Down (躺漂)")]
public float layDownThreshold = 0.15f; // 低于 15% 浸没 → 转入躺漂模式
public float layDownUprightMultiplier = 0.2f; // 躺漂时保留多少站立力度(越小越“翘头”)
private Rigidbody rb;
private void Awake()
{
rb = GetComponent<Rigidbody>();
rb.useGravity = true;
// 重心稍微靠上,配合 AddForceAtPosition才能让“底在水里、头上翘”
rb.centerOfMass = new Vector3(0, bobberHeight * 0.4f, 0);
}
private void FixedUpdate()
{
ApplyBuoyancy();
ApplyFlowForce();
ApplyOrientationControl();
}
void ApplyBuoyancy()
{
float bottom = rb.position.y; // 原点就是最底部
float depth = waterLevel - bottom; // 浸入深度 = 水面 - 底部
if (depth <= 0f) return; // 完全在水面上方,无浮力
// 当前浸没比例
float submersionRatio = Mathf.Clamp01(depth / bobberHeight);
// 基础浮力(和你之前一致)
float baseForce = maxBuoyancy * submersionRatio * buoyancyMultiplier;
// ⭐ 竖直速度(用你原来习惯的 linearVelocity
float vy = rb.linearVelocity.y;
// ⭐ 阻尼项:速度越快,反向力越大
// 下沉很快 → 给一个向上的阻尼(减缓下沉)
// 向上很快 → 给一个向下的阻尼(防止弹出水面)
float damping = -vy * verticalDamping;
// 总的向上力:基础浮力 + 阻尼修正
float totalUpForce = baseForce + damping;
// 物理上浮力不能把它“往下按”,所以最少为 0
if (totalUpForce < 0f) totalUpForce = 0f;
// ⭐ 浮力作用点 = 浸没体积中心(不动,保持你之前的设计)
float clampedDepth = Mathf.Clamp(depth, 0, bobberHeight);
float centerY = bottom + clampedDepth * 0.5f;
Vector3 buoyancyPoint = new Vector3(rb.position.x, centerY, rb.position.z);
rb.AddForceAtPosition(Vector3.up * totalUpForce, buoyancyPoint, ForceMode.Acceleration);
// 水中阻力(保留原逻辑)
rb.AddForce(-rb.linearVelocity * waterDrag, ForceMode.Acceleration);
rb.AddTorque(-rb.angularVelocity * waterAngularDrag, ForceMode.Acceleration);
}
void ApplyFlowForce()
{
if (waterFlow.sqrMagnitude <= 0.0001f) return;
rb.AddForce((waterFlow - rb.linearVelocity) * 0.3f, ForceMode.Acceleration);
}
void ApplyOrientationControl()
{
float bottom = rb.position.y;
float depth = waterLevel - bottom;
float submersionRatio = Mathf.Clamp01(depth / bobberHeight);
Vector3 up = transform.up;
Vector3 worldUp = Vector3.up;
if (submersionRatio > layDownThreshold)
{
// 深浸 → 正常站漂
Vector3 uprightTorqueVec =
Vector3.Cross(up, worldUp) * uprightStrength
- rb.angularVelocity * uprightDamping;
rb.AddTorque(uprightTorqueVec, ForceMode.Acceleration);
}
else
{
// 浅浸 → “躺漂”,只保留少量站立力,让它自然斜、头上翘
float reduced = uprightStrength * layDownUprightMultiplier;
Vector3 uprightTorqueVec =
Vector3.Cross(up, worldUp) * reduced
- rb.angularVelocity * uprightDamping;
rb.AddTorque(uprightTorqueVec, ForceMode.Acceleration);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0d2d3d7643d84524b8841fcf62193a04
timeCreated: 1764424969

View File

@@ -7,14 +7,14 @@ namespace NBF
public int Error { get; set; }
}
/// <summary>
/// 相机模式切换
/// </summary>
public struct CameraChangeMode
{
public CameraShowMode Mode;
public MapUnit Unit;
}
// /// <summary>
// /// 相机模式切换
// /// </summary>
// public struct CameraChangeMode
// {
// public CameraShowMode Mode;
// public MapUnit Unit;
// }
/// <summary>
/// 开始切换场景

View File

@@ -1,4 +1,5 @@
using UnityEngine;
using KWS;
using UnityEngine;
public class SceneSettings : MonoBehaviour
{
@@ -14,6 +15,7 @@ public class SceneSettings : MonoBehaviour
public Transform GearNode;
public KWS_Ocean Water;
// public ObiLateFixedUpdater obiFixedUpdater;

View File

@@ -1,69 +0,0 @@
using Fantasy.Async;
using NBC;
using Fantasy.Entitas;
using Fantasy.Entitas.Interface;
using Fantasy.Event;
using UnityEngine;
namespace NBF.Fishing2
{
public enum CameraShowMode
{
Player,
Free,
}
public class CameraComponent : Entity
{
public CameraShowMode Mode;
public Camera Camera;
public MapUnit MapUnit;
}
public class CameraChangeModeEvent : AsyncEventSystem<CameraChangeMode>
{
protected override async FTask Handler(CameraChangeMode self)
{
var cameraComponent = App.Main.GetComponent<CameraComponent>();
cameraComponent.Mode = self.Mode;
cameraComponent.MapUnit = self.Unit;
cameraComponent.ChangeCameraMode();
await FTask.CompletedTask;
}
}
public static class CameraComponentSystem
{
public class CameraComponentAwakeSystem : AwakeSystem<CameraComponent>
{
protected override void Awake(CameraComponent self)
{
self.Camera = BaseCamera.Main;
}
}
public static void ChangeCameraMode(this CameraComponent self)
{
if (self.Mode == CameraShowMode.Player)
{
if (self.MapUnit != null)
{
var unityComponent = self.MapUnit.GetComponent<UnitUnityComponent>();
if (unityComponent != null)
{
var root = unityComponent.Asset.FPSCamera;
self.Camera.transform.SetParent(root);
self.Camera.transform.localPosition = Vector3.zero;
self.Camera.transform.localRotation = Quaternion.identity;
self.Camera.transform.localScale = Vector3.one;
}
}
}
else if (self.Mode == CameraShowMode.Free)
{
self.Camera.transform.SetParent(null);
}
}
}
}

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,105 @@
using Fantasy.Async;
using Fantasy.Entitas;
using Fantasy.Entitas.Interface;
using Fantasy.Event;
using NBC;
using NBC.Event;
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

@@ -57,6 +57,7 @@ namespace NBF.Fishing2
var map = App.Main.AddComponent<Map>();
map.MapId = mapId;
map.RoomCode = roomCode;
map.SelfId = Game.SelfId;
foreach (var mapUnitInfo in units)
{
map.CreateMapUnit(mapUnitInfo);
@@ -97,20 +98,15 @@ namespace NBF.Fishing2
/// <param name="self"></param>
public static async FTask LoadAllUnit(this Map self)
{
MapUnit mapUnit = null;
foreach (var (_, unit) in self.Units)
{
await unit.CreateView();
if (unit.IsSelf())
{
mapUnit = unit;
}
}
if (mapUnit != null)
var cameraComponent = self.Scene.GetComponent<CameraComponent>();
if (cameraComponent != null)
{
await self.Scene.EventComponent.PublishAsync(new CameraChangeMode()
{ Mode = CameraShowMode.Player, Unit = mapUnit });
cameraComponent.Mode = CameraShowMode.FPP;
}
}

View File

@@ -7,7 +7,7 @@ namespace NBF.Fishing2
{
public static class PrefabsHelper
{
private static GameObject LoadPrefab(string path, Transform parent = null)
public static GameObject LoadPrefab(string path, Transform parent = null)
{
var prefab = Resources.Load<GameObject>(path);
return parent == null ? Object.Instantiate(prefab) : Object.Instantiate(prefab, parent);
@@ -17,10 +17,11 @@ namespace NBF.Fishing2
/// 创建角色预制体
/// </summary>
/// <param name="parent"></param>
/// <param name="modelName"></param>
/// <returns></returns>
public static GameObject CreatePlayer(Transform parent)
public static GameObject CreatePlayer(Transform parent, string modelName = "Player")
{
var model = LoadPrefab("Prefabs/Player/Human_Male", parent);
var model = LoadPrefab($"Prefabs/Player/{modelName}", parent);
return model;
}
@@ -35,7 +36,7 @@ namespace NBF.Fishing2
//创建主物体
var mainObject = LoadPrefab(config.GetFullModelPath());
//创建配件
return mainObject;
}
}

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using Fantasy;
using NBC;
using Fantasy.Entitas;
using Fantasy.Entitas.Interface;
namespace NBF.Fishing2
{
@@ -12,6 +13,11 @@ namespace NBF.Fishing2
public string RoomCode;
/// <summary>
/// 自己的实体id
/// </summary>
public long SelfId;
/// <summary>
/// 好友房地图
/// </summary>
@@ -22,20 +28,26 @@ namespace NBF.Fishing2
/// </summary>
public Dictionary<long, MapUnit> Units = new Dictionary<long, MapUnit>();
/// <summary>
/// 创建地图单位
/// 自己的实体
/// </summary>
public void CreteMapUnit()
public MapUnit SelfMapUnit => GetUnit(SelfId);
#region System
public class MapDestroySystem : DestroySystem<Map>
{
// //创建自己
// var role = Scene.GetComponent<Role>();
// var mapUnitInfo = role.GetMapUnitInfo();
// CreteMapUnit(mapUnitInfo);
//
// //创建其他玩家
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)
{

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

@@ -18,8 +18,8 @@ namespace NBF.Fishing2
{
var numericComponent = self.Parent.GetComponent<NumericComponent>();
var unityComponent = self.Parent.GetComponent<UnitUnityComponent>();
self._fishingLight = unityComponent.Asset.FishingLight;
self.Change(numericComponent[NumericType.Flashlight]);
// self._fishingLight = unityComponent.Asset.FishingLight;
// self.Change(numericComponent[NumericType.Flashlight]);
var mapUnit = self.Parent as MapUnit;
if (mapUnit.IsSelf())

View File

@@ -2,6 +2,7 @@
using Fantasy.Async;
using NBC;
using Fantasy.Entitas;
using Fantasy.Entitas.Interface;
using Unity.Mathematics;
using UnityEngine;
@@ -14,6 +15,19 @@ namespace NBF.Fishing2
{
public int ConfigId { get; set; } //配置表id
/// <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
@@ -45,10 +59,22 @@ namespace NBF.Fishing2
}
}
public uint State { get; set; }
public MapUnitState State { get; set; }
public string StateArgs { get; set; }
public void ChangeState(uint state, string args)
#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 });
}
@@ -68,16 +94,6 @@ namespace NBF.Fishing2
}
}
// public UnitConfig Config()
// {
// return UnitConfig.Get(ConfigId);
// }
//
// public UnitType UnitType()
// {
// return Config().Type;
// }
#region View
public async FTask CreateView()
@@ -91,7 +107,7 @@ namespace NBF.Fishing2
unitUnity = AddComponent<UnitUnityComponent>();
await unitUnity.InitUnityObject();
}
#endregion
}
}

View File

@@ -24,7 +24,7 @@ namespace NBF.Fishing2
public bool IsSelf;
public bool Run;
public CharacterController characterController;
public PlayerAsset PlayerAsset;
public PlayerModelAsset PlayerModelAsset;
public readonly Queue<MoveState> MoveStateQueue = new Queue<MoveState>();
@@ -80,7 +80,7 @@ namespace NBF.Fishing2
}
}
self.PlayerAsset = null;
self.PlayerModelAsset = null;
}
}
@@ -89,7 +89,7 @@ namespace NBF.Fishing2
protected override void Awake(CharacterControllerComponent self)
{
var unitUnityComponent = self.Parent.GetComponent<UnitUnityComponent>();
self.PlayerAsset = unitUnityComponent.Asset;
self.PlayerModelAsset = unitUnityComponent.ModelAsset;
self.characterController = unitUnityComponent.GameObject.GetComponent<CharacterController>();
self.lastSyncedFacing = self.characterController.transform.forward;
// 初始化目标位置和旋转

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,204 @@
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;
float num = Quaternion.Angle(rotation, lastRotation);
// float num2 = Vector3.Cross(lastRotation * Vector3.forward, rotation * Vector3.forward).y > 0f
// ? 1f
// : -1f;
bool flag = num > 0f;
if (!flag)
{
MapUnit.RotationSpeed = Mathf.Lerp(MapUnit.RotationSpeed, 0f, 5 * Time.deltaTime);
}
lastRotation = rotation;
// var TargetMultiplier = 15;
// float num3 = MapUnit.RotationSpeed < 1f ? TargetMultiplier * 5f : TargetMultiplier;
// MapUnit.RotationSpeed += (flag ? 1f : 0f) * num2 * Time.deltaTime *
// (Run ? num3 * 0.075f : num3);
}
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

@@ -16,7 +16,7 @@ namespace NBF.Fishing2
public struct ChangeState
{
public MapUnit MapUnit;
public uint State;
public MapUnitState State;
public string Args;
}
}

View File

@@ -0,0 +1,81 @@
using Fantasy.Entitas;
using Fantasy.Entitas.Interface;
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");
#endregion
public Animator Animator { get; private set; }
public MapUnit MapUnit;
#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();
}
}
#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 value4 = Mathf.Lerp(Animator.GetFloat(Turn), MapUnit.RotationSpeed, Time.deltaTime * 15f);
Animator.SetFloat(Turn, Mathf.Clamp(value4, -1f, 1f));
}
}
}

View File

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

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1228e92e0b3744cdb44cd5144a12b241
timeCreated: 1765283747

View File

@@ -0,0 +1,153 @@
using RootMotion.FinalIK;
using UnityEngine;
namespace NBF
{
public class PlayerIK : MonoBehaviour
{
public enum UpdateType
{
Update = 0,
FixedUpdate = 1,
LateUpdate = 2,
Default = 3
}
public UpdateType UpdateSelected;
[SerializeField] private Transform _LeftHandTransform;
private LookAtIK _LookAtIK;
private AimIK _AimIK;
private FullBodyBipedIK _FullBodyIK;
private ArmIK _ArmIK;
private bool _isLeftHandEnabled;
private bool _isRightHandEnabled;
public bool isAimEnabled;
private bool _isFishingLeftArmEnabled;
[SerializeField] private float transitionWeightTimeScale = 1f;
public Transform CurrentTarget => _FullBodyIK.solver.leftHandEffector.target;
public Transform LeftHandTransform => _LeftHandTransform;
private void Awake()
{
_LookAtIK = GetComponent<LookAtIK>();
_AimIK = GetComponent<AimIK>();
_FullBodyIK = GetComponent<FullBodyBipedIK>();
_ArmIK = GetComponent<ArmIK>();
SetAimIK(enabled: false);
}
public void SetBipedIK(bool enabled)
{
}
public void SetFishingLeftArm(bool enabled)
{
_isFishingLeftArmEnabled = enabled;
}
public void SetFishingLeftArm(bool enabled, Transform target)
{
_isFishingLeftArmEnabled = enabled;
_ArmIK.solver.arm.target = target;
}
public void SetBipedLeftHandIK(bool enabled, bool instant = false)
{
_isLeftHandEnabled = enabled;
if (instant)
{
_FullBodyIK.solver.leftArmMapping.weight = (enabled ? 1f : 0f);
}
}
public void SetBipedRightHandIK(bool enabled, bool instant = false)
{
_isRightHandEnabled = enabled;
if (instant)
{
_FullBodyIK.solver.rightArmMapping.weight = (enabled ? 1f : 0f);
}
}
public void SetBipedLeftHandIK(bool enabled, Transform target, bool instant = false)
{
_isLeftHandEnabled = enabled;
_FullBodyIK.solver.leftHandEffector.target = target;
if (instant)
{
_FullBodyIK.solver.leftArmMapping.weight = (enabled ? 1f : 0f);
}
}
public void SetBipedRightHandIK(bool enabled, Transform target, bool instant = false)
{
_isRightHandEnabled = enabled;
_FullBodyIK.solver.rightHandEffector.target = target;
if (instant)
{
_FullBodyIK.solver.rightArmMapping.weight = (enabled ? 1f : 0f);
}
}
public void SetAimIK(bool enabled)
{
isAimEnabled = enabled;
}
private void Update()
{
if (UpdateSelected == UpdateType.Update)
{
IKUpdateHandler();
}
}
private void FixedUpdate()
{
if (UpdateSelected == UpdateType.FixedUpdate)
{
IKUpdateHandler();
}
}
private void LateUpdate()
{
if (UpdateSelected == UpdateType.LateUpdate)
{
IKUpdateHandler();
}
}
private void IKUpdateHandler()
{
_AimIK.UpdateSolverExternal();
_LookAtIK.UpdateSolverExternal();
_FullBodyIK.UpdateSolverExternal();
_FullBodyIK.solver.Update();
_AimIK.solver.IKPositionWeight = Mathf.MoveTowards(_AimIK.solver.IKPositionWeight, isAimEnabled ? 1f : 0f,
Time.deltaTime * transitionWeightTimeScale);
_FullBodyIK.solver.leftArmMapping.weight = Mathf.MoveTowards(_FullBodyIK.solver.leftArmMapping.weight,
_isLeftHandEnabled ? 1f : 0f, Time.deltaTime * transitionWeightTimeScale);
_FullBodyIK.solver.rightArmMapping.weight = Mathf.MoveTowards(_FullBodyIK.solver.rightArmMapping.weight,
_isRightHandEnabled ? 1f : 0f, Time.deltaTime * transitionWeightTimeScale);
_FullBodyIK.solver.IKPositionWeight = Mathf.MoveTowards(_FullBodyIK.solver.IKPositionWeight,
_isLeftHandEnabled ? 1f : 0f, Time.deltaTime * transitionWeightTimeScale);
_ArmIK.solver.IKPositionWeight = Mathf.MoveTowards(_ArmIK.solver.IKPositionWeight,
_isFishingLeftArmEnabled ? 1f : 0f, Time.deltaTime * transitionWeightTimeScale);
_ArmIK.solver.IKRotationWeight = Mathf.MoveTowards(_ArmIK.solver.IKRotationWeight,
_isFishingLeftArmEnabled ? 1f : 0f, Time.deltaTime * transitionWeightTimeScale);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cb36ecc5b1784d948837600cf18808cd
timeCreated: 1765121426

View File

@@ -0,0 +1,12 @@
using UnityEngine;
namespace NBF.Fishing2
{
public class PlayerRootAsset : MonoBehaviour
{
public Transform Root;
public Transform Eye;
public Transform FppLook;
public Transform IK;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 95ffc3d5f1c94a59aab905ba2d3e5de0
timeCreated: 1765286777

View File

@@ -1,4 +1,6 @@
using Fantasy.Async;
using ECM2;
using ECM2.Examples.FirstPerson;
using Fantasy.Async;
using NBC;
using Fantasy.Entitas;
using Fantasy.Entitas.Interface;
@@ -13,22 +15,18 @@ namespace NBF.Fishing2
public class UnitUnityComponent : Entity
{
public GameObject GameObject { get; set; }
public GameObject ModelGameObject { get; set; }
public Transform Transform { get; set; }
public PlayerAsset Asset { get; set; }
public PlayerModelAsset ModelAsset { get; set; }
public async FTask InitUnityObject()
{
var gameObject = PrefabsHelper.CreatePlayer(SceneSettings.Instance.Node);
GameObject = gameObject;
Transform = gameObject.transform;
Transform.localPosition = new Vector3(484, 1, 422);
Asset = gameObject.GetComponent<PlayerAsset>();
Parent.GetOrAddComponent<FlashlightComponent>();
Parent.GetOrAddComponent<CharacterControllerComponent>();
}
public CharacterMovement Character { get; set; }
public FirstPersonCharacter FirstPerson { get; set; }
public PlayerRootAsset RootAsset { get; set; }
#region System
public class UnitUnityComponentDestroySystem : DestroySystem<UnitUnityComponent>
{
@@ -39,10 +37,38 @@ namespace NBF.Fishing2
Object.Destroy(self.GameObject);
}
self.Asset = null;
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

@@ -2,360 +2,104 @@
public class FloatBobberController : MonoBehaviour
{
[Header("水属性")]
public float waterLevel = 0f;
[Header("浮漂属性")]
public float bobberVolume = 30f; // 浮漂最大排水体积 (cm³)
public float bobberMass = 1f; // 浮漂自重 (g)
public float bobberHeight = 0.25f; // 浮漂总高度
[Range(0, 1)] public float bobberFloatPartRatio = 0.7f; // 浮漂浮体部分占总高度的比例
[Header("配件重量")]
public float sinkerWeight = 2f;
[SerializeField] private Rigidbody _rigidbody;
[Header("水属性")] public float waterLevel = 0f;
[Header("浮漂最大浮力")] public float bobberVolume = 30f; // 浮漂最大浮力 (cm³)
public float bobberHeight = 0.25f; // 浮漂长度,用来决定躺漂角度
[Header("配件重量")] public float sinkerWeight = 2f;
public float baitWeight = 0.5f;
public float hookWeight = 0.2f;
[Header("行为参数")]
public float fallSpeed = 8f;
[Header("Behaviour")] public float fallSpeed = 8f;
public float riseSpeed = 3f;
public float smoothDamping = 8f;
// 私有变量
private float totalDownwardWeight;
private float maxBuoyancyForce;
private float currentSubmergedLength; // 当前浸没长度
private float bobberFloatPartHeight; // 浮体部分高度
// 浮漂状态
private float currentBuoyancy; // 当前实际浮力
private Vector3 targetPosition;
// 冲击力相关
private float impulseForce = 0f;
private float impulseDecay = 4f;
// public float smoothDamping = 8f; // 插值平滑
void Start()
{
InitializeBobber();
}
[Header("Noise")] public float noiseAmp = 0.015f;
public float noiseFreq = 1.5f;
void InitializeBobber()
{
// 计算浮体部分高度(能够产生浮力的部分)
bobberFloatPartHeight = bobberHeight * bobberFloatPartRatio;
// 最大浮力 = 浮体部分完全浸没时的排水量
maxBuoyancyForce = bobberFloatPartHeight * 100f; // 简化计算,可根据需要调整系数
// 初始位置调整:让浮漂底部刚好在水面
Vector3 pos = transform.position;
pos.y = waterLevel - (bobberHeight * 0.5f); // 假设原点在中心,调整到浮漂底部在水面
transform.position = pos;
RecalculateWeights();
}
float impulseForce = 0f;
float impulseDecay = 4f;
void FixedUpdate()
{
SimulateBobber();
}
void RecalculateWeights()
{
totalDownwardWeight = bobberMass + sinkerWeight + baitWeight + hookWeight;
}
void SimulateBobber()
{
RecalculateWeights();
if (!_rigidbody.isKinematic) return;
float totalDownwardWeight = sinkerWeight + baitWeight + hookWeight;
float maxBuoyancy = bobberVolume; // 最大浮力 = 体积
float netBuoyancy = maxBuoyancy - totalDownwardWeight;
float targetY;
// -------------------------
// 1. 计算当前浸没长度和浮力
// 1. 判断浮漂应该沉多少(吃水深度)
// -------------------------
// 浮漂的基准位置(底部位置)
float bobberBottomY = transform.position.y;
float bobberTopY = bobberBottomY + bobberHeight;
// 计算浸没长度浮漂底部到水面的距离限制在0到浮体高度之间
float submergedLength = Mathf.Clamp(waterLevel - bobberBottomY, 0f, bobberFloatPartHeight);
currentSubmergedLength = submergedLength;
// 当前浮力 = (浸没长度 / 浮体高度) * 最大浮力
float submergedRatio = submergedLength / bobberFloatPartHeight;
currentBuoyancy = submergedRatio * maxBuoyancyForce;
// -------------------------
// 2. 计算净力并决定运动
// -------------------------
float netForce = currentBuoyancy - totalDownwardWeight;
// 目标Y位置基于净力计算
float targetY = transform.position.y;
if (Mathf.Abs(netForce) < 0.01f) // 基本平衡
if (netBuoyancy > 0)
{
// 保持当前位置,微小波动可以在这里添加
targetY = transform.position.y;
float buoyPercent = Mathf.Clamp01(netBuoyancy / maxBuoyancy);
float rise = buoyPercent * 0.1f; // 浮漂露出水面的高度
targetY = waterLevel + rise;
}
else if (netForce > 0) // 浮力大于重力,上浮
else
{
float riseAmount = netForce * 0.001f * riseSpeed;
targetY += riseAmount * Time.deltaTime;
// 限制不能浮出太多(露出部分不能超过非浮体部分)
float maxBobberTopY = waterLevel + (bobberHeight - bobberFloatPartHeight);
if (bobberTopY + riseAmount > maxBobberTopY)
{
targetY = maxBobberTopY - bobberHeight;
}
// 净浮力为负 → 说明浮漂整体被拉下,沉入水中
float sinkDistance = Mathf.Abs(netBuoyancy) * 0.03f;
targetY = waterLevel - sinkDistance;
}
else // 重力大于浮力,下沉
{
float sinkAmount = Mathf.Abs(netForce) * 0.001f * fallSpeed;
targetY -= sinkAmount * Time.deltaTime;
// 限制不能沉没太多(浮体部分完全浸没后浮力达到最大)
float minBobberBottomY = waterLevel - bobberFloatPartHeight;
if (bobberBottomY - sinkAmount < minBobberBottomY)
{
targetY = minBobberBottomY;
}
}
// -------------------------
// 3. 应用冲击力
// -------------------------
if (Mathf.Abs(impulseForce) > 0.01f)
targetY += Mathf.Sin(Time.time * noiseFreq) * noiseAmp; // 微扰模拟波浪
// 顿口/顶漂力
if (impulseForce != 0f)
{
targetY += impulseForce * Time.deltaTime;
impulseForce = Mathf.Lerp(impulseForce, 0, Time.deltaTime * impulseDecay);
}
// -------------------------
// 4. 平滑移动
// -------------------------
targetPosition = new Vector3(transform.position.x, targetY, transform.position.z);
transform.position = Vector3.Lerp(transform.position, targetPosition, Time.deltaTime * smoothDamping);
// 调试信息
DebugDisplay();
}
void DebugDisplay()
{
Debug.Log($"浸没比例: {(currentSubmergedLength / bobberFloatPartHeight):P1} " +
$"当前浮力: {currentBuoyancy:F2} " +
$"总重力: {totalDownwardWeight:F2} " +
$"净力: {currentBuoyancy - totalDownwardWeight:F2}");
}
// ----------------------------------------
// 公共方法 - 用于调漂和鱼咬钩
// ----------------------------------------
/// <summary>
/// 调整配重(用于调漂)
/// </summary>
public void AdjustSinkerWeight(float newWeight)
{
sinkerWeight = newWeight;
RecalculateWeights();
}
/// <summary>
/// 获取当前调目(浮漂露出水面的格数)
/// </summary>
public float GetCurrentVisibleMarks()
{
float bobberBottomY = transform.position.y;
float visibleHeight = (bobberBottomY + bobberHeight) - waterLevel;
float markHeight = bobberHeight / 10f; // 假设浮漂有10格
return Mathf.Max(0, visibleHeight / markHeight);
}
/// <summary>
/// 设置目标调目(自动计算需要的配重)
/// </summary>
public void SetTargetMarks(float targetMarks)
{
float markHeight = bobberHeight / 10f;
float targetVisibleHeight = targetMarks * markHeight;
float targetSubmergedLength = bobberFloatPartHeight - targetVisibleHeight;
// 需要的浮力 = (浸没长度 / 浮体高度) * 最大浮力
float requiredBuoyancy = (targetSubmergedLength / bobberFloatPartHeight) * maxBuoyancyForce;
// 配重 = 浮漂自重 + 钩饵重 - 需要的浮力
float requiredSinkerWeight = bobberMass + hookWeight + baitWeight - requiredBuoyancy;
sinkerWeight = Mathf.Max(0, requiredSinkerWeight);
RecalculateWeights();
// -----------------------------
// ③ 上浮 / 下沉差速
// -----------------------------
float y = transform.position.y;
float diff = targetY - y;
if (diff > 0) // 上浮
y += diff * Time.deltaTime * riseSpeed;
else
y += diff * Time.deltaTime * fallSpeed;
transform.position = new Vector3(transform.position.x, y, transform.position.z);
}
// ----------------------------------------
// 鱼咬钩相关方法
// 外部控制接口
// ----------------------------------------
public void TriggerDownPulse(float strength = 0.8f)
public void TriggerDownPulse(float s = 0.8f)
{
impulseForce -= Mathf.Abs(strength);
impulseForce -= Mathf.Abs(s);
}
public void TriggerUpPulse(float strength = 0.8f)
public void TriggerUpPulse(float s = 0.8f)
{
impulseForce += Mathf.Abs(strength);
impulseForce += Mathf.Abs(s);
}
public void AddFishPull(float pullForce)
public void AddFishPull(float v)
{
// 鱼的拉力相当于增加向下的力
sinkerWeight += pullForce;
sinkerWeight += v;
}
public void ReleaseFishPull(float pullForce)
public void ReleaseFishPull(float v)
{
sinkerWeight -= pullForce;
sinkerWeight -= v;
}
// ----------------------------------------
// 可视化调试
// ----------------------------------------
void OnDrawGizmos()
{
// 绘制水面
Gizmos.color = Color.blue;
Gizmos.DrawLine(new Vector3(-1, waterLevel, 0), new Vector3(1, waterLevel, 0));
// 绘制浮漂
if (Application.isPlaying)
{
// 浸没部分用蓝色
Gizmos.color = Color.cyan;
float submergedBottom = transform.position.y;
float submergedTop = submergedBottom + currentSubmergedLength;
Gizmos.DrawWireCube(
new Vector3(transform.position.x, (submergedBottom + submergedTop) * 0.5f, transform.position.z),
new Vector3(0.1f, currentSubmergedLength, 0.1f)
);
// 露出部分用红色
Gizmos.color = Color.red;
float visibleBottom = submergedTop;
float visibleTop = transform.position.y + bobberHeight;
float visibleHeight = visibleTop - visibleBottom;
if (visibleHeight > 0)
{
Gizmos.DrawWireCube(
new Vector3(transform.position.x, (visibleBottom + visibleTop) * 0.5f, transform.position.z),
new Vector3(0.1f, visibleHeight, 0.1f)
);
}
}
}
}
// using UnityEngine;
//
// public class FloatBobberController : MonoBehaviour
// {
// [Header("水属性")] public float waterLevel = 0f;
// [Header("浮漂最大浮力")] public float bobberVolume = 30f; // 浮漂最大浮力 (cm³)
// [Header("浮漂自重")] public float bobberMass = 1f; // 浮漂自重 (g)
// public float bobberHeight = 0.25f; // 浮漂长度,用来决定躺漂角度
//
// [Header("配件重量")] public float sinkerWeight = 2f;
// public float baitWeight = 0.5f;
// public float hookWeight = 0.2f;
//
// [Header("Behaviour")] public float fallSpeed = 8f;
// public float riseSpeed = 3f;
// public float smoothDamping = 8f; // 插值平滑
//
// // [Header("Noise")] public float noiseAmp = 0.015f;
// // public float noiseFreq = 1.5f;
//
// float impulseForce = 0f;
// float impulseDecay = 4f;
//
// void FixedUpdate()
// {
// SimulateBobber();
// }
//
// void SimulateBobber()
// {
// float totalDownwardWeight = bobberMass + sinkerWeight + baitWeight + hookWeight;
//
// float maxBuoyancy = bobberVolume; // 最大浮力 = 体积
// float netBuoyancy = maxBuoyancy - totalDownwardWeight;
//
// float targetY;
//
// // -------------------------
// // 1. 判断浮漂应该沉多少(吃水深度)
// // -------------------------
// if (netBuoyancy > 0)
// {
// float buoyPercent = Mathf.Clamp01(netBuoyancy / maxBuoyancy);
// float rise = buoyPercent * 0.1f; // 浮漂露出水面的高度
//
// targetY = waterLevel + rise;
//
// // targetY += Mathf.Sin(Time.time * noiseFreq) * noiseAmp; // 微扰模拟波浪
// }
// else
// {
// // 净浮力为负 → 说明浮漂整体被拉下,沉入水中
// float sinkDistance = Mathf.Abs(netBuoyancy) * 0.03f;
// targetY = waterLevel - sinkDistance;
// }
//
// // 顿口/顶漂力
// if (impulseForce != 0f)
// {
// targetY += impulseForce * Time.deltaTime;
// impulseForce = Mathf.Lerp(impulseForce, 0, Time.deltaTime * impulseDecay);
// }
//
// // -----------------------------
// // ③ 上浮 / 下沉差速
// // -----------------------------
// float y = transform.position.y;
// float diff = targetY - y;
//
// if (diff > 0) // 上浮
// y += diff * Time.deltaTime * riseSpeed;
// else
// y += diff * Time.deltaTime * fallSpeed;
//
// transform.position = new Vector3(transform.position.x, y, transform.position.z);
// }
//
//
// // ----------------------------------------
// // 外部控制接口
// // ----------------------------------------
//
// public void TriggerDownPulse(float s = 0.8f)
// {
// impulseForce -= Mathf.Abs(s);
// }
//
// public void TriggerUpPulse(float s = 0.8f)
// {
// impulseForce += Mathf.Abs(s);
// }
//
// public void AddFishPull(float v)
// {
// sinkerWeight += v;
// }
//
// public void ReleaseFishPull(float v)
// {
// sinkerWeight -= v;
// }
// }
}

View File

@@ -7,26 +7,28 @@ namespace NBF
public class Game : MonoBehaviour
{
public static Game Instance { get; private set; }
public static InputComponent Input;
/// <summary>
/// 主摄像机
/// </summary>
public static Camera MainCamera { get; private set; }
/// <summary>
/// 摄像机配置
/// </summary>
// public static CameraScriptObject CameraConfig { get; private set; }
/// <summary>
/// 自身的unit id
/// </summary>
public static long SelfId;
private void Awake()
{
Instance = this;
// CameraConfig = Resources.Load<CameraScriptObject>(nameof(CameraConfig));
}
}
}

View File

@@ -1,94 +0,0 @@
using System;
using RootMotion.FinalIK;
using UnityEngine;
namespace NBF
{
public enum PlayerState
{
idle = 0,
move = 1,
prepare = 2,
casting = 3,
fishing = 4,
baitFlies = 5,
fight = 6,
fishView = 7,
collectFish = 8,
throwFish = 9,
vehicle = 10,
swiming = 11,
flyModeDebug = 12,
vehicleFishing = 13,
preciseCastIdle = 14,
preciseCastThrow = 15
}
public class PlayerAsset : MonoBehaviour
{
public Transform FPSCamera;
public GameObject FishingLight;
public Animator Animator { get; private set; }
public LookAtIK LookAtIK { get; private set; }
public CharacterController CharacterController { get; private set; }
public Rigidbody Rigidbody { get; private set; }
#region
#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");
#endregion
#region
/// <summary>
/// 抛竿开始
/// </summary>
public void RodForceThrowStart()
{
// if (Player.Fsm.CurrentState is PlayerThrow playerThrow)
// {
// playerThrow.RodForceThrowStart();
// }
}
#endregion
#endregion
private void Awake()
{
Animator = GetComponent<Animator>();
LookAtIK = GetComponent<LookAtIK>();
CharacterController = GetComponent<CharacterController>();
Rigidbody = GetComponent<Rigidbody>();
LookAtIK.enabled = false;
}
}
}

View File

@@ -0,0 +1,47 @@
using System;
using KINEMATION.MagicBlend.Runtime;
using RootMotion.FinalIK;
using UnityEngine;
namespace NBF
{
public enum PlayerState
{
idle = 0,
move = 1,
prepare = 2,
casting = 3,
fishing = 4,
baitFlies = 5,
fight = 6,
fishView = 7,
collectFish = 8,
throwFish = 9,
vehicle = 10,
swiming = 11,
flyModeDebug = 12,
vehicleFishing = 13,
preciseCastIdle = 14,
preciseCastThrow = 15
}
public class PlayerModelAsset : MonoBehaviour
{
public Animator Animator { get; private set; }
public PlayerIK IK { get; private set; }
public MagicBlending MagicBlending { get; private set; }
public Transform NeckTransform;
public LookAtIK LookIk;
private void Awake()
{
LookIk = GetComponent<LookAtIK>();
Animator = GetComponent<Animator>();
Animator.keepAnimatorStateOnDisable = true;
MagicBlending = GetComponent<MagicBlending>();
IK = GetComponent<PlayerIK>();
}
}
}

View File

@@ -13,8 +13,14 @@ namespace NBF
private void Awake()
{
#if CINEMACHINE_URP
int i = 0;
#endif
Init();
DontDestroyOnLoad(gameObject);
DepthOfField dof = ScriptableObject.CreateInstance<DepthOfField>();
dof.aperture.value = 0;
dof.focalLength.value = 0;
}
public void Init()

View File

@@ -0,0 +1,22 @@
namespace NBF
{
public enum MapUnitState
{
idle = 0,
move = 1,
prepare = 2,
casting = 3,
fishing = 4,
baitFlies = 5,
fight = 6,
fishView = 7,
collectFish = 8,
throwFish = 9,
vehicle = 10,
swiming = 11,
flyModeDebug = 12,
vehicleFishing = 13,
preciseCastIdle = 14,
preciseCastThrow = 15
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6a25ab9f9b4140c7bd3e463da484301e
timeCreated: 1765284104

View File

@@ -80,7 +80,7 @@ namespace NBF
Log.Warning("账号没有进入过地图,进入新手引导地图");
mapId = 99;
}
// await MapHelper.EnterMap(mapId, role.RoomCode);
await MapHelper.EnterMap(mapId, role.RoomCode);
}
}
}

View File

@@ -18,6 +18,10 @@ namespace NBC
public string Get(string key)
{
if (string.IsNullOrEmpty(key))
{
return string.Empty;
}
if (_currentLanguageDictionary != null && _currentLanguageDictionary.TryGetValue(key, out var value))
{
return value;

View File

@@ -17,6 +17,7 @@ namespace NBF.Fishing2
scene.AddComponent<ObjectWait>();
scene.AddComponent<MapManageComponent>();
scene.AddComponent<CameraComponent>();
scene.AddComponent<CursorComponent>();
var input = scene.AddComponent<InputComponent>();
scene.AddComponent<SettingComponent>();

View File

@@ -47,7 +47,7 @@ namespace NBF
if (action == InputDef.UI.Back)
{
if (!IsTop) return;
HomePanel.Show();
// HomePanel.Show();
}
}

View File

@@ -32,7 +32,7 @@ namespace NBF
// BagPanel.Show();
// BagSlotPanel.Show();
FishingShopPanel.Show();
// FishingShopPanel.Show();
Del();
}