건설 인터랙션 시 움직이지 못하는 문제 수정 2개로 분리되어 있던 타워 데이터를 하나로 통합 - 대신 타워가 아닌 건물도 공격력 등을 정의할 수 있음
205 lines
6.8 KiB
C#
205 lines
6.8 KiB
C#
using Unity.Netcode;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
using UnityEngine.AI;
|
|
using Northbound;
|
|
|
|
namespace Northbound.Editor
|
|
{
|
|
public class TemplateCreator
|
|
{
|
|
private const string TEMPLATE_BASE_PATH = "Assets/Data/Templates";
|
|
|
|
[MenuItem("Tools/Data/Create Monster Template")]
|
|
public static void CreateMonsterTemplate()
|
|
{
|
|
CreateTemplate("Monster", SetupMonsterComponents);
|
|
}
|
|
|
|
[MenuItem("Tools/Data/Create Tower Template")]
|
|
public static void CreateTowerTemplate()
|
|
{
|
|
CreateTemplate("Tower", SetupTowerComponents);
|
|
}
|
|
|
|
[MenuItem("Tools/Data/Create Player Template")]
|
|
public static void CreatePlayerTemplate()
|
|
{
|
|
CreateTemplate("Player", SetupPlayerComponents);
|
|
}
|
|
|
|
private static void CreateTemplate(string typeName, System.Action<GameObject> setupComponents)
|
|
{
|
|
if (!AssetDatabase.IsValidFolder(TEMPLATE_BASE_PATH))
|
|
{
|
|
System.IO.Directory.CreateDirectory(Application.dataPath + "/Data/Templates");
|
|
AssetDatabase.Refresh();
|
|
}
|
|
|
|
string templateName = $"{typeName}Template";
|
|
string templatePath = $"{TEMPLATE_BASE_PATH}/{templateName}.prefab";
|
|
|
|
GameObject templateGO = new GameObject(templateName);
|
|
|
|
setupComponents(templateGO);
|
|
|
|
PrefabUtility.SaveAsPrefabAsset(templateGO, templatePath);
|
|
GameObject.DestroyImmediate(templateGO);
|
|
|
|
Debug.Log($"[TemplateCreator] Created template: {templatePath}");
|
|
AssetDatabase.Refresh();
|
|
Selection.activeObject = AssetDatabase.LoadAssetAtPath<GameObject>(templatePath);
|
|
}
|
|
|
|
private static void SetupMonsterComponents(GameObject go)
|
|
{
|
|
Transform t = go.transform;
|
|
t.localPosition = Vector3.zero;
|
|
t.localRotation = Quaternion.identity;
|
|
t.localScale = Vector3.one;
|
|
|
|
if (go.GetComponent<CapsuleCollider>() == null)
|
|
{
|
|
CapsuleCollider collider = go.AddComponent<CapsuleCollider>();
|
|
collider.isTrigger = false;
|
|
collider.radius = 0.5f;
|
|
collider.height = 2f;
|
|
collider.direction = 1;
|
|
collider.center = Vector3.zero;
|
|
}
|
|
|
|
if (go.GetComponent<Animator>() == null)
|
|
{
|
|
Animator animator = go.AddComponent<Animator>();
|
|
animator.runtimeAnimatorController = null;
|
|
animator.avatar = null;
|
|
animator.applyRootMotion = false;
|
|
animator.updateMode = AnimatorUpdateMode.Normal;
|
|
animator.cullingMode = AnimatorCullingMode.CullUpdateTransforms;
|
|
}
|
|
|
|
if (go.GetComponent<NetworkObject>() == null)
|
|
go.AddComponent<NetworkObject>();
|
|
|
|
if (go.GetComponent<EnemyUnit>() == null)
|
|
go.AddComponent<EnemyUnit>();
|
|
|
|
if (go.GetComponent<MonsterDataComponent>() == null)
|
|
go.AddComponent<MonsterDataComponent>();
|
|
|
|
if (go.GetComponent<NavMeshAgent>() == null)
|
|
{
|
|
NavMeshAgent agent = go.AddComponent<NavMeshAgent>();
|
|
agent.speed = 2.6f;
|
|
agent.angularSpeed = 120f;
|
|
agent.acceleration = 8f;
|
|
agent.stoppingDistance = 0f;
|
|
agent.autoBraking = true;
|
|
agent.radius = 0.5f;
|
|
agent.height = 2f;
|
|
}
|
|
|
|
if (go.GetComponent<EnemyAIController>() == null)
|
|
{
|
|
EnemyAIController ai = go.AddComponent<EnemyAIController>();
|
|
ai.aiType = TeamType.Monster;
|
|
ai.detectionRange = 6f;
|
|
ai.detectionAngle = 360f;
|
|
ai.maxChaseDistance = 30f;
|
|
ai.attackRange = 1f;
|
|
ai.attackInterval = 1.2f;
|
|
ai.attackDamage = 3;
|
|
ai.moveSpeed = 2.6f;
|
|
ai.chaseSpeedMultiplier = 1.2f;
|
|
}
|
|
|
|
MeshFilter meshFilter = go.GetComponent<MeshFilter>();
|
|
if (meshFilter == null)
|
|
meshFilter = go.AddComponent<MeshFilter>();
|
|
|
|
MeshRenderer meshRenderer = go.GetComponent<MeshRenderer>();
|
|
if (meshRenderer == null)
|
|
meshRenderer = go.AddComponent<MeshRenderer>();
|
|
|
|
int monsterLayer = LayerMask.NameToLayer("Monster");
|
|
if (monsterLayer >= 0)
|
|
{
|
|
go.layer = monsterLayer;
|
|
}
|
|
else
|
|
{
|
|
go.layer = 0;
|
|
}
|
|
|
|
NetworkObject netObj = go.GetComponent<NetworkObject>();
|
|
if (netObj != null)
|
|
{
|
|
netObj.SynchronizeTransform = true;
|
|
netObj.SpawnWithObservers = true;
|
|
netObj.AlwaysReplicateAsRoot = false;
|
|
}
|
|
|
|
EnemyUnit enemyUnit = go.GetComponent<EnemyUnit>();
|
|
if (enemyUnit != null)
|
|
{
|
|
enemyUnit.enemyTeam = TeamType.Monster;
|
|
}
|
|
}
|
|
|
|
private static void SetupTowerComponents(GameObject go)
|
|
{
|
|
Transform t = go.transform;
|
|
t.localPosition = Vector3.zero;
|
|
t.localRotation = Quaternion.identity;
|
|
t.localScale = Vector3.one;
|
|
|
|
if (go.GetComponent<NetworkObject>() == null)
|
|
go.AddComponent<NetworkObject>();
|
|
|
|
if (go.GetComponent<Building>() == null)
|
|
go.AddComponent<Building>();
|
|
|
|
if (go.GetComponent<BoxCollider>() == null)
|
|
{
|
|
BoxCollider collider = go.AddComponent<BoxCollider>();
|
|
collider.size = new Vector3(1f, 2f, 1f);
|
|
collider.center = new Vector3(0f, 1f, 0f);
|
|
}
|
|
|
|
if (go.GetComponent<NavMeshObstacle>() == null)
|
|
{
|
|
NavMeshObstacle obstacle = go.AddComponent<NavMeshObstacle>();
|
|
obstacle.shape = NavMeshObstacleShape.Box;
|
|
obstacle.size = new Vector3(1f, 1f, 1f);
|
|
obstacle.center = new Vector3(0f, 0.5f, 0f);
|
|
}
|
|
|
|
int defaultLayer = LayerMask.NameToLayer("Default");
|
|
if (defaultLayer >= 0)
|
|
{
|
|
go.layer = defaultLayer;
|
|
}
|
|
else
|
|
{
|
|
go.layer = 0;
|
|
}
|
|
}
|
|
|
|
private static void SetupPlayerComponents(GameObject go)
|
|
{
|
|
if (go.GetComponent<NetworkObject>() == null)
|
|
go.AddComponent<NetworkObject>();
|
|
|
|
int playerLayer = LayerMask.NameToLayer("Player");
|
|
if (playerLayer >= 0)
|
|
{
|
|
go.layer = playerLayer;
|
|
}
|
|
else
|
|
{
|
|
go.layer = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|