Race_fields/Assets/_Project/Scripts/Editor/BuggyPrefabBuilder.cs
2026-07-15 15:16:00 +03:00

157 lines
5.8 KiB
C#

using RaceFields.CameraSystem;
using RaceFields.Vehicles;
using UnityEditor;
using UnityEngine;
namespace RaceFields.EditorTools
{
public static class BuggyPrefabBuilder
{
private const string BuggyPrefabPath = "Assets/_Project/Prefabs/Vehicles/Player/Buggy_Player.prefab";
private const string CameraPrefabPath = "Assets/_Project/Prefabs/Cameras/Buggy_ThirdPersonCamera.prefab";
[MenuItem("Race Fields/Setup/Rebuild Buggy Prefab")]
public static void RebuildBuggyPrefab()
{
GameObject root = PrefabUtility.LoadPrefabContents(BuggyPrefabPath);
try
{
EnsureComponent<Rigidbody>(root, ConfigureBody);
EnsureComponent<BoxCollider>(root, ConfigureBodyCollider);
EnsureComponent<ArcadeBuggyController>(root, null);
EnsureComponent<BuggyWheelSetup>(root, setup => setup.AlignAllWheels());
SetupWheel(root.transform, "F_L", "WheelCollider_FL");
SetupWheel(root.transform, "F_R", "WheelCollider_FR");
SetupWheel(root.transform, "B_L", "WheelCollider_RL");
SetupWheel(root.transform, "B_R", "WheelCollider_RR");
BuggyWheelSetup wheelSetup = root.GetComponent<BuggyWheelSetup>();
wheelSetup.AlignAllWheels();
PrefabUtility.SaveAsPrefabAsset(root, BuggyPrefabPath);
}
finally
{
PrefabUtility.UnloadPrefabContents(root);
}
RebuildCameraPrefab();
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
private static void RebuildCameraPrefab()
{
GameObject cameraObject = new GameObject("Buggy_ThirdPersonCamera");
try
{
Camera camera = cameraObject.AddComponent<Camera>();
camera.fieldOfView = 62f;
camera.nearClipPlane = 0.05f;
camera.farClipPlane = 600f;
cameraObject.AddComponent<AudioListener>();
cameraObject.AddComponent<BuggyFollowCamera>().SnapToTarget();
cameraObject.transform.position = new Vector3(0f, 4.2f, -7.5f);
cameraObject.transform.rotation = Quaternion.Euler(18f, 0f, 0f);
PrefabUtility.SaveAsPrefabAsset(cameraObject, CameraPrefabPath);
}
finally
{
Object.DestroyImmediate(cameraObject);
}
}
private static void SetupWheel(Transform root, string visualName, string colliderName)
{
Transform visual = FindDescendant(root, visualName);
if (visual == null)
{
Debug.LogWarning($"Wheel visual '{visualName}' was not found in {BuggyPrefabPath}.");
return;
}
Transform colliderTransform = FindDescendant(root, colliderName);
GameObject colliderObject = colliderTransform != null
? colliderTransform.gameObject
: new GameObject(colliderName);
colliderObject.name = colliderName;
colliderObject.transform.SetParent(root, true);
colliderObject.transform.position = visual.position;
colliderObject.transform.rotation = root.rotation;
colliderObject.transform.localScale = Vector3.one;
WheelCollider wheelCollider = colliderObject.GetComponent<WheelCollider>();
if (wheelCollider == null)
wheelCollider = colliderObject.AddComponent<WheelCollider>();
ConfigureWheel(wheelCollider, visual);
}
private static void ConfigureBody(Rigidbody body)
{
body.mass = 850f;
body.linearDamping = 0.05f;
body.angularDamping = 0.8f;
body.interpolation = RigidbodyInterpolation.Interpolate;
body.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
}
private static void ConfigureBodyCollider(BoxCollider collider)
{
collider.center = new Vector3(0f, 0.55f, 0f);
collider.size = new Vector3(1.8f, 0.9f, 3.1f);
}
private static void ConfigureWheel(WheelCollider wheelCollider, Transform visual)
{
wheelCollider.mass = 20f;
wheelCollider.radius = EstimateRadius(visual);
wheelCollider.suspensionDistance = 0.28f;
wheelCollider.forceAppPointDistance = 0.05f;
wheelCollider.wheelDampingRate = 0.35f;
JointSpring spring = wheelCollider.suspensionSpring;
spring.spring = 35000f;
spring.damper = 4500f;
spring.targetPosition = 0.5f;
wheelCollider.suspensionSpring = spring;
}
private static float EstimateRadius(Transform visual)
{
Renderer renderer = visual.GetComponentInChildren<Renderer>();
if (renderer == null)
return 0.34f;
Vector3 size = renderer.bounds.size;
return Mathf.Max(0.12f, Mathf.Max(size.y, size.z) * 0.5f);
}
private static T EnsureComponent<T>(GameObject gameObject, System.Action<T> configure) where T : Component
{
T component = gameObject.GetComponent<T>();
if (component == null)
component = gameObject.AddComponent<T>();
configure?.Invoke(component);
return component;
}
private static Transform FindDescendant(Transform root, string name)
{
Transform[] children = root.GetComponentsInChildren<Transform>(true);
for (int i = 0; i < children.Length; i++)
{
if (children[i].name == name)
return children[i];
}
return null;
}
}
}