1
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Lightbug.CharacterControllerPro.Core;
|
||||
using Lightbug.Utilities;
|
||||
|
||||
namespace Lightbug.CharacterControllerPro.Demo
|
||||
{
|
||||
|
||||
[AddComponentMenu("Character Controller Pro/Demo/Material Controller")]
|
||||
[DefaultExecutionOrder(-10)]
|
||||
public class MaterialController : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
MaterialsProperties materialsProperties = null;
|
||||
|
||||
CharacterActor characterActor = null;
|
||||
|
||||
/// <summary>
|
||||
/// This event is called when the character enters a volume.
|
||||
///
|
||||
/// The volume is passed as an argument.
|
||||
/// </summary>
|
||||
public event System.Action<Volume> OnVolumeEnter;
|
||||
|
||||
/// <summary>
|
||||
/// This event is called when the character exits a volume.
|
||||
///
|
||||
/// The volume is passed as an argument.
|
||||
/// </summary>
|
||||
public event System.Action<Volume> OnVolumeExit;
|
||||
|
||||
/// <summary>
|
||||
/// This event is called when the character step on a surface.
|
||||
///
|
||||
/// The surface is passed as an argument.
|
||||
/// </summary>
|
||||
public event System.Action<Surface> OnSurfaceEnter;
|
||||
|
||||
/// <summary>
|
||||
/// This event is called when the character step off a surface.
|
||||
///
|
||||
/// The surface is passed as an argument.
|
||||
/// </summary>
|
||||
public event System.Action<Surface> OnSurfaceExit;
|
||||
|
||||
// Environment ------------------------------------------------------
|
||||
Volume currentVolume = null;
|
||||
Surface currentSurface = null;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the surface the character is colliding with. If this returns null the surface will be considered as "default".
|
||||
/// </summary>
|
||||
public Surface CurrentSurface => currentSurface;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the volume the character is colliding with. If this returns null the volume will be considered as "default".
|
||||
/// </summary>
|
||||
public Volume CurrentVolume => currentVolume;
|
||||
|
||||
|
||||
void GetSurfaceData()
|
||||
{
|
||||
if (!characterActor.IsGrounded)
|
||||
{
|
||||
SetCurrentSurface(materialsProperties.DefaultSurface);
|
||||
}
|
||||
else
|
||||
{
|
||||
var ground = characterActor.GroundObject;
|
||||
if (ground != null)
|
||||
{
|
||||
bool validSurface = materialsProperties.GetSurface(ground, out Surface surface);
|
||||
|
||||
if (validSurface)
|
||||
{
|
||||
SetCurrentSurface(surface);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Untagged ground
|
||||
if (ground.CompareTag("Untagged"))
|
||||
{
|
||||
SetCurrentSurface(materialsProperties.DefaultSurface);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetCurrentSurface(Surface surface)
|
||||
{
|
||||
if (surface != currentSurface)
|
||||
{
|
||||
if (OnSurfaceExit != null)
|
||||
OnSurfaceExit(currentSurface);
|
||||
|
||||
if (OnSurfaceEnter != null)
|
||||
OnSurfaceEnter(surface);
|
||||
}
|
||||
|
||||
currentSurface = surface;
|
||||
}
|
||||
|
||||
|
||||
void GetVolumeData()
|
||||
{
|
||||
var triggerObject = characterActor.CurrentTrigger.gameObject;
|
||||
if (triggerObject == null)
|
||||
{
|
||||
if (currentVolume != materialsProperties.DefaultVolume)
|
||||
{
|
||||
if (OnVolumeExit != null)
|
||||
OnVolumeExit(currentVolume);
|
||||
|
||||
SetCurrentVolume(materialsProperties.DefaultVolume);
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool validVolume = materialsProperties.GetVolume(triggerObject, out Volume volume);
|
||||
|
||||
if (validVolume)
|
||||
{
|
||||
SetCurrentVolume(volume);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the current trigger is not a valid volume, then search for one that is.
|
||||
|
||||
int currentTriggerIndex = characterActor.Triggers.Count - 1;
|
||||
|
||||
for (int i = currentTriggerIndex; i >= 0; i--)
|
||||
{
|
||||
validVolume = materialsProperties.GetVolume(characterActor.Triggers[i].gameObject, out volume);
|
||||
|
||||
if (validVolume)
|
||||
{
|
||||
SetCurrentVolume(volume);
|
||||
}
|
||||
}
|
||||
|
||||
if (!validVolume)
|
||||
{
|
||||
SetCurrentVolume(materialsProperties.DefaultVolume);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void SetCurrentVolume(Volume volume)
|
||||
{
|
||||
if (volume != currentVolume)
|
||||
{
|
||||
if (OnVolumeExit != null)
|
||||
OnVolumeExit(currentVolume);
|
||||
|
||||
if (OnVolumeEnter != null)
|
||||
OnVolumeEnter(volume);
|
||||
}
|
||||
|
||||
currentVolume = volume;
|
||||
}
|
||||
|
||||
void Awake()
|
||||
{
|
||||
characterActor = this.GetComponentInBranch<CharacterActor>();
|
||||
|
||||
if (characterActor == null)
|
||||
{
|
||||
this.enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
SetCurrentSurface(materialsProperties.DefaultSurface);
|
||||
SetCurrentVolume(materialsProperties.DefaultVolume);
|
||||
}
|
||||
|
||||
void FixedUpdate()
|
||||
{
|
||||
GetSurfaceData();
|
||||
GetVolumeData();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,66 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Lightbug.CharacterControllerPro.Demo
|
||||
{
|
||||
/// <summary>
|
||||
/// This ScriptableObject contains all the properties used by the volumes and the surfaces. Create many instances as you want to create different environments.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(menuName = "Character Controller Pro/Demo/Materials/Material Properties")]
|
||||
public class MaterialsProperties : ScriptableObject
|
||||
{
|
||||
[SerializeField]
|
||||
Surface defaultSurface = new Surface();
|
||||
|
||||
[SerializeField]
|
||||
Volume defaultVolume = new Volume();
|
||||
|
||||
[SerializeField]
|
||||
Surface[] surfaces = null;
|
||||
|
||||
[SerializeField]
|
||||
Volume[] volumes = null;
|
||||
|
||||
public Surface DefaultSurface => defaultSurface;
|
||||
public Volume DefaultVolume => defaultVolume;
|
||||
public Surface[] Surfaces => surfaces;
|
||||
public Volume[] Volumes => volumes;
|
||||
|
||||
public bool GetSurface(GameObject gameObject, out Surface outputSurface)
|
||||
{
|
||||
outputSurface = null;
|
||||
|
||||
for (int i = 0; i < surfaces.Length; i++)
|
||||
{
|
||||
var surface = surfaces[i];
|
||||
|
||||
if (gameObject.CompareTag(surface.tagName))
|
||||
{
|
||||
outputSurface = surface;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool GetVolume(GameObject gameObject, out Volume outputVolume)
|
||||
{
|
||||
outputVolume = null;
|
||||
|
||||
for (int i = 0; i < volumes.Length; i++)
|
||||
{
|
||||
var volume = volumes[i];
|
||||
|
||||
if (gameObject.CompareTag(volume.tagName))
|
||||
{
|
||||
outputVolume = volume;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,219 @@
|
||||
using UnityEngine;
|
||||
using Lightbug.Utilities;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEditorInternal;
|
||||
|
||||
namespace Lightbug.CharacterControllerPro.Demo
|
||||
{
|
||||
|
||||
[CustomEditor(typeof(MaterialsProperties))]
|
||||
public class MaterialsPropertiesEditor : Editor
|
||||
{
|
||||
ReorderableList surfacesList = null;
|
||||
ReorderableList volumesList = null;
|
||||
|
||||
SerializedProperty defaultSurface = null;
|
||||
SerializedProperty surfaceAccelerationMultiplier = null;
|
||||
SerializedProperty surfaceDecelerationMultiplier = null;
|
||||
SerializedProperty surfaceSpeedMultiplier = null;
|
||||
|
||||
SerializedProperty defaultVolume = null;
|
||||
SerializedProperty volumeAccelerationMultiplier = null;
|
||||
SerializedProperty volumeDecelerationMultiplier = null;
|
||||
SerializedProperty volumeSpeedMultiplier = null;
|
||||
SerializedProperty volumeGravityPositiveMultiplier = null;
|
||||
SerializedProperty volumeGravityNegativeMultiplier = null;
|
||||
|
||||
|
||||
|
||||
SerializedProperty surfaces = null;
|
||||
SerializedProperty volumes = null;
|
||||
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
defaultSurface = serializedObject.FindProperty("defaultSurface");
|
||||
surfaceAccelerationMultiplier = defaultSurface.FindPropertyRelative("accelerationMultiplier");
|
||||
surfaceDecelerationMultiplier = defaultSurface.FindPropertyRelative("decelerationMultiplier");
|
||||
surfaceSpeedMultiplier = defaultSurface.FindPropertyRelative("speedMultiplier");
|
||||
|
||||
defaultVolume = serializedObject.FindProperty("defaultVolume");
|
||||
volumeAccelerationMultiplier = defaultVolume.FindPropertyRelative("accelerationMultiplier");
|
||||
volumeDecelerationMultiplier = defaultVolume.FindPropertyRelative("decelerationMultiplier");
|
||||
volumeSpeedMultiplier = defaultVolume.FindPropertyRelative("speedMultiplier");
|
||||
volumeGravityPositiveMultiplier = defaultVolume.FindPropertyRelative("gravityPositiveMultiplier");
|
||||
volumeGravityNegativeMultiplier = defaultVolume.FindPropertyRelative("gravityNegativeMultiplier");
|
||||
|
||||
|
||||
surfaces = serializedObject.FindProperty("surfaces");
|
||||
volumes = serializedObject.FindProperty("volumes");
|
||||
|
||||
surfacesList = new ReorderableList(
|
||||
serializedObject, surfaces,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
volumesList = new ReorderableList(
|
||||
serializedObject, volumes,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
volumes.isExpanded = true;
|
||||
volumesList.elementHeight = 10 * EditorGUIUtility.singleLineHeight;
|
||||
volumesList.headerHeight = 0f;
|
||||
|
||||
surfaces.isExpanded = true;
|
||||
surfacesList.elementHeight = 8 * EditorGUIUtility.singleLineHeight;
|
||||
surfacesList.headerHeight = 0f;
|
||||
|
||||
volumesList.drawElementCallback += OnDrawElementVolumes;
|
||||
surfacesList.drawElementCallback += OnDrawElementSurfaces;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
volumesList.drawElementCallback -= OnDrawElementVolumes;
|
||||
surfacesList.drawElementCallback -= OnDrawElementSurfaces;
|
||||
}
|
||||
|
||||
|
||||
void OnDrawElementVolumes(Rect rect, int index, bool isActive, bool isFocused)
|
||||
{
|
||||
Rect fieldRect = rect;
|
||||
fieldRect.height = EditorGUIUtility.singleLineHeight;
|
||||
|
||||
|
||||
|
||||
SerializedProperty item = volumes.GetArrayElementAtIndex(index);
|
||||
item.isExpanded = true;
|
||||
|
||||
SerializedProperty itr = item.Copy();
|
||||
|
||||
EditorGUI.LabelField(fieldRect, itr.FindPropertyRelative("tagName").stringValue);
|
||||
|
||||
|
||||
itr.Next(true);
|
||||
|
||||
fieldRect.y += 1.5f * fieldRect.height;
|
||||
|
||||
//bool enterChildren = true;
|
||||
|
||||
EditorGUI.PropertyField(fieldRect, itr, false);
|
||||
|
||||
int children = item.CountInProperty() - 1;
|
||||
for (int i = 0; i < children; i++)
|
||||
{
|
||||
EditorGUI.PropertyField(fieldRect, itr, false);
|
||||
itr.Next(false);
|
||||
fieldRect.y += fieldRect.height;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void OnDrawElementSurfaces(Rect rect, int index, bool isActive, bool isFocused)
|
||||
{
|
||||
Rect fieldRect = rect;
|
||||
fieldRect.height = EditorGUIUtility.singleLineHeight;
|
||||
|
||||
|
||||
|
||||
SerializedProperty item = surfaces.GetArrayElementAtIndex(index);
|
||||
item.isExpanded = true;
|
||||
|
||||
SerializedProperty itr = item.Copy();
|
||||
|
||||
EditorGUI.LabelField(fieldRect, itr.FindPropertyRelative("tagName").stringValue);
|
||||
|
||||
itr.Next(true);
|
||||
|
||||
fieldRect.y += 1.5f * fieldRect.height;
|
||||
|
||||
//bool enterChildren = true;
|
||||
|
||||
EditorGUI.PropertyField(fieldRect, itr, false);
|
||||
|
||||
int children = item.CountInProperty() - 1;
|
||||
for (int i = 0; i < children; i++)
|
||||
{
|
||||
EditorGUI.PropertyField(fieldRect, itr, false);
|
||||
itr.Next(false);
|
||||
fieldRect.y += fieldRect.height;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
CustomUtilities.DrawScriptableObjectField<MaterialsProperties>((MaterialsProperties)target);
|
||||
|
||||
CustomUtilities.DrawEditorLayoutHorizontalLine(Color.gray, 8);
|
||||
EditorGUILayout.LabelField("Default material", EditorStyles.boldLabel);
|
||||
|
||||
EditorGUILayout.HelpBox("A default material parameter corresponds to any ground or spatial volume without a specific \"material tag\". " +
|
||||
"A Surface affects grounded movement, while a Volume affects not grounded movement.", MessageType.Info);
|
||||
GUILayout.Space(10);
|
||||
|
||||
CustomUtilities.DrawEditorLayoutHorizontalLine(Color.gray);
|
||||
|
||||
EditorGUILayout.LabelField("Default surface", EditorStyles.boldLabel);
|
||||
CustomUtilities.DrawArrayElement(defaultSurface, null, true);
|
||||
|
||||
CustomUtilities.DrawEditorLayoutHorizontalLine(Color.gray);
|
||||
|
||||
EditorGUILayout.LabelField("Default volume", EditorStyles.boldLabel);
|
||||
CustomUtilities.DrawArrayElement(defaultVolume, null, true);
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
|
||||
GUILayout.Space(10);
|
||||
|
||||
|
||||
|
||||
CustomUtilities.DrawEditorLayoutHorizontalLine(Color.gray);
|
||||
|
||||
|
||||
EditorGUILayout.LabelField("Tagged materials", EditorStyles.boldLabel);
|
||||
GUILayout.Space(10);
|
||||
|
||||
|
||||
CustomUtilities.DrawEditorLayoutHorizontalLine(Color.gray, 8);
|
||||
EditorGUILayout.LabelField("Surfaces", EditorStyles.boldLabel);
|
||||
|
||||
CustomUtilities.DrawArray(surfaces, "tagName");
|
||||
|
||||
|
||||
CustomUtilities.DrawEditorLayoutHorizontalLine(Color.gray, 8);
|
||||
|
||||
EditorGUILayout.LabelField("Volumes", EditorStyles.boldLabel);
|
||||
|
||||
CustomUtilities.DrawArray(volumes, "tagName");
|
||||
|
||||
|
||||
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@@ -0,0 +1,27 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Lightbug.CharacterControllerPro.Demo
|
||||
{
|
||||
[System.Serializable]
|
||||
public class Surface
|
||||
{
|
||||
public string tagName = "";
|
||||
|
||||
[Header("Movement")]
|
||||
|
||||
[Min(0.01f)]
|
||||
public float accelerationMultiplier = 1f;
|
||||
|
||||
[Min(0.01f)]
|
||||
public float decelerationMultiplier = 1f;
|
||||
|
||||
[Min(0.01f)]
|
||||
public float speedMultiplier = 1f;
|
||||
|
||||
[Header("Particles")]
|
||||
|
||||
public Color color = Color.gray;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,31 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Lightbug.CharacterControllerPro.Demo
|
||||
{
|
||||
[System.Serializable]
|
||||
public class Volume
|
||||
{
|
||||
public string tagName = "";
|
||||
|
||||
[Header("Movement")]
|
||||
|
||||
[Min(0.01f)]
|
||||
public float accelerationMultiplier = 1f;
|
||||
|
||||
[Min(0.01f)]
|
||||
public float decelerationMultiplier = 1f;
|
||||
|
||||
[Min(0.01f)]
|
||||
public float speedMultiplier = 1f;
|
||||
|
||||
[Range(0.05f, 50f)]
|
||||
public float gravityAscendingMultiplier = 1f;
|
||||
|
||||
[Range(0.05f, 50f)]
|
||||
public float gravityDescendingMultiplier = 1f;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user