Commit 1
This commit is contained in:
170
Assets/Scripts/GameSetup/CharacterAutoSetup.cs
Normal file
170
Assets/Scripts/GameSetup/CharacterAutoSetup.cs
Normal file
@@ -0,0 +1,170 @@
|
||||
using UnityEngine;
|
||||
using System.Text;
|
||||
|
||||
namespace OnlyScove.Scripts.GameSetup
|
||||
{
|
||||
[RequireComponent(typeof(CharacterController))]
|
||||
public class CharacterAutoSetup : MonoBehaviour
|
||||
{
|
||||
[Header("Manual Overrides (If Detection Fails)")]
|
||||
[SerializeField] private float defaultHeight = 1.8f;
|
||||
[SerializeField] private float defaultShoulderWidth = 0.4f;
|
||||
|
||||
[Header("Settings")]
|
||||
[SerializeField] private Transform modelRoot;
|
||||
[SerializeField] private bool autoDetectOnStart = true;
|
||||
[SerializeField] private float zCenterOffset = 0.05f;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (autoDetectOnStart)
|
||||
{
|
||||
ApplyAutoSetup();
|
||||
}
|
||||
}
|
||||
|
||||
[ContextMenu("Apply Auto Setup")]
|
||||
public void ApplyAutoSetup()
|
||||
{
|
||||
CharacterController controller = GetComponent<CharacterController>();
|
||||
PlayerStateMachine stateMachine = GetComponent<PlayerStateMachine>();
|
||||
Animator animator = GetComponentInChildren<Animator>();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.AppendLine($"<color=#4FC3F7><b>[AUTO-SETUP REPORT]</b></color> Character: <b>{gameObject.name}</b>");
|
||||
sb.AppendLine("<color=#757575>------------------------------------------------------------</color>");
|
||||
|
||||
// 1. HEIGHT DETECTION
|
||||
float finalHeight = defaultHeight;
|
||||
string heightMethod = "Default Fallback";
|
||||
|
||||
if (animator != null && animator.GetBoneTransform(HumanBodyBones.Head) != null)
|
||||
{
|
||||
heightMethod = "Humanoid Bones (Feet to Head)";
|
||||
Transform head = animator.GetBoneTransform(HumanBodyBones.Head);
|
||||
// We measure from the local Y=0 (feet) to the head bone and add 10% for the skull/hair
|
||||
float headHeight = transform.InverseTransformPoint(head.position).y;
|
||||
finalHeight = headHeight * 1.12f; // 12% extra for the top of the skull
|
||||
}
|
||||
else
|
||||
{
|
||||
heightMethod = "Local Mesh Bounds";
|
||||
Bounds localBounds = GetRelativeBounds();
|
||||
if (localBounds.size.y > 0) finalHeight = localBounds.size.y;
|
||||
}
|
||||
|
||||
sb.AppendLine(string.Format("<b>1. HEIGHT:</b> {0:F3}m ({1}) ➔ <color=#81C784>{2:F3}m</color>", finalHeight, heightMethod, finalHeight));
|
||||
|
||||
// 2. RADIUS DETECTION
|
||||
float shoulderWidth = defaultShoulderWidth;
|
||||
string radiusMethod = "Default Fallback";
|
||||
|
||||
if (animator != null && animator.GetBoneTransform(HumanBodyBones.Hips) != null)
|
||||
{
|
||||
radiusMethod = "Humanoid Bones (Shoulders)";
|
||||
Transform leftArm = animator.GetBoneTransform(HumanBodyBones.LeftUpperArm);
|
||||
Transform rightArm = animator.GetBoneTransform(HumanBodyBones.RightUpperArm);
|
||||
|
||||
if (leftArm != null && rightArm != null)
|
||||
{
|
||||
float distance = Vector3.Distance(leftArm.position, rightArm.position);
|
||||
shoulderWidth = distance * 1.2f; // Add 20% for arm/shoulder thickness
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
radiusMethod = "Bounds Width Fallback";
|
||||
Bounds b = GetRelativeBounds();
|
||||
shoulderWidth = b.size.x * 0.25f;
|
||||
}
|
||||
|
||||
float finalRadius = shoulderWidth / 2f;
|
||||
sb.AppendLine(string.Format("<b>2. RADIUS:</b> {0:F3}m ({1}) [/ 2] ➔ <color=#81C784>{2:F3}m</color>", shoulderWidth, radiusMethod, finalRadius));
|
||||
|
||||
// 3. COLLISION PRECISION
|
||||
float skinWidth = finalRadius * 0.10f;
|
||||
sb.AppendLine(string.Format("<b>3. SKIN WIDTH:</b> {0:F3}m (Radius) [x 0.10] ➔ <color=#81C784>{1:F3}m</color>", finalRadius, skinWidth));
|
||||
|
||||
// 4. CAPSULE CENTER
|
||||
// Center Y = (Height / 2) + SkinWidth
|
||||
float centerY = (finalHeight / 2f) + skinWidth;
|
||||
sb.AppendLine(string.Format("<b>4. CENTER Y:</b> ({0:F3}m / 2) + {1:F3}m (Skin) ➔ <color=#81C784>{2:F3}m</color>", finalHeight, skinWidth, centerY));
|
||||
sb.AppendLine(string.Format("<b>5. CENTER Z:</b> [Fixed Offset] ➔ <color=#81C784>{0:F3}m</color>", zCenterOffset));
|
||||
|
||||
// 5. MOVEMENT CONSTRAINTS
|
||||
float stepOffset = finalHeight * 0.15f;
|
||||
sb.AppendLine(string.Format("<b>6. STEP OFFSET:</b> {0:F3}m (Height) [x 0.15] ➔ <color=#81C784>{1:F3}m</color>", finalHeight, stepOffset));
|
||||
|
||||
// 6. GROUND CHECK (STATE MACHINE)
|
||||
sb.AppendLine("<color=#757575>------------------------------------------------------------</color>");
|
||||
if (stateMachine != null)
|
||||
{
|
||||
float groundCheckRadius = finalRadius * 0.6f;
|
||||
float groundCheckOffsetY = finalHeight / 24f;
|
||||
Vector3 groundCheckOffset = new Vector3(0, groundCheckOffsetY, zCenterOffset);
|
||||
|
||||
stateMachine.SetGroundCheck(groundCheckRadius, groundCheckOffset);
|
||||
|
||||
sb.AppendLine("<b>7. GROUND CHECK SETUP:</b>");
|
||||
sb.AppendLine(string.Format(" - Radius: {0:F3}m (Radius) [x 0.60] ➔ <color=#81C784>{1:F3}m</color>", finalRadius, groundCheckRadius));
|
||||
sb.AppendLine(string.Format(" - Offset Y: {0:F3}m (Height) [/ 24] ➔ <color=#81C784>{1:F3}m</color>", finalHeight, groundCheckOffsetY));
|
||||
sb.AppendLine(string.Format(" - Offset Z: [Sync Center Z] ➔ <color=#81C784>{0:F3}m</color>", zCenterOffset));
|
||||
}
|
||||
|
||||
sb.AppendLine("<color=#757575>------------------------------------------------------------</color>");
|
||||
|
||||
// Apply to Controller
|
||||
controller.height = finalHeight;
|
||||
controller.radius = finalRadius;
|
||||
controller.skinWidth = skinWidth;
|
||||
controller.center = new Vector3(0, centerY, zCenterOffset);
|
||||
controller.slopeLimit = 45f;
|
||||
controller.stepOffset = stepOffset;
|
||||
controller.minMoveDistance = 0.001f;
|
||||
|
||||
Debug.Log(sb.ToString());
|
||||
}
|
||||
|
||||
private Bounds GetRelativeBounds()
|
||||
{
|
||||
Transform targetRoot = modelRoot != null ? modelRoot : transform;
|
||||
Renderer[] renderers = targetRoot.GetComponentsInChildren<Renderer>();
|
||||
|
||||
if (renderers.Length == 0) return new Bounds(Vector3.zero, Vector3.zero);
|
||||
|
||||
// Using local bounds of SkinnedMeshRenderers for better accuracy on animated characters
|
||||
Bounds combinedLocalBounds = new Bounds();
|
||||
bool first = true;
|
||||
|
||||
foreach (Renderer renderer in renderers)
|
||||
{
|
||||
if (renderer is ParticleSystemRenderer) continue;
|
||||
|
||||
Bounds localB;
|
||||
if (renderer is SkinnedMeshRenderer smr)
|
||||
{
|
||||
localB = smr.localBounds;
|
||||
}
|
||||
else
|
||||
{
|
||||
// For static meshes, convert world bounds back to local root space
|
||||
Vector3 min = transform.InverseTransformPoint(renderer.bounds.min);
|
||||
Vector3 max = transform.InverseTransformPoint(renderer.bounds.max);
|
||||
localB = new Bounds((min + max) / 2f, max - min);
|
||||
}
|
||||
|
||||
if (first)
|
||||
{
|
||||
combinedLocalBounds = localB;
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
combinedLocalBounds.Encapsulate(localB);
|
||||
}
|
||||
}
|
||||
|
||||
return combinedLocalBounds;
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/GameSetup/CharacterAutoSetup.cs.meta
Normal file
2
Assets/Scripts/GameSetup/CharacterAutoSetup.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e16a6690e589f0449ad89a6bf508ab62
|
||||
26
Assets/Scripts/GameSetup/CharacterSetupSettings.cs
Normal file
26
Assets/Scripts/GameSetup/CharacterSetupSettings.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace OnlyScove.Scripts.GameSetup
|
||||
{
|
||||
[CreateAssetMenu(fileName = "CharacterSetupSettings", menuName = "Setup/Character Setup Settings")]
|
||||
public class CharacterSetupSettings : ScriptableObject
|
||||
{
|
||||
[Header("Movement Constraints")]
|
||||
public float slopeLimit = 45f;
|
||||
[Range(0.01f, 0.5f)] public float stepHeightRatio = 0.15f; // Step offset as % of height
|
||||
|
||||
[Header("Precision & Collision")]
|
||||
public float skinWidthRatio = 0.1f; // Skin width as % of radius
|
||||
public float minMoveDistance = 0.001f;
|
||||
|
||||
[Header("Dimension Multipliers")]
|
||||
[Tooltip("Multiplies the detected shoulder width to define Radius.")]
|
||||
public float radiusMultiplier = 0.8f;
|
||||
[Tooltip("Multiplies the detected bounding box height.")]
|
||||
public float heightMultiplier = 1.0f;
|
||||
|
||||
[Header("Center Offset")]
|
||||
[Tooltip("Y-axis offset for the center of the capsule (0.5 means exact middle).")]
|
||||
public float centerYRatio = 0.5f;
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/GameSetup/CharacterSetupSettings.cs.meta
Normal file
2
Assets/Scripts/GameSetup/CharacterSetupSettings.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0d44cb4bd45c0e24bb3d8196a137db00
|
||||
Reference in New Issue
Block a user