提交修改

This commit is contained in:
2026-03-24 23:46:11 +08:00
parent af639cdefc
commit 09540ad1a8
22 changed files with 257 additions and 266 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 MiB

After

Width:  |  Height:  |  Size: 4.9 MiB

View File

@@ -1,4 +1,4 @@
using System;
using System;
using KINEMATION.MagicBlend.Runtime;
using RootMotion.FinalIK;
using UnityEngine;

View File

@@ -1,3 +1,2 @@
fileFormatVersion: 2
guid: 553e656eacf648afb33751a88352d216
timeCreated: 1757836335
guid: 553e656eacf648afb33751a88352d216

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 18a6db7ab47a454ba05592a6ae895bb9
timeCreated: 1774362636

View File

@@ -0,0 +1,20 @@
using UnityEngine;
namespace NBF
{
public interface IPlayerThrowAnimation
{
bool IsPlaying { get; }
void Play(ThrowAnimationRequest request);
void Tick(float deltaTime);
void Stop(bool snapToTarget);
}
public struct ThrowAnimationRequest
{
public LureController Lure;
public Vector3 StartPosition;
public Vector3 Forward;
public float ChargedProgress;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 51e9c4e20e460b34ca8ec4de6b7cab4b

View File

@@ -1,230 +0,0 @@
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
using System;
namespace NBF
{
/// <summary>
/// 抛竿输入参数
/// </summary>
[Serializable]
public struct ThrowInput
{
[Range(0, 1)] public float power; // 力度 0-1
[Range(5, 50)] public float lureWeight; // 钓饵重量 g
[Range(0.1f, 1f)] public float lineDiameter; // 线直径 mm
public Vector3 windDirection;
public float windStrength;
}
/// <summary>
/// 路亚抛竿轨迹控制器
/// 使用预计算轨迹 + DOTween动画实现确定性抛竿
/// </summary>
public class LureThrowTrajectory : IDisposable
{
// 物理常量
private const float AirDensity = 1.225f;
// 默认参数
protected float _minThrowPower = 15f;
protected float _maxThrowPower = 45f;
private float _dragCoefficient = 0.2f;
private float _lureArea = 0.001f;
private float _timeStep = 0.02f;
private int _maxSteps = 500;
private Sequence _throwSequence;
private List<Vector3> _trajectory;
public bool IsPlaying => _throwSequence != null && _throwSequence.IsPlaying();
public List<Vector3> Trajectory => _trajectory;
/// <summary>
/// 计算抛竿轨迹
/// </summary>
public List<Vector3> CalculateTrajectory(ThrowInput input, Vector3 startPos, Vector3 throwDirection)
{
_trajectory = new List<Vector3>();
Vector3 position = startPos;
Vector3 direction = throwDirection.normalized;
float throwPower = Mathf.Lerp(_minThrowPower, _maxThrowPower, input.power);
Vector3 velocity = direction * throwPower;
float lureMass = input.lureWeight / 1000f;
Vector3 windDir = input.windDirection.normalized;
float windStrength = input.windStrength;
float currentTime = 0f;
int steps = 0;
while (currentTime < 10f && steps < _maxSteps)
{
if (position.y <= 0f) break;
// 风力影响
float windInfluenceFactor = Mathf.Clamp01(currentTime / 1.5f);
Vector3 windVelocity = windDir * windStrength * windInfluenceFactor;
Vector3 relVelocity = velocity - windVelocity;
// 空气阻力
float dragMag = 0.5f * AirDensity * relVelocity.sqrMagnitude * _dragCoefficient * _lureArea;
// 钓线阻力
float lineLength = Vector3.Distance(
new Vector3(position.x, 0, position.z),
new Vector3(startPos.x, 0, startPos.z));
float lineRadius = input.lineDiameter / 2000f;
float lineArea = lineLength * (lineRadius * 2f);
float lineDragMag = 0.5f * AirDensity * velocity.sqrMagnitude * _dragCoefficient * lineArea;
Vector3 lineDragForce = -velocity.normalized * lineDragMag;
Vector3 dragForce = -relVelocity.normalized * dragMag;
Vector3 totalForce = dragForce + lineDragForce;
Vector3 acceleration = Physics.gravity + totalForce / lureMass;
velocity += acceleration * _timeStep;
position += velocity * _timeStep;
_trajectory.Add(position);
currentTime += _timeStep;
steps++;
}
return _trajectory;
}
/// <summary>
/// 执行抛竿动画
/// </summary>
public void ExecuteThrow(
Transform lureTransform,
Rigidbody lureRigidbody,
List<Vector3> trajectory,
float duration,
Action onComplete = null)
{
if (trajectory == null || trajectory.Count < 2)
{
onComplete?.Invoke();
return;
}
// 停止之前的动画
Kill();
// 设置为运动学模式
lureRigidbody.isKinematic = true;
lureRigidbody.useGravity = false;
// 创建路径动画
_throwSequence = DOTween.Sequence();
// 使用 DOPath 沿路径移动
var pathArray = trajectory.ToArray();
_throwSequence.Append(
lureTransform.DOPath(pathArray, duration, PathType.Linear, PathMode.Full3D)
.SetEase(Ease.Linear)
.SetLookAt(0.01f) // 让Lure朝向运动方向
);
_throwSequence.OnComplete(() =>
{
// 动画结束,恢复物理
lureRigidbody.isKinematic = false;
lureRigidbody.useGravity = true;
lureRigidbody.linearVelocity = Vector3.zero;
lureRigidbody.angularVelocity = Vector3.zero;
onComplete?.Invoke();
});
}
/// <summary>
/// 计算合适的飞行时间(基于轨迹长度)
/// </summary>
public float CalculateDuration(List<Vector3> trajectory, float speedFactor = 1f)
{
if (trajectory == null || trajectory.Count < 2) return 1f;
float totalLength = 0f;
for (int i = 1; i < trajectory.Count; i++)
{
totalLength += Vector3.Distance(trajectory[i - 1], trajectory[i]);
}
// 根据轨迹长度计算时间,越长越慢
return Mathf.Clamp(totalLength / (20f * speedFactor), 0.5f, 3f);
}
/// <summary>
/// 使用简化轨迹(减少点位,优化性能)
/// </summary>
public List<Vector3> SimplifyTrajectory(List<Vector3> points, float tolerance = 0.1f)
{
if (points == null || points.Count < 3) return new List<Vector3>(points ?? new List<Vector3>());
var result = new List<Vector3>();
SimplifySection(points, 0, points.Count - 1, tolerance, result);
result.Add(points[points.Count - 1]);
return result;
}
private void SimplifySection(List<Vector3> points, int start, int end, float tolerance, List<Vector3> result)
{
if (end <= start + 1) return;
float maxDistance = -1f;
int index = -1;
for (int i = start + 1; i < end; i++)
{
float distance = PerpendicularDistance(points[i], points[start], points[end]);
if (distance > maxDistance)
{
maxDistance = distance;
index = i;
}
}
if (maxDistance > tolerance)
{
SimplifySection(points, start, index, tolerance, result);
result.Add(points[index]);
SimplifySection(points, index, end, tolerance, result);
}
}
private float PerpendicularDistance(Vector3 point, Vector3 lineStart, Vector3 lineEnd)
{
if (lineStart == lineEnd) return Vector3.Distance(point, lineStart);
Vector3 projected = Vector3.Project(point - lineStart, lineEnd - lineStart);
return Vector3.Distance(point, lineStart + projected);
}
public void Kill()
{
if (_throwSequence != null)
{
_throwSequence.Kill();
_throwSequence = null;
}
}
public void Dispose()
{
Kill();
_trajectory?.Clear();
}
/// <summary>
/// 设置抛竿力度范围
/// </summary>
public void SetPowerRange(float min, float max)
{
_minThrowPower = min;
_maxThrowPower = max;
}
}
}

View File

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

View File

@@ -0,0 +1,159 @@
using UnityEngine;
namespace NBF
{
public class ParabolaPlayerThrowAnimation : IPlayerThrowAnimation
{
private const int TrajectorySampleCount = 24;
private readonly float _minThrowDistance;
private readonly float _maxThrowDistance;
private readonly float _throwDuration;
private readonly float _throwArcHeight;
private readonly float _targetHeightOffset;
private readonly AnimationCurve _throwHeightCurve;
private readonly Vector3[] _lastTrajectoryPoints = new Vector3[TrajectorySampleCount + 1];
private bool _hasLastTrajectory;
private float _chargedProgress;
private float _castElapsedTime;
private Vector3 _castStartPos;
private Vector3 _castTargetPos;
private LureController _castingLure;
public bool IsPlaying => _castingLure != null;
public ParabolaPlayerThrowAnimation(
float minThrowDistance = 6f,
float maxThrowDistance = 25f,
float throwDuration = 0.65f,
float throwArcHeight = 4f,
float targetHeightOffset = 0f,
AnimationCurve throwHeightCurve = null)
{
_minThrowDistance = minThrowDistance;
_maxThrowDistance = maxThrowDistance;
_throwDuration = throwDuration;
_throwArcHeight = throwArcHeight;
_targetHeightOffset = targetHeightOffset;
_throwHeightCurve = throwHeightCurve ?? AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
}
public void Play(ThrowAnimationRequest request)
{
if (request.Lure == null)
{
return;
}
Stop(snapToTarget: false);
_castingLure = request.Lure;
_chargedProgress = Mathf.Clamp01(request.ChargedProgress);
_castElapsedTime = 0f;
var lureBody = request.Lure.RBody;
_castStartPos = request.StartPosition;
Vector3 forward = request.Forward;
forward.y = 0f;
if (forward.sqrMagnitude < 0.001f)
{
forward = Vector3.forward;
}
float distance = Mathf.Lerp(_minThrowDistance, _maxThrowDistance, _chargedProgress);
_castTargetPos = _castStartPos + forward.normalized * distance;
_castTargetPos.y = _castStartPos.y + _targetHeightOffset;
CacheTrajectoryPoints();
lureBody.isKinematic = true;
lureBody.useGravity = false;
lureBody.linearVelocity = Vector3.zero;
lureBody.angularVelocity = Vector3.zero;
lureBody.position = _castStartPos;
}
public void Tick(float deltaTime)
{
DrawLastTrajectory();
UpdateCastAnimation(deltaTime);
}
public void Stop(bool snapToTarget)
{
if (_castingLure == null)
{
return;
}
var lureBody = _castingLure.RBody;
if (snapToTarget)
{
_castingLure.transform.position = _castTargetPos;
lureBody.position = _castTargetPos;
}
lureBody.linearVelocity = Vector3.zero;
lureBody.angularVelocity = Vector3.zero;
lureBody.useGravity = true;
lureBody.isKinematic = false;
_castingLure = null;
}
private void UpdateCastAnimation(float deltaTime)
{
if (_castingLure == null)
{
return;
}
float duration = Mathf.Max(_throwDuration, 0.01f);
_castElapsedTime += deltaTime;
float progress = Mathf.Clamp01(_castElapsedTime / duration);
_castingLure.transform.position = EvaluateTrajectoryPosition(progress);
if (progress >= 1f)
{
Stop(snapToTarget: true);
}
}
private void CacheTrajectoryPoints()
{
for (int i = 0; i <= TrajectorySampleCount; i++)
{
float progress = i / (float)TrajectorySampleCount;
_lastTrajectoryPoints[i] = EvaluateTrajectoryPosition(progress);
}
_hasLastTrajectory = true;
}
private Vector3 EvaluateTrajectoryPosition(float progress)
{
Vector3 position = Vector3.Lerp(_castStartPos, _castTargetPos, progress);
float arc = _throwHeightCurve.Evaluate(progress) * _throwArcHeight * _chargedProgress;
position.y += arc;
return position;
}
private void DrawLastTrajectory()
{
if (!_hasLastTrajectory)
{
return;
}
for (int i = 1; i <= TrajectorySampleCount; i++)
{
Debug.DrawLine(_lastTrajectoryPoints[i - 1], _lastTrajectoryPoints[i], Color.yellow);
}
Debug.DrawRay(_lastTrajectoryPoints[TrajectorySampleCount], Vector3.up * 0.3f, Color.cyan);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 86121f3f07035144fadd467716b4b3a9

View File

@@ -1,4 +1,4 @@
using NBC;
using NBC;
using UnityEngine;
namespace NBF
@@ -6,10 +6,10 @@ namespace NBF
public class PlayerStageViewThrow : PlayerStageViewBase
{
private bool _nextState = false;
public float ChargedProgress;
private bool _throwAnimEnded = false;
private IPlayerThrowAnimation _throwAnimation;
[Header("抛竿参数")]
[SerializeField] private float throwUpAngle = 0.7f; // 向上抛出的角度系数,越大抛得越高
public float ChargedProgress;
protected override void OnEnter()
{
@@ -24,53 +24,86 @@ namespace NBF
Debug.Log($"PlayerThrow ChargedProgress={ChargedProgress}");
_nextState = false;
// Stage = Phase.Waiting;
// _owner.Gears.Reel?.Unlock();
_throwAnimEnded = false;
_throwAnimation = null;
}
protected override void OnUpdate()
{
CheckStateTimeout(10);
_throwAnimation?.Tick(Time.deltaTime);
if (_throwAnimEnded && (_throwAnimation == null || !_throwAnimation.IsPlaying))
{
_nextState = true;
}
if (_nextState)
{
// return (uint)PlayerState.Fishing;
_nextState = false;
Player.ChangeState(PlayerState.Fishing);
}
}
protected override void OnExit()
{
_throwAnimation?.Stop(snapToTarget: false);
_throwAnimation = null;
}
#region
/// <summary>
/// 抛竿动画事件
/// </summary>
public void OnRodThrowStart()
{
Debug.LogError("OnRodThrowStart");
UnTakeLine();
PlayerView.Unity.ModelAsset.PlayerAnimator.PrepareThrow = false;
PlayerView.Unity.ModelAsset.PlayerAnimator.StartThrow = false;
var rod = GetRod();
if (rod != null && rod.Line != null && rod.Line.Lure != null)
if (rod == null || rod.Line == null || rod.Line.Lure == null)
{
// 使用 ChargedProgress 作为力度系数 (0-1)
float throwForce = 20f + ChargedProgress * 90f;
// 水平向前 + 向上抛出,形成抛物线轨迹
Vector3 throwDirection = PlayerView.Unity.transform.forward;// + Vector3.up * throwUpAngle;
rod.Line.Lure.RBody.AddForce(throwDirection.normalized * throwForce, ForceMode.VelocityChange);
return;
}
_throwAnimation = CreateThrowAnimation(rod);
_throwAnimation?.Play(new ThrowAnimationRequest
{
Lure = rod.Line.Lure,
StartPosition = rod.Line.Lure.RBody.position,
Forward = PlayerView.Unity.transform.forward,
ChargedProgress = ChargedProgress
});
}
public void OnRodThrownEnd()
{
Debug.LogError("OnRodThrownEnd");
_nextState = true;
_throwAnimEnded = true;
if (_throwAnimation == null || !_throwAnimation.IsPlaying)
{
_nextState = true;
}
}
#endregion
private IPlayerThrowAnimation CreateThrowAnimation(FRod rod)
{
if (rod == null || rod.Line == null)
{
return null;
}
switch (rod.Line.LineType)
{
case LineType.Spinning:
case LineType.SpinningFloat:
case LineType.Hand:
case LineType.HandDouble:
default:
return new ParabolaPlayerThrowAnimation();
}
}
}
}
}

View File

@@ -1,3 +1,2 @@
fileFormatVersion: 2
guid: 240bbc6c969a4d2e9759ac1df5e6ccf2
timeCreated: 1773064512
guid: 240bbc6c969a4d2e9759ac1df5e6ccf2

View File

@@ -10,6 +10,7 @@ namespace NBF
public static void BindAll()
{
UIObjectFactory.SetPackageItemExtension(SelectPages.URL, typeof(SelectPages));
UIObjectFactory.SetPackageItemExtension(UIBlurBackground.URL, typeof(UIBlurBackground));
UIObjectFactory.SetPackageItemExtension(BottomMenu.URL, typeof(BottomMenu));
UIObjectFactory.SetPackageItemExtension(CommonInput.URL, typeof(CommonInput));
UIObjectFactory.SetPackageItemExtension(CommonMenuRight.URL, typeof(CommonMenuRight));

View File

@@ -32,9 +32,9 @@ namespace NBF
{
await LoginHelper.Login(InputAccount.text);
// await Fishing.Instance.Go(RoleModel.Instance.Info.MapId);
await Fishing.Instance.Go(RoleModel.Instance.Info.MapId);
TestPanel.Show();
// TestPanel.Show();
// ChatTestPanel.Show();

View File

@@ -11,13 +11,13 @@ namespace NBF
{
public const string URL = "ui://6hgkvlau8hy8la";
public GImage back;
public GImage Img;
public override void ConstructFromXML(XML xml)
{
base.ConstructFromXML(xml);
back = (GImage)GetChild("back");
Img = (GImage)GetChild("Img");
OnInited();
UILanguage.TrySetComponentLanguage(this);
}

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<component size="1920,1080" overflow="hidden" extention="Label">
<displayList>
<image id="n40_jd2r" name="n40" src="jd2r18i" fileName="ImagesNew/Back/back1.png" xy="0,0"/>
<image id="n40_jd2r" name="Img" src="jd2r18i" fileName="ImagesNew/Back/back1.png" xy="0,0"/>
<image id="n39_ay5q" name="n39" src="vbojnh" fileName="ImagesNew/Square/square128_fill.png" xy="0,0" size="1920,1080" alpha="0.3" color="#000000"/>
</displayList>
</component>

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<component size="480,70" designImage="ui://6hgkvlauh6z617o" designImageOffsetY="-72" designImageAlpha="0">
<displayList>
<list id="n2_jd2r" name="List" xy="63,0" pivot="0.5,0.5" size="354,70" layout="row" overflow="hidden" scroll="horizontal" defaultItem="ui://6hgkvlauvbojxi" autoItemSize="false" vAlign="middle" autoClearItems="true">
<list id="n2_jd2r" name="List" xy="63,0" pivot="0.5,0.5" size="354,70" layout="row" overflow="hidden" scroll="horizontal" defaultItem="ui://6hgkvlauvbojxi" autoItemSize="false" vAlign="middle">
<relation target="" sidePair="center-center,middle-middle"/>
<item title="主页"/>
<item title="排行榜"/>

View File

@@ -11,7 +11,7 @@
<component id="n3_h6z6" name="BtnNext" src="r03ut" fileName="Com/Buttons/BtnInputControl.xml" xy="1312,25" size="22,22" aspect="true">
<relation target="n7_jd2r" sidePair="middle-middle,right-right"/>
</component>
<list id="n7_jd2r" name="List" xy="604,0" pivot="0.5,0.5" size="660,72" layout="row" overflow="hidden" scroll="horizontal" defaultItem="ui://6hgkvlaujd2r17t" autoItemSize="false" autoClearItems="true">
<list id="n7_jd2r" name="List" xy="604,0" pivot="0.5,0.5" size="660,72" layout="row" overflow="hidden" scroll="horizontal" defaultItem="ui://6hgkvlaujd2r17t" autoItemSize="false">
<relation target="" sidePair="center-center,middle-middle"/>
<item title="主页"/>
<item title="排行榜"/>

View File

@@ -6,7 +6,11 @@
<gearDisplay controller="button" pages="3,4,5"/>
<relation target="" sidePair="width-width,center-center,bottom-bottom"/>
</image>
<image id="n14_jd2r" name="selectLine" src="r03uiu" fileName="Images/Panels/Gradient.png" xy="-1,69" size="94,2" alpha="0.7">
<image id="n15_bp6b" name="n15" src="bp6b18j" fileName="ImagesNew/花纹/pattern128_47.png" xy="0,0" pivot="0.5,1" size="92,72" alpha="0.05">
<gearDisplay controller="button" pages="3,5"/>
<relation target="" sidePair="width-width,height-height,center-center,bottom-bottom"/>
</image>
<image id="n14_jd2r" name="selectLine" src="r03uiu" fileName="ImagesNew/Glow/Gradient.png" xy="-1,70" size="94,2" alpha="0.7">
<gearLook controller="button" pages="2,4" values="0,0,0,0|0,0,0,0" default="0.7,0,0,0" tween="true"/>
<relation target="" sidePair="width-width,center-center,bottom-bottom"/>
</image>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -482,6 +482,7 @@
<component id="jd2r18g" name="ItemsItem.xml" path="/ComNew/Item/" exported="true"/>
<component id="jd2r18h" name="RewardItem.xml" path="/ComNew/Item/" exported="true"/>
<image id="jd2r18i" name="back1.png" path="/ImagesNew/Back/"/>
<image id="bp6b18j" name="pattern128_47.png" path="/ImagesNew/花纹/" exported="true" scale="tile"/>
</resources>
<publish name="" path="../Assets/ResRaw/Fgui/Common" packageCount="2" genCode="true"/>
</packageDescription>