去掉复杂结构,一切从简

This commit is contained in:
Bob.Song
2026-04-29 16:39:15 +08:00
parent bf2f9f7a27
commit d552a83ccb
90 changed files with 1198 additions and 411 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,65 @@
using System.Collections.Generic;
using Fantasy;
using Fantasy.Async;
using Fantasy.Entitas;
using NBF.Fishing2;
using RootMotion.FinalIK;
using Log = NBC.Log;
namespace NBF
{
public class Fishing
{
private static Fishing _instance;
public static Fishing Instance
{
get
{
_instance ??= new Fishing();
return _instance;
}
}
public bool Loading { get; private set; }
public async FTask<bool> Go(int mapId, string roomCode = "")
{
Loading = true;
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}");
if (response.ErrorCode != 0)
{
Notices.Error("enter room error");
return false;
}
LoadingPanel.Show();
await ChangeMap(response.MapId, response.RoomCode, response.Units);
LoadingPanel.Hide();
Loading = false;
return true;
}
public async FTask ChangeMap(int mapId, string roomCode, List<MapUnitInfo> units)
{
var sceneName = "Map1";
//加载场景==
await SceneHelper.LoadScene(sceneName);
Map.Instance.SetData(mapId, roomCode, units);
Map.Instance.InstancePlayers();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 31a84e44641f4115a5531e1b7328630a
timeCreated: 1777438436

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a752ba9ae5b04fed93d81cf0764c5d00
timeCreated: 1777437774

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,48 @@
using Fantasy;
using NBC;
using NBC.Asset;
using NBF.Utils;
using UnityEngine;
namespace NBF
{
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,3 @@
fileFormatVersion: 2
guid: be8d099db51445eea5a3eeb70849904a
timeCreated: 1777449783

View File

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

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f4bdd31c4ed448ecb00eca659d9d9db1
timeCreated: 1777449812

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ab0e597ee4744959abdc5dc66546dacb
timeCreated: 1777211780

View File

@@ -0,0 +1,586 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NBC;
// using Obi;
using UnityEngine;
namespace NBF
{
public enum LineType
{
Hand,
HandDouble,
Spinning,
SpinningFloat,
}
/// <summary>
/// 线模式
/// </summary>
public enum LineMode
{
Joint,
Constraint
}
public class FLine : FGearBase
{
public LineType LineType;
[Header("连接点配置")] [SerializeField] private Transform anchorTransform;
[SerializeField] private List<FLineLogicNode> lineNodes = new List<FLineLogicNode>();
[Header("物理参数")] [SerializeField] private float positionCorrectionForce = 100f;
[SerializeField] private float dampingCoefficient = 10f;
[SerializeField] private int constraintIterations = 10;
[SerializeField] private bool useMassWeighting = true;
[SerializeField] private bool showDebugInfo = true;
[Header("动态间距设置")] [SerializeField] private float defaultTransitionSpeed = 2f; // 默认长度变化速度(单位/秒)
private LineMode _lineMode = LineMode.Joint;
// [SerializeField] private bool isLureConnect;
//
// [SerializeField] private RodLine rodLine;
//
// /// <summary>
// /// 主线
// /// </summary>
// [SerializeField] private Rope fishingRope;
//
// /// <summary>
// /// 浮漂和鱼钩线
// /// </summary>
// [SerializeField] private Rope bobberRope;
// public LureController Lure;
// public BobberController Bobber;
//
// public JointPinchController PinchController;
private readonly List<ConnectionConstraint> _constraints = new List<ConnectionConstraint>();
public FLineLogicNode StartNode { get; private set; }
public FLineLogicNode BobberNode => GetNode(FLineLogicNodeType.Bobber);
public FLineLogicNode EndNode { get; private set; }
public LineMode LineMode => _lineMode;
public float LinelenghtDiferent;
[System.Serializable]
public class ConnectionConstraint
{
public FLineLogicNodeType NodeType;
public Rigidbody bodyA;
public Rigidbody bodyB;
public float maxDistance;
public float minDistance;
public float currentDistance;
public Vector3 direction;
// 动态目标距离(用于平滑过渡)
public float targetMaxDistance;
public bool hasPendingTransition;
public bool hasPendingMaxTransition;
public float maxTransitionSpeed;
public ConnectionConstraint(Rigidbody a, Rigidbody b, float maxDist, float minDist = 0f)
{
bodyA = a;
bodyB = b;
maxDistance = maxDist;
minDistance = minDist;
targetMaxDistance = maxDist;
hasPendingTransition = false;
hasPendingMaxTransition = false;
maxTransitionSpeed = 0f;
}
public void UpdateCurrentState()
{
if (bodyA && bodyB)
{
Vector3 delta = bodyB.position - bodyA.position;
currentDistance = delta.magnitude;
direction = currentDistance > 0.0001f ? delta.normalized : Vector3.right;
}
}
}
protected override void OnInit()
{
if (anchorTransform == null)
{
var tipRb = Rod.Asset.LineConnectorRigidbody;
anchorTransform = tipRb.transform;
}
}
private void Start()
{
BuildConstraints();
StartNode = GetNode(FLineLogicNodeType.Start);
EndNode = GetNode(FLineLogicNodeType.End);
}
private void Update()
{
LinelenghtDiferent = GetLineDistance();
//非钓鱼状态
if (Rod) Rod.Tension = Mathf.Clamp(LinelenghtDiferent, 0f, 0.05f);
}
private void FixedUpdate()
{
UpdateAnchorNode();
FixedUpdateConstraints();
}
public void ChangeMode(LineMode mode)
{
_lineMode = mode;
foreach (var fLineLogicNode in lineNodes)
{
fLineLogicNode.ChangeMode(mode);
}
}
public List<FLineLogicNode> GetLineNodes()
{
return new List<FLineLogicNode>(lineNodes);
}
public void Print()
{
// Log.Info($"当前线情况 TotalLength={TotalLength} CurrentStretchLength={CurrentStretchLength}");
}
#region
private void UpdateAnchorNode()
{
if (anchorTransform == null || lineNodes.Count < 1)
{
return;
}
var startNode = lineNodes[0].Rigidbody;
startNode.transform.SetPositionAndRotation(anchorTransform.position, anchorTransform.rotation);
if (!startNode.isKinematic)
{
startNode.linearVelocity = Vector3.zero;
startNode.angularVelocity = Vector3.zero;
}
}
/// <summary>
/// 获取一个节点
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public FLineLogicNode GetNode(FLineLogicNodeType type)
{
foreach (var node in lineNodes)
{
if (node.NodeType == type)
{
return node;
}
}
return null;
}
public void SetLenght(float lenght, FLineLogicNodeType type = FLineLogicNodeType.Bobber)
{
var node = GetNode(type);
if (node != null)
{
if (_lineMode == LineMode.Joint)
{
node.SetLenght(lenght);
}
else
{
SetSegmentMaxLength(lenght, type);
}
}
}
#endregion
#region
private void FixedUpdateConstraints()
{
if (_lineMode != LineMode.Constraint) return;
if (!enabled || lineNodes.Count < 2) return;
// 更新动态过渡
UpdateTransitions();
for (int iteration = 0; iteration < constraintIterations; iteration++)
{
ApplyDistanceConstraints();
}
ApplyDamping();
}
private void BuildConstraints()
{
_constraints.Clear();
if (lineNodes.Count < 2) return;
// 创建约束
for (int i = 0; i < lineNodes.Count - 1; i++)
{
FLineLogicNode currentNode = lineNodes[i];
FLineLogicNode nextNode = lineNodes[i + 1];
Rigidbody bodyA = currentNode ? currentNode.Rigidbody : null;
Rigidbody bodyB = nextNode ? nextNode.Rigidbody : null;
if (bodyA != null && bodyB != null)
{
var constraint = new ConnectionConstraint(
bodyA,
bodyB,
nextNode.Lenght
);
constraint.NodeType = nextNode.NodeType;
_constraints.Add(constraint);
}
}
}
private void ApplyDistanceConstraints()
{
for (int i = 0; i < _constraints.Count; i++)
{
var constraint = _constraints[i];
if (!constraint.bodyA || !constraint.bodyB) continue;
constraint.UpdateCurrentState();
float currentDist = constraint.currentDistance;
float maxDist = constraint.maxDistance;
float minDist = constraint.minDistance;
float error = 0f;
bool needCorrection = false;
if (currentDist > maxDist)
{
error = currentDist - maxDist;
needCorrection = true;
}
if (!needCorrection || Mathf.Abs(error) < 0.0001f) continue;
float invMassA = constraint.bodyA.isKinematic ? 0f : 1f / constraint.bodyA.mass;
float invMassB = constraint.bodyB.isKinematic ? 0f : 1f / constraint.bodyB.mass;
float totalInvMass = invMassA + invMassB;
if (totalInvMass < 0.0001f) continue;
float weightA = useMassWeighting ? (invMassA / totalInvMass) : 0.5f;
float weightB = useMassWeighting ? (invMassB / totalInvMass) : 0.5f;
Vector3 correction = constraint.direction * error;
Vector3 positionCorrectionA = correction * weightA;
Vector3 positionCorrectionB = -correction * weightB;
constraint.bodyA.position += positionCorrectionA;
constraint.bodyB.position += positionCorrectionB;
Vector3 velocityCorrectionA = positionCorrectionA / Time.fixedDeltaTime;
Vector3 velocityCorrectionB = positionCorrectionB / Time.fixedDeltaTime;
constraint.bodyA.AddForce(velocityCorrectionA * constraint.bodyA.mass, ForceMode.Impulse);
constraint.bodyB.AddForce(velocityCorrectionB * constraint.bodyB.mass, ForceMode.Impulse);
}
}
private void ApplyDamping()
{
for (int i = 0; i < _constraints.Count; i++)
{
var constraint = _constraints[i];
if (!constraint.bodyA || !constraint.bodyB) continue;
if (constraint.currentDistance <= constraint.maxDistance) continue;
Vector3 relativeVelocity = constraint.bodyB.linearVelocity - constraint.bodyA.linearVelocity;
float velocityInConstraintDir = Vector3.Dot(relativeVelocity, constraint.direction);
if (velocityInConstraintDir > 0)
{
float dampingForce = -velocityInConstraintDir * dampingCoefficient;
Vector3 dampingImpulse = constraint.direction * dampingForce * Time.fixedDeltaTime;
constraint.bodyA.AddForce(-dampingImpulse * constraint.bodyA.mass, ForceMode.Impulse);
constraint.bodyB.AddForce(dampingImpulse * constraint.bodyB.mass, ForceMode.Impulse);
}
}
}
/// <summary>
/// 按速度过渡某段的最大距离
/// </summary>
private void SetSegmentMaxLength(float targetLength, FLineLogicNodeType type = FLineLogicNodeType.Bobber,
float transitionSpeed = 2f)
{
var constraint = _constraints.Find(t => t.NodeType == type);
if (constraint == null) return;
targetLength = Mathf.Max(0.01f, targetLength);
float speed = Mathf.Max(0.01f, transitionSpeed > 0 ? transitionSpeed : defaultTransitionSpeed);
constraint.targetMaxDistance = targetLength;
constraint.maxTransitionSpeed = speed;
constraint.hasPendingMaxTransition = Mathf.Abs(constraint.maxDistance - targetLength) >= 0.0001f;
constraint.hasPendingTransition = constraint.hasPendingMaxTransition;
}
/// <summary>
/// 更新所有活跃的过渡
/// </summary>
private void UpdateTransitions()
{
float deltaTime = Time.fixedDeltaTime;
for (int i = 0; i < _constraints.Count; i++)
{
var constraint = _constraints[i];
if (constraint.hasPendingMaxTransition)
{
float nextMaxDistance = Mathf.MoveTowards(
constraint.maxDistance,
constraint.targetMaxDistance,
constraint.maxTransitionSpeed * deltaTime
);
constraint.maxDistance = nextMaxDistance;
var node = GetNode(constraint.NodeType);
// SyncSegmentMaxLength(i, nextMaxDistance);
node.SetLenght(nextMaxDistance);
if (Mathf.Abs(nextMaxDistance - constraint.targetMaxDistance) < 0.0001f)
{
constraint.maxDistance = constraint.targetMaxDistance;
constraint.hasPendingMaxTransition = false;
// SyncSegmentMaxLength(i, constraint.targetMaxDistance);
node.SetLenght(constraint.targetMaxDistance);
}
}
constraint.hasPendingTransition = constraint.hasPendingMaxTransition;
}
}
/// <summary>
/// 获取某个段是否正在进行过渡
/// </summary>
public bool IsSegmentTransitioning(int segmentIndex)
{
if (segmentIndex >= 0 && segmentIndex < _constraints.Count)
{
return _constraints[segmentIndex].hasPendingTransition;
}
return false;
}
#endregion
// #region 极限判定
//
// /// <summary>
// /// 当前逻辑链总长度超出配置总长度的部分,小于等于零时记为 0。
// /// </summary>
// [Header("Limit Detection")]
// public float CurrentStretchLength { get; private set; }
//
// /// <summary>
// /// 总长度
// /// </summary>
// public float TotalLength { get; private set; }
//
// [Min(0f)]
// // 极限判定的长度容差,允许链路在总长或单段长度上存在少量误差。
// [SerializeField]
// private float lengthLimitTolerance = 0.01f;
//
// [Min(0f)]
// // 达到极限后,只有当前超长值大于该阈值时,才开始进入断线候选计时。
// [SerializeField]
// private float breakStretchThreshold = 0.3f;
//
// [Min(0f)]
// // UI 百分比开始起算的最小超长值;低于或等于该值时统一按 0% 处理。
// [SerializeField]
// private float breakStretchPercentMinThreshold = 0.06f;
//
// [Min(0f)]
// // 断线候选状态允许持续的最大时间;超过后会发出一次断线消息。
// [SerializeField]
// private float breakLimitDuration = 3f;
//
// /// <summary>
// /// 当鱼线达到断线条件时发出的一次性消息。
// /// 外部可订阅该事件,在回调中执行切线、播放表现或状态切换。
// /// </summary>
// public event Action<FLine> OnLineBreakRequested;
//
// /// <summary>
// /// 当前是否处于极限状态。
// /// 只要整链超出总长度容差,或任一逻辑段超出单段容差,即认为到达极限。
// /// </summary>
// public bool IsAtLimit { get; private set; }
//
// /// <summary>
// /// 当前断线候选状态的累计时间。
// /// 只有在处于极限状态,且 CurrentStretchLength 大于断线阈值时才会累加;否则重置为 0。
// /// </summary>
// public float LimitStateTime { get; private set; }
//
// /// <summary>
// /// 当前极限断线消息是否已经发出过。
// /// 在退出断线候选状态前只会发一次,避免重复通知。
// /// </summary>
// public bool HasBreakNotificationSent { get; private set; }
//
// /// <summary>
// /// 当前拉力极限百分比。
// /// 当超长值小于等于 breakStretchPercentMinThreshold 时为 0
// /// 当超长值大于等于 breakStretchThreshold 时为 100
// /// 中间区间按线性比例映射,供 UI 显示使用。
// /// </summary>
// public float CurrentBreakStretchPercent => EvaluateBreakStretchPercent(CurrentStretchLength);
//
// /// <summary>
// /// 当前是否正在进行断线候选计时。
// /// </summary>
// public bool IsBreakCountdownActive => IsAtLimit && CurrentStretchLength > breakStretchThreshold;
//
// private float EvaluateBreakStretchPercent(float stretchLength)
// {
// var percentMinThreshold = Mathf.Max(lengthLimitTolerance, breakStretchPercentMinThreshold);
//
// if (stretchLength <= percentMinThreshold)
// {
// return 0f;
// }
//
// if (stretchLength >= breakStretchThreshold)
// {
// return 100f;
// }
//
// if (breakStretchThreshold <= percentMinThreshold)
// {
// return 100f;
// }
//
// return Mathf.InverseLerp(percentMinThreshold, breakStretchThreshold, stretchLength) * 100f;
// }
//
// private void SetLimitState(bool isAtLimit)
// {
// IsAtLimit = isAtLimit;
// }
//
// private void UpdateBreakCountdown(float deltaTime)
// {
// if (lineNodes.Count < 2)
// {
// SetLimitState(false);
// ResetLimitState();
// return;
// }
//
//
// var startNode = lineNodes[0];
// var endNode = lineNodes[^1];
// TotalLength = 0;
// foreach (var node in lineNodes)
// {
// TotalLength += node.Lenght;
// }
//
// var realLen = Vector3.Distance(startNode.transform.position, endNode.transform.position);
// CurrentStretchLength = realLen - TotalLength;
// if (CurrentStretchLength < 0f)
// {
// CurrentStretchLength = 0f;
// }
//
// SetLimitState(CurrentStretchLength > lengthLimitTolerance);
// if (LineMode != LineMode.Constraint) return;
//
// if (!IsBreakCountdownActive)
// {
// LimitStateTime = 0f;
// HasBreakNotificationSent = false;
// return;
// }
//
// LimitStateTime += Mathf.Max(0f, deltaTime);
// if (HasBreakNotificationSent || LimitStateTime < breakLimitDuration)
// {
// return;
// }
//
// HasBreakNotificationSent = true;
// NotifyLineBreakRequested();
// }
//
// /// <summary>
// /// 发出鱼线达到断线条件的消息。
// /// 这里预留给外部订阅,当前不在求解器内部直接执行断线逻辑。
// /// </summary>
// private void NotifyLineBreakRequested()
// {
// OnLineBreakRequested?.Invoke(this);
// }
//
// private void ResetLimitState()
// {
// CurrentStretchLength = 0f;
// IsAtLimit = false;
// LimitStateTime = 0f;
// HasBreakNotificationSent = false;
// }
//
// #endregion
#region Tension
private float GetLineDistance()
{
//第一个节点到竿稍的位置-第一段鱼线长度
return Vector3.Distance(StartNode.transform.position, BobberNode.transform.position) -
BobberNode.Lenght;
}
public float GetTension(float weight)
{
return weight * GetLineDistance();
}
#endregion
}
}

View File

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

View File

@@ -0,0 +1,102 @@
using System;
using System.Collections;
using UnityEngine;
namespace NBF
{
public enum FLineLogicNodeType
{
Start,
Bobber,
Weight,
End
}
public class FLineLogicNode : MonoBehaviour
{
[Header("节点设置")] public FLineLogicNodeType NodeType = FLineLogicNodeType.Bobber;
[SerializeField] private Rope rope;
[SerializeField] private Rigidbody preRigidbody;
private Rigidbody _rb;
private SpringJoint _joint;
private FLine _parentCable;
private float _lenght;
public Rigidbody PreRigidbody => preRigidbody;
public Rigidbody Rigidbody => _rb;
public FLine ParentCable => _parentCable;
public SpringJoint Joint => _joint;
public float Lenght => _lenght;
public Rope Rope => rope;
private void Awake()
{
_rb = GetComponent<Rigidbody>();
_parentCable = GetComponentInParent<FLine>();
_joint = GetComponent<SpringJoint>();
}
public void SetLenght(float lenght)
{
_lenght = lenght;
if (_joint)
{
_joint.maxDistance = lenght;
}
if (rope)
{
rope.SetTargetLength(lenght);
}
}
/// <summary>
/// 切换约束模式
/// </summary>
/// <param name="mode"></param>
public void ChangeMode(LineMode mode)
{
if (mode == LineMode.Joint)
{
if (_joint)
{
StartCoroutine(ReconnectedBody());
}
}
else if (mode == LineMode.Constraint)
{
if (_joint) _joint.connectedBody = null;
if (NodeType == FLineLogicNodeType.End)
{
Rigidbody.isKinematic = true;
}
}
}
private IEnumerator ReconnectedBody()
{
_joint.connectedBody = preRigidbody;
yield return 1;
Rigidbody.position = preRigidbody.position;
preRigidbody.isKinematic = true;
preRigidbody.linearVelocity = Vector3.zero;
preRigidbody.angularVelocity = Vector3.zero;
if (NodeType != FLineLogicNodeType.Start)
{
preRigidbody.isKinematic = false;
}
yield return 1;
preRigidbody.linearVelocity = Vector3.zero;
preRigidbody.angularVelocity = Vector3.zero;
if (NodeType == FLineLogicNodeType.End)
{
Rigidbody.isKinematic = false;
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7f840e1966fd4c2aafe2f37ca260cdd2
timeCreated: 1777211794

View File

@@ -0,0 +1,268 @@
using System.Collections.Generic;
using UnityEngine;
namespace NBF
{
/// <summary>
/// 硬线系统测试脚本,直接读取 FLine 已配置的节点。
/// </summary>
public class FLineTest : MonoBehaviour
{
[Header("测试控制")] [SerializeField] private KeyCode fixMiddleKey = KeyCode.M;
[Header("动态间距控制")] [SerializeField] private KeyCode pullFirstKey = KeyCode.UpArrow;
[SerializeField] private KeyCode relaxFirstKey = KeyCode.DownArrow;
[SerializeField] private KeyCode fixedKey = KeyCode.F;
[SerializeField] private KeyCode debugKey = KeyCode.D;
[SerializeField, Min(0.01f)] private float extendAmount = 0.5f;
[SerializeField, Min(0.01f)] private float holdAdjustSpeed = 1f;
[SerializeField, Min(0.01f)] private float transitionSpeed = 2f;
[SerializeField] private bool smoothTransition = true;
[SerializeField] private FLine line;
private float[] initialLengths;
private void OnValidate()
{
extendAmount = Mathf.Max(0.01f, extendAmount);
holdAdjustSpeed = Mathf.Max(0.01f, holdAdjustSpeed);
transitionSpeed = Mathf.Max(0.01f, transitionSpeed);
}
private void Start()
{
RefreshInitialLengths(true);
line.SetLenght(0.2f);
line.SetLenght(0.2f, FLineLogicNodeType.End);
}
private void Update()
{
if (!EnsureCable())
return;
RefreshInitialLengths();
HandleInput();
// if (line.CurrentBreakStretchPercent > 10f)
// {
// if (line.LineMode == LineMode.Constraint)
// Debug.LogError(
// $"当前极限情况CurrentBreakStretchPercent={line.CurrentBreakStretchPercent} CurrentStretchLength={line.CurrentStretchLength} TotalLength={line.TotalLength} LimitStateTime={line.LimitStateTime}");
// }
}
private bool EnsureCable()
{
if (line)
return true;
line = GetComponent<FLine>();
return line != null;
}
private List<FLineLogicNode> GetNodes()
{
return line != null ? line.GetLineNodes() : null;
}
private void RefreshInitialLengths(bool force = false)
{
List<FLineLogicNode> nodes = GetNodes();
int segmentCount = nodes != null ? Mathf.Max(0, nodes.Count - 1) : 0;
if (!force && initialLengths != null && initialLengths.Length == segmentCount)
return;
initialLengths = new float[nodes.Count];
for (var i = 0; i < nodes.Count; i++)
{
var node = nodes[i];
initialLengths[i] = Mathf.Max(0.01f, node.Lenght);
}
}
private float GetCurrentMaxLength(int segmentIndex)
{
var nodes = line.GetLineNodes();
var node = nodes[segmentIndex];
// float length = line.GetSegmentMaxLength(segmentIndex);
return Mathf.Max(0.01f, node.Lenght);
}
private float GetTargetMaxLength(int segmentIndex)
{
var nodes = line.GetLineNodes();
var node = nodes[segmentIndex];
float length = node.Lenght;
// if (length <= 0f)
// length = line.GetSegmentMaxLength(segmentIndex);
return Mathf.Max(0.01f, length);
}
private int GetSegmentCount()
{
return initialLengths != null ? initialLengths.Length : 0;
}
private void HandleInput()
{
HandleOriginalControls();
HandleDynamicDistanceControls();
}
private void HandleOriginalControls()
{
List<FLineLogicNode> nodes = GetNodes();
if (nodes == null)
return;
if (Input.GetKeyDown(fixMiddleKey) && nodes.Count >= 3)
{
int middleIndex = nodes.Count / 2;
FLineLogicNode middleNode = nodes[middleIndex];
Rigidbody middleRb = middleNode ? middleNode.Rigidbody : null;
if (middleNode && middleRb)
{
bool newState = !middleRb.isKinematic;
Debug.Log($"中间节点({middleIndex}) {(newState ? "" : "")} - 观察其他节点变化");
}
}
}
private void HandleDynamicDistanceControls()
{
if (line == null || initialLengths == null || initialLengths.Length == 0)
return;
if (Input.GetKeyDown(pullFirstKey))
PullFirstSegment(extendAmount * 0.5f);
if (Input.GetKeyDown(relaxFirstKey))
RelaxFirstSegment(extendAmount * 0.5f);
if (Input.GetKeyDown(fixedKey))
{
if (line.LineMode == LineMode.Joint) line.ChangeMode(LineMode.Constraint);
else line.ChangeMode(LineMode.Joint);
}
if (Input.GetKeyDown(debugKey))
{
line.Print();
}
}
private void ApplySegmentTargetLength(FLineLogicNodeType type, float targetLength)
{
line.SetLenght(targetLength, type);
}
private void PullFirstSegment(float amount)
{
if (GetSegmentCount() <= 0)
return;
float targetLength = Mathf.Max(0.1f, GetTargetMaxLength(0) - amount);
ApplySegmentTargetLength(0, targetLength);
Debug.Log($"拉紧第一段到 {targetLength:F2}");
}
private void RelaxFirstSegment(float amount)
{
if (GetSegmentCount() <= 0)
return;
float targetLength = GetTargetMaxLength(0) + amount;
ApplySegmentTargetLength(0, targetLength);
Debug.Log($"放松第一段到 {targetLength:F2}");
}
private void OnGUI()
{
if (!EnsureCable())
return;
RefreshInitialLengths();
List<FLineLogicNode> nodes = GetNodes();
int nodeCount = nodes != null ? nodes.Count : 0;
GUILayout.BeginArea(new Rect(10f, 10f, 360f, 260f));
GUILayout.Label("=== 硬线系统测试控制 ===");
GUILayout.Label("原始控制:");
GUILayout.Label($" {fixMiddleKey} - 固定/释放中间节点");
GUILayout.Space(10f);
GUILayout.Label("动态间距控制:");
GUILayout.Label($" {pullFirstKey} - 拉紧第一段");
GUILayout.Label($" {relaxFirstKey} - 放松第一段");
GUILayout.Label(" Shift+滚轮 - 调整最近段");
GUILayout.Space(10f);
GUILayout.Label("设置:");
GUILayout.Label($" 节点数: {nodeCount}");
GUILayout.Label(" 初始长度来源: FLine 节点配置");
GUILayout.Label($" 过渡模式: {(smoothTransition ? "" : "")}");
if (smoothTransition)
GUILayout.Label($" 过渡速度: {transitionSpeed:F1}");
GUILayout.EndArea();
GUILayout.BeginArea(new Rect(10f, 280f, 360f, 220f));
GUILayout.Label("=== 各段实际长度 ===");
// for (int i = 0; i < Mathf.Min(GetSegmentCount(), 10); i++)
// {
// Rigidbody bodyA = nodes[i] ? nodes[i].Rigidbody : null;
// Rigidbody bodyB = nodes[i + 1] ? nodes[i + 1].Rigidbody : null;
// if (!bodyA || !bodyB)
// continue;
//
// float actualDistance = Vector3.Distance(bodyA.position, bodyB.position);
// float currentLimit = GetCurrentMaxLength(i);
// float targetLimit = GetTargetMaxLength(i);
//
// string segmentInfo = $"段{i}: {actualDistance:F2} (限制: {currentLimit:F2}";
// if (line.IsSegmentTransitioning(i))
// segmentInfo += $" -> {targetLimit:F2}";
//
// segmentInfo += ")";
//
// if (actualDistance > targetLimit * 1.1f)
// {
// GUI.color = Color.red;
// }
// else if (line.IsSegmentTransitioning(i))
// {
// GUI.color = Color.yellow;
// }
// else
// {
// GUI.color = Color.green;
// }
//
// GUILayout.Label(segmentInfo);
// }
GUI.color = Color.white;
bool anyTransitioning = false;
for (int i = 0; i < GetSegmentCount(); i++)
{
if (line.IsSegmentTransitioning(i))
{
anyTransitioning = true;
break;
}
}
if (anyTransitioning)
GUILayout.Label("状态: 过渡中...");
GUILayout.EndArea();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 535734a3b6eb4e16847b2fc9d9dee1c3
timeCreated: 1777263325

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -0,0 +1,26 @@
using System.Collections.Generic;
using UnityEngine;
namespace NBF
{
public abstract class PlayerItem : MonoBehaviour
{
/// <summary>
/// 配置id
/// </summary>
public int ConfigID;
public List<int> BindItems = new List<int>();
public Player Owner;
public virtual void Init(Player player, int configId, List<int> bindItems)
{
Owner = player;
ConfigID = configId;
BindItems.Clear();
BindItems.AddRange(bindItems);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ef008d609b8049ac8416abb496cbec72
timeCreated: 1777451467

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,17 @@
using UnityEngine;
namespace NBF
{
public class FBobber : FGearBase
{
protected override void OnInit()
{
// transform.position = Rod.lineHandler.LineConnector_1.transform.position;
var endNode = Rod.Line.GetNode(FLineLogicNodeType.Bobber);
SetParent(endNode.transform);
transform.localPosition = Vector3.zero;
// var buoyancy = GetComponentInParent<CapsuleBuoyancyStable>();
// buoyancy.InitBobber();
}
}
}

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,35 @@
using Fantasy;
using UnityEngine;
namespace NBF
{
public abstract class FGearBase : MonoBehaviour
{
public FRod Rod { get; protected set; }
public int ConfigId;
public virtual void Init(FRod rod)
{
Rod = rod;
OnInit();
}
public void SetItemConfigId(int id)
{
ConfigId = id;
}
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,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);
var endNode = Rod.Line.GetNode(FLineLogicNodeType.End);
SetParent(endNode.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,22 @@
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);
var endNode = Rod.Line.GetNode(FLineLogicNodeType.End);
SetParent(endNode.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,443 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Fantasy;
using Fantasy.Async;
using NBC.Asset;
using NBF.Utils;
using UnityEngine;
using Object = UnityEngine.Object;
namespace NBF
{
public class FRod : FHandItem
{
public RodAsset Asset;
public FReel Reel;
public FHook Hook;
public FBobber Bobber;
public FBait Bait;
public FLure Lure;
public FWeight Weight;
public FLine Line;
public Transform GearRoot;
#region Rod专属
private bool _stretchRope = true;
public bool StretchRope
{
get => _stretchRope;
set
{
_stretchRope = value;
// Scene.EventComponent.Publish(new PlayerItemRodLingChangeEvent
// {
// Item = this
// });
}
}
private float _lineLength = 4.2f;
/// <summary>
/// 线长度
/// </summary>
public float LineLength
{
get => _lineLength;
set
{
_lineLength = value;
// Scene.EventComponent.Publish(new PlayerItemRodLingChangeEvent
// {
// Item = this
// });
}
}
private float _floatLength = 0.7f;
/// <summary>
/// 浮漂线长度
/// </summary>
public float FloatLength
{
get => _floatLength;
set
{
_floatLength = value;
// Scene.EventComponent.Publish(new PlayerItemRodLingChangeEvent
// {
// Item = this
// });
}
}
private float _tension;
/// <summary>
/// 拉力
/// </summary>
public float Tension
{
get => _tension;
set
{
if (!Mathf.Approximately(_tension, value))
{
_tension = value;
}
// Scene.EventComponent.Publish(new PlayerItemRodLingChangeEvent
// {
// Item = this
// });
}
}
#endregion
// public FWaterDisplacement LureHookWaterDisplacement;
[HideInInspector] public FFish currentFish;
public RodRingNode[] rings;
private void Awake()
{
Asset = GetComponent<RodAsset>();
}
private void Start()
{
Asset.CCDIK.enabled = true;
}
private void Update()
{
BendControl();
}
public void SetLineLength()
{
if (!Line) return;
if (Line.LineType == LineType.Spinning)
{
//没有浮漂类型
Line.SetLenght(LineLength);
}
else
{
//有浮漂
Line.SetLenght(LineLength - FloatLength);
Line.SetLenght(FloatLength, FLineLogicNodeType.End);
}
}
private void LateUpdate()
{
Test();
}
public IEnumerator Destroy()
{
if (GearRoot != null)
{
Object.Destroy(GearRoot.gameObject);
}
yield return 1;
}
public async FTask InitRod()
{
transform.localPosition = Vector3.zero;
transform.localRotation = Quaternion.identity;
transform.localScale = Vector3.one;
Map.Instance.GearsNode.position = transform.position;
await FTask.WaitFrame(Game.Main); //等待1帧
var obj = new GameObject($"rod_{ConfigID}");
obj.transform.SetParent(Map.Instance.GearsNode);
obj.transform.position = transform.position;
obj.transform.rotation = transform.rotation;
obj.transform.localScale = Vector3.one;
GearRoot = obj.transform;
var parent = GearRoot;
CreateFishingHandler();
await FTask.WaitFrame(Game.Main); //等待1帧
// children.Sort();
foreach (var childConfigId in BindItems)
{
var itemType = childConfigId.GetItemType();
var config = Game.Tables.TbItem.Get(childConfigId);
if (itemType == ItemType.Reel)
{
Reel = config.InstantiateAndComponent<FReel>(Asset.ReelConnector, Vector3.zero,
Quaternion.identity);
Reel.SetItemConfigId(childConfigId);
}
else if (itemType == ItemType.Bobber)
{
Bobber = config.InstantiateAndComponent<FBobber>(parent, Vector3.zero,
Quaternion.identity);
Bobber.SetItemConfigId(childConfigId);
}
else if (itemType == ItemType.Hook)
{
Hook = config.InstantiateAndComponent<FHook>(parent, Vector3.zero,
Quaternion.identity);
Hook.SetItemConfigId(childConfigId);
}
else if (itemType == ItemType.Bait)
{
Bait = config.InstantiateAndComponent<FBait>(parent, Vector3.zero,
Quaternion.identity);
Bait.SetItemConfigId(childConfigId);
}
else if (itemType == ItemType.Lure)
{
Lure = config.InstantiateAndComponent<FLure>(parent, Vector3.zero,
Quaternion.identity);
Lure.SetItemConfigId(childConfigId);
}
else if (itemType == ItemType.Weight)
{
Weight = config.InstantiateAndComponent<FWeight>(parent, Vector3.zero,
Quaternion.identity);
Weight.SetItemConfigId(childConfigId);
}
else if (itemType == ItemType.Line)
{
// lineItemInfo = child;
}
}
await FTask.WaitFrame(Game.Main); //等待1帧
SetLineLength();
if (Reel)
{
Reel.reelingDrag = 0.699f;
Reel.transform.SetParent(Asset.ReelConnector);
Reel.transform.localPosition = Vector3.zero;
Reel.transform.localEulerAngles = Vector3.zero;
Reel.Init(this);
}
if (Bobber)
{
Bobber.Init(this);
}
if (Hook)
{
Hook.Init(this);
}
if (Bait)
{
Bait.Init(this);
}
if (Lure)
{
Lure.Init(this);
}
if (Weight)
{
Weight.Init(this);
}
await FTask.WaitFrame(Game.Main); //等待1帧
transform.SetParent(Owner.ModelAsset.RodRoot);
transform.localPosition = Vector3.zero;
transform.rotation = Owner.ModelAsset.RodRoot.rotation;
}
public void CreateFishingHandler()
{
if (Line == null)
{
Debug.LogError("创建钓组=====");
var itemConfig = Game.Tables.TbItem.Get(ConfigID);
var rodType = (ItemSubType)itemConfig.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);
}
}
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();
}
#region 竿
private List<float> previousWeights = Enumerable.Repeat(0f, 10).ToList();
private float bendSmooth = 1f;
public float maxRodStrength = 1f;
public float CurrentTension01
{
get
{
float value = 0f;
// if ((bool)currentReel && (bool)fishingLine)
// {
// float linePullingForce = currentReel.LinePullingForce;
// value = Mathf.Min(fishingLine.CurrentLineTension, linePullingForce) / maxRodStrength;
// }
if (Line)
{
value = Tension / maxRodStrength;
}
return Mathf.Clamp01(value);
}
}
private void BendControl()
{
// var _ccdik = Asset.CCDIK;
//
// var state = Owner.State;
//
//
// Vector3 vector = Line.EndNode.transform.position;
//
// // 当前物体的朝向与指向 Lure 的方向之间的夹角,在 0完全对齐到 1完全相反之间的一个比例值
// float headingAlignment = Vector3.Angle(base.transform.forward,
// (Line.EndNode.transform.position - transform.position).normalized) / 180f;
// // 经过朝向调制后的有效张力
// var effectiveTension = Mathf.Clamp(CurrentTension01 * headingAlignment, 0f, 1f);
//
// float multiple = 0;
// if (state == PlayerState.Fight)
// {
// multiple = 1;
// }
// else
// {
// multiple = 0.1f;
// }
//
// float targetWeight = effectiveTension * multiple;
// if (targetWeight > 0)
// {
// // Debug.Log($"CurrentTension01={CurrentTension01} LinelenghtDiferent={Line.LinelenghtDiferent} Tension={PlayerItem.Tension} num2={effectiveTension} num3={headingAlignment} num6={multiple}");
// }
//
// if (state == PlayerState.Prepare)
// {
// targetWeight = 0.002f;
// }
//
// float item = Mathf.MoveTowards(_ccdik.solver.IKPositionWeight, targetWeight, Time.deltaTime * bendSmooth);
// previousWeights.RemoveAt(0);
// previousWeights.Add(item);
// float averageWeight = previousWeights.Average();
// if (currentFish)
// {
// averageWeight = Math.Min(averageWeight, 0.01f);
// }
//
// _ccdik.solver.SetIKPosition(vector);
// _ccdik.solver.SetIKPositionWeight(averageWeight);
}
#endregion
#region
private void BendingRod()
{
}
#endregion
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,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

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c6dfe3235d0347008d10859d322eabd6
timeCreated: 1777447863

View File

@@ -0,0 +1,101 @@
using System.Collections.Generic;
using Enviro;
using Fantasy;
using NBC;
using UnityEngine;
using WaveHarmonic.Crest;
namespace NBF
{
public class Map : SingletonMono<Map>
{
[Header("节点信息")] public WaterRenderer Water;
public Transform Node;
public Transform GearsNode;
[Header("角色参数")] public int MapId;
public string RoomCode;
public readonly List<MapUnitInfo> Units = new List<MapUnitInfo>();
public readonly List<Player> Players = new List<Player>();
public void SetData(int mapId, string code, List<MapUnitInfo> units)
{
MapId = mapId;
RoomCode = code;
Units.AddRange(units);
}
private void Start()
{
EnviroManager.instance.Time.Settings.simulate = true;
}
private void Update()
{
UpdateFPS();
UpdateTimeOfDay();
}
#region FPS
public int FPS;
public float updateInterval = 0.2f; // 更新间隔(秒)
private float accum = 0;
private int frames = 0;
private float timeleft;
void UpdateFPS()
{
timeleft -= Time.deltaTime;
accum += Time.timeScale / Time.deltaTime;
frames++;
if (timeleft <= 0.0f)
{
FPS = (int)(accum / frames);
timeleft = updateInterval;
accum = 0.0f;
frames = 0;
}
}
#endregion
#region
private void UpdateTimeOfDay()
{
var p = GameTimer.GetGameDayProgress();
p = 0.3f;
// Debug.Log(p);
EnviroManager.instance.Time.SetTimeOfDay(p * 24f);
// if(AzureCoreSystem)
// AzureCoreSystem.timeSystem.timeline = 24F * p;
}
#endregion
#region Player
public void InstancePlayers()
{
var playerObject = PrefabsHelper.CreatePlayer(Node);
playerObject.transform.localPosition = new Vector3(484, 1, 422);
var player = playerObject.GetComponent<Player>();
Players.Add(player);
player.IsSelf = true;
if (player.IsSelf)
{
CameraManager.Instance.SetFppLook(player);
}
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1f820874d054495abd4d378473a14bcf
timeCreated: 1777438296

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c38d17daa1164359ad9f9466be692b7c
timeCreated: 1773038185

View File

@@ -0,0 +1,98 @@
using System;
using UnityEngine;
namespace NBF
{
public class JointPinchController : MonoBehaviour
{
// 配置参数
[SerializeField] private float moveSpeed = 5f;
[SerializeField] private float snapDistance = 0.1f;
private FixedJoint pinchJoint;
private Rigidbody rb;
private float maxCatchupDuration = 0.5f;
private Transform targetTransform;
private float originalSpring;
private float pinchElapsedTime;
public bool isPinched { get; private set; }
private bool moveToTargetDone;
private float _speed;
void Start()
{
rb = GetComponent<Rigidbody>();
}
void FixedUpdate()
{
if (isPinched && !moveToTargetDone && targetTransform != null)
{
pinchElapsedTime += Time.fixedDeltaTime;
transform.position =
Vector3.MoveTowards(transform.position, targetTransform.position, Time.deltaTime * _speed);
if (Vector3.Distance(transform.position, targetTransform.position) < 0.1f ||
pinchElapsedTime >= maxCatchupDuration)
{
moveToTargetDone = true;
}
}
}
private void LateUpdate()
{
// SyncPosition();
}
private void Update()
{
SyncPosition();
}
private void SyncPosition()
{
if (!isPinched) return;
if (!moveToTargetDone) return;
transform.position = targetTransform.position;
}
// 外部调用:开始捏住流程
public void StartPinch(Transform fingerTransform, float speed = 3, float _maxCatchupDuration = 0.3f)
{
_speed = speed;
Rigidbody fingerRb = fingerTransform.GetComponent<Rigidbody>();
if (fingerRb == null)
{
Debug.LogError("目标必须带有Rigidbody");
return;
}
maxCatchupDuration = _maxCatchupDuration;
pinchElapsedTime = 0f;
isPinched = true;
rb.useGravity = false;
rb.isKinematic = true;
moveToTargetDone = false;
targetTransform = fingerTransform;
}
// 外部调用:释放捏住
public void ReleasePinch()
{
isPinched = false;
rb.useGravity = true;
rb.linearVelocity = Vector3.zero;
rb.angularVelocity = Vector3.zero;
rb.isKinematic = false;
rb.linearVelocity = Vector3.zero;
rb.angularVelocity = Vector3.zero;
targetTransform = null;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1de1bec90e454664a860c5248170ff95
timeCreated: 1773588197

View File

@@ -0,0 +1,184 @@
using System;
using KINEMATION.MagicBlend.Runtime;
using NBC;
using NBF.Utils;
using UnityEngine;
namespace NBF
{
public class PlayerAnimator : PlayerMonoBehaviour
{
public Animator _Animator;
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
protected override void OnAwake()
{
_magicBlending = GetComponent<MagicBlending>();
_Animator = GetComponent<Animator>();
_Animator.keepAnimatorStateOnDisable = true;
_IK = GetComponent<PlayerIK>();
_isInit = true;
}
public void OnUnUseItem()
{
_isRodLayerEnabled = false;
}
// public void OnUseItem(PlayerItemView item)
// {
// var itemType = item.Item.ConfigID.GetItemType();
// if (itemType == ItemType.Rod)
// {
// _isRodLayerEnabled = true;
// // _IK.SetBipedLeftHandIK(enabled: false, reel.FingersIKAnchor);
// }
// }
public void SetLayerWeight(string layer, float weight)
{
_Animator.SetLayerWeight(_Animator.GetLayerIndex(layer), weight);
}
private void LateUpdate()
{
{
float value3 = Mathf.Lerp(_Animator.GetFloat(Forward), Player.Speed / 5f,
Time.deltaTime * 20f);
float value4 = Mathf.Lerp(_Animator.GetFloat(Turn), Player.RotationSpeed,
Time.deltaTime * 15f);
_Animator.SetFloat(Forward, Mathf.Clamp01(value3));
_Animator.SetFloat(Turn, Mathf.Clamp(value4, -1f, 1f));
}
_Animator.SetBool(OnGroundHash, _IsInVehicle || Player.IsGrounded);
var isHandRodLayerEnabled = _isRodLayerEnabled && !Player.IsLureRod ? 1 : 0;
float handRodLayerWeight = _Animator.GetLayerWeight(_Animator.GetLayerIndex(HandRodLayer));
SetLayerWeight(HandRodLayer,
Mathf.MoveTowards(handRodLayerWeight, isHandRodLayerEnabled, Time.deltaTime * 3f));
var isLureRodLayerEnabled = _isRodLayerEnabled && Player.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()
{
Debug.LogError("OnRodThrowStart");
// if (Player.State == PlayerState.Throw)
// {
// var playerStateView = Player.GetComponent<PlayerStateView>();
// if (playerStateView.CurrentStateView is PlayerStageViewThrow playerStateThrow)
// {
// playerStateThrow.OnRodThrowStart();
// }
// }
}
/// <summary>
/// 抛竿结束动画事件
/// </summary>
public void OnRodThrownEnd()
{
Debug.LogError("OnRodThrownEnd");
// if (Player.State == PlayerState.Throw)
// {
// var playerStateView = Player.GetComponent<PlayerStateView>();
// if (playerStateView.CurrentStateView is PlayerStageViewThrow 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 : PlayerMonoBehaviour
{
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;
protected override void OnAwake()
{
}
private void LateUpdate()
{
}
}
}

View File

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

View File

@@ -0,0 +1,24 @@
using UnityEngine;
namespace NBF
{
public class PlayerChest : PlayerMonoBehaviour
{
private const int MaxFixEyeAngle = 15;
private const int MinFixEyeAngle = -10;
private void LateUpdate()
{
FixArmAngle();
}
private void FixArmAngle()
{
var angle = Player.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,26 @@
using System;
using UnityEngine;
namespace NBF
{
public class PlayerDebug : PlayerMonoBehaviour
{
private void Update()
{
DrawLastTrajectory();
}
private void DrawLastTrajectory()
{
if (Player == null) return;
// for (int i = 1; i < Player.TrajectoryPoints.Count; i++)
// {
// Debug.DrawLine(Player.TrajectoryPoints[i - 1], Player.TrajectoryPoints[i], Color.yellow);
// }
// Debug.DrawRay(Player.TrajectoryPoints[Player.TrajectoryPoints.Count], Vector3.up * 0.3f, Color.cyan);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0fe64f6594c24eef9fbaf147754871f8
timeCreated: 1774445468

View File

@@ -0,0 +1,58 @@
using System;
using RootMotion.FinalIK;
using UnityEngine;
namespace NBF
{
public class PlayerIK : PlayerMonoBehaviour
{
public enum UpdateType
{
Update = 0,
FixedUpdate = 1,
LateUpdate = 2,
Default = 3
}
public UpdateType UpdateSelected;
private LookAtIK _LookAtIK;
[SerializeField] private float transitionWeightTimeScale = 1f;
protected override void OnAwake()
{
_LookAtIK = GetComponent<LookAtIK>();
}
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()
{
_LookAtIK.UpdateSolverExternal();
}
}
}

View File

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

View File

@@ -0,0 +1,24 @@
using UnityEngine;
namespace NBF
{
public abstract class PlayerMonoBehaviour : MonoBehaviour
{
public Player Player { get; private set; }
protected void Awake()
{
Player = GetComponent<Player>();
if (Player == null)
{
Player = GetComponentInParent<Player>();
}
OnAwake();
}
protected virtual void OnAwake()
{
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7fbde40efe5345cd8c05ea6c1f1914cf
timeCreated: 1773040970

View File

@@ -0,0 +1,25 @@
// using ECM2;
// using ECM2.Examples.FirstPerson;
// using UnityEngine;
//
// namespace NBF
// {
// public class PlayerUnityComponent : MonoBehaviour
// {
// public Player Player { get; set; }
// public Transform Root;
// public Transform Eye;
// public Transform FppLook;
// public Transform IK;
// public PlayerModelAsset ModelAsset;
// public CharacterMovement Character;
// public FirstPersonCharacter FirstPerson;
//
// [Header("视角相关")] public float MouseSensitivity = 0.1f;
// [Space(15f)] public bool invertLook = true;
//
// public float minPitch = -60f;
//
// public float maxPitch = 60f;
// }
// }

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a25908f34e4e4464a922b88337a5b733
timeCreated: 1773038189

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e599a1ea5e4441f888ed9157dfbd0565
timeCreated: 1777437826

View File

@@ -0,0 +1,137 @@
using System;
using System.Collections.Generic;
using ECM2;
using ECM2.Examples.FirstPerson;
using Fantasy.Async;
using UnityEngine;
namespace NBF
{
public class Player : MonoBehaviour
{
[Header("角色参数")] public float EyeAngle;
public bool IsGrounded;
public float Speed;
public float RotationSpeed;
public Vector2 MoveInput;
public bool Run;
[Header("角色节点")] public Transform Root;
public Transform Eye;
public Transform FppLook;
public Transform IK;
[Header("角色控制")] public PlayerModelAsset ModelAsset;
public CharacterMovement Character;
public FirstPersonCharacter FirstPerson;
[Header("视角相关")] public float MouseSensitivity = 0.1f;
[Space(15f)] public bool invertLook = true;
public float minPitch = -60f;
public float maxPitch = 60f;
public bool IsLureRod => false;
public bool IsSelf;
#region
private void Awake()
{
}
private void Start()
{
CreatePlayerModel();
if (IsSelf)
{
gameObject.AddComponent<PlayerInput>();
}
}
private void Update()
{
}
private void FixedUpdate()
{
}
#endregion
#region
private FHandItem HandItem;
private bool IsChangeItemIng;
public async FTask UseItem(int configId, List<int> bindItems)
{
if (IsChangeItemIng) return;
IsChangeItemIng = true;
if (HandItem != null)
{
await UnUseItem();
}
// ModelAsset.PlayerAnimator.OnUseItem(itemView);
// if (currItem == null)
// {
// //收起物品
// await UnUseItem(prevItem);
// }
// else
// {
// // 先收起旧的物品
// await UnUseItemConfirm(prevItem);
// var handItem = Player.HandItem;
// //拿起新物品
// var itemType = handItem.ConfigID.GetItemType();
// if (itemType == ItemType.Rod)
// {
// var itemView = handItem.GetOrAddComponent<PlayerItemView>();
// await itemView.InitShow(handItem);
// Unity.ModelAsset.PlayerAnimator.OnUseItem(itemView);
// }
// }
//
// var stateView = Player.GetComponent<PlayerStateView>();
// if (stateView != null && stateView.CurrentStateView is PlayerStageViewIdle playerStageViewIdle)
// {
// playerStageViewIdle.TakeLine();
// }
IsChangeItemIng = false;
}
public async FTask UnUseItem()
{
if (HandItem != null)
{
ModelAsset.PlayerAnimator.OnUnUseItem();
await FTask.Wait(Game.Main, 100);
}
Destroy(HandItem.gameObject);
HandItem = null;
}
#endregion
#region
private void CreatePlayerModel()
{
var modelObject = PrefabsHelper.CreatePlayer(Root, "Human_Male");
modelObject.transform.localPosition = Vector3.zero;
ModelAsset = modelObject.GetComponent<PlayerModelAsset>();
ModelAsset.SetPlayer(FppLook);
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7c69e72330154a86b756d89e82d276e9
timeCreated: 1777437830

View File

@@ -0,0 +1,205 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Fantasy;
using Fantasy.Entitas.Interface;
using UnityEngine;
using UnityEngine.InputSystem;
namespace NBF
{
public class PlayerInput : PlayerMonoBehaviour
{
#region
protected override void OnAwake()
{
AddInputEvent();
}
private void Update()
{
UpdateInput();
UpdateMove();
}
private void OnDestroy()
{
RemoveInputEvent();
}
#endregion
#region Input
private void UpdateInput()
{
if (Input.GetKeyDown(KeyCode.Alpha0))
{
// SetLineLength(lineLength);
}
else if (Input.GetKeyDown(KeyCode.Plus) || Input.GetKeyDown(KeyCode.Equals))
{
// Player.HandItem.LineLength += 0.1f;
}
else if (Input.GetKeyDown(KeyCode.Minus))
{
// Player.HandItem.LineLength -= 0.1f;
}
}
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)
{
Player.Run = true;
}
}
private void OnPlayerCanceled(string action)
{
if (action == InputDef.Player.Run)
{
Player.Run = false;
}
else if (action == InputDef.Player.ToBag)
{
//取消手持物品
Log.Info($"取消手持物品");
Player.UnUseItem().Coroutine();
}
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)
{
List<ItemInfo> children = RoleModel.Instance.GetBindItems(item.Id);
List<int> bindItems = children.Select(itemInfo => itemInfo.ConfigId).ToList();
Player.UseItem(item.ConfigId, bindItems).Coroutine();
}
}
}
private void OnPlayerValueCanceled(InputAction.CallbackContext context)
{
var actionName = context.action.name;
if (actionName == InputDef.Player.Move)
{
Player.MoveInput = Vector2.zero;
}
}
private void OnPlayerValuePerformed(InputAction.CallbackContext context)
{
var actionName = context.action.name;
if (actionName == InputDef.Player.Move)
{
var v2 = context.ReadValue<Vector2>();
Player.MoveInput = v2;
}
else if (actionName == InputDef.Player.Look)
{
}
}
#endregion
#region Move
private Quaternion _lastRotation;
private void UpdateMove()
{
UpdateGrounded();
ProcessMoveStates();
UpdateLookInput();
}
private void ProcessMoveStates()
{
{
var num2 = Player.Run ? 7 : 5;
Vector3 vector2 = Player.FirstPerson.GetRightVector() * Player.MoveInput.x * num2;
vector2 += Player.FirstPerson.GetForwardVector() * Player.MoveInput.y * num2;
// if (checkWaterBound)
// {
// SetMovementDirectionWithRaycastCheck(vector2);
// }
// else
{
Player.FirstPerson.SetMovementDirection(vector2);
}
}
}
private void UpdateGrounded()
{
Player.IsGrounded = Player.FirstPerson.IsGrounded();
Player.Speed = Player.FirstPerson.velocity.magnitude;
Quaternion rotation = Player.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);
Player.RotationSpeed = turnValue;
_lastRotation = rotation;
}
#endregion
#region Look
private void UpdateLookInput()
{
Vector2 value = InputManager.GetLookInput();
var u3d = Player;
u3d.FirstPerson.AddControlYawInput(value.x * u3d.MouseSensitivity);
u3d.FirstPerson.AddControlPitchInput((u3d.invertLook ? 0f - value.y : value.y) * u3d.MouseSensitivity,
u3d.minPitch, u3d.maxPitch);
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b0ff16b93bf44060b69e6b052a4f3d63
timeCreated: 1777449292

View File

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

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 83d5c2102a7749f0acb36f871d75566e
timeCreated: 1777438074

File diff suppressed because it is too large Load Diff

View File

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