/// ---------------------------------------------
/// Ultimate Character Controller
/// Copyright (c) Opsive. All Rights Reserved.
/// https://www.opsive.com
/// ---------------------------------------------
namespace Opsive.UltimateCharacterController.Editor.Managers
{
using Opsive.UltimateCharacterController.Game;
using Opsive.UltimateCharacterController.Objects;
using Opsive.UltimateCharacterController.Objects.CharacterAssist;
using Opsive.UltimateCharacterController.Objects.ItemAssist;
using Opsive.UltimateCharacterController.Traits;
using UnityEditor;
using UnityEngine;
///
/// The ObjectManager will draw any item properties
///
[OrderedEditorItem("Object", 5)]
public class ObjectManager : Manager
{
///
/// The type of object to build.
///
private enum ObjectType
{
ItemPickup, // Builds an ItemPickup with a Respawner component.
DroppedItem, // Builds an ItemPickup that can be dropped from the character with the TrajectoryObject.
HealthPickup, // Builds a HealthPickup with a Respawner component.
#if ULTIMATE_CHARACTER_CONTROLLER_SHOOTER
Projectile, // Builds a Projectile that can be fired.
MuzzleFlash, // Builds an object with the MuzzleFlash component.
Shell, // Builds an object with the Shell component.
Smoke, // Builds an object with the Smoke component.
#endif
#if ULTIMATE_CHARACTER_CONTROLLER_MELEE
MeleeTrail, // Builds an object with the Trail component.
#endif
Grenade, // Builds a Grenade TrajectoryObject.
Explosion, // Builds an object with the Explosion and ParticleSystem components.
MagicProjectile, // Builds an object with the MagicProjectile and ParticleSystem components.
Particle, // Builds an object with the ParticlePooler and ParticleSystem components
}
[SerializeField] private string m_Name;
[SerializeField] private ObjectType m_ObjectType;
[SerializeField] private GameObject m_Object;
[SerializeField] private bool m_MagicParticleCollisions;
private bool m_CanBuild;
///
/// Draws the ObjectManager.
///
public override void OnGUI()
{
ManagerUtility.DrawControlBox("Object Builder", DrawObjectTypes, "Builds a new object with the specified type.",
m_Name != null && (m_Object != null || !RequiresGameObject()) && m_CanBuild,
"Build Object", BuildObject, string.Empty);
}
///
/// Draws the object type popup.
///
private void DrawObjectTypes()
{
m_CanBuild = true;
m_Name = EditorGUILayout.TextField("Name", m_Name);
m_ObjectType = (ObjectType)EditorGUILayout.EnumPopup("Object Type", m_ObjectType);
if (RequiresGameObject()) {
m_Object = EditorGUILayout.ObjectField("GameObject", m_Object, typeof(GameObject), true) as GameObject;
if (m_Object != null && m_ObjectType == ObjectType.ItemPickup) {
if (m_Object.GetComponent() != null) {
EditorGUILayout.HelpBox("The Item Pickup should not reference an already created item. This GameObject should reference the item model.", MessageType.Error);
m_CanBuild = false;
}
}
} else {
m_Object = null;
}
if (m_ObjectType == ObjectType.MagicProjectile || m_ObjectType == ObjectType.Particle) {
m_MagicParticleCollisions = EditorGUILayout.Toggle(new GUIContent("Magic Particle Collisions", "Should the particles respond to magic collision events?"),
m_MagicParticleCollisions);
}
}
///
/// Does the object type require the GameObject field?
///
/// True if the object type requires the GameObject field.
private bool RequiresGameObject()
{
return m_ObjectType != ObjectType.Explosion
#if ULTIMATE_CHARACTER_CONTROLLER_MELEE
&& m_ObjectType != ObjectType.MeleeTrail
#endif
&& m_ObjectType != ObjectType.MagicProjectile && m_ObjectType != ObjectType.Particle;
}
///
/// Builds the object.
///
private void BuildObject()
{
var path = EditorUtility.SaveFilePanel("Save Object", "Assets", m_Name + ".prefab", "prefab");
if (path.Length == 0 || Application.dataPath.Length > path.Length) {
return;
}
var createdObject = m_Object;
if (createdObject == null) {
createdObject = new GameObject();
} else if (EditorUtility.IsPersistent(createdObject)) {
var name = createdObject.name;
createdObject = GameObject.Instantiate(createdObject) as GameObject;
}
createdObject.name = m_Name;
SphereCollider sphereCollider;
switch (m_ObjectType) {
case ObjectType.ItemPickup:
createdObject.layer = LayerManager.VisualEffect;
AddComponentIfNotAdded(createdObject);
sphereCollider = AddComponentIfNotAdded(createdObject);
sphereCollider.isTrigger = true;
AddComponentIfNotAdded(createdObject);
AddComponentIfNotAdded(createdObject);
break;
case ObjectType.DroppedItem:
createdObject.layer = LayerManager.VisualEffect;
AddComponentIfNotAdded(createdObject);
sphereCollider = AddComponentIfNotAdded(createdObject);
sphereCollider.isTrigger = true;
AddComponentIfNotAdded(createdObject);
var trajectoryObject = AddComponentIfNotAdded(createdObject);
trajectoryObject.ImpactLayers = ~(1 << LayerManager.IgnoreRaycast | 1 << LayerManager.Water | 1 << LayerManager.SubCharacter | 1 << LayerManager.Overlay |
1 << LayerManager.VisualEffect | 1 << LayerManager.SubCharacter | 1 << LayerManager.Character);
break;
case ObjectType.HealthPickup:
AddComponentIfNotAdded(createdObject);
AddComponentIfNotAdded(createdObject);
AddComponentIfNotAdded(createdObject);
break;
#if ULTIMATE_CHARACTER_CONTROLLER_SHOOTER
case ObjectType.Projectile:
AddComponentIfNotAdded(createdObject);
AddComponentIfNotAdded(createdObject);
AddComponentIfNotAdded(createdObject);
break;
case ObjectType.MuzzleFlash:
AddComponentIfNotAdded(createdObject);
break;
case ObjectType.Shell:
AddComponentIfNotAdded(createdObject);
AddComponentIfNotAdded(createdObject);
AddComponentIfNotAdded(createdObject);
var audioSource = AddComponentIfNotAdded(createdObject);
audioSource.spatialBlend = 1;
audioSource.maxDistance = 10;
break;
case ObjectType.Smoke:
AddComponentIfNotAdded(createdObject);
AddComponentIfNotAdded(createdObject);
break;
#endif
#if ULTIMATE_CHARACTER_CONTROLLER_MELEE
case ObjectType.MeleeTrail:
AddComponentIfNotAdded(createdObject);
AddComponentIfNotAdded(createdObject);
AddComponentIfNotAdded(createdObject);
break;
#endif
case ObjectType.Grenade:
AddComponentIfNotAdded(createdObject);
AddComponentIfNotAdded(createdObject);
var grenade = AddComponentIfNotAdded(createdObject);
grenade.DestroyOnCollision = false;
break;
case ObjectType.Explosion:
AddComponentIfNotAdded(createdObject);
AddComponentIfNotAdded(createdObject);
break;
case ObjectType.MagicProjectile:
AddComponentIfNotAdded(createdObject);
AddComponentIfNotAdded(createdObject);
var magicParticle = AddComponentIfNotAdded(createdObject);
magicParticle.Collision = TrajectoryObject.CollisionMode.Ignore;
if (m_MagicParticleCollisions) {
AddComponentIfNotAdded(createdObject);
}
break;
case ObjectType.Particle:
var particleSystem = AddComponentIfNotAdded(createdObject);
AddComponentIfNotAdded(createdObject);
if (m_MagicParticleCollisions) {
AddComponentIfNotAdded(createdObject);
}
break;
}
var relativePath = path.Replace(Application.dataPath, "");
#if UNITY_2018_3_OR_NEWER
PrefabUtility.SaveAsPrefabAsset(createdObject, "Assets" + relativePath);
#else
PrefabUtility.CreatePrefab("Assets" + relativePath, createdObject);
#endif
Selection.activeGameObject = AssetDatabase.LoadAssetAtPath("Assets" + relativePath, typeof(GameObject)) as GameObject;
Object.DestroyImmediate(createdObject, true);
}
///
/// Adds the component to the specified GameObject if it isn't already added.
///
/// The type of component to add.
/// The GameObject to add the component to.
/// The component of type T.
private T AddComponentIfNotAdded(GameObject obj) where T : Component
{
T component;
if ((component = obj.GetComponent()) == null) {
component = obj.AddComponent();
}
return component;
}
}
}