303 lines
10 KiB
C#
303 lines
10 KiB
C#
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
using UnityEditor;
|
||
using UnityEditor.Animations;
|
||
|
||
public class PlayerBuilderTool : EditorWindow
|
||
{
|
||
// Модель
|
||
private GameObject characterModel;
|
||
private Transform headBone;
|
||
|
||
// Параметры движения
|
||
private float walkSpeed = 5f;
|
||
private float runSpeed = 9f;
|
||
private float crouchSpeed = 2.5f;
|
||
private float jumpHeight = 1.5f;
|
||
private float gravity = -9.81f;
|
||
|
||
// Коллайдер
|
||
private float height = 1.8f;
|
||
private float radius = 0.5f;
|
||
private float centerY = 0.9f;
|
||
|
||
// Камера
|
||
private bool addCamera = true;
|
||
private float cameraHeight = 1.7f;
|
||
|
||
// Анимации
|
||
private AnimationClip idleClip;
|
||
private AnimationClip walkClip;
|
||
private AnimationClip runClip;
|
||
private AnimationClip jumpClip;
|
||
private AnimationClip crouchIdleClip;
|
||
private AnimationClip crouchWalkClip;
|
||
|
||
// Аниматор контроллер
|
||
private AnimatorController animatorController;
|
||
private bool createAnimatorController = true;
|
||
|
||
[MenuItem("Tools/Player Builder")]
|
||
public static void ShowWindow()
|
||
{
|
||
GetWindow<PlayerBuilderTool>("Конструктор Персонажа");
|
||
}
|
||
|
||
void OnGUI()
|
||
{
|
||
GUILayout.Label("Настройки персонажа", EditorStyles.boldLabel);
|
||
|
||
// Секция модели
|
||
GUILayout.Label("Модель", EditorStyles.miniBoldLabel);
|
||
characterModel = (GameObject)EditorGUILayout.ObjectField("Модель персонажа", characterModel, typeof(GameObject), false);
|
||
headBone = (Transform)EditorGUILayout.ObjectField("Кость головы", headBone, typeof(Transform), true);
|
||
|
||
GUILayout.Space(10);
|
||
|
||
// Секция движения
|
||
GUILayout.Label("Движение", EditorStyles.miniBoldLabel);
|
||
walkSpeed = EditorGUILayout.FloatField("Скорость ходьбы", walkSpeed);
|
||
runSpeed = EditorGUILayout.FloatField("Скорость бега", runSpeed);
|
||
crouchSpeed = EditorGUILayout.FloatField("Скорость краулинга", crouchSpeed);
|
||
jumpHeight = EditorGUILayout.FloatField("Высота прыжка", jumpHeight);
|
||
gravity = EditorGUILayout.FloatField("Гравитация", gravity);
|
||
|
||
GUILayout.Space(10);
|
||
|
||
// Секция коллайдера
|
||
GUILayout.Label("Коллайдер", EditorStyles.miniBoldLabel);
|
||
height = EditorGUILayout.FloatField("Высота", height);
|
||
radius = EditorGUILayout.FloatField("Радиус", radius);
|
||
centerY = EditorGUILayout.FloatField("Центр Y", centerY);
|
||
|
||
GUILayout.Space(10);
|
||
|
||
// Секция камеры
|
||
GUILayout.Label("Камера", EditorStyles.miniBoldLabel);
|
||
addCamera = EditorGUILayout.Toggle("Добавить камеру", addCamera);
|
||
if (addCamera)
|
||
{
|
||
cameraHeight = EditorGUILayout.Slider("Высота камеры", cameraHeight, 1f, 2f);
|
||
}
|
||
|
||
GUILayout.Space(10);
|
||
|
||
// Секция анимаций
|
||
GUILayout.Label("Анимации", EditorStyles.miniBoldLabel);
|
||
createAnimatorController = EditorGUILayout.Toggle("Создать контроллер", createAnimatorController);
|
||
idleClip = (AnimationClip)EditorGUILayout.ObjectField("Idle", idleClip, typeof(AnimationClip), false);
|
||
walkClip = (AnimationClip)EditorGUILayout.ObjectField("Walk", walkClip, typeof(AnimationClip), false);
|
||
runClip = (AnimationClip)EditorGUILayout.ObjectField("Run", runClip, typeof(AnimationClip), false);
|
||
jumpClip = (AnimationClip)EditorGUILayout.ObjectField("Jump", jumpClip, typeof(AnimationClip), false);
|
||
crouchIdleClip = (AnimationClip)EditorGUILayout.ObjectField("Crouch Idle", crouchIdleClip, typeof(AnimationClip), false);
|
||
crouchWalkClip = (AnimationClip)EditorGUILayout.ObjectField("Crouch Walk", crouchWalkClip, typeof(AnimationClip), false);
|
||
|
||
if (characterModel != null)
|
||
{
|
||
var animator = characterModel.GetComponent<Animator>();
|
||
if (animator != null && animator.avatar != null)
|
||
{
|
||
EditorGUILayout.HelpBox("Модель содержит Animator - аватар будет скопирован", MessageType.Info);
|
||
}
|
||
}
|
||
|
||
GUILayout.Space(20);
|
||
|
||
// Кнопки действий
|
||
GUI.color = Color.green;
|
||
if (GUILayout.Button("Создать в сцене"))
|
||
{
|
||
BuildPlayer("Player");
|
||
}
|
||
|
||
GUI.color = Color.cyan;
|
||
if (GUILayout.Button("Сохранить как префаб"))
|
||
{
|
||
SaveAsPrefab();
|
||
}
|
||
|
||
GUI.color = Color.yellow;
|
||
if (GUILayout.Button("Создать с тестовой моделью (капсула)"))
|
||
{
|
||
BuildTestPlayer();
|
||
}
|
||
|
||
GUI.color = Color.white;
|
||
|
||
GUILayout.Space(10);
|
||
EditorGUILayout.HelpBox(
|
||
"1. Назначьте модель персонажа\n" +
|
||
"2. Назначьте анимации (опционально)\n" +
|
||
"3. Настройте параметры\n" +
|
||
"4. Нажмите 'Создать в сцене'",
|
||
MessageType.Info);
|
||
}
|
||
|
||
void BuildPlayer(string playerName)
|
||
{
|
||
GameObject player = new GameObject(playerName);
|
||
|
||
// CharacterController
|
||
var cc = player.AddComponent<CharacterController>();
|
||
cc.height = height;
|
||
cc.radius = radius;
|
||
cc.center = new Vector3(0, centerY, 0);
|
||
|
||
// Скрипт персонажа
|
||
var character = player.AddComponent<charecter>();
|
||
character.walkSpeed = walkSpeed;
|
||
character.runSpeed = runSpeed;
|
||
character.crouchSpeed = crouchSpeed;
|
||
character.jumpHeight = jumpHeight;
|
||
character.gravity = gravity;
|
||
|
||
// Модель
|
||
GameObject model = null;
|
||
if (characterModel != null)
|
||
{
|
||
model = Instantiate(characterModel, player.transform);
|
||
model.transform.localPosition = Vector3.zero;
|
||
model.transform.localRotation = Quaternion.identity;
|
||
|
||
// Голова
|
||
if (headBone != null)
|
||
{
|
||
character.head = headBone;
|
||
}
|
||
else
|
||
{
|
||
character.head = FindChildBone(model.transform, "Head");
|
||
}
|
||
|
||
//Animator
|
||
var modelAnimator = model.GetComponent<Animator>();
|
||
if (modelAnimator != null && modelAnimator.avatar != null)
|
||
{
|
||
var animator = player.AddComponent<Animator>();
|
||
animator.avatar = modelAnimator.avatar;
|
||
}
|
||
}
|
||
|
||
// Голова если не найдена
|
||
if (character.head == null)
|
||
{
|
||
GameObject headObj = new GameObject("HeadPoint");
|
||
headObj.transform.SetParent(model != null ? model.transform : player.transform);
|
||
headObj.transform.localPosition = new Vector3(0, height - 0.2f, 0);
|
||
character.head = headObj.transform;
|
||
}
|
||
|
||
// Камера
|
||
if (addCamera && character.head != null)
|
||
{
|
||
GameObject cameraObj = new GameObject("PlayerCamera");
|
||
cameraObj.transform.SetParent(character.head);
|
||
cameraObj.transform.localPosition = new Vector3(0, 0.1f, 0);
|
||
|
||
var cam = cameraObj.AddComponent<Camera>();
|
||
cam.tag = "MainCamera";
|
||
cam.nearClipPlane = 0.1f;
|
||
|
||
// Удалить старую
|
||
var oldCam = GameObject.FindWithTag("MainCamera");
|
||
if (oldCam != null && oldCam != cameraObj)
|
||
{
|
||
DestroyImmediate(oldCam);
|
||
}
|
||
}
|
||
|
||
// Тег
|
||
player.tag = "Player";
|
||
|
||
// Позиция
|
||
player.transform.position = new Vector3(0, 2, -5);
|
||
|
||
Selection.activeGameObject = player;
|
||
Debug.Log($"[PlayerBuilder] Создан: {playerName}");
|
||
}
|
||
|
||
void SaveAsPrefab()
|
||
{
|
||
string path = EditorUtility.SaveFilePanelInProject(
|
||
"Сохранить префаб",
|
||
"Player",
|
||
"prefab",
|
||
"Выберите место");
|
||
|
||
if (string.IsNullOrEmpty(path)) return;
|
||
|
||
BuildPlayer("PlayerTemp");
|
||
|
||
GameObject player = GameObject.Find("PlayerTemp");
|
||
if (player == null)
|
||
{
|
||
Debug.LogError("Не удалось создать игрока");
|
||
return;
|
||
}
|
||
|
||
GameObject prefab = PrefabUtility.SaveAsPrefabAsset(player, path);
|
||
DestroyImmediate(player);
|
||
|
||
Selection.activeObject = prefab;
|
||
Debug.Log($"[PlayerBuilder] Сохранено: {path}");
|
||
}
|
||
|
||
void BuildTestPlayer()
|
||
{
|
||
characterModel = null;
|
||
headBone = null;
|
||
BuildPlayer("TestPlayer");
|
||
|
||
GameObject player = Selection.activeGameObject;
|
||
if (player == null) return;
|
||
|
||
// Создаём визуальную часть
|
||
GameObject body = GameObject.CreatePrimitive(PrimitiveType.Capsule);
|
||
body.name = "Body";
|
||
body.transform.SetParent(player.transform);
|
||
body.transform.localPosition = Vector3.zero;
|
||
DestroyImmediate(body.GetComponent<Collider>());
|
||
|
||
GameObject head = new GameObject("Head");
|
||
head.transform.SetParent(player.transform);
|
||
head.transform.localPosition = new Vector3(0, centerY + 0.2f, 0);
|
||
|
||
var character = player.GetComponent<charecter>();
|
||
if (character != null)
|
||
{
|
||
character.head = head.transform;
|
||
}
|
||
|
||
if (addCamera)
|
||
{
|
||
GameObject camObj = new GameObject("PlayerCamera");
|
||
camObj.transform.SetParent(head.transform);
|
||
camObj.transform.localPosition = new Vector3(0, 0.1f, 0);
|
||
var cam = camObj.AddComponent<Camera>();
|
||
cam.tag = "MainCamera";
|
||
|
||
var oldCam = GameObject.FindWithTag("MainCamera");
|
||
if (oldCam != null && oldCam != camObj)
|
||
{
|
||
DestroyImmediate(oldCam);
|
||
}
|
||
}
|
||
|
||
Debug.Log("[PlayerBuilder] Создан тестовый игрок");
|
||
}
|
||
|
||
Transform FindChildBone(Transform parent, string boneName)
|
||
{
|
||
if (parent == null) return null;
|
||
|
||
if (parent.name.ToLower().Contains(boneName.ToLower()))
|
||
return parent;
|
||
|
||
foreach (Transform child in parent)
|
||
{
|
||
var result = FindChildBone(child, boneName);
|
||
if (result != null) return result;
|
||
}
|
||
return null;
|
||
}
|
||
} |