首次提交

This commit is contained in:
Bob.Song
2026-03-05 18:07:55 +08:00
commit e125bb869e
4534 changed files with 563920 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: dcae353a013f4bd8bd4818abbcbe6959
timeCreated: 1766743259

View File

@@ -0,0 +1,55 @@
using UnityEngine;
namespace NBF
{
public class ReelAnimator : MonoBehaviour
{
public FReel Reel;
private Animator _animator;
#region
private static readonly int ReelingHash = Animator.StringToHash("Reeling");
private static readonly int LineOutHash = Animator.StringToHash("LineOut");
private static readonly int UnlockHash = Animator.StringToHash("Unlock");
private static readonly int LineOutUnlockHash = Animator.StringToHash("LineOutUnlock");
public float Reeling
{
get => _animator.GetFloat(ReelingHash);
set => _animator.SetFloat(ReelingHash, value);
}
public float Reeling2
{
get => _animator.GetFloat(ReelingHash);
set => _animator.SetFloat(ReelingHash, value);
}
public float LineOut
{
get => _animator.GetFloat(LineOutHash);
set => _animator.SetFloat(LineOutHash, value);
}
public bool Unlock
{
get => _animator.GetBool(UnlockHash);
set => _animator.SetBool(UnlockHash, value);
}
public bool LineOutUnlock
{
get => _animator.GetBool(LineOutUnlockHash);
set => _animator.SetBool(LineOutUnlockHash, value);
}
#endregion
private void Awake()
{
_animator = GetComponent<Animator>();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: dad5b24d68464595b58a0d8fea28a10b
timeCreated: 1766743262

View File

@@ -0,0 +1,38 @@
using UnityEngine;
namespace NBF
{
public class BobberController : MonoBehaviour
{
[SerializeField] private Rigidbody _rbody;
[SerializeField] private ConfigurableJoint joint;
// [SerializeField] private Buoyancy _buoyancy;
public Rigidbody rbody => _rbody;
public void SetJoint(Rigidbody rb)
{
joint = joint == null ? GetComponent<ConfigurableJoint>() : joint;
joint.connectedBody = rb;
}
public void SetJointDistance(float limit)
{
joint.linearLimit = new SoftJointLimit
{
limit = limit
};
}
public void SetDetectCollisionEnabled(bool en)
{
_rbody.detectCollisions = en;
// _buoyancy.EnablePhysics(en);
}
public void SetVelocity(Vector3 velocity)
{
_rbody.linearVelocity = velocity;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8e9411b5edc6466a8014c59e3821bbaa
timeCreated: 1768918059

View File

@@ -0,0 +1,63 @@
using System.Collections.Generic;
using Fantasy;
using Fantasy.Async;
using NBF.Fishing2;
using RootMotion.FinalIK;
using Log = NBC.Log;
namespace NBF
{
public class Fishing
{
public FPlayer Player { get; private set; }
private static Fishing _instance;
public static Fishing Instance
{
get
{
_instance ??= new Fishing();
return _instance;
}
}
public async FTask<bool> Go(int mapId, string roomCode = "")
{
if (mapId == 0)
{
Log.Warning("账号没有进入过地图,进入新手引导地图");
mapId = 99;
}
var response = (G2C_EnterMapResponse)await Net.Call(new C2G_EnterMapRequest()
{
MapId = mapId,
RoomCode = roomCode
});
Log.Info($"进入地图请求返回={response.ErrorCode}");
LoadingPanel.Show();
await ChangeMap(response.MapId, response.RoomCode, response.Units);
LoadingPanel.Hide();
return true;
}
public async FTask ChangeMap(int mapId, string roomCode, List<MapUnitInfo> units)
{
var sceneName = "Map1";
//加载场景==
await SceneHelper.LoadScene(sceneName);
CreateUnit();
}
private void CreateUnit()
{
var gameObject = PrefabsHelper.CreatePlayer(SceneSettings.Instance.Node);
Player = gameObject.GetComponent<FPlayer>();
CameraManager.Instance.Mode = CameraShowMode.FPP;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0afcee9eb5f848e08b2fae2cc673b6d8
timeCreated: 1766414593

View File

@@ -0,0 +1,7 @@
namespace NBF
{
public class FishingMap
{
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c361da1bcda647eb96fa27af894d2a7a
timeCreated: 1766417823

View File

@@ -0,0 +1,33 @@
using System;
using UnityEngine;
namespace NBF
{
public class FixedLine : MonoBehaviour
{
public Transform target;
private Rigidbody _rigidbody;
private void Awake()
{
_rigidbody = GetComponent<Rigidbody>();
}
private void LateUpdate()
{
FixLine();
}
private void FixedUpdate()
{
FixLine();
}
private void FixLine()
{
if (!target) return;
_rigidbody.MovePosition(target.position);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ec22ad0246c24123a6511e60e753ee38
timeCreated: 1766586205

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b4177c0c4cf94787b06ec92973ba4722
timeCreated: 1766412118

View File

@@ -0,0 +1,67 @@
using Fantasy;
using Fantasy.Async;
using Fantasy.Network;
using NBC;
using NBF.Fishing2;
using Newtonsoft.Json;
using Log = NBC.Log;
namespace NBF
{
public static class LoginHelper
{
private static Session _session;
public static async FTask Login(string account)
{
_session = Net.CreateSession("127.0.0.1:20001");
// _session.Scene.AddComponent<UnitUnityComponent>();
var acc = account;
// 发送登录的请求给服务器
var response = (A2C_LoginResponse)await Net.Call(new C2A_LoginRequest()
{
Username = acc,
Password = acc,
LoginType = 1
});
if (response.ErrorCode != 0)
{
Log.Error($"登录发生错误{response.ErrorCode}");
return;
}
if (!Game.Main.GetComponent<JWTParseComponent>().Parse(response.ToKen, out var payload))
{
return;
}
// 根据ToKen返回的Address登录到Gate服务器
_session = Net.CreateSession(payload.Address);
// 发送登录请求到Gate服务器
var loginResponse = (G2C_LoginResponse)await Net.Call(new C2G_LoginRequest()
{
ToKen = response.ToKen
});
if (loginResponse.ErrorCode != 0)
{
Log.Error($"登录发生错误{loginResponse.ErrorCode}");
return;
}
// var role = Game.Main.AddComponent<Role>(loginResponse.RoleId);
RoleModel.Instance.Id = loginResponse.RoleId;
Log.Info($"登录到Gate服务器成功ErrorCode:{loginResponse.ErrorCode}");
await RoleModel.Instance.GetRoleInfo();
Log.Info(
$"获取角色信息成功roleId={RoleModel.Instance.Id} Room={RoleModel.Instance.RoomCode} RoleInfo={JsonConvert.SerializeObject(RoleModel.Instance.Info)}");
//获取背包数据
await RoleModel.Instance.GetBagInfo();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 031ed023449844cdb9d6c4eb5d7fee90
timeCreated: 1755698636

View File

@@ -0,0 +1,115 @@
// using System;
// using System.Collections.Generic;
// using Fantasy;
// using Fantasy.Async;
// using NBC;
// using Fantasy.Entitas;
// using UnityEngine;
// using Log = NBC.Log;
// using Object = System.Object;
//
// namespace NBF.Fishing2
// {
// public static class MapHelper
// {
// #region Map
//
// /// <summary>
// /// 开始进入地图
// /// </summary>
// public static async FTask<int> EnterMap(int mapId, string roomCode = "")
// {
// try
// {
// var root = Game.Main;
//
// var response = (G2C_EnterMapResponse)await Net.Call(new C2G_EnterMapRequest()
// {
// MapId = mapId,
// RoomCode = roomCode
// });
// Log.Info($"进入地图请求返回={response.ErrorCode}");
//
// await ChangeMap(response.MapId, response.RoomCode, response.Units);
// // 等待场景切换完成
// // await root.GetComponent<ObjectWait>().Wait<Wait_SceneChangeFinish>();
// Log.Info($"等待场景切换结束");
// await root.EventComponent.PublishAsync(new EnterMapFinish());
// LoadingPanel.Hide();
// }
// catch (Exception e)
// {
// Log.Error(e);
// return ErrorCode.Error;
// }
//
// return ErrorCode.Success;
// }
//
//
// public static async FTask ChangeMap(int mapId, string roomCode, List<MapUnitInfo> units)
// {
// LoadingPanel.Show();
//
// var oldMap = App.Main.GetComponent<Map>();
// await oldMap.UnLoadMap();
//
// var map = App.Main.AddComponent<Map>();
// map.MapId = mapId;
// map.RoomCode = roomCode;
// map.SelfId = Game.SelfId;
// foreach (var mapUnitInfo in units)
// {
// map.CreateMapUnit(mapUnitInfo);
// }
//
// await map.LoadMap();
// }
//
//
// /// <summary>
// /// 卸载旧场景
// /// </summary>
// /// <param name="self"></param>
// public static async FTask UnLoadMap(this Map self)
// {
// await FTask.CompletedTask;
// }
//
// public static async FTask LoadMap(this Map self)
// {
// var sceneName = "Map1";
// //加载场景==
// await SceneHelper.LoadScene(sceneName);
// await self.LoadAllUnit();
// FishingPanel.Show();
//
// // 通知等待场景切换的协程
// App.Main.GetComponent<ObjectWait>().Notify(new Wait_SceneChangeFinish());
// }
//
// #endregion
//
// #region Unit
//
// /// <summary>
// /// 加载所有unit单位
// /// </summary>
// /// <param name="self"></param>
// public static async FTask LoadAllUnit(this Map self)
// {
// foreach (var (_, unit) in self.Units)
// {
// await unit.CreateView();
// }
//
// var cameraComponent = self.Scene.GetComponent<CameraComponent>();
// if (cameraComponent != null)
// {
// cameraComponent.Mode = CameraShowMode.FPP;
// }
// }
//
// #endregion
// }
// }

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: dfc04c7d83084b7784cb7cf69dde1be6
timeCreated: 1756132207

View File

@@ -0,0 +1,48 @@
using Fantasy;
using NBC;
using NBC.Asset;
using NBF.Utils;
using UnityEngine;
namespace NBF.Fishing2
{
public static class PrefabsHelper
{
public static GameObject LoadPrefab(string path, Transform parent = null)
{
var prefab = Assets.Load<GameObject>(path);
if (prefab == null)
{
}
return parent == null ? Object.Instantiate(prefab) : Object.Instantiate(prefab, parent);
}
/// <summary>
/// 创建角色预制体
/// </summary>
/// <param name="parent"></param>
/// <param name="modelName"></param>
/// <returns></returns>
public static GameObject CreatePlayer(Transform parent, string modelName = "Player")
{
var model = LoadPrefab($"Assets/ResRaw/Prefabs/Player/{modelName}.prefab", parent);
return model;
}
/// <summary>
/// 创建物品预制体
/// </summary>
/// <param name="config"></param>
/// <param name="isPreview">是否预览模式</param>
/// <returns></returns>
public static GameObject CreateItem(cfg.Item config, bool isPreview = false)
{
//创建主物体
var mainObject = LoadPrefab(config.GetFullModelPath());
//创建配件
return mainObject;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 18ffcf16981040b2a88990281adcb4ac
timeCreated: 1756451102

View File

@@ -0,0 +1,39 @@
using System;
using Fantasy.Async;
using NBC;
using UnityEngine.SceneManagement;
namespace NBF
{
public static class SceneHelper
{
public static async FTask LoadScene(string sceneName)
{
try
{
Game.Main.EventComponent.Publish(new SceneChangeStart());
LoadingPanel.Show();
var asyncOperation = SceneManager.LoadSceneAsync(sceneName);
if (asyncOperation == null) throw new Exception($"Scene not found,name={sceneName}");
while (true)
{
await Game.Main.EventComponent.PublishAsync(new LoadingProgress()
{
Progress = asyncOperation.progress
});
LoadingPanel.SetProgress(asyncOperation.progress);
// 等待0.5秒后执行下面的逻辑。
await Game.Main.TimerComponent.Net.WaitAsync(500);
if (asyncOperation.isDone)
{
break;
}
}
}
catch (Exception e)
{
Log.Error(e);
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d4a2e9c0ac6d4faabbec4bccdb7a2917
timeCreated: 1756367987

View File

@@ -0,0 +1,41 @@
using UnityEngine;
namespace NBF
{
public class LureController : MonoBehaviour
{
[SerializeField] private Rigidbody rBody;
[SerializeField] private ConfigurableJoint joint;
public Rigidbody RBody => rBody;
public ConfigurableJoint Joint => joint;
public void SetJoint(Rigidbody rb)
{
joint.connectedBody = rb;
}
public void EnableCollision(bool enable)
{
if (rBody == null)
{
rBody = GetComponent<Rigidbody>();
}
rBody.detectCollisions = enable;
}
public void SetKinematic(bool value)
{
rBody.isKinematic = value;
}
public void SetJointDistance(float limit)
{
joint.linearLimit = new SoftJointLimit
{
limit = limit
};
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ed5bbbc032ec4ca1bb56991d9141e311
timeCreated: 1768918224

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4f89752d44de4cf798a163bf6a554e8e
timeCreated: 1766419447

View File

@@ -0,0 +1,93 @@
using NBC;
using NBF.Utils;
using UnityEngine;
using UnityEngine.InputSystem;
namespace NBF
{
public partial class FPlayer
{
#region Input
private void AddInputEvent()
{
InputManager.OnPlayerPerformed += OnPlayerCanceled;
InputManager.OnPlayerPerformed += OnPlayerPerformed;
InputManager.OnPlayerValueCanceled += OnPlayerValueCanceled;
InputManager.OnPlayerValuePerformed += OnPlayerValuePerformed;
}
private void RemoveInputEvent()
{
InputManager.OnPlayerPerformed += OnPlayerCanceled;
InputManager.OnPlayerPerformed += OnPlayerPerformed;
InputManager.OnPlayerValueCanceled += OnPlayerValueCanceled;
InputManager.OnPlayerValuePerformed += OnPlayerValuePerformed;
}
private void OnPlayerPerformed(string action)
{
if (action == InputDef.Player.Run)
{
Data.Run = true;
}
}
private void OnPlayerCanceled(string action)
{
if (action == InputDef.Player.Run)
{
Data.Run = false;
}
else if (action == InputDef.Player.ToBag)
{
//取消手持物品
Log.Info($"取消手持物品");
Game.Instance.StartCoroutine(UnUseItem());
}
else if (action.StartsWith(InputDef.Player.QuickStarts))
{
var index = int.Parse(action.Replace(InputDef.Player.QuickStarts, string.Empty));
Log.Info($"快速使用===={index}");
var item = RoleModel.Instance.GetSlotItem(index - 1);
if (item != null)
{
Game.Instance.StartCoroutine(UseItem(item));
}
}
}
private void OnPlayerValueCanceled(InputAction.CallbackContext context)
{
var actionName = context.action.name;
if (actionName == InputDef.Player.Move)
{
// var v2 = context.ReadValue<Vector2>();
Data.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 actionName = context.action.name;
if (actionName == InputDef.Player.Move)
{
var v2 = context.ReadValue<Vector2>();
Data.MoveInput = v2;
// SendMoveMessage(v2, false);
}
else if (actionName == InputDef.Player.Look)
{
var v2 = context.ReadValue<Vector2>();
// UpdatePlayerRotation(v2);
}
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ea2c2e2d4b4344f0bc9d58ba0aeec6fd
timeCreated: 1766505279

View File

@@ -0,0 +1,146 @@
using UnityEngine;
namespace NBF
{
public partial class FPlayer
{
#region Move
private Quaternion lastRotation;
private void UpdateMove()
{
UpdateGrounded();
UpdateWater();
ProcessMoveStates();
UpdateLookInput();
}
private void UpdateGrounded()
{
Data.IsGrounded = FirstPerson.IsGrounded();
Data.Speed = FirstPerson.velocity.magnitude;
Quaternion rotation = FirstPerson.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);
Data.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
{
var num2 = Data.Run ? 7 : 5;
//(IsRunPressed.Value ? MovementSpeed.Value : (MovementSpeed.Value * 0.5f));
// num2 = (IsFlyModeEnabled ? (num2 * (float)FlySpeed) : num2);
Vector3 vector2 = FirstPerson.GetRightVector() * Data.MoveInput.x * num2;
vector2 += FirstPerson.GetForwardVector() * Data.MoveInput.y * num2;
// if (checkWaterBound)
// {
// SetMovementDirectionWithRaycastCheck(vector2);
// }
// else
{
FirstPerson.SetMovementDirection(vector2);
}
}
}
#endregion
#region Look
public float MouseSensitivity = 0.1f;
[Space(15f)] public bool invertLook = true;
public float minPitch = -60f;
public float maxPitch = 60f;
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 = InputManager.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;
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ae72860c045147af8022a3cbb30481ab
timeCreated: 1766471468

View File

@@ -0,0 +1,165 @@
using System;
using System.Collections;
using System.Collections.Generic;
using ECM2;
using ECM2.Examples.FirstPerson;
using Fantasy;
using NBC;
using NBF.Fishing2;
using NBF.Utils;
using UnityEngine;
using UnityEngine.InputSystem;
using Object = UnityEngine.Object;
namespace NBF
{
public partial class FPlayer : MonoService<FPlayer>
{
public Transform Root;
public Transform Eye;
public Transform FppLook;
public Transform IK;
public PlayerModelAsset ModelAsset;
public CharacterMovement Character;
public FirstPersonCharacter FirstPerson;
public GameObject ModelGameObject { get; set; }
public FPlayerData Data { get; private set; }
public readonly List<FRod> Tackles = new List<FRod>();
public FRod Rod { get; private set; }
public Fsm<FPlayer> Fsm { get; private set; }
public event Action<FHandItem> OnFishingSetEquiped;
public event Action OnFishingSetUnequip;
protected override void OnAwake()
{
Character = gameObject.GetComponent<CharacterMovement>();
FirstPerson = gameObject.GetComponent<FirstPersonCharacter>();
Data = FPlayerData.Instance;
transform.localPosition = new Vector3(484, 1, 422);
// Data.NeedChangeRightArmAngle = true;
}
private void Start()
{
InitFsm();
AddInputEvent();
CreatePlayerModel();
}
private void Update()
{
}
private void LateUpdate()
{
UpdateMove();
Fsm?.Update();
Data.EyeAngle = GameUtils.GetVerticalAngle(transform, FppLook);
}
private void OnDestroy()
{
RemoveInputEvent();
}
#region
private void InitFsm()
{
Fsm = new Fsm<FPlayer>("Player", this, true);
Fsm.RegisterState<PlayerStateIdle>();
Fsm.RegisterState<PlayerStateThrow>();
Fsm.RegisterState<PlayerStateFishing>();
Fsm.RegisterState<PlayerStateFight>();
Fsm.RegisterState<PlayerStatePrepare>();
Fsm.Start<PlayerStateIdle>();
}
#endregion
#region
private void CreatePlayerModel()
{
var modelObject = PrefabsHelper.CreatePlayer(Root, "Human_Male");
modelObject.transform.localPosition = Vector3.zero;
ModelGameObject = modelObject;
ModelAsset = modelObject.GetComponent<PlayerModelAsset>();
ModelAsset.SetPlayer(this);
}
#endregion
#region 使
public IEnumerator UseItem(ItemInfo item)
{
if (Data.ChangeItem) yield break;
Data.ChangeItem = true;
var itemType = item?.ConfigId.GetItemType();
if (itemType == ItemType.Rod)
{
//判断旧的是否要收回
yield return UnUseItemConfirm();
Data.IsLureRod = true;
var rodType = (ItemSubType)item.Config.Type;
if (rodType == ItemSubType.RodTele)
{
Data.IsLureRod = false;
}
Rod =
item.Config.InstantiateAndComponent<FRod>(SceneSettings.Instance.GearNode, Vector3.zero,
Quaternion.identity);
yield return Rod.InitRod(this, item);
Tackles.Add(Rod);
OnFishingSetEquiped?.Invoke(Rod);
}
Data.ChangeItem = false;
}
public IEnumerator UnUseItem()
{
if (Data.ChangeItem) yield break;
Data.ChangeItem = true;
yield return UnUseItemConfirm();
Data.ChangeItem = false;
}
private IEnumerator UnUseItemConfirm()
{
if (Rod != null)
{
OnFishingSetUnequip?.Invoke();
yield return Rod.Destroy();
yield return new WaitForSeconds(0.35f);
Destroy(Rod.gameObject);
Tackles.Remove(Rod);
Rod = null;
yield return new WaitForSeconds(0.15f);
}
}
#endregion
/// <summary>
/// 线断了
/// </summary>
/// <param name="msg"></param>
/// <param name="loseBaitChance"></param>
public void LineBreak(string msg, float loseBaitChance)
{
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 625346c970c542bab9f3a36f78720a77
timeCreated: 1766419452

View File

@@ -0,0 +1,116 @@
using System;
using UnityEngine;
namespace NBF
{
// [Serializable]
// 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
// }
[Serializable]
public enum PlayerState : uint
{
None = 0,
/// <summary>
/// 闲置等待中
/// </summary>
Idle = 1,
/// <summary>
/// 准备抛竿
/// </summary>
Prepare = 2,
/// <summary>
/// 抛竿中
/// </summary>
Throw = 3,
/// <summary>
/// 钓鱼中
/// </summary>
Fishing = 4,
/// <summary>
/// 溜鱼中
/// </summary>
Fight = 5
}
public class FPlayerData : MonoService<FPlayerData>
{
private PlayerState _previousPlayerState = PlayerState.Idle;
private PlayerState _playerState;
public bool ChangeItem;
public bool Run;
public bool IsGrounded;
public float Speed;
public float RotationSpeed;
public float ReelSpeed;
public float LineTension;
/// <summary>
/// 是否路亚竿
/// </summary>
public bool IsLureRod;
public Vector2 MoveInput;
/// <summary>
///
/// </summary>
public float EyeAngle;
public PlayerState PreviousState => _previousPlayerState;
public PlayerState State
{
get => _playerState;
set
{
_previousPlayerState = _playerState;
_playerState = value;
NextState = value;
OnStateChange?.Invoke(_playerState);
}
}
[SerializeField] private PlayerState NextState;
public event Action<PlayerState> OnStateChange;
private void Start()
{
NextState = State;
}
private void Update()
{
if (NextState != State)
{
State = NextState;
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 53629a9cec2b4caf9a739c21f7abdf3c
timeCreated: 1766471002

View File

@@ -0,0 +1,306 @@
using System;
using KINEMATION.MagicBlend.Runtime;
using NBC;
using UnityEngine;
namespace NBF
{
public class PlayerAnimator : MonoBehaviour
{
public Animator _Animator;
public FPlayer Player { get; private set; }
private bool _isRodLayerEnabled;
private bool _isInit;
private PlayerIK _IK;
private MagicBlending _magicBlending;
private bool _IsInVehicle;
#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 OnGroundHash = Animator.StringToHash("OnGround");
public static readonly int PrepareThrowHash = Animator.StringToHash("PrepareThrow");
public static readonly int StartThrowHash = Animator.StringToHash("StartThrow");
public static readonly int BaitThrownHash = Animator.StringToHash("BaitThrown");
private static readonly int FishingUpHash = Animator.StringToHash("FishingUp");
public static readonly string LureRodLayer = "LureRod";
public static readonly string HandRodLayer = "HandRod";
public float FishingUp
{
get => _Animator.GetFloat(FishingUpHash);
set => _Animator.SetFloat(FishingUpHash, value);
}
public bool OnGround
{
get => _Animator.GetBool(OnGroundHash);
set => _Animator.SetBool(OnGroundHash, value);
}
public bool StartThrow
{
get => _Animator.GetBool(StartThrowHash);
set => _Animator.SetBool(StartThrowHash, value);
}
public bool BaitThrown
{
get => _Animator.GetBool(BaitThrownHash);
set => _Animator.SetBool(BaitThrownHash, value);
}
public bool PrepareThrow
{
get => _Animator.GetBool(PrepareThrowHash);
set => _Animator.SetBool(PrepareThrowHash, value);
}
#endregion
private void Awake()
{
Player = GetComponentInParent<FPlayer>();
_magicBlending = GetComponent<MagicBlending>();
_Animator = GetComponent<Animator>();
_Animator.keepAnimatorStateOnDisable = true;
_IK = GetComponent<PlayerIK>();
_isInit = true;
Player.OnFishingSetEquiped += OnFishingSetEquiped_OnRaised;
Player.OnFishingSetUnequip += OnFishingSetUnequip;
Player.Data.OnStateChange += PlayerFSMState_OnValueChanged;
}
private void OnDestroy()
{
Player.OnFishingSetEquiped -= OnFishingSetEquiped_OnRaised;
Player.OnFishingSetUnequip -= OnFishingSetUnequip;
Player.Data.OnStateChange += PlayerFSMState_OnValueChanged;
}
private void OnFishingSetUnequip()
{
_isRodLayerEnabled = false;
// _IK.SetBipedLeftHandIK(enabled: false, null);
}
private void OnFishingSetEquiped_OnRaised(FHandItem item)
{
if (item is FRod rod)
{
_isRodLayerEnabled = true;
// var reel = Player.Rod.Reel;
// _IK.SetBipedLeftHandIK(enabled: false, reel.FingersIKAnchor);
}
else
{
}
}
public void SetLayerWeight(string layer, float weight)
{
_Animator.SetLayerWeight(_Animator.GetLayerIndex(layer), weight);
}
private void PlayerFSMState_OnValueChanged(PlayerState state)
{
// switch (Player.Data.PreviousState)
// {
// case PlayerState.vehicle:
// _IsInVehicle = false;
// _Animator.SetBool(BoatDriving, value: false);
// break;
// case PlayerState.swiming:
// _Animator.SetBool(IsSwiming, value: false);
// break;
// case PlayerState.preciseCastIdle:
// _Animator.SetBool(PreciseIdle, value: false);
// break;
// case PlayerState.prepare:
// _Animator.SetBool(RodArming, value: false);
// break;
// case PlayerState.casting:
// _Animator.SetBool(ThrowFar, value: false);
// break;
// case PlayerState.collectFish:
// _magicBlending.BlendAsset.globalWeight = 0f;
// break;
// }
//
// switch (state)
// {
// switch (Player.Data.PreviousState)
// {
// case PlayerState.vehicle:
// _IsInVehicle = false;
// _Animator.SetBool(BoatDriving, value: false);
// break;
// case PlayerState.swiming:
// _Animator.SetBool(IsSwiming, value: false);
// break;
// case PlayerState.preciseCastIdle:
// _Animator.SetBool(PreciseIdle, value: false);
// break;
// case PlayerState.prepare:
// _Animator.SetBool(RodArming, value: false);
// break;
// case PlayerState.casting:
// _Animator.SetBool(ThrowFar, value: false);
// break;
// case PlayerState.collectFish:
// _magicBlending.BlendAsset.globalWeight = 0f;
// break;
// }
//
// switch (state)
// {
// case PlayerState.idle:
// case PlayerState.move:
// _Animator.SetBool(BaitInWater, value: false);
// _Animator.SetBool(HeldRod, value: false);
// _Animator.SetBool(ThrowFar, value: false);
// _Animator.SetBool(RodArming, value: false);
// break;
// case PlayerState.prepare:
// _Animator.SetBool(RodArming, value: true);
// _Animator.SetBool(HeldRod, value: true);
// break;
// case PlayerState.fishing:
// _Animator.SetBool(HeldRod, value: true);
// _Animator.SetBool(BaitInWater, value: true);
// break;
// case PlayerState.vehicle:
// _Animator.SetBool(BaitInWater, value: false);
// _Animator.SetBool(HeldRod, value: false);
// _Animator.SetBool(ThrowFar, value: false);
// _Animator.SetBool(RodArming, value: false);
// _Animator.SetBool(BoatDriving, value: true);
// _IK.SetBipedLeftHandIK(enabled: true);
// _IsInVehicle = true;
// break;
// case PlayerState.vehicleFishing:
// _Animator.SetBool(BaitInWater, value: false);
// _Animator.SetBool(HeldRod, value: false);
// _Animator.SetBool(ThrowFar, value: false);
// _Animator.SetBool(RodArming, value: false);
// _IsInVehicle = true;
// break;
// case PlayerState.swiming:
// _Animator.SetBool(IsSwiming, value: true);
// break;
// case PlayerState.collectFish:
// _Animator.SetBool(BaitInWater, value: false);
// _IK.SetAimIK(enabled: false);
// _magicBlending.BlendAsset.globalWeight = 1f;
// break;
// case PlayerState.preciseCastIdle:
// _Animator.SetBool(PreciseIdle, value: true);
// break;
// case PlayerState.casting:
// case PlayerState.baitFlies:
// case PlayerState.fight:
// case PlayerState.fishView:
// case PlayerState.throwFish:
// case PlayerState.flyModeDebug:
// break;
// }
}
private void LateUpdate()
{
// if (Player.Data.State == PlayerState.swiming)
// {
// float value = Mathf.Lerp(_Animator.GetFloat(Forward), Player.Data.Speed / 2.5f,
// Time.deltaTime * 5f);
// float value2 = Mathf.Lerp(_Animator.GetFloat(Turn), Player.Data.RotationSpeed, Time.deltaTime * 5f);
// _Animator.SetFloat(Forward, Mathf.Clamp01(value));
// _Animator.SetFloat(Turn, Mathf.Clamp(value2, -1f, 1f));
// }
// else
{
float value3 = Mathf.Lerp(_Animator.GetFloat(Forward), Player.Data.Speed / 5f,
Time.deltaTime * 20f);
float value4 = Mathf.Lerp(_Animator.GetFloat(Turn), Player.Data.RotationSpeed, Time.deltaTime * 15f);
_Animator.SetFloat(Forward, Mathf.Clamp01(value3));
_Animator.SetFloat(Turn, Mathf.Clamp(value4, -1f, 1f));
}
// var rod = Vector3.zero;
// if (Player.Rod)
// {
// rod = Player.Rod.transform.position;
// }
_Animator.SetBool(OnGroundHash, _IsInVehicle || Player.Data.IsGrounded);
var isHandRodLayerEnabled = _isRodLayerEnabled && !Player.Data.IsLureRod ? 1 : 0;
float handRodLayerWeight = _Animator.GetLayerWeight(_Animator.GetLayerIndex(HandRodLayer));
SetLayerWeight(HandRodLayer,
Mathf.MoveTowards(handRodLayerWeight, isHandRodLayerEnabled, Time.deltaTime * 3f));
var isLureRodLayerEnabled = _isRodLayerEnabled && Player.Data.IsLureRod ? 1 : 0;
float lureRodLayerWeight = _Animator.GetLayerWeight(_Animator.GetLayerIndex(LureRodLayer));
SetLayerWeight(LureRodLayer,
Mathf.MoveTowards(lureRodLayerWeight, isLureRodLayerEnabled, Time.deltaTime * 3f));
}
#region
/// <summary>
/// 抬杆到底动画事件
/// </summary>
public void OnRodPowerUp()
{
}
/// <summary>
/// 开始抛出动画事件
/// </summary>
public void OnRodThrowStart()
{
if (Player.Fsm.CurrentState is PlayerStateThrow playerStateThrow)
{
playerStateThrow.OnRodThrowStart();
}
}
/// <summary>
/// 抛竿结束动画事件
/// </summary>
public void OnRodThrownEnd()
{
if (Player.Fsm.CurrentState is PlayerStateThrow playerStateThrow)
{
playerStateThrow.OnRodThrownEnd();
}
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0fc336a939c4416db623f3b4ae855265
timeCreated: 1766470716

View File

@@ -0,0 +1,29 @@
using System;
using RootMotion.FinalIK;
using UnityEngine;
namespace NBF
{
public class PlayerArm : MonoBehaviour
{
public bool FixLowerArm;
public bool IsLeft;
public LimbIK IK;
public Transform LowerArm;
public Transform RodContainer;
public FingerRig FingerRig;
[HideInInspector] public float interactionTargetWeight;
private const int MaxFixEyeAngle = 15;
public void Awake()
{
}
private void LateUpdate()
{
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 01ef40348d8b4d4da250acf0a921fc2a
timeCreated: 1768660096

View File

@@ -0,0 +1,25 @@
using UnityEngine;
namespace NBF
{
public class PlayerChest : MonoBehaviour
{
private const int MaxFixEyeAngle = 15;
private const int MinFixEyeAngle = -10;
private void LateUpdate()
{
FixArmAngle();
}
private void FixArmAngle()
{
var angle = FPlayerData.Instance.EyeAngle;
if (angle > MaxFixEyeAngle) angle = MaxFixEyeAngle;
else if (angle < MinFixEyeAngle) angle = MinFixEyeAngle;
var val = transform.localEulerAngles;
transform.localEulerAngles = new Vector3(val.x, val.y, val.z - angle);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e152a74e74b54d17ace5403a1570e12a
timeCreated: 1768668096

View File

@@ -0,0 +1,156 @@
using System;
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,3 @@
fileFormatVersion: 2
guid: a3b57223c7f94237869524280afe1672
timeCreated: 1768138483

View File

@@ -0,0 +1,21 @@
using NBC;
using UnityEngine;
namespace NBF
{
public abstract class PlayerStateBase : FsmBaseState<FPlayer>
{
protected FPlayer Player => _owner;
/// <summary>
/// 检查状态超时
/// </summary>
public void CheckStateTimeout(float time)
{
if (Time.time - EnterTime >= time)
{
Root.Start<PlayerStateIdle>();
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 080f1176c3ac4eefa37f615b22cac7ed
timeCreated: 1768138530

View File

@@ -0,0 +1,20 @@
namespace NBF
{
public class PlayerStateFight : PlayerStateBase
{
public override uint StateId => (uint)PlayerState.Fight;
protected override void onEnter()
{
}
protected override void onExit()
{
}
protected override uint onUpdate()
{
return States.None;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0720dd0d400641bea639e36f169aafde
timeCreated: 1768138922

View File

@@ -0,0 +1,102 @@
using NBC;
using UnityEngine;
namespace NBF
{
/// <summary>
/// 钓鱼中
/// </summary>
public class PlayerStateFishing : PlayerStateBase
{
public override uint StateId => (uint)PlayerState.Fishing;
protected override void onEnter()
{
Debug.LogError("enter PlayerStateFishing");
_owner.ModelAsset.PlayerAnimator.BaitThrown = true;
}
protected override void onExit()
{
_owner.ModelAsset.PlayerAnimator.BaitThrown = false;
}
protected override uint onUpdate()
{
var ret = States.None;
var isUpRod = false;
var isSubLine = false;
if (InputManager.IsOp1)
{
if (!Player.Data.IsLureRod)
{
//抬杆
isUpRod = true;
}
else
{
//收线
isSubLine = true;
}
}
if (InputManager.IsOp2)
{
if (Player.Data.IsLureRod)
{
//抬杆
isUpRod = true;
}
}
//Player.ModelAsset.PlayerAnimator.FishingUp = 0;
if (isUpRod || Player.ModelAsset.PlayerAnimator.FishingUp > 0)
{
var upForce = 1;
var addNum = upForce * Time.deltaTime;
if (!isUpRod)
{
addNum *= -1;
}
else
{
addNum *= 0.5f;
}
// Debug.Log($"addNum={addNum}");
Player.ModelAsset.PlayerAnimator.FishingUp += addNum;
// Debug.LogError($"ishingFinal={Player.ModelAsset.PlayerAnimator.FishingUp}");
if (Player.ModelAsset.PlayerAnimator.FishingUp >= 1)
{
Player.ModelAsset.PlayerAnimator.FishingUp = 1;
}
else if (Player.ModelAsset.PlayerAnimator.FishingUp < 0)
{
Player.ModelAsset.PlayerAnimator.FishingUp = 0;
}
if (Player.ModelAsset.PlayerAnimator.FishingUp >= 0.8f)
{
ret = CheckTackFish();
}
}
else
{
Player.ModelAsset.PlayerAnimator.FishingUp = 0;
}
return ret;
}
#region
private uint CheckTackFish()
{
return (uint)PlayerState.Idle;
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6953fd92b2c54c6e846a0363520a9010
timeCreated: 1768138900

View File

@@ -0,0 +1,44 @@
using NBC;
namespace NBF
{
/// <summary>
/// 闲置中
/// </summary>
public class PlayerStateIdle : PlayerStateBase
{
public override uint StateId => (uint)PlayerState.Idle;
private bool _nextState = false;
protected override void onEnter()
{
Log.Info("enter PlayerStateIdle");
_nextState = false;
InputManager.OnOp1Action += OnOp1Action;
}
private void OnOp1Action(bool performed)
{
if (!Player.Rod) return;
if (performed)
{
_nextState = true;
}
}
protected override void onExit()
{
InputManager.OnOp1Action -= OnOp1Action;
}
protected override uint onUpdate()
{
if (_nextState)
{
return (uint)PlayerState.Prepare;
}
return States.None;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a6146dcfbaf54972ac75c8115041ed3e
timeCreated: 1768138510

View File

@@ -0,0 +1,76 @@
using NBC;
using UnityEngine;
namespace NBF
{
/// <summary>
/// 准备抛竿中
/// </summary>
public class PlayerStatePrepare : PlayerStateBase
{
public override uint StateId => (uint)PlayerState.Prepare;
public enum Phase
{
/// <summary>
/// 蓄力
/// </summary>
Charged,
/// <summary>
/// 确认蓄力结果
/// </summary>
Confirm,
}
public Phase Stage = Phase.Charged;
public float ChargedProgress;
protected override void onEnter()
{
Log.Info("enter PlayerStatePrepare");
Stage = Phase.Charged;
Player.ModelAsset.PlayerAnimator.PrepareThrow = true;
Player.ModelAsset.PlayerAnimator.FishingUp = 0;
}
protected override uint onUpdate()
{
if (Stage == Phase.Charged)
{
ThrowPowerCharged();
}
else if (Stage == Phase.Confirm)
{
//确认蓄力结果,
Debug.Log($"确认蓄力结果,ChargedProgress={ChargedProgress}");
Params.Add(ChargedProgress);
return (uint)PlayerState.Throw;
}
return base.onUpdate();
}
#region
private void ThrowPowerCharged()
{
if (ChargedProgress < 1)
{
ChargedProgress += Time.deltaTime;
}
else if (ChargedProgress > 1)
{
ChargedProgress = 1;
}
if (!InputManager.IsOp1)
{
Stage = Phase.Confirm;
}
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1301b70435cd44c8ba3cc6085f35a782
timeCreated: 1768138823

View File

@@ -0,0 +1,100 @@
using NBC;
using UnityEngine;
namespace NBF
{
/// <summary>
/// 抛竿中
/// </summary>
public class PlayerStateThrow : PlayerStateBase
{
public override uint StateId => (uint)PlayerState.Throw;
// public enum Phase
// {
// /// <summary>
// /// 等待动画事件回调
// /// </summary>
// Waiting,
//
// /// <summary>
// /// 前摇动画
// /// </summary>
// AnimBegin,
//
// /// <summary>
// /// 抛线动画
// /// </summary>
// ThrowAnim,
//
// /// <summary>
// /// 结束
// /// </summary>
// Done,
// ErrorDone
// }
//
// public Phase Stage = Phase.Waiting;
private bool _nextState = false;
public float ChargedProgress;
protected override void onEnter()
{
Log.Info("enter PlayerStateThrow");
_owner.ModelAsset.PlayerAnimator.StartThrow = true;
ChargedProgress = (float)Params.Get(0);
Debug.Log($"PlayerThrow ChargedProgress={ChargedProgress}");
_nextState = false;
// Stage = Phase.Waiting;
// _owner.Gears.Reel?.Unlock();
}
protected override uint onUpdate()
{
CheckStateTimeout(10);
if (_nextState)
{
return (uint)PlayerState.Fishing;
}
return base.onUpdate();
}
// IEnumerator ThrowCoroutine(float distance)
// {
// float startLength = 0.5f;
// Debug.Log($"REST LENGTH : {rope.restLength}");
// do
// {
// float a = Vector3.Distance(rodTipTarget.position, attachedBody.transform.position);
// attachedBody.RBody.AddForce(playerForward.Value, ForceMode.VelocityChange);
// startLength = Mathf.Max(a, startLength);
// UnwindLine(attachedBody.RBody.linearVelocity.magnitude * Time.deltaTime);
// yield return null;
// }
// while ((bool)isBailOpen);
// }
#region
/// <summary>
/// 抛竿动画事件
/// </summary>
public void OnRodThrowStart()
{
Debug.LogError("OnRodThrowStart");
_owner.ModelAsset.PlayerAnimator.PrepareThrow = false;
_owner.ModelAsset.PlayerAnimator.StartThrow = false;
}
public void OnRodThrownEnd()
{
Debug.LogError("OnRodThrownEnd");
_nextState = true;
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1a0b4bc6f668446cab7baf752da60477
timeCreated: 1768138870

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: b245d0b3de2c4fb4aa46602e8a5b1416

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1330e7f73f804eea8ae09724f6bb1039
timeCreated: 1766759962

View File

@@ -0,0 +1,55 @@
// using Obi;
using UnityEngine;
public class RodLine : MonoBehaviour
{
// private ObiRope obiRope;
private LineRenderer lineRenderer;
private Transform[] points;
public void GenerateLineRendererRope(Transform[] points, float thickness)
{
if (points.Length < 2)
{
Debug.LogError("LineRenderer requires at least two points.");
return;
}
this.points = points;
if (lineRenderer == null)
{
lineRenderer = base.gameObject.GetComponent<LineRenderer>();
if (lineRenderer == null)
{
lineRenderer = base.gameObject.AddComponent<LineRenderer>();
}
}
lineRenderer.positionCount = points.Length;
lineRenderer.startWidth = thickness;
lineRenderer.endWidth = thickness;
for (int i = 0; i < points.Length; i++)
{
lineRenderer.SetPosition(i, points[i].position);
}
}
private void LateUpdate()
{
if (lineRenderer == null)
{
return;
}
for (var i = 0; i < points.Length; i++)
{
var point = points[i];
if (point)
{
lineRenderer.SetPosition(i, point.position);
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5625b86b9e4b4482b82d83b962d0c873
timeCreated: 1766759973

View File

@@ -0,0 +1,669 @@
using System;
using NBF;
using UnityEngine;
[RequireComponent(typeof(LineRenderer))]
public class Rope : MonoBehaviour
{
[Header("Anchors")] [SerializeField] public Rigidbody startAnchor;
[SerializeField] public Rigidbody endAnchor;
/// <summary>鱼线宽度倍数</summary>
public int LineMultiple = 1;
[Header("Physics (Dynamic Nodes, Fixed Segment Len)")] [SerializeField, Min(0.01f), Tooltip("物理每段固定长度(越小越细致越耗)")]
private float physicsSegmentLen = 0.15f;
[SerializeField, Range(2, 200)] private int minPhysicsNodes = 12;
[SerializeField, Range(2, 400), Tooltip("物理节点上限(仅用于性能保护;与“最大长度不限制”不是一回事)")]
private int maxPhysicsNodes = 120;
[SerializeField] private float gravityStrength = 2.0f;
[SerializeField, Range(0f, 1f)] private float velocityDampen = 0.95f;
[SerializeField, Range(0.0f, 1.0f), Tooltip("约束修正强度越大越硬。0.6~0.9 常用")]
private float stiffness = 0.8f;
[SerializeField, Range(1, 80), Tooltip("迭代次数。鱼线 10~30 通常够用")]
private int iterations = 20;
[Header("Length Control (No Min/Max Clamp)")]
[Tooltip("初始总长度(米)。如果为 0则用 physicsSegmentLen*(minPhysicsNodes-1) 作为初始长度")]
[SerializeField, Min(0f)]
private float initialLength = 0f;
[Tooltip("长度变化平滑时间(越小越跟手,越大越稳)")] [SerializeField, Min(0.0001f)]
private float lengthSmoothTime = 0.15f;
[Tooltip("当长度在变化时额外把速度压掉一些防抖。0=不额外处理1=变化时几乎清速度(建议只在收线生效)")] [SerializeField, Range(0f, 1f)]
private float lengthChangeVelocityKill = 0.6f;
[Tooltip("允许的最小松弛余量(避免目标长度刚好等于锚点距离时抖动)")] [SerializeField, Min(0f)]
private float minSlack = 0.002f;
[Header("Head Segment Clamp")] [Tooltip("第一段(起点->第1节点允许的最小长度避免收线时第一段被压到0导致数值炸")] [SerializeField, Min(0.0001f)]
private float headMinLen = 0.01f;
[Header("Node Count Stability")] [SerializeField, Tooltip("节点数切换迟滞(米)。避免长度在临界点抖动导致节点数来回跳 -> 卡顿")]
private float nodeHysteresis = 0.05f;
[Header("Simple Ground/Water Constraint (Cheap)")] [SerializeField]
private bool constrainToGround = true;
[SerializeField] private LayerMask groundMask = ~0;
[SerializeField, Min(0f)] private float groundRadius = 0.01f;
[SerializeField, Min(0f)] private float groundCastHeight = 1.0f;
[SerializeField, Min(0.01f)] private float groundCastDistance = 2.5f;
[SerializeField, Range(1, 8), Tooltip("每隔多少个节点做一次地面检测;越大越省")]
private int groundSampleStep = 3;
[SerializeField, Tooltip("未采样的点用插值还是直接拷贝邻近采样值")]
private bool groundInterpolate = true;
[SerializeField, Range(1, 8), Tooltip("每隔多少次FixedUpdate更新一次地面约束")]
private int groundUpdateEvery = 2;
private int _groundFrameCounter;
[Header("Render (High Resolution)")] [SerializeField, Min(1), Tooltip("静止时每段物理线段插值加密数量(越大越顺,越耗)")]
private int renderSubdivisionsIdle = 6;
[SerializeField, Min(1), Tooltip("甩动时每段物理线段插值加密数量动态降LOD以防卡顿")]
private int renderSubdivisionsMoving = 2;
[SerializeField, Min(0f), Tooltip("平均速度超过该阈值认为在甩动(用于动态降 subdiv")]
private float movingSpeedThreshold = 2.0f;
[SerializeField, Tooltip("是否使用 Catmull-Rom 平滑(开启更顺,但更耗)")]
private bool smooth = true;
[SerializeField, Min(0.0001f)] private float lineWidth = 0.001f;
[Header("Air Drag (Stable)")] [SerializeField, Range(0f, 5f), Tooltip("空气阻力Y向指数衰减越大越不飘")]
private float airDrag = 0.9f;
[SerializeField, Range(0f, 2f), Tooltip("横向额外阻力XZ指数衰减越大越不左右飘")]
private float airDragXZ = 0.6f;
private LineRenderer _lineRenderer;
// physics
private int _physicsNodes;
private Vector3[] _pCurr;
private Vector3[] _pPrev;
// render (一次性分配到最大,后续不再 new)
private Vector3[] _rPoints;
private int _rCapacity;
private Vector3 _gravity;
// length control runtime
private float _targetLength;
private float _currentLength;
private float _lengthSmoothVel;
// rest length head
private float _headRestLen;
// node stability
private int _lastDesiredNodes = 0;
// caches
private Transform _startTr;
private Transform _endTr;
// precomputed
private float _dt;
private float _dt2;
private float _kY;
private float _kXZ;
private FRod _rod;
public void Init(FRod rod) => _rod = rod;
// Catmull t caches只缓存 idle/moving 两档,减少每帧重复乘法)
private struct TCaches
{
public float[] t;
public float[] t2;
public float[] t3;
}
private TCaches _tIdle;
private TCaches _tMoving;
private void Awake()
{
_lineRenderer = GetComponent<LineRenderer>();
_gravity = new Vector3(0f, -gravityStrength, 0f);
_startTr = startAnchor ? startAnchor.transform : null;
_endTr = endAnchor ? endAnchor.transform : null;
InitLengthSystem();
AllocateAndInitNodes();
// ✅ 渲染点一次性分配到最大: (maxNodes-1)*idle + 1
int maxSubdiv = Mathf.Max(1, renderSubdivisionsIdle);
_rCapacity = (maxPhysicsNodes - 1) * maxSubdiv + 1;
_rPoints = new Vector3[_rCapacity];
BuildTCaches(renderSubdivisionsIdle, ref _tIdle);
BuildTCaches(renderSubdivisionsMoving, ref _tMoving);
}
private void OnValidate()
{
renderSubdivisionsIdle = Mathf.Max(renderSubdivisionsIdle, 1);
renderSubdivisionsMoving = Mathf.Max(renderSubdivisionsMoving, 1);
iterations = Mathf.Clamp(iterations, 1, 80);
groundCastDistance = Mathf.Max(groundCastDistance, 0.01f);
groundCastHeight = Mathf.Max(groundCastHeight, 0f);
lineWidth = Mathf.Max(lineWidth, 0.0001f);
lengthSmoothTime = Mathf.Max(lengthSmoothTime, 0.0001f);
physicsSegmentLen = Mathf.Max(physicsSegmentLen, 0.01f);
minPhysicsNodes = Mathf.Max(minPhysicsNodes, 2);
maxPhysicsNodes = Mathf.Max(maxPhysicsNodes, minPhysicsNodes);
headMinLen = Mathf.Max(headMinLen, 0.0001f);
nodeHysteresis = Mathf.Max(0f, nodeHysteresis);
}
private void InitLengthSystem()
{
float defaultLen = physicsSegmentLen * (Mathf.Max(minPhysicsNodes, 2) - 1);
_currentLength = (initialLength > 0f) ? initialLength : defaultLen;
_targetLength = _currentLength;
}
private void AllocateAndInitNodes()
{
_physicsNodes = Mathf.Clamp(ComputeDesiredNodesStable(_currentLength), 2, maxPhysicsNodes);
_pCurr = new Vector3[maxPhysicsNodes];
_pPrev = new Vector3[maxPhysicsNodes];
Vector3 start = startAnchor ? startAnchor.position : transform.position;
Vector3 dir = Vector3.down;
for (int i = 0; i < _physicsNodes; i++)
{
Vector3 pos = start + dir * (physicsSegmentLen * i);
_pCurr[i] = pos;
_pPrev[i] = pos;
}
UpdateHeadRestLenFromCurrentLength();
if (startAnchor && endAnchor)
LockAnchorsHard();
}
private int ComputeDesiredNodes(float lengthMeters)
{
int desired = Mathf.FloorToInt(Mathf.Max(0f, lengthMeters) / physicsSegmentLen) + 1;
desired = Mathf.Clamp(desired, minPhysicsNodes, maxPhysicsNodes);
return desired;
}
private int ComputeDesiredNodesStable(float lengthMeters)
{
int desired = ComputeDesiredNodes(lengthMeters);
if (_lastDesiredNodes == 0)
{
_lastDesiredNodes = desired;
return desired;
}
if (desired == _lastDesiredNodes)
return desired;
float boundary = (_lastDesiredNodes - 1) * physicsSegmentLen;
if (Mathf.Abs(lengthMeters - boundary) < nodeHysteresis)
return _lastDesiredNodes;
_lastDesiredNodes = desired;
return desired;
}
public void SetTargetLength(float lengthMeters) => _targetLength = Mathf.Max(0f, lengthMeters);
public float GetCurrentLength() => _currentLength;
public float GetTargetLength() => _targetLength;
private void FixedUpdate()
{
if (!startAnchor || !endAnchor) return;
// cache dt
_dt = Time.fixedDeltaTime;
if (_dt < 1e-6f) _dt = 1e-6f;
_dt2 = _dt * _dt;
// gravity
_gravity.y = -gravityStrength;
// drag cachesexp 比较贵,但这里每 FixedUpdate 一次OK
_kY = Mathf.Exp(-airDrag * _dt);
_kXZ = Mathf.Exp(-airDragXZ * _dt);
UpdateLengthSmooth();
UpdateNodesFromLength();
UpdateHeadRestLenFromCurrentLength();
Simulate_VerletFast();
// anchors
LockAnchorsHard();
// constraints
for (int it = 0; it < iterations; it++)
SolveDistanceConstraints_HeadOnly_Fast();
LockAnchorsHard();
if (constrainToGround)
{
_groundFrameCounter++;
if (_groundFrameCounter >= groundUpdateEvery)
{
_groundFrameCounter = 0;
ConstrainToGround();
}
}
LockAnchorsHard();
}
private void LateUpdate()
{
if (!startAnchor || !endAnchor || _pCurr == null || _physicsNodes < 2) return;
int last = _physicsNodes - 1;
// 用缓存 transform避免多次属性链
Vector3 s = _startTr.position;
Vector3 e = _endTr.position;
_pCurr[0] = s;
_pPrev[0] = s;
_pCurr[last] = e;
_pPrev[last] = e;
DrawHighResLine_Fast();
}
private void UpdateLengthSmooth()
{
float minFeasible = 0.01f;
float desired = Mathf.Max(_targetLength, minFeasible);
_currentLength = Mathf.SmoothDamp(
_currentLength,
desired,
ref _lengthSmoothVel,
lengthSmoothTime,
Mathf.Infinity,
Time.fixedDeltaTime
);
}
private void UpdateNodesFromLength()
{
int desired = ComputeDesiredNodesStable(_currentLength);
desired = Mathf.Clamp(desired, 2, maxPhysicsNodes);
if (desired == _physicsNodes) return;
if (desired > _physicsNodes) AddNodesAtStart(desired - _physicsNodes);
else RemoveNodesAtStart(_physicsNodes - desired);
_physicsNodes = desired;
}
private void AddNodesAtStart(int addCount)
{
if (addCount <= 0) return;
int oldCount = _physicsNodes;
int newCount = Mathf.Min(oldCount + addCount, maxPhysicsNodes);
addCount = newCount - oldCount;
if (addCount <= 0) return;
Array.Copy(_pCurr, 1, _pCurr, 1 + addCount, oldCount - 1);
Array.Copy(_pPrev, 1, _pPrev, 1 + addCount, oldCount - 1);
Vector3 s = _startTr ? _startTr.position : startAnchor.position;
Vector3 dir = Vector3.down;
int firstOld = 1 + addCount;
if (oldCount >= 2 && firstOld < maxPhysicsNodes)
{
Vector3 toOld1 = (_pCurr[firstOld] - s);
float sq = toOld1.sqrMagnitude;
if (sq > 1e-6f) dir = toOld1 / Mathf.Sqrt(sq);
}
// inherit displacement (Verlet)
Vector3 inheritDisp = Vector3.zero;
if (oldCount >= 2 && firstOld < maxPhysicsNodes)
inheritDisp = (_pCurr[firstOld] - _pPrev[firstOld]);
for (int k = 1; k <= addCount; k++)
{
Vector3 pos = s + dir * (physicsSegmentLen * k);
_pCurr[k] = pos;
_pPrev[k] = pos - inheritDisp; // 保持动感
}
LockAnchorsHard();
}
private void RemoveNodesAtStart(int removeCount)
{
if (removeCount <= 0) return;
int oldCount = _physicsNodes;
int newCount = Mathf.Max(oldCount - removeCount, 2);
removeCount = oldCount - newCount;
if (removeCount <= 0) return;
Array.Copy(_pCurr, 1 + removeCount, _pCurr, 1, newCount - 2);
Array.Copy(_pPrev, 1 + removeCount, _pPrev, 1, newCount - 2);
LockAnchorsHard();
}
private void UpdateHeadRestLenFromCurrentLength()
{
int fixedSegCount = Mathf.Max(0, _physicsNodes - 2);
float baseLen = fixedSegCount * physicsSegmentLen;
_headRestLen = _currentLength - baseLen;
_headRestLen = Mathf.Clamp(_headRestLen, headMinLen, physicsSegmentLen * 1.5f);
}
/// <summary>
/// ✅ 更快的 Verlet去掉 /dt 和 *dt 抵消的无效计算
/// </summary>
private void Simulate_VerletFast()
{
// displacement = curr - prev
// next = curr + displacement*drag*dampen + gravity*dt^2
for (int i = 1; i < _physicsNodes - 1; i++)
{
Vector3 disp = _pCurr[i] - _pPrev[i];
disp.x *= _kXZ;
disp.z *= _kXZ;
disp.y *= _kY;
disp *= velocityDampen;
Vector3 next = _pCurr[i] + disp + _gravity * _dt2;
_pPrev[i] = _pCurr[i];
_pCurr[i] = next;
}
}
private void LockAnchorsHard()
{
if (!startAnchor || !endAnchor || _pCurr == null || _pPrev == null || _physicsNodes < 2) return;
Vector3 s = _startTr ? _startTr.position : startAnchor.position;
Vector3 e = _endTr ? _endTr.position : endAnchor.position;
_pCurr[0] = s;
_pPrev[0] = s - startAnchor.linearVelocity * _dt;
int last = _physicsNodes - 1;
_pCurr[last] = e;
_pPrev[last] = e - endAnchor.linearVelocity * _dt;
}
/// <summary>
/// ✅ 约束:减少临时变量、用 sqrMagnitude + invDist
/// </summary>
private void SolveDistanceConstraints_HeadOnly_Fast()
{
int last = _physicsNodes - 1;
for (int i = 0; i < last; i++)
{
float rest = (i == 0) ? _headRestLen : physicsSegmentLen;
Vector3 a = _pCurr[i];
Vector3 b = _pCurr[i + 1];
Vector3 delta = b - a;
float sq = delta.sqrMagnitude;
if (sq < 1e-12f) continue;
float dist = Mathf.Sqrt(sq);
float diff = (dist - rest) / dist; // = 1 - rest/dist
Vector3 corr = delta * (diff * stiffness);
// i==0 锚点固定last 锚点固定
if (i != 0) _pCurr[i] = a + corr * 0.5f;
if (i + 1 != last) _pCurr[i + 1] = b - corr * 0.5f;
}
}
// private void ConstrainToGround()
// {
// if (groundMask == 0) return;
//
// // RaycastHit 是 struct这里不会 GC
// for (int i = 1; i < _physicsNodes - 1; i++)
// {
// Vector3 p = _pCurr[i];
// Vector3 origin = p + Vector3.up * groundCastHeight;
//
// if (Physics.Raycast(origin, Vector3.down, out RaycastHit hit, groundCastDistance, groundMask,
// QueryTriggerInteraction.Ignore))
// {
// float minY = hit.point.y + groundRadius;
// if (p.y < minY) p.y = minY;
// }
//
// _pCurr[i] = p;
// }
// }
private void ConstrainToGround()
{
if (groundMask == 0) return;
int last = _physicsNodes - 1;
int step = Mathf.Max(1, groundSampleStep);
// 记录采样点的“最低允许Y”
// 不想分配数组就用局部变量滚动插值
int prevSampleIdx = 1;
float prevMinY = SampleMinY(_pCurr[prevSampleIdx]);
// 把采样点先处理掉
ApplyMinY(prevSampleIdx, prevMinY);
for (int i = 1 + step; i < last; i += step)
{
float nextMinY = SampleMinY(_pCurr[i]);
ApplyMinY(i, nextMinY);
if (groundInterpolate)
{
// 在两个采样点之间插值 minY视觉更平滑
int a = prevSampleIdx;
int b = i;
int span = b - a;
for (int j = 1; j < span; j++)
{
int idx = a + j;
float t = j / (float)span;
float minY = Mathf.Lerp(prevMinY, nextMinY, t);
ApplyMinY(idx, minY);
}
}
else
{
// 直接用 prevMinY 填充中间点(更省)
for (int idx = prevSampleIdx + 1; idx < i; idx++)
ApplyMinY(idx, prevMinY);
}
prevSampleIdx = i;
prevMinY = nextMinY;
}
// 尾巴剩余部分用最后一个采样值填
for (int i = prevSampleIdx + 1; i < last; i++)
ApplyMinY(i, prevMinY);
}
private float SampleMinY(Vector3 p)
{
Vector3 origin = p + Vector3.up * groundCastHeight;
if (Physics.Raycast(origin, Vector3.down, out RaycastHit hit, groundCastDistance, groundMask,
QueryTriggerInteraction.Ignore))
return hit.point.y + groundRadius;
// 没命中就不抬(返回极小值)
return float.NegativeInfinity;
}
private void ApplyMinY(int i, float minY)
{
if (float.IsNegativeInfinity(minY)) return;
Vector3 p = _pCurr[i];
if (p.y < minY) p.y = minY;
_pCurr[i] = p;
}
private void DrawHighResLine_Fast()
{
if (_pCurr == null || _physicsNodes < 2) return;
float w = lineWidth * LineMultiple;
_lineRenderer.startWidth = w;
_lineRenderer.endWidth = w;
if (!smooth)
{
_lineRenderer.positionCount = _physicsNodes;
_lineRenderer.SetPositions(_pCurr);
return;
}
int subdiv = PickRenderSubdivisions_Fast();
TCaches tc = (subdiv == renderSubdivisionsMoving) ? _tMoving : _tIdle;
int needed = (_physicsNodes - 1) * subdiv + 1;
if (needed > _rCapacity)
{
// 理论上不该发生_rCapacity 用 maxNodes & idle 分配)
// 保险扩容一次
_rCapacity = needed;
_rPoints = new Vector3[_rCapacity];
}
int idx = 0;
int last = _physicsNodes - 1;
for (int seg = 0; seg < last; seg++)
{
int i0 = seg - 1;
if (i0 < 0) i0 = 0;
int i1 = seg;
int i2 = seg + 1;
int i3 = seg + 2;
if (i3 > last) i3 = last;
Vector3 p0 = _pCurr[i0];
Vector3 p1 = _pCurr[i1];
Vector3 p2 = _pCurr[i2];
Vector3 p3 = _pCurr[i3];
for (int s = 0; s < subdiv; s++)
{
float t = tc.t[s];
float t2 = tc.t2[s];
float t3 = tc.t3[s];
// inline CatmullRom少一次函数调用
Vector3 cr =
0.5f * (
(2f * p1) +
(-p0 + p2) * t +
(2f * p0 - 5f * p1 + 4f * p2 - p3) * t2 +
(-p0 + 3f * p1 - 3f * p2 + p3) * t3
);
// Linear Y
cr.y = p1.y + (p2.y - p1.y) * t;
_rPoints[idx++] = cr;
}
}
_rPoints[idx++] = _pCurr[last];
_lineRenderer.positionCount = idx;
_lineRenderer.SetPositions(_rPoints);
}
/// <summary>
/// ✅ 用 sqrMagnitude 比较阈值,避免 sqrt
/// </summary>
private int PickRenderSubdivisions_Fast()
{
int idle = Mathf.Max(1, renderSubdivisionsIdle);
int moving = Mathf.Max(1, renderSubdivisionsMoving);
float thr = movingSpeedThreshold;
float thrSq = (thr * _dt) * (thr * _dt); // 因为我们用 disp = curr-prev单位是米/step所以阈值要乘 dt
float sumSq = 0f;
int count = Mathf.Max(1, _physicsNodes - 2);
for (int i = 1; i < _physicsNodes - 1; i++)
{
Vector3 disp = _pCurr[i] - _pPrev[i];
sumSq += disp.sqrMagnitude;
}
float avgSq = sumSq / count;
return (avgSq > thrSq) ? moving : idle;
}
private static void BuildTCaches(int subdiv, ref TCaches caches)
{
subdiv = Mathf.Max(1, subdiv);
caches.t = new float[subdiv];
caches.t2 = new float[subdiv];
caches.t3 = new float[subdiv];
float inv = 1f / subdiv;
for (int s = 0; s < subdiv; s++)
{
float t = s * inv;
float t2 = t * t;
caches.t[s] = t;
caches.t2[s] = t2;
caches.t3[s] = t2 * t;
}
}
private void OnDrawGizmosSelected()
{
if (_pCurr == null) return;
Gizmos.color = Color.yellow;
for (int i = 0; i < _physicsNodes; i++)
Gizmos.DrawSphere(_pCurr[i], 0.01f);
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 98ba9d435a0e49c9bb527c34cc91894d
timeCreated: 1766759607

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 139e43e2a118492c974b67decf15056d
timeCreated: 1766477309

View File

@@ -0,0 +1,14 @@
using UnityEngine;
namespace NBF
{
public class FBait : FGearBase
{
protected override void OnInit()
{
var baitConnector = Rod.Hook.hookAsset.baitConnector;
transform.position = baitConnector.position;
transform.SetParent(baitConnector);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ed7126c6f37c427e88ba321c63aeac2f
timeCreated: 1766582532

View File

@@ -0,0 +1,14 @@
using UnityEngine;
namespace NBF
{
public class FBobber : FGearBase
{
protected override void OnInit()
{
// transform.position = Rod.lineHandler.LineConnector_1.transform.position;
SetParent(Rod.Line.Bobber.transform);
transform.localPosition = Vector3.zero;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 89060cfcd521410caf2f00ae7ecfa135
timeCreated: 1766477995

View File

@@ -0,0 +1,9 @@
using UnityEngine;
namespace NBF
{
public class FFish : MonoBehaviour
{
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d76aeec1876a4df2a93e8e8dcaee30fa
timeCreated: 1766586324

View File

@@ -0,0 +1,36 @@
using Fantasy;
using UnityEngine;
namespace NBF
{
public abstract class FGearBase : MonoBehaviour
{
public FPlayer Player { get; protected set; }
public FRod Rod { get; protected set; }
public ItemInfo ItemInfo;
public virtual void Init(FPlayer player, FRod rod)
{
Player = player;
Rod = rod;
OnInit();
}
public void SetItemInfo(ItemInfo itemInfo)
{
ItemInfo = itemInfo;
}
protected void SetParent(Transform parent)
{
transform.SetParent(parent);
transform.localPosition = Vector3.zero;
transform.localEulerAngles = Vector3.zero;
transform.localScale = Vector3.one;
}
protected abstract void OnInit();
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 708753789f5b41f48b9b18197f54a9df
timeCreated: 1766582740

View File

@@ -0,0 +1,9 @@
using UnityEngine;
namespace NBF
{
public class FHandItem : MonoBehaviour
{
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5460b0f542fd45e38145b2a4fb12e329
timeCreated: 1766583615

View File

@@ -0,0 +1,30 @@
using UnityEngine;
namespace NBF
{
public class FHook : FGearBase
{
public HookAsset hookAsset;
private void Awake()
{
hookAsset = GetComponent<HookAsset>();
}
protected override void OnInit()
{
// transform.position = Rod.lineHandler.LineConnector_2.transform.position;
// transform.rotation = Rod.lineHandler.LineConnector_2.transform.rotation; // 确保旋转也同步
// SetParent(Rod.lineHandler.LineConnector_2.transform);
SetParent(Rod.Line.Lure.transform);
transform.localPosition = Vector3.zero;
// var target = lineHandler.LineConnector_2.GetComponent<Rigidbody>();
// var joint = Hook.gameObject.GetComponent<ConfigurableJoint>();
// joint.connectedBody = target;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0b4736177aeb4b70ba352e385554e5ab
timeCreated: 1766477615

View File

@@ -0,0 +1,127 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NBC;
// using Obi;
using UnityEngine;
namespace NBF
{
public class FLine : FGearBase
{
// [SerializeField] private ObiParticleAttachment startParticleAttachment;
[SerializeField] private bool isLureConnect;
[SerializeField] private RodLine rodLine;
[SerializeField] private Rope fishingRope;
[SerializeField] private Rope bobberRope;
public LureController Lure;
public BobberController Bobber;
private float _groundSetting = 0.5f;
private float _LineOnSpool = 100f;
private float _LineThickness = 0.0007f;
public bool IsLure => isLureConnect;
// public event Action OnLinePulled;
protected override void OnInit()
{
var tipRb = Rod.Asset.LineConnectorRigidbody;
if (isLureConnect)
{
Lure.SetJoint(tipRb);
Lure.EnableCollision(false);
}
else
{
fishingRope.startAnchor = tipRb;
Bobber.SetJoint(tipRb);
Lure.SetJoint(Bobber.rbody);
Lure.gameObject.SetActive(true);
Lure.EnableCollision(false);
Lure.SetKinematic(false);
}
GetComponentsInChildren<Transform>(includeInactive: true).ToList().ForEach(delegate(Transform i)
{
i.gameObject.SetActive(true);
});
StartCoroutine(LureUseGravity());
if (isLureConnect)
{
fishingRope.Init(Rod);
}
else
{
fishingRope.Init(Rod);
bobberRope.Init(Rod);
}
// rodLine.GenerateLineRendererRope(guides.ToArray(), _LineThickness);
}
public void InitTest(Rigidbody tipRb)
{
if (isLureConnect)
{
Lure.SetJoint(tipRb);
Lure.EnableCollision(false);
}
else
{
fishingRope.startAnchor = tipRb;
Bobber.SetJoint(tipRb);
Lure.SetJoint(Bobber.rbody);
Lure.gameObject.SetActive(true);
Lure.EnableCollision(false);
Lure.SetKinematic(false);
}
GetComponentsInChildren<Transform>(includeInactive: true).ToList().ForEach(delegate(Transform i)
{
i.gameObject.SetActive(true);
});
StartCoroutine(LureUseGravity());
if (isLureConnect)
{
fishingRope.Init(Rod);
}
else
{
fishingRope.Init(Rod);
bobberRope.Init(Rod);
}
}
private IEnumerator LureUseGravity()
{
yield return 1;
Lure.gameObject.SetActive(false);
Lure.gameObject.SetActive(true);
yield return 1;
Lure.RBody.useGravity = true;
}
public void EnableLineRenderers()
{
// foreach (ObiRopeExtrudedRenderer item in GetComponentsInChildren<ObiRopeExtrudedRenderer>().ToList())
// {
// item.enabled = true;
// }
}
public void SetObiRopeStretch(float value)
{
Log.Error($"SetObiRopeStretch={value}");
fishingRope.SetTargetLength(value - 0.2f);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c0403ffd74ce46fab8bd4ef057e51432
timeCreated: 1766582567

View File

@@ -0,0 +1,194 @@
// using NBF;
// using Obi;
// using UnityEngine;
//
// public class FLineHandler : MonoBehaviour
// {
// public enum LineType
// {
// None = 0,
// OneSegment = 1,
// TwoSegment = 2,
// ThereSegment = 3
// }
//
// public LineType lineType = LineType.TwoSegment;
//
// // public ObiParticleAttachment startParticleAttachment;
//
// public ObiRope obiRopeSegment_1;
//
// public ObiRope obiRopeSegment_2;
//
// public ObiRope obiRopeSegment_3;
//
// public FixedLine LineConnector_0;
//
// public SpringJoint LineConnector_1;
//
// public SpringJoint LineConnector_2;
//
// public SpringJoint LineConnector_3;
//
// // [HideInInspector] public FFishingLine currentRodFishingLineComponent;
//
// // public ObiParticleAttachment toRodConnector;
//
// // public float PhisicsLineOut { get; set; }
//
// public float ObiLineOut;
//
// [HideInInspector] public Rigidbody EndLineRigidbody_0;
//
// [HideInInspector] public Rigidbody EndLineRigidbody_1;
//
// [HideInInspector] public Rigidbody EndLineRigidbody_2;
//
// [HideInInspector] public Rigidbody EndLineRigidbody_3;
//
// // public JointPinchController pinchController;
//
// public FRod Rod;
//
// private Transform waterPlane;
//
//
// public LineRenderer LineRenderer1;
// public LineRenderer LineRenderer2;
//
// // public float ropeToHookDistance;
//
// void Start()
// {
// ObiLineOut = obiRopeSegment_1.stretchingScale;
// if ((bool)LineConnector_0)
// {
// EndLineRigidbody_0 = LineConnector_0.GetComponent<Rigidbody>();
// }
//
// if ((bool)LineConnector_1)
// {
// EndLineRigidbody_1 = LineConnector_1.GetComponent<Rigidbody>();
// }
//
// if ((bool)LineConnector_2)
// {
// EndLineRigidbody_2 = LineConnector_2.GetComponent<Rigidbody>();
// // var fixedJoint = LineConnector_2.GetComponent<FixedJoint>();
// // pinchController = LineConnector_2.gameObject.AddComponent<JointPinchController>();
// }
//
// if ((bool)LineConnector_3)
// {
// EndLineRigidbody_3 = LineConnector_3.GetComponent<Rigidbody>();
// }
//
// waterPlane = GameObject.FindGameObjectWithTag("Water").transform;
//
// Debug.LogError($"rope.restLength={obiRopeSegment_1.restLength} LineConnector_1={LineConnector_1.maxDistance}");
// }
//
//
// void Update()
// {
// if (!Rod) return;
//
//
// // ropeToHookDistance = Vector3.Distance(toRodConnector.transform.position, LineConnector_1.transform.position);
//
// ObiLineOut = 0.1f + Rod.lineLength;
// float target = (0f - Mathf.Clamp(Rod.linelenghtDiferent, -1f, 0f)) * 0.1f;
// if (Rod.linelenghtDiferent >= 0f)
// {
// obiRopeSegment_1.stretchCompliance = Mathf.MoveTowards(obiRopeSegment_1.stretchCompliance, target,
// Time.smoothDeltaTime * (1f * Rod.linelenghtDiferent));
// }
// else
// {
// obiRopeSegment_1.stretchCompliance = Mathf.MoveTowards(obiRopeSegment_1.stretchCompliance, target,
// Time.smoothDeltaTime * 0.1f);
// }
//
// if (Rod.lineLength == 0f)
// {
// obiRopeSegment_1.stretchCompliance = 0f;
// }
//
// if ((bool)obiRopeSegment_2)
// {
// if (!Rod.currentFish)
// {
// obiRopeSegment_2.stretchCompliance = obiRopeSegment_2.stretchingScale * 0.004f;
// }
// else
// {
// obiRopeSegment_2.stretchCompliance = 0f;
// }
//
// //TODO:TEST
// obiRopeSegment_2.stretchingScale = 0.13F;
// }
//
// obiRopeSegment_1.stretchingScale = ObiLineOut;
// obiRopeSegment_1.stretchingScale = 1;
// LineConnector_1.maxDistance = 0.1f + Rod.lineLength;
// if (Input.GetKey(KeyCode.E))
// {
// // var speed = 1;
// // obiRopeCursor_1.ChangeLength(LineConnector_1.maxDistance);
// // Debug.Log(obiRopeSegment_1.restLength);
// }
//
// // var addLength = LineConnector_1.maxDistance - obiRopeSegment_1.restLength;
// // if (Mathf.Abs(addLength) > 0.001f)
// // {
// // obiRopeCursor_1.ChangeLength(LineConnector_1.maxDistance);
// // }
//
// // if (!Mathf.Approximately(LineConnector_1.maxDistance, obiRopeSegment_1.restLength))
// // {
// // obiRopeCursor_1.ChangeLength(LineConnector_1.maxDistance);
// // }
//
// // obiRopeCursor_1.pos
//
//
// // LineConnector_1.minDistance = LineConnector_1.maxDistance;
// }
//
//
// public void SetSegmentTwoLenght(float lenght)
// {
// LineConnector_2.maxDistance = lenght;
// // obiRopeCursor_2.ChangeLength(lenght);
// // LineConnector_2.minDistance = LineConnector_2.maxDistance;
// }
//
// private void FixedUpdate()
// {
// // BindRod();
// LineWaterDisplacement();
// }
//
// private void BindRod()
// {
// if (!Rod || !Rod.Asset) return;
// LineConnector_0.transform.position = Rod.Asset.lineConnector.position;
// }
//
// private void LineWaterDisplacement()
// {
// if (!waterPlane)
// {
// return;
// }
//
// for (int i = 0; i < obiRopeSegment_1.activeParticleCount; i++)
// {
// if (obiRopeSegment_1.GetParticlePosition(i).y < waterPlane.position.y)
// {
// // obiRopeSegment_1.AddForceParticle(i, Vector3.up * 10f, ForceMode.Acceleration);
// }
// }
// }
// }

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 331fde19f47e431092cf5bd57c7bcfe4
timeCreated: 1766586159

View File

@@ -0,0 +1,21 @@
using UnityEngine;
namespace NBF
{
public class FLure : FGearBase
{
protected override void OnInit()
{
// transform.position = Rod.lineHandler.LineConnector_1.transform.position;
// Lure.gameObject.GetComponent<ConfigurableJoint>().connectedBody =
// lineHandler.LineConnector_1.GetComponent<Rigidbody>();
// LureHookWaterDisplacement = Lure.GetComponent<FWaterDisplacement>();
// SetParent(Rod.lineHandler.LineConnector_1.transform);
SetParent(Rod.Line.Lure.transform);
transform.localPosition = Vector3.zero;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3f91ba5f4ca745d4b29fb2116781e25f
timeCreated: 1766478011

View File

@@ -0,0 +1,32 @@
using System.Collections;
using Fantasy;
using UnityEngine;
namespace NBF
{
public class FReel : FGearBase
{
public bool isBlockLineByFinger { get; set; }
[SerializeField] public float reelingDrag = 1f;
public ReelAsset Asset;
public ReelAnimator AnimatorCtrl;
private void Awake()
{
Asset = GetComponent<ReelAsset>();
AnimatorCtrl = Asset.animator.gameObject.GetComponent<ReelAnimator>();
if (AnimatorCtrl == null)
{
AnimatorCtrl = Asset.animator.gameObject.AddComponent<ReelAnimator>();
}
}
protected override void OnInit()
{
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b48fc45344c5439c9d19897cb5987abf
timeCreated: 1766478030

View File

@@ -0,0 +1,350 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Fantasy;
using NBC.Asset;
using NBF.Utils;
using UnityEngine;
using Object = UnityEngine.Object;
namespace NBF
{
public class FRod : FHandItem
{
private float _tension;
/// <summary>
/// 可用的
/// </summary>
public bool Usable { get; private set; }
public RodAsset Asset;
public FPlayer Player { get; protected set; }
public ItemInfo ItemInfo;
public FReel Reel;
public FHook Hook;
public FBobber Bobber;
public FBait Bait;
public FLure Lure;
public FWeight Weight;
public FLine Line;
// /// <summary>
// /// 鱼线处理器
// /// </summary>
// public FLineHandler lineHandler;
public Transform GearRoot;
// public FWaterDisplacement LureHookWaterDisplacement;
[HideInInspector] public FFish currentFish;
public RodRingNode[] rings;
/// <summary>
/// 线长度
/// </summary>
public float lineLength = 1.5f;
/// <summary>
/// 浮漂线长度
/// </summary>
public float floatLength = 0.5f;
public float Tension
{
get => _tension;
private set
{
if (!Mathf.Approximately(_tension, value))
{
_tension = value;
// OnTensionChanged?.Invoke(_tension);
}
}
}
public float currentLineTension;
public float linelenghtDiferent;
public float currentLineStrenght;
private void Awake()
{
Asset = GetComponent<RodAsset>();
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Alpha0))
{
SetLineLength(lineLength);
}
else if (Input.GetKeyDown(KeyCode.Plus) || Input.GetKeyDown(KeyCode.Equals))
{
lineLength += 0.1f;
SetLineLength(lineLength);
}
else if (Input.GetKeyDown(KeyCode.Minus))
{
lineLength -= 0.1f;
SetLineLength(lineLength);
}
}
public void SetLineLength(float lineLength, bool stretchRope = true)
{
if (!Line) return;
if (Line.IsLure)
{
//没有浮漂类型
Line.Lure.SetJointDistance(lineLength);
if (stretchRope)
{
Line.SetObiRopeStretch(Tension > 0f ? 0f : lineLength);
}
}
else
{
//有浮漂
Line.Lure.SetJointDistance(floatLength);
Line.Bobber.SetJointDistance(lineLength - floatLength);
if (stretchRope)
{
Line.SetObiRopeStretch(Tension > 0f ? 0f : lineLength - floatLength);
}
}
}
private void LateUpdate()
{
Test();
}
public IEnumerator Destroy()
{
if (GearRoot != null)
{
Object.Destroy(GearRoot.gameObject);
}
yield return 1;
}
public IEnumerator InitRod(FPlayer player, ItemInfo itemInfo)
{
ItemInfo = itemInfo;
Player = player;
transform.localPosition = Vector3.zero;
transform.localRotation = Quaternion.identity;
transform.localScale = Vector3.one;
SceneSettings.Instance.GearNode.position = Player.transform.position;
yield return 1;
var obj = new GameObject($"rod_{itemInfo.Id}_{itemInfo.ConfigId}");
obj.transform.SetParent(SceneSettings.Instance.GearNode);
// obj.transform.SetParent(player.transform);
// obj.transform.localPosition = Vector3.zero;
obj.transform.position = player.transform.position;
obj.transform.rotation = player.transform.rotation;
obj.transform.localScale = Vector3.one;
GearRoot = obj.transform;
var parent = GearRoot;
List<ItemInfo> children = RoleModel.Instance.GetBindItems(itemInfo.Id);
ItemInfo lineItemInfo = null;
CreateFishingHandler();
yield return 1; //等待1帧
// children.Sort();
foreach (var child in children)
{
var itemType = child.ConfigId.GetItemType();
if (itemType == ItemType.Reel)
{
Reel = child.Config.InstantiateAndComponent<FReel>(Asset.ReelConnector, Vector3.zero,
Quaternion.identity);
Reel.SetItemInfo(child);
}
else if (itemType == ItemType.Bobber)
{
Bobber = child.Config.InstantiateAndComponent<FBobber>(parent, Vector3.zero,
Quaternion.identity);
Bobber.SetItemInfo(child);
}
else if (itemType == ItemType.Hook)
{
Hook = child.Config.InstantiateAndComponent<FHook>(parent, Vector3.zero,
Quaternion.identity);
Hook.SetItemInfo(child);
}
else if (itemType == ItemType.Bait)
{
Bait = child.Config.InstantiateAndComponent<FBait>(parent, Vector3.zero,
Quaternion.identity);
Bait.SetItemInfo(child);
}
else if (itemType == ItemType.Lure)
{
Lure = child.Config.InstantiateAndComponent<FLure>(parent, Vector3.zero,
Quaternion.identity);
Lure.SetItemInfo(child);
}
else if (itemType == ItemType.Weight)
{
Weight = child.Config.InstantiateAndComponent<FWeight>(parent, Vector3.zero,
Quaternion.identity);
Weight.SetItemInfo(child);
}
else if (itemType == ItemType.Line)
{
lineItemInfo = child;
}
}
yield return 1;
if (Reel)
{
Reel.reelingDrag = 0.699f;
Reel.transform.SetParent(Asset.ReelConnector);
Reel.transform.localPosition = Vector3.zero;
Reel.transform.localEulerAngles = Vector3.zero;
Reel.Init(player, this);
}
if (Bobber)
{
Bobber.Init(Player, this);
}
if (Hook)
{
Hook.Init(Player, this);
// LureHookWaterDisplacement = Hook.GetComponent<FWaterDisplacement>();
}
if (Bait)
{
Bait.Init(Player, this);
}
if (Lure)
{
Lure.Init(Player, this);
}
if (Weight)
{
Weight.Init(Player, this);
}
yield return 1; //等待1帧
transform.SetParent(Player.ModelAsset.RodRoot);
transform.localPosition = Vector3.zero;
transform.rotation = Player.ModelAsset.RodRoot.rotation;
Usable = true;
}
public void CreateFishingHandler()
{
if (Line == null)
{
Debug.LogError("创建钓组=====");
var rodType = (ItemSubType)ItemInfo.Config.Type;
if (rodType == ItemSubType.RodTele)
{
CreateObiFishingLine(0);
}
else if (rodType == ItemSubType.RodSpine || rodType == ItemSubType.RodBolo)
{
CreateObiFishingLine(1);
}
}
}
public void CreateObiFishingLine(int currentLineTypeIndex)
{
if (!Line)
{
var lineSolverPrefab = Assets.Load<GameObject>("Assets/ResRaw/Prefabs/Line/LineSolver.prefab");
var solver = Instantiate(lineSolverPrefab, GearRoot);
solver.transform.position = Asset.lineConnector.position;
solver.transform.rotation = Asset.lineConnector.rotation;
var indexNames = new[] { "fishing line float set", "fishing line spinning" };
var path =
$"Assets/ResRaw/Prefabs/Line/{indexNames[currentLineTypeIndex]}.prefab";
var prefab = Assets.Load<GameObject>(path);
GameObject obj = Instantiate(prefab, solver.transform);
obj.transform.localPosition = Vector3.zero;
obj.transform.localScale = Vector3.one;
obj.transform.rotation = Quaternion.identity;
Line = obj.GetComponent<FLine>();
Line.transform.position = Asset.lineConnector.position;
Line.Init(this.Player, this);
// var obiSolver = solver.GetComponent<ObiSolver>();
// obiSolver.parameters.ambientWind = Vector3.zero;
// obiSolver.wind.
// obiSolver.simulateWhenInvisible
}
}
public void SetRing(RodRingAsset ringAsset)
{
if (Asset.rings == null || Asset.rings.Length < 1) return;
var trans = ringAsset.rings;
RodRingNode lastRingNode = null;
List<RodRingNode> list = new List<RodRingNode>();
for (int i = 0; i < Asset.rings.Length; i++)
{
var ring = Asset.rings[i];
if (ring == null)
{
Log.Error($"ring is null,index={i}");
continue;
}
var lastName = ring.name.GetLastString();
foreach (var tran in trans)
{
var ringNode = tran.ring;
var lastName2 = ringNode.name.GetLastString();
if (lastName != lastName2) continue;
list.Add(tran);
ringNode.SetParent(ring);
ringNode.localPosition = Vector3.zero;
ringNode.localRotation = Quaternion.identity;
lastRingNode = tran;
break;
}
}
if (lastRingNode != null)
{
Asset.lineConnector = lastRingNode.point;
}
rings = list.ToArray();
}
private void Test()
{
// var root = Player.ModelAsset.RodRoot;
// if (!root) return;
// transform.SetPositionAndRotation(root.position, root.rotation);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ef4dfd89c0c34916be91b55490eb1c9f
timeCreated: 1766477316

View File

@@ -0,0 +1,233 @@
// using System.Collections;
// using Fantasy;
// using UnityEngine;
//
// namespace NBF
// {
// /// <summary>
// /// 虚拟钓组
// /// </summary>
// public class FVirtualTackle
// {
// private ItemInfo _itemInfo;
// private FPlayer _player;
//
//
// public FRod Rod;
//
//
// public FVirtualTackle(ItemInfo itemInfo, FPlayer player)
// {
// _itemInfo = itemInfo;
// _player = player;
// }
//
// public IEnumerator Create()
// {
// var parent = _player.transform;
// // parent.position = _player.transform.position;
//
//
// Rod = _itemInfo.Config.InstantiateAndComponent<FRod>(parent, Vector3.zero, Quaternion.identity);
//
//
// // var rodObject = _itemInfo.Config.Instantiate(parent, Vector3.zero, Quaternion.identity);
// // Rod = rodObject.GetComponent<FRod>();
// // if (Rod == null)
// // {
// // Rod = rodObject.AddComponent<FRod>();
// // }
// // var rodConfig = RodConfig.Get(itemInfo.ConfigId);
// // itemInfo.Config
//
// // var data = Player.Data.currentGear;
// // var rodConfig = data.rod.Config;
// // var cloneObj = rodConfig.Instantiate(parent, Vector3.zero, Player.MainArm.RodContainer.rotation);
// // if (cloneObj == null)
// // {
// // yield break;
// // }
// //
// // Rod = cloneObj.GetComponent<FRod>();
// // if (Rod == null)
// // {
// // Rod = cloneObj.AddComponent<FRod>();
// // }
// //
// //
// // if (Rod)
// // {
// // Rod.transform.localPosition = Vector3.zero;
// // Rod.transform.rotation = Player.MainArm.RodContainer.rotation;
// //
// // if (rodConfig.ring > 0)
// // {
// // var ringConfig = GameRings.Get(rodConfig.ring);
// // var ringObject = ringConfig.Instantiate(Rod.transform);
// // ringObject.SetActive(false);
// // Rod.SetRing(ringObject.GetComponent<RodRingAsset>());
// // }
// // }
// // else
// // {
// // yield break;
// // }
// //
// // if (data.line != null)
// // {
// // var linePrefab = data.line.Config.Instantiate(parent);
// // Line = linePrefab.GetComponent<FLine>();
// // }
// //
// // if (data.reel != null)
// // {
// // var reelPrefab = data.reel.Config.Create(parent);
// // Reel = reelPrefab.GetComponent<FReel>();
// // }
// //
// // if (data.bobber != null)
// // {
// // var bobberPrefab = data.bobber.Config.Create(parent);
// // Bobber = bobberPrefab.GetComponent<FFloat>();
// // }
// //
// // if (data.hook != null)
// // {
// // var hookPrefab = data.hook.Config.Create(parent);
// // Hook = hookPrefab.GetComponent<FHook>();
// // }
// //
// // if (data.bait != null)
// // {
// // var baitPrefab = data.bait.Config.Create(parent);
// //
// // if (baitPrefab.TryGetComponent<FBait>(out var bait))
// // {
// // Bait = bait;
// // }
// // }
// //
// // if (data.lure != null)
// // {
// // var baitPrefab = data.lure.Config.Create(parent);
// // if (baitPrefab.TryGetComponent<FLure>(out var lure))
// // {
// // Lure = lure;
// // }
// // }
// //
// //
// // if (data.weight != null)
// // {
// // var weightPrefab = data.weight.Config.Instantiate(parent);
// // Weight = weightPrefab.GetComponent<FWeight>();
// // }
// //
// // Debug.LogError("CreateOrHideGear");
// // yield return 1;
// // Rod.Initialize(Player, data.rod);
// // Rod.CreateFishingHandler();
// //
// // if (Line)
// // {
// // Line.Initialize(Player, data.line);
// //
// //
// // if ((bool)Rod.lineHandler.obiRopeSegment_1)
// // {
// // Rod.lineHandler.obiRopeSegment_1.GetComponent<MeshRenderer>().material =
// // Line.lineMat;
// // }
// //
// // if ((bool)Rod.lineHandler.obiRopeSegment_2)
// // {
// // Rod.lineHandler.obiRopeSegment_2.GetComponent<MeshRenderer>().material =
// // Line.lineMat;
// // }
// //
// // if ((bool)Rod.lineHandler.obiRopeSegment_3)
// // {
// // Rod.lineHandler.obiRopeSegment_3.GetComponent<MeshRenderer>().material =
// // Line.lineMat;
// // }
// // }
// //
// // if (Reel)
// // {
// // // Reel.maxReelStrength = data.reel.Config.strength;
// // // Reel.reelingSpeed = 0.5f; //slotsEquip.reel.currentSpeed;
// // Reel.reelingDrag = 0.699f; //slotsEquip.reel.currentDrag;
// // Reel.transform.SetParent(Rod.rodAsset.ReelConnector);
// // Reel.transform.localPosition = Vector3.zero;
// // Reel.transform.localEulerAngles = Vector3.zero;
// // // Reel.reelAsset.szpulaObject.GetComponent<MeshRenderer>().material = Line.szpulaMat;
// // Reel.Initialize(Player, data.reel);
// // }
// //
// // if (Bobber)
// // {
// // Bobber.floatDisplacement = data.bobber.Config.displacement;
// // // if ((double)slotsEquip.ffloat.lastSetGroundValue > 0.2)
// // // {
// // // Bobber.newDeepth = slotsEquip.ffloat.lastSetGroundValue;
// // // }
// //
// // Bobber.newDeepth = 0.5f;
// //
// // Bobber.Initialize(Player, data.bobber);
// // Bobber.transform.position = Rod.lineHandler.LineConnector_1.transform.position;
// // Bobber.gameObject.GetComponent<ConfigurableJoint>().connectedBody =
// // Rod.lineHandler.LineConnector_1.GetComponent<Rigidbody>();
// // }
// //
// //
// // if (Hook)
// // {
// // Hook.Initialize(Player, data.hook);
// //
// // Hook.transform.position = Rod.lineHandler.LineConnector_2.transform.position;
// // Hook.transform.rotation = Rod.lineHandler.LineConnector_2.transform.rotation; // 确保旋转也同步
// // var target = Rod.lineHandler.LineConnector_2.GetComponent<Rigidbody>();
// // var joint = Hook.gameObject.GetComponent<ConfigurableJoint>();
// // // // 关键设置:关闭自动锚点计算,手动设置锚点
// // // joint.autoConfigureConnectedAnchor = false;
// // // joint.anchor = Vector3.zero; // 以 Hook 自身中心为锚点
// // // joint.connectedAnchor = Vector3.zero; // 以目标物体的中心为锚点
// // joint.connectedBody = target;
// // // // 强制物理引擎立即更新变换避免1帧延迟
// // // Physics.SyncTransforms();
// // // joint.autoConfigureConnectedAnchor = false;
// // // joint.anchor = Vector3.zero;
// // // joint.connectedAnchor = Vector3.zero;
// // Rod.LureHookWaterDisplacement = Hook.GetComponent<FWaterDisplacement>();
// // }
// //
// // if (Bait)
// // {
// // Bait.Initialize(Player, data.bait);
// // Bait.transform.position = Hook.hookAsset.baitConnector.position;
// // Bait.transform.SetParent(Hook.hookAsset.baitConnector);
// // }
// //
// // if (Lure)
// // {
// // Lure.Initialize(Player, data.bait);
// // Lure.transform.position = Rod.lineHandler.LineConnector_1.transform.position;
// // Lure.gameObject.GetComponent<ConfigurableJoint>().connectedBody =
// // Rod.lineHandler.LineConnector_1.GetComponent<Rigidbody>();
// // Rod.LureHookWaterDisplacement = Lure.GetComponent<FWaterDisplacement>();
// // }
// //
// // if (Weight)
// // {
// // Weight.weight = data.weight.Config.weight;
// // Weight.Initialize(Player, data.weight);
// // }
// }
//
// public IEnumerator Destroy()
// {
// yield return 1;
// }
// }
// }

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4092f341d83540c0b6ba0e2db3669f1b
timeCreated: 1766478162

View File

@@ -0,0 +1,12 @@
using UnityEngine;
namespace NBF
{
public class FWeight : FGearBase
{
protected override void OnInit()
{
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a68c58e07092402dbc37a5f287e70b9b
timeCreated: 1766582543