设置相关功能
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using NBF;
|
||||
using UnityEngine;
|
||||
|
||||
public class ArmTest : MonoBehaviour
|
||||
@@ -8,28 +9,50 @@ public class ArmTest : MonoBehaviour
|
||||
public Transform targetTransform;
|
||||
// public float Value;
|
||||
|
||||
private Quaternion initialCameraRotation;
|
||||
private Quaternion initialLocalRotation;
|
||||
private Quaternion initialRelativeRotation;
|
||||
|
||||
|
||||
[SerializeField] private float smoothSpeed = 5f;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// target = transform.localEulerAngles;
|
||||
|
||||
// 记录初始状态
|
||||
initialCameraRotation = BaseCamera.Main.transform.rotation;
|
||||
initialLocalRotation = transform.localRotation;
|
||||
|
||||
// 计算物体相对于相机的旋转
|
||||
initialRelativeRotation = Quaternion.Inverse(initialCameraRotation) * transform.rotation;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private Quaternion lastCameraRotation;
|
||||
[SerializeField] private float angleThreshold = 0.1f; // 角度阈值(度)
|
||||
private bool needsUpdate;
|
||||
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (!targetTransform) return;
|
||||
// transform.localEulerAngles = target;
|
||||
targetTransform.localRotation = Quaternion.Euler(target.x, target.y, target.z);
|
||||
//我草拟吗。transform.localEulerAngle = target;
|
||||
//wo shi da sha bi. ArmTest Monobehaviour
|
||||
//我草拟大爷的。transofrm.localEulerAngles = target;
|
||||
Debug.LogError(targetTransform.rotation);
|
||||
|
||||
// void LateUpdate()
|
||||
// {
|
||||
// Transform shoulder = animator.GetBoneTransform(HumanBodyBones.RightUpperArm);
|
||||
// if (shoulder != null)
|
||||
// {
|
||||
// // 局部旋转叠加(例如绕Z轴微调)
|
||||
// shoulder.localRotation *= Quaternion.Euler(0, 0, shoulderOffsetAngle);
|
||||
// }
|
||||
// }
|
||||
|
||||
// 计算物体应有的世界旋转
|
||||
Quaternion targetWorldRotation = BaseCamera.Main.transform.rotation * initialRelativeRotation;
|
||||
|
||||
// 转换为本地旋转(如果是子物体)
|
||||
transform.localRotation = Quaternion.Inverse(transform.parent.rotation) * targetWorldRotation;
|
||||
|
||||
|
||||
// // 使用Lerp平滑过渡
|
||||
// transform.localRotation = Quaternion.Lerp(transform.localRotation, Quaternion.Euler(target.x, target.y, target.z), smoothSpeed * Time.deltaTime);
|
||||
// // targetTransform.localRotation = Quaternion.Euler(target.x, target.y, target.z);
|
||||
}
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NBF
|
||||
{
|
||||
public static class TypeCache
|
||||
{
|
||||
private static readonly Dictionary<Type, List<Type>> _subTypeCache = new Dictionary<Type, List<Type>>();
|
||||
private static readonly Dictionary<Type, List<Type>> _attributeCache = new Dictionary<Type, List<Type>>();
|
||||
private static readonly Dictionary<string, Type> _typeNameCache = new Dictionary<string, Type>();
|
||||
private static Type[] _filteredTypes;
|
||||
|
||||
// 目标命名空间
|
||||
private static readonly string[] TargetNamespaces = { "NBF", "NBC" };
|
||||
|
||||
// 初始化缓存
|
||||
static TypeCache()
|
||||
{
|
||||
InitializeCache();
|
||||
}
|
||||
|
||||
// 初始化缓存(仅缓存指定命名空间的类型)
|
||||
private static void InitializeCache()
|
||||
{
|
||||
// 获取Unity默认的主程序集Assembly-CSharp
|
||||
var mainAssembly = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.FirstOrDefault(a => a.GetName().Name == "Assembly-CSharp");
|
||||
|
||||
if (mainAssembly == null)
|
||||
{
|
||||
Debug.LogError("找不到Assembly-CSharp程序集");
|
||||
_filteredTypes = Array.Empty<Type>();
|
||||
return;
|
||||
}
|
||||
|
||||
// 过滤出NBF和NBC命名空间的类型
|
||||
_filteredTypes = mainAssembly.GetTypes()
|
||||
.Where(t => TargetNamespaces.Any(ns => t.Namespace != null && t.Namespace.StartsWith(ns)))
|
||||
.ToArray();
|
||||
|
||||
// 预缓存类型名
|
||||
foreach (var type in _filteredTypes)
|
||||
{
|
||||
if (type.FullName != null) _typeNameCache[type.FullName] = type;
|
||||
}
|
||||
|
||||
Debug.Log($"TypeCache初始化完成,缓存了{_filteredTypes.Length}个类型(仅限NBF和NBC命名空间)");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有已缓存的类型
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Type[] GetAllTypes()
|
||||
{
|
||||
if (_filteredTypes == null)
|
||||
{
|
||||
InitializeCache();
|
||||
}
|
||||
|
||||
return _filteredTypes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过基类或接口获取所有子类/实现类
|
||||
/// </summary>
|
||||
/// <typeparam name="TBase"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static List<Type> GetTypesWithBaseType<TBase>() where TBase : class
|
||||
{
|
||||
return GetTypesWithBaseType(typeof(TBase));
|
||||
}
|
||||
|
||||
public static List<Type> GetTypesWithBaseType(Type baseType)
|
||||
{
|
||||
if (_subTypeCache.TryGetValue(baseType, out var cachedTypes))
|
||||
{
|
||||
return cachedTypes;
|
||||
}
|
||||
|
||||
var types = GetAllTypes()
|
||||
.Where(t => baseType.IsAssignableFrom(t) && t != baseType && !t.IsAbstract && !t.IsInterface)
|
||||
.ToList();
|
||||
|
||||
_subTypeCache[baseType] = types;
|
||||
return types;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过特性获取所有类型
|
||||
/// </summary>
|
||||
/// <typeparam name="TAttribute"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static List<Type> GetTypesWithAttribute<TAttribute>() where TAttribute : Attribute
|
||||
{
|
||||
var attributeType = typeof(TAttribute);
|
||||
if (_attributeCache.TryGetValue(attributeType, out var cachedTypes))
|
||||
{
|
||||
return cachedTypes;
|
||||
}
|
||||
|
||||
var types = GetAllTypes()
|
||||
.Where(t => t.IsDefined(attributeType, false))
|
||||
.ToList();
|
||||
|
||||
_attributeCache[attributeType] = types;
|
||||
return types;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过类型名获取类型
|
||||
/// </summary>
|
||||
/// <param name="typeName"></param>
|
||||
/// <returns></returns>
|
||||
public static Type GetTypeByName(string typeName)
|
||||
{
|
||||
return _typeNameCache.GetValueOrDefault(typeName);
|
||||
}
|
||||
|
||||
// 清除缓存
|
||||
public static void ClearCache()
|
||||
{
|
||||
_subTypeCache.Clear();
|
||||
_attributeCache.Clear();
|
||||
_typeNameCache.Clear();
|
||||
_filteredTypes = null;
|
||||
Debug.Log("TypeCache已清除");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 12e6673112ac446b8d4658b32d38a5b3
|
||||
timeCreated: 1748510780
|
||||
@@ -88,6 +88,7 @@ namespace NBF
|
||||
|
||||
public bool isWater;
|
||||
|
||||
|
||||
private void Start()
|
||||
{
|
||||
m_CharacterController = GetComponent<CharacterController>();
|
||||
|
||||
@@ -13,6 +13,11 @@ namespace NBF
|
||||
_rigidbody = GetComponent<Rigidbody>();
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void FixedUpdate()
|
||||
{
|
||||
if (!target) return;
|
||||
|
||||
@@ -21,10 +21,10 @@ namespace NBF
|
||||
|
||||
private bool _isRun;
|
||||
|
||||
|
||||
|
||||
public LookAtIK lookAtIK; // 挂在背部上的 LookAtIK 脚本
|
||||
public float aimDistance = 1.5f; // 目标点离相机多远
|
||||
|
||||
|
||||
private Transform lookTarget; // 实际目标点
|
||||
[Header("限制角度(单位:度)")] public float maxUpAngle = 20f; // 相机抬头最多20°
|
||||
public float maxDownAngle = 40f; // 相机低头最多40°
|
||||
@@ -54,7 +54,7 @@ namespace NBF
|
||||
|
||||
InputManager.OnPlayerCanceled += OnPlayerCanceled;
|
||||
InputManager.OnPlayerPerformed += OnPlayerPerformed;
|
||||
|
||||
|
||||
lookAtIK = GetComponent<LookAtIK>();
|
||||
lookTarget = new GameObject("SpineLookTarget").transform;
|
||||
lookTarget.SetParent(_player.transform);
|
||||
@@ -169,20 +169,22 @@ namespace NBF
|
||||
var cameraTransform = BaseCamera.Main.transform;
|
||||
Vector3 cameraForward = cameraTransform.forward;
|
||||
Vector3 flatForward = Vector3.ProjectOnPlane(cameraForward, Vector3.up).normalized;
|
||||
|
||||
|
||||
// 获取相机 pitch 角度(负值是上看,正值是下看)
|
||||
float pitchAngle = Vector3.SignedAngle(flatForward, cameraForward, cameraTransform.right);
|
||||
|
||||
|
||||
// 限制 pitch 角度
|
||||
pitchAngle = Mathf.Clamp(pitchAngle, -maxUpAngle, maxDownAngle);
|
||||
|
||||
|
||||
// 重新构造限制后的目标方向
|
||||
Quaternion limitedPitch = Quaternion.AngleAxis(pitchAngle, cameraTransform.right);
|
||||
Vector3 limitedDirection = limitedPitch * flatForward;
|
||||
|
||||
|
||||
// 设置目标点
|
||||
lookTarget.position = cameraTransform.position + limitedDirection * aimDistance;
|
||||
lookAtIK.solver.target = lookTarget;
|
||||
//
|
||||
// lookAtIK.
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using FairyGUI;
|
||||
using NBC;
|
||||
using NBF;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.Video;
|
||||
|
||||
namespace NBF
|
||||
@@ -120,9 +116,9 @@ namespace NBF
|
||||
PermanentCommon.Init();
|
||||
InputDef.LoadIcon();
|
||||
// UI.Inst.OpenUI<FishingShopPanel>();
|
||||
UI.Inst.OpenUI<SettingPanel>();
|
||||
// UI.Inst.OpenUI<SettingPanel>();
|
||||
LoadData();
|
||||
// Fishing.Inst.Go(1);
|
||||
Fishing.Inst.Go(1);
|
||||
}
|
||||
|
||||
private void LoadData()
|
||||
|
||||
263
Assets/Scripts/Utils/Extends/Extensions.cs
Normal file
263
Assets/Scripts/Utils/Extends/Extensions.cs
Normal file
@@ -0,0 +1,263 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace NBF
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Return the square of the given value.
|
||||
/// </summary>
|
||||
|
||||
public static int square(this int value)
|
||||
{
|
||||
return value * value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the square of the given value.
|
||||
/// </summary>
|
||||
|
||||
public static float square(this float value)
|
||||
{
|
||||
return value * value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether value is near to zero within a tolerance.
|
||||
/// </summary>
|
||||
|
||||
public static bool isZero(this float value)
|
||||
{
|
||||
const float kTolerance = 0.0000000001f;
|
||||
|
||||
return Mathf.Abs(value) < kTolerance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a copy of given vector with only X component of the vector.
|
||||
/// </summary>
|
||||
|
||||
public static Vector3 onlyX(this Vector3 vector3)
|
||||
{
|
||||
vector3.y = 0.0f;
|
||||
vector3.z = 0.0f;
|
||||
|
||||
return vector3;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a copy of given vector with only Y component of the vector.
|
||||
/// </summary>
|
||||
|
||||
public static Vector3 onlyY(this Vector3 vector3)
|
||||
{
|
||||
vector3.x = 0.0f;
|
||||
vector3.z = 0.0f;
|
||||
|
||||
return vector3;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a copy of given vector with only Z component of the vector.
|
||||
/// </summary>
|
||||
|
||||
public static Vector3 onlyZ(this Vector3 vector3)
|
||||
{
|
||||
vector3.x = 0.0f;
|
||||
vector3.y = 0.0f;
|
||||
|
||||
return vector3;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a copy of given vector with only X and Y components of the vector.
|
||||
/// </summary>
|
||||
|
||||
public static Vector3 onlyXY(this Vector3 vector3)
|
||||
{
|
||||
vector3.z = 0.0f;
|
||||
|
||||
return vector3;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a copy of given vector with only X and Z components of the vector.
|
||||
/// </summary>
|
||||
|
||||
public static Vector3 onlyXZ(this Vector3 vector3)
|
||||
{
|
||||
vector3.y = 0.0f;
|
||||
|
||||
return vector3;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether vector is near to zero within a tolerance.
|
||||
/// </summary>
|
||||
|
||||
public static bool isZero(this Vector2 vector2)
|
||||
{
|
||||
return vector2.sqrMagnitude < 9.99999943962493E-11;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether vector is near to zero within a tolerance.
|
||||
/// </summary>
|
||||
|
||||
public static bool isZero(this Vector3 vector3)
|
||||
{
|
||||
return vector3.sqrMagnitude < 9.99999943962493E-11;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether vector is exceeding the magnitude within a small error tolerance.
|
||||
/// </summary>
|
||||
|
||||
public static bool isExceeding(this Vector3 vector3, float magnitude)
|
||||
{
|
||||
// Allow 1% error tolerance, to account for numeric imprecision.
|
||||
|
||||
const float kErrorTolerance = 1.01f;
|
||||
|
||||
return vector3.sqrMagnitude > magnitude * magnitude * kErrorTolerance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a copy of given vector with a magnitude of 1,
|
||||
/// and outs its magnitude before normalization.
|
||||
///
|
||||
/// If the vector is too small to be normalized a zero vector will be returned.
|
||||
/// </summary>
|
||||
|
||||
public static Vector3 normalized(this Vector3 vector3, out float magnitude)
|
||||
{
|
||||
magnitude = vector3.magnitude;
|
||||
if (magnitude > 9.99999974737875E-06)
|
||||
return vector3 / magnitude;
|
||||
|
||||
magnitude = 0.0f;
|
||||
|
||||
return Vector3.zero;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dot product of two vectors.
|
||||
/// </summary>
|
||||
|
||||
public static float dot(this Vector3 vector3, Vector3 otherVector3)
|
||||
{
|
||||
return Vector3.Dot(vector3, otherVector3);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a copy of given vector projected onto normal vector.
|
||||
/// </summary>
|
||||
|
||||
public static Vector3 projectedOn(this Vector3 thisVector, Vector3 normal)
|
||||
{
|
||||
return Vector3.Project(thisVector, normal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a copy of given vector projected onto a plane defined by a normal orthogonal to the plane.
|
||||
/// </summary>
|
||||
|
||||
public static Vector3 projectedOnPlane(this Vector3 thisVector, Vector3 planeNormal)
|
||||
{
|
||||
return Vector3.ProjectOnPlane(thisVector, planeNormal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a copy of given vector with its magnitude clamped to maxLength.
|
||||
/// </summary>
|
||||
|
||||
public static Vector3 clampedTo(this Vector3 vector3, float maxLength)
|
||||
{
|
||||
return Vector3.ClampMagnitude(vector3, maxLength);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a copy of given vector perpendicular to other vector.
|
||||
/// </summary>
|
||||
|
||||
public static Vector3 perpendicularTo(this Vector3 thisVector, Vector3 otherVector)
|
||||
{
|
||||
return Vector3.Cross(thisVector, otherVector).normalized;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a copy of given vector adjusted to be tangent to a specified surface normal relatively to given up axis.
|
||||
/// </summary>
|
||||
|
||||
public static Vector3 tangentTo(this Vector3 thisVector, Vector3 normal, Vector3 up)
|
||||
{
|
||||
Vector3 r = thisVector.perpendicularTo(up);
|
||||
Vector3 t = normal.perpendicularTo(r);
|
||||
|
||||
return t * thisVector.magnitude;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transforms a vector to be relative to given transform.
|
||||
/// If isPlanar == true, the transform will be applied on the plane defined by world up axis.
|
||||
/// </summary>
|
||||
|
||||
public static Vector3 relativeTo(this Vector3 vector3, Transform relativeToThis, bool isPlanar = true)
|
||||
{
|
||||
Vector3 forward = relativeToThis.forward;
|
||||
|
||||
if (isPlanar)
|
||||
{
|
||||
Vector3 upAxis = Vector3.up;
|
||||
forward = forward.projectedOnPlane(upAxis);
|
||||
|
||||
if (forward.isZero())
|
||||
forward = Vector3.ProjectOnPlane(relativeToThis.up, upAxis);
|
||||
}
|
||||
|
||||
Quaternion q = Quaternion.LookRotation(forward);
|
||||
|
||||
return q * vector3;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transforms a vector to be relative to given transform.
|
||||
/// If isPlanar == true, the transform will be applied on the plane defined by upAxis.
|
||||
/// </summary>
|
||||
|
||||
public static Vector3 relativeTo(this Vector3 vector3, Transform relativeToThis, Vector3 upAxis, bool isPlanar = true)
|
||||
{
|
||||
Vector3 forward = relativeToThis.forward;
|
||||
|
||||
if (isPlanar)
|
||||
{
|
||||
forward = Vector3.ProjectOnPlane(forward, upAxis);
|
||||
|
||||
if (forward.isZero())
|
||||
forward = Vector3.ProjectOnPlane(relativeToThis.up, upAxis);
|
||||
}
|
||||
|
||||
Quaternion q = Quaternion.LookRotation(forward, upAxis);
|
||||
|
||||
return q * vector3;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clamps the given quaternion pitch rotation between the given minPitchAngle and maxPitchAngle.
|
||||
/// </summary>
|
||||
|
||||
public static Quaternion clampPitch(this Quaternion quaternion, float minPitchAngle, float maxPitchAngle)
|
||||
{
|
||||
quaternion.x /= quaternion.w;
|
||||
quaternion.y /= quaternion.w;
|
||||
quaternion.z /= quaternion.w;
|
||||
quaternion.w = 1.0f;
|
||||
|
||||
float pitch = Mathf.Clamp(2.0f * Mathf.Rad2Deg * Mathf.Atan(quaternion.x), minPitchAngle, maxPitchAngle);
|
||||
|
||||
quaternion.x = Mathf.Tan(pitch * 0.5f * Mathf.Deg2Rad);
|
||||
|
||||
return quaternion;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/Utils/Extends/Extensions.cs.meta
Normal file
3
Assets/Scripts/Utils/Extends/Extensions.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3308733cfb774828bac0a5740bedd645
|
||||
timeCreated: 1748527846
|
||||
163
Assets/Scripts/Utils/VectorUtil.cs
Normal file
163
Assets/Scripts/Utils/VectorUtil.cs
Normal file
@@ -0,0 +1,163 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace NBF
|
||||
{
|
||||
public static class VectorUtil
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns Value mapped from one range into another.
|
||||
/// </summary>
|
||||
public static float Remap(float inA, float inB, float outA, float outB, float value)
|
||||
{
|
||||
float t = Mathf.InverseLerp(inA, inB, value);
|
||||
|
||||
return Mathf.Lerp(outA, outB, t);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the square of the given value.
|
||||
/// </summary>
|
||||
public static float Square(float value)
|
||||
{
|
||||
return value * value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the direction adjusted to be tangent to a specified surface normal relatively to given up axis.
|
||||
/// </summary>
|
||||
public static Vector3 GetTangent(Vector3 direction, Vector3 normal, Vector3 up)
|
||||
{
|
||||
Vector3 right = direction.perpendicularTo(up);
|
||||
|
||||
return normal.perpendicularTo(right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Projects a given point onto the plane defined by plane origin and plane normal.
|
||||
/// </summary>
|
||||
public static Vector3 ProjectPointOnPlane(Vector3 point, Vector3 planeOrigin, Vector3 planeNormal)
|
||||
{
|
||||
Vector3 toPoint = point - planeOrigin;
|
||||
Vector3 toPointProjected = Vector3.Project(toPoint, planeNormal);
|
||||
|
||||
return point - toPointProjected;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clamps given angle within min - max range.
|
||||
/// </summary>
|
||||
public static float ClampAngle(float a, float min, float max)
|
||||
{
|
||||
while (max < min)
|
||||
max += 360.0f;
|
||||
|
||||
while (a > max)
|
||||
a -= 360.0f;
|
||||
|
||||
while (a < min)
|
||||
a += 360.0f;
|
||||
|
||||
return a > max ? a - (max + min) * 0.5f < 180.0f ? max : min : a;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns Angle in the range (0, 360)
|
||||
/// </summary>
|
||||
public static float ClampAngle(float angle)
|
||||
{
|
||||
// returns angle in the range (-360, 360)
|
||||
|
||||
angle = angle % 360.0f;
|
||||
|
||||
if (angle < 0.0f)
|
||||
{
|
||||
// shift to (0, 360) range
|
||||
|
||||
angle += 360.0f;
|
||||
}
|
||||
|
||||
return angle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return angle in range -180 to 180
|
||||
/// </summary>
|
||||
public static float NormalizeAngle(float angle)
|
||||
{
|
||||
// returns angle in the range (0, 360)
|
||||
|
||||
angle = ClampAngle(angle);
|
||||
|
||||
if (angle > 180.0f)
|
||||
{
|
||||
// shift to (-180,180)
|
||||
|
||||
angle -= 360.0f;
|
||||
}
|
||||
|
||||
return angle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clamps the given angle into 0 - 360 degrees range.
|
||||
/// </summary>
|
||||
private static float Clamp0360(float eulerAngles)
|
||||
{
|
||||
float result = eulerAngles - Mathf.CeilToInt(eulerAngles / 360f) * 360f;
|
||||
if (result < 0) result += 360f;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new rotation angle (interpolated) clamped in the range (0.0f , 360.0f)
|
||||
/// </summary>
|
||||
public static float FixedTurn(float current, float target, float maxDegreesDelta)
|
||||
{
|
||||
if (maxDegreesDelta == 0.0f)
|
||||
return Clamp0360(current);
|
||||
|
||||
if (maxDegreesDelta >= 360.0f)
|
||||
return Clamp0360(target);
|
||||
|
||||
float result = Clamp0360(current);
|
||||
current = result;
|
||||
target = Clamp0360(target);
|
||||
|
||||
if (current > target)
|
||||
{
|
||||
if (current - target < 180.0f)
|
||||
result -= Mathf.Min(current - target, Mathf.Abs(maxDegreesDelta));
|
||||
else
|
||||
result += Mathf.Min(target + 360.0f - current, Mathf.Abs(maxDegreesDelta));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (target - current < 180.0f)
|
||||
result += Mathf.Min(target - current, Mathf.Abs(maxDegreesDelta));
|
||||
else
|
||||
result -= Mathf.Min(current + 360.0f - target, Mathf.Abs(maxDegreesDelta));
|
||||
}
|
||||
|
||||
return Clamp0360(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Frame Rate Independent Damping.
|
||||
/// Source: https://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/
|
||||
/// </summary>
|
||||
public static float Damp(float a, float b, float lambda, float dt)
|
||||
{
|
||||
return Mathf.Lerp(a, b, 1.0f - Mathf.Exp(-lambda * dt));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Frame Rate Independent Damping.
|
||||
/// Source: https://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/
|
||||
/// </summary>
|
||||
public static Vector3 Damp(Vector3 a, Vector3 b, float lambda, float dt)
|
||||
{
|
||||
return Vector3.Lerp(a, b, 1.0f - Mathf.Exp(-lambda * dt));
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/Utils/VectorUtil.cs.meta
Normal file
3
Assets/Scripts/Utils/VectorUtil.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8f5057ebeaca4f7bbcf90011280b93b8
|
||||
timeCreated: 1748528114
|
||||
Reference in New Issue
Block a user