This commit is contained in:
CortexCore
2023-10-04 16:50:27 +08:00
parent 947e52e748
commit 5cd094ed9a
263 changed files with 144068 additions and 66 deletions

View File

@@ -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();
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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;
}
}