Introduce background spawning with parallax effect (#86)
Co-authored-by: Michal Pikulski <michal.a.pikulski@gmail.com> Reviewed-on: #86
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
using Minigames.Airplane.Core.Spawning;
|
||||
using Minigames.Airplane.Data;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Editor.Minigames.Airplane
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom editor for ParallaxBackgroundSpawner.
|
||||
/// Enforces exactly 3 pools with custom labels (Background/Middle/Foreground).
|
||||
/// Prevents array manipulation and provides clean, designer-friendly interface.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(ParallaxBackgroundSpawner))]
|
||||
public class ParallaxBackgroundSpawnerEditor : UnityEditor.Editor
|
||||
{
|
||||
private SerializedProperty _poolsProperty;
|
||||
private SerializedProperty _parallaxSortLayerProperty;
|
||||
private SerializedProperty _backgroundSortOrderProperty;
|
||||
private SerializedProperty _sortOrderIncrementProperty;
|
||||
private SerializedProperty _globalStrengthProperty;
|
||||
private SerializedProperty _backgroundSpeedProperty;
|
||||
private SerializedProperty _middleSpeedProperty;
|
||||
private SerializedProperty _foregroundSpeedProperty;
|
||||
private SerializedProperty _cameraManagerProperty;
|
||||
private SerializedProperty _showDebugLogsProperty;
|
||||
|
||||
private readonly string[] _layerNames = { "Background Layer", "Middle Layer", "Foreground Layer" };
|
||||
private readonly string[] _layerDescriptions =
|
||||
{
|
||||
"Slowest parallax - furthest back",
|
||||
"Medium parallax - middle depth",
|
||||
"Fastest parallax - closest to camera"
|
||||
};
|
||||
|
||||
private bool[] _poolFoldouts = new bool[3];
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_poolsProperty = serializedObject.FindProperty("pools");
|
||||
_parallaxSortLayerProperty = serializedObject.FindProperty("parallaxSortLayer");
|
||||
_backgroundSortOrderProperty = serializedObject.FindProperty("backgroundSortOrder");
|
||||
_sortOrderIncrementProperty = serializedObject.FindProperty("sortOrderIncrement");
|
||||
_globalStrengthProperty = serializedObject.FindProperty("globalStrength");
|
||||
_backgroundSpeedProperty = serializedObject.FindProperty("backgroundSpeed");
|
||||
_middleSpeedProperty = serializedObject.FindProperty("middleSpeed");
|
||||
_foregroundSpeedProperty = serializedObject.FindProperty("foregroundSpeed");
|
||||
_cameraManagerProperty = serializedObject.FindProperty("cameraManager");
|
||||
_showDebugLogsProperty = serializedObject.FindProperty("showDebugLogs");
|
||||
|
||||
// Ensure exactly 3 pools exist
|
||||
EnsureThreePools();
|
||||
}
|
||||
|
||||
private void EnsureThreePools()
|
||||
{
|
||||
if (_poolsProperty.arraySize != 3)
|
||||
{
|
||||
_poolsProperty.arraySize = 3;
|
||||
|
||||
// Initialize pool descriptions
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
var poolElement = _poolsProperty.GetArrayElementAtIndex(i);
|
||||
var descProperty = poolElement.FindPropertyRelative("description");
|
||||
if (string.IsNullOrEmpty(descProperty.stringValue))
|
||||
{
|
||||
descProperty.stringValue = _layerNames[i];
|
||||
}
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
EditorGUILayout.HelpBox("Note: Spawn distances, recency tracking, and debug settings are configured globally in AirplaneSettings. Containers are configured in AirplaneSpawnManager.", MessageType.Info);
|
||||
EditorGUILayout.Space();
|
||||
|
||||
// Camera Integration
|
||||
EditorGUILayout.PropertyField(_cameraManagerProperty);
|
||||
EditorGUILayout.Space();
|
||||
|
||||
// Parallax Configuration (CENTRALIZED SETTINGS)
|
||||
EditorGUILayout.LabelField("Parallax Configuration", EditorStyles.boldLabel);
|
||||
EditorGUILayout.HelpBox("These settings apply to ALL parallax elements spawned by this spawner. Adjust speeds to control depth perception.", MessageType.Info);
|
||||
|
||||
EditorGUILayout.PropertyField(_globalStrengthProperty, new GUIContent("Global Strength", "Overall parallax intensity (0 = no effect, 1 = full)"));
|
||||
EditorGUILayout.Space(5);
|
||||
|
||||
EditorGUILayout.LabelField("Per-Layer Speeds", EditorStyles.miniBoldLabel);
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(_backgroundSpeedProperty, new GUIContent("Background Speed", "Slowest layer, appears furthest (e.g., 0.3)"));
|
||||
EditorGUILayout.PropertyField(_middleSpeedProperty, new GUIContent("Middle Speed", "Medium speed layer (e.g., 0.6)"));
|
||||
EditorGUILayout.PropertyField(_foregroundSpeedProperty, new GUIContent("Foreground Speed", "Fastest layer, appears closest (e.g., 0.9)"));
|
||||
EditorGUI.indentLevel--;
|
||||
|
||||
// Validation warnings
|
||||
if (_backgroundSpeedProperty.floatValue >= _middleSpeedProperty.floatValue)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Warning: Background speed should be less than Middle speed for proper depth effect", MessageType.Warning);
|
||||
}
|
||||
if (_middleSpeedProperty.floatValue >= _foregroundSpeedProperty.floatValue)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Warning: Middle speed should be less than Foreground speed for proper depth effect", MessageType.Warning);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
// Sort Configuration
|
||||
EditorGUILayout.LabelField("Sort Configuration", EditorStyles.boldLabel);
|
||||
EditorGUILayout.HelpBox("All parallax objects use the same sort layer with different sort orders for depth.", MessageType.Info);
|
||||
EditorGUILayout.PropertyField(_parallaxSortLayerProperty, new GUIContent("Sort Layer", "Sort layer for all parallax elements (typically 'Background')"));
|
||||
EditorGUILayout.PropertyField(_backgroundSortOrderProperty, new GUIContent("Background Sort Order", "Sort order for furthest back layer (e.g., -50)"));
|
||||
EditorGUILayout.PropertyField(_sortOrderIncrementProperty, new GUIContent("Sort Order Increment", "Increment between layers (e.g., 10 → Middle: -40, Foreground: -30)"));
|
||||
|
||||
// Show calculated sort orders
|
||||
int middleOrder = _backgroundSortOrderProperty.intValue + _sortOrderIncrementProperty.intValue;
|
||||
int foregroundOrder = _backgroundSortOrderProperty.intValue + (_sortOrderIncrementProperty.intValue * 2);
|
||||
EditorGUILayout.LabelField($"Calculated: Background={_backgroundSortOrderProperty.intValue}, Middle={middleOrder}, Foreground={foregroundOrder}", EditorStyles.miniLabel);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
// Pool Mode (locked to Exclusive)
|
||||
EditorGUILayout.LabelField("Spawn Mode", EditorStyles.boldLabel);
|
||||
EditorGUI.BeginDisabledGroup(true);
|
||||
EditorGUILayout.TextField("Pool Mode", "Exclusive (Fixed)");
|
||||
EditorGUI.EndDisabledGroup();
|
||||
EditorGUILayout.HelpBox("Parallax spawner always uses Exclusive mode - each layer spawns independently", MessageType.Info);
|
||||
EditorGUILayout.Space();
|
||||
|
||||
// Parallax Layers (exactly 3, custom display)
|
||||
EditorGUILayout.LabelField("Parallax Layers (Fixed: 3 layers)", EditorStyles.boldLabel);
|
||||
|
||||
EnsureThreePools(); // Safety check
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
var poolElement = _poolsProperty.GetArrayElementAtIndex(i);
|
||||
var prefabsProperty = poolElement.FindPropertyRelative("prefabs");
|
||||
var descProperty = poolElement.FindPropertyRelative("description");
|
||||
var overrideMinDistProperty = poolElement.FindPropertyRelative("overrideMinDistance");
|
||||
var overrideMaxDistProperty = poolElement.FindPropertyRelative("overrideMaxDistance");
|
||||
|
||||
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
|
||||
|
||||
// Foldout with custom label
|
||||
_poolFoldouts[i] = EditorGUILayout.Foldout(_poolFoldouts[i], $"{_layerNames[i]} (Pool {i})", true, EditorStyles.foldoutHeader);
|
||||
|
||||
if (_poolFoldouts[i])
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
EditorGUILayout.LabelField(_layerDescriptions[i], EditorStyles.miniLabel);
|
||||
EditorGUILayout.Space(5);
|
||||
|
||||
EditorGUILayout.PropertyField(descProperty, new GUIContent("Description"));
|
||||
EditorGUILayout.PropertyField(prefabsProperty, new GUIContent("Prefabs"), true);
|
||||
|
||||
EditorGUILayout.Space(5);
|
||||
EditorGUILayout.LabelField("Spawn Distance Overrides", EditorStyles.miniBoldLabel);
|
||||
EditorGUILayout.HelpBox("Leave at 0 to use global settings. Set > 0 to override for this layer.", MessageType.Info);
|
||||
EditorGUILayout.PropertyField(overrideMinDistProperty, new GUIContent("Min Distance Override", "Minimum distance between objects (0 = use global)"));
|
||||
EditorGUILayout.PropertyField(overrideMaxDistProperty, new GUIContent("Max Distance Override", "Maximum distance between objects (0 = use global)"));
|
||||
|
||||
// Show info about prefab count
|
||||
if (prefabsProperty.arraySize == 0)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Add prefabs for this layer", MessageType.Warning);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField($"Prefabs: {prefabsProperty.arraySize}", EditorStyles.miniLabel);
|
||||
}
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
EditorGUILayout.Space(5);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user