Pulver trash maze sequence
This commit is contained in:
72
Assets/Art/Levels/Dump/Animation/TrashGate/LeverIdle.anim
Normal file
72
Assets/Art/Levels/Dump/Animation/TrashGate/LeverIdle.anim
Normal file
@@ -0,0 +1,72 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!74 &7400000
|
||||
AnimationClip:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: LeverIdle
|
||||
serializedVersion: 7
|
||||
m_Legacy: 0
|
||||
m_Compressed: 0
|
||||
m_UseHighQualityCurve: 1
|
||||
m_RotationCurves: []
|
||||
m_CompressedRotationCurves: []
|
||||
m_EulerCurves: []
|
||||
m_PositionCurves: []
|
||||
m_ScaleCurves: []
|
||||
m_FloatCurves: []
|
||||
m_PPtrCurves:
|
||||
- serializedVersion: 2
|
||||
curve:
|
||||
- time: 0
|
||||
value: {fileID: 1983369653, guid: aa293e7c44a20ca40aa2cdd1c9989e53, type: 3}
|
||||
attribute: m_Sprite
|
||||
path:
|
||||
classID: 212
|
||||
script: {fileID: 0}
|
||||
flags: 2
|
||||
m_SampleRate: 30
|
||||
m_WrapMode: 0
|
||||
m_Bounds:
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
m_Extent: {x: 0, y: 0, z: 0}
|
||||
m_ClipBindingConstant:
|
||||
genericBindings:
|
||||
- serializedVersion: 2
|
||||
path: 0
|
||||
attribute: 0
|
||||
script: {fileID: 0}
|
||||
typeID: 212
|
||||
customType: 23
|
||||
isPPtrCurve: 1
|
||||
isIntCurve: 0
|
||||
isSerializeReferenceCurve: 0
|
||||
pptrCurveMapping:
|
||||
- {fileID: 1983369653, guid: aa293e7c44a20ca40aa2cdd1c9989e53, type: 3}
|
||||
m_AnimationClipSettings:
|
||||
serializedVersion: 2
|
||||
m_AdditiveReferencePoseClip: {fileID: 0}
|
||||
m_AdditiveReferencePoseTime: 0
|
||||
m_StartTime: 0
|
||||
m_StopTime: 0.033333335
|
||||
m_OrientationOffsetY: 0
|
||||
m_Level: 0
|
||||
m_CycleOffset: 0
|
||||
m_HasAdditiveReferencePose: 0
|
||||
m_LoopTime: 0
|
||||
m_LoopBlend: 0
|
||||
m_LoopBlendOrientation: 0
|
||||
m_LoopBlendPositionY: 0
|
||||
m_LoopBlendPositionXZ: 0
|
||||
m_KeepOriginalOrientation: 0
|
||||
m_KeepOriginalPositionY: 1
|
||||
m_KeepOriginalPositionXZ: 0
|
||||
m_HeightFromFeet: 0
|
||||
m_Mirror: 0
|
||||
m_EditorCurves: []
|
||||
m_EulerEditorCurves: []
|
||||
m_HasGenericRootTransform: 0
|
||||
m_HasMotionFloatCurves: 0
|
||||
m_Events: []
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9fa6031302d433f408438e70a14fffc8
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
93
Assets/Art/Levels/Dump/Animation/TrashGate/LeverOver.anim
Normal file
93
Assets/Art/Levels/Dump/Animation/TrashGate/LeverOver.anim
Normal file
@@ -0,0 +1,93 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!74 &7400000
|
||||
AnimationClip:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: LeverOver
|
||||
serializedVersion: 7
|
||||
m_Legacy: 0
|
||||
m_Compressed: 0
|
||||
m_UseHighQualityCurve: 1
|
||||
m_RotationCurves: []
|
||||
m_CompressedRotationCurves: []
|
||||
m_EulerCurves: []
|
||||
m_PositionCurves: []
|
||||
m_ScaleCurves: []
|
||||
m_FloatCurves: []
|
||||
m_PPtrCurves:
|
||||
- serializedVersion: 2
|
||||
curve:
|
||||
- time: 0
|
||||
value: {fileID: 1983369653, guid: aa293e7c44a20ca40aa2cdd1c9989e53, type: 3}
|
||||
- time: 0.033333335
|
||||
value: {fileID: 182198627, guid: aa293e7c44a20ca40aa2cdd1c9989e53, type: 3}
|
||||
- time: 0.06666667
|
||||
value: {fileID: 2099342698, guid: aa293e7c44a20ca40aa2cdd1c9989e53, type: 3}
|
||||
- time: 0.1
|
||||
value: {fileID: 1141896416, guid: aa293e7c44a20ca40aa2cdd1c9989e53, type: 3}
|
||||
- time: 0.13333334
|
||||
value: {fileID: 1211958902, guid: aa293e7c44a20ca40aa2cdd1c9989e53, type: 3}
|
||||
- time: 0.16666667
|
||||
value: {fileID: 1892208514, guid: aa293e7c44a20ca40aa2cdd1c9989e53, type: 3}
|
||||
- time: 0.2
|
||||
value: {fileID: 1469259267, guid: aa293e7c44a20ca40aa2cdd1c9989e53, type: 3}
|
||||
- time: 0.23333333
|
||||
value: {fileID: -1077132752, guid: aa293e7c44a20ca40aa2cdd1c9989e53, type: 3}
|
||||
attribute: m_Sprite
|
||||
path:
|
||||
classID: 212
|
||||
script: {fileID: 0}
|
||||
flags: 2
|
||||
m_SampleRate: 30
|
||||
m_WrapMode: 0
|
||||
m_Bounds:
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
m_Extent: {x: 0, y: 0, z: 0}
|
||||
m_ClipBindingConstant:
|
||||
genericBindings:
|
||||
- serializedVersion: 2
|
||||
path: 0
|
||||
attribute: 0
|
||||
script: {fileID: 0}
|
||||
typeID: 212
|
||||
customType: 23
|
||||
isPPtrCurve: 1
|
||||
isIntCurve: 0
|
||||
isSerializeReferenceCurve: 0
|
||||
pptrCurveMapping:
|
||||
- {fileID: 1983369653, guid: aa293e7c44a20ca40aa2cdd1c9989e53, type: 3}
|
||||
- {fileID: 182198627, guid: aa293e7c44a20ca40aa2cdd1c9989e53, type: 3}
|
||||
- {fileID: 2099342698, guid: aa293e7c44a20ca40aa2cdd1c9989e53, type: 3}
|
||||
- {fileID: 1141896416, guid: aa293e7c44a20ca40aa2cdd1c9989e53, type: 3}
|
||||
- {fileID: 1211958902, guid: aa293e7c44a20ca40aa2cdd1c9989e53, type: 3}
|
||||
- {fileID: 1892208514, guid: aa293e7c44a20ca40aa2cdd1c9989e53, type: 3}
|
||||
- {fileID: 1469259267, guid: aa293e7c44a20ca40aa2cdd1c9989e53, type: 3}
|
||||
- {fileID: -1077132752, guid: aa293e7c44a20ca40aa2cdd1c9989e53, type: 3}
|
||||
m_AnimationClipSettings:
|
||||
serializedVersion: 2
|
||||
m_AdditiveReferencePoseClip: {fileID: 0}
|
||||
m_AdditiveReferencePoseTime: 0
|
||||
m_StartTime: 0
|
||||
m_StopTime: 0.26666668
|
||||
m_OrientationOffsetY: 0
|
||||
m_Level: 0
|
||||
m_CycleOffset: 0
|
||||
m_HasAdditiveReferencePose: 0
|
||||
m_LoopTime: 0
|
||||
m_LoopBlend: 0
|
||||
m_LoopBlendOrientation: 0
|
||||
m_LoopBlendPositionY: 0
|
||||
m_LoopBlendPositionXZ: 0
|
||||
m_KeepOriginalOrientation: 0
|
||||
m_KeepOriginalPositionY: 1
|
||||
m_KeepOriginalPositionXZ: 0
|
||||
m_HeightFromFeet: 0
|
||||
m_Mirror: 0
|
||||
m_EditorCurves: []
|
||||
m_EulerEditorCurves: []
|
||||
m_HasGenericRootTransform: 0
|
||||
m_HasMotionFloatCurves: 0
|
||||
m_Events: []
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0e15051dcb3df814fab52e617496fc40
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,5 +1,27 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1101 &-9052709553426898635
|
||||
AnimatorStateTransition:
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name:
|
||||
m_Conditions: []
|
||||
m_DstStateMachine: {fileID: 0}
|
||||
m_DstState: {fileID: 6005905035337375392}
|
||||
m_Solo: 0
|
||||
m_Mute: 0
|
||||
m_IsExit: 0
|
||||
serializedVersion: 3
|
||||
m_TransitionDuration: 0.25
|
||||
m_TransitionOffset: 0
|
||||
m_ExitTime: 1
|
||||
m_HasExitTime: 1
|
||||
m_HasFixedDuration: 1
|
||||
m_InterruptionSource: 0
|
||||
m_OrderedInterruption: 1
|
||||
m_CanTransitionToSelf: 1
|
||||
--- !u!1107 &-4471614901610054980
|
||||
AnimatorStateMachine:
|
||||
serializedVersion: 6
|
||||
@@ -11,17 +33,23 @@ AnimatorStateMachine:
|
||||
m_ChildStates:
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: -4348510085696419942}
|
||||
m_Position: {x: 200, y: 0, z: 0}
|
||||
m_Position: {x: 260, y: 110, z: 0}
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: -314990716293606577}
|
||||
m_Position: {x: 110, y: 220, z: 0}
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: 6005905035337375392}
|
||||
m_Position: {x: 460, y: 230, z: 0}
|
||||
m_ChildStateMachines: []
|
||||
m_AnyStateTransitions: []
|
||||
m_EntryTransitions: []
|
||||
m_StateMachineTransitions: {}
|
||||
m_StateMachineBehaviours: []
|
||||
m_AnyStatePosition: {x: 50, y: 20, z: 0}
|
||||
m_EntryPosition: {x: 50, y: 120, z: 0}
|
||||
m_AnyStatePosition: {x: 100, y: -30, z: 0}
|
||||
m_EntryPosition: {x: -20, y: 110, z: 0}
|
||||
m_ExitPosition: {x: 800, y: 120, z: 0}
|
||||
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
|
||||
m_DefaultState: {fileID: -4348510085696419942}
|
||||
m_DefaultState: {fileID: -314990716293606577}
|
||||
--- !u!1102 &-4348510085696419942
|
||||
AnimatorState:
|
||||
serializedVersion: 6
|
||||
@@ -32,7 +60,8 @@ AnimatorState:
|
||||
m_Name: Lever
|
||||
m_Speed: 1
|
||||
m_CycleOffset: 0
|
||||
m_Transitions: []
|
||||
m_Transitions:
|
||||
- {fileID: -9052709553426898635}
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
@@ -48,6 +77,58 @@ AnimatorState:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
--- !u!1101 &-2774546409871568984
|
||||
AnimatorStateTransition:
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name:
|
||||
m_Conditions:
|
||||
- m_ConditionMode: 1
|
||||
m_ConditionEvent: PushLever
|
||||
m_EventTreshold: 0
|
||||
m_DstStateMachine: {fileID: 0}
|
||||
m_DstState: {fileID: -4348510085696419942}
|
||||
m_Solo: 0
|
||||
m_Mute: 0
|
||||
m_IsExit: 0
|
||||
serializedVersion: 3
|
||||
m_TransitionDuration: 0.25
|
||||
m_TransitionOffset: 0
|
||||
m_ExitTime: 0.75
|
||||
m_HasExitTime: 1
|
||||
m_HasFixedDuration: 1
|
||||
m_InterruptionSource: 0
|
||||
m_OrderedInterruption: 1
|
||||
m_CanTransitionToSelf: 1
|
||||
--- !u!1102 &-314990716293606577
|
||||
AnimatorState:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Idle
|
||||
m_Speed: 1
|
||||
m_CycleOffset: 0
|
||||
m_Transitions:
|
||||
- {fileID: -2774546409871568984}
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
m_WriteDefaultValues: 1
|
||||
m_Mirror: 0
|
||||
m_SpeedParameterActive: 0
|
||||
m_MirrorParameterActive: 0
|
||||
m_CycleOffsetParameterActive: 0
|
||||
m_TimeParameterActive: 0
|
||||
m_Motion: {fileID: 7400000, guid: 9fa6031302d433f408438e70a14fffc8, type: 2}
|
||||
m_Tag:
|
||||
m_SpeedParameter:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
--- !u!91 &9100000
|
||||
AnimatorController:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -56,7 +137,13 @@ AnimatorController:
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: gate_lever0001
|
||||
serializedVersion: 5
|
||||
m_AnimatorParameters: []
|
||||
m_AnimatorParameters:
|
||||
- m_Name: PushLever
|
||||
m_Type: 9
|
||||
m_DefaultFloat: 0
|
||||
m_DefaultInt: 0
|
||||
m_DefaultBool: 0
|
||||
m_Controller: {fileID: 9100000}
|
||||
m_AnimatorLayers:
|
||||
- serializedVersion: 5
|
||||
m_Name: Base Layer
|
||||
@@ -70,3 +157,29 @@ AnimatorController:
|
||||
m_IKPass: 0
|
||||
m_SyncedLayerAffectsTiming: 0
|
||||
m_Controller: {fileID: 9100000}
|
||||
--- !u!1102 &6005905035337375392
|
||||
AnimatorState:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: LeverOver
|
||||
m_Speed: 1
|
||||
m_CycleOffset: 0
|
||||
m_Transitions: []
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
m_WriteDefaultValues: 1
|
||||
m_Mirror: 0
|
||||
m_SpeedParameterActive: 0
|
||||
m_MirrorParameterActive: 0
|
||||
m_CycleOffsetParameterActive: 0
|
||||
m_TimeParameterActive: 0
|
||||
m_Motion: {fileID: 7400000, guid: 0e15051dcb3df814fab52e617496fc40, type: 2}
|
||||
m_Tag:
|
||||
m_SpeedParameter:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
|
||||
@@ -7,33 +7,39 @@ namespace Editor
|
||||
/// <summary>
|
||||
/// Custom editor for ControllerSwitchItem that shows only relevant fields based on camera switch mode.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(ControllerSwitchItem))]
|
||||
[CustomEditor(typeof(ControllerSwitchItem), true)]
|
||||
public class ControllerSwitchItemEditor : UnityEditor.Editor
|
||||
{
|
||||
private SerializedProperty _targetControllerName;
|
||||
private SerializedProperty _cameraSwitchMode;
|
||||
private SerializedProperty _targetVirtualCamera;
|
||||
private SerializedProperty _targetCameraState;
|
||||
private SerializedProperty _visualRepresentation;
|
||||
protected SerializedProperty _targetControllerName;
|
||||
protected SerializedProperty _visualRepresentation;
|
||||
|
||||
// Base class properties
|
||||
private SerializedProperty _isOneTime;
|
||||
private SerializedProperty _cooldown;
|
||||
private SerializedProperty _characterToInteract;
|
||||
protected SerializedProperty _isOneTime;
|
||||
protected SerializedProperty _cooldown;
|
||||
protected SerializedProperty _characterToInteract;
|
||||
|
||||
private void OnEnable()
|
||||
// Base interactable events
|
||||
protected SerializedProperty _interactionStarted;
|
||||
protected SerializedProperty _interactionInterrupted;
|
||||
protected SerializedProperty _characterArrived;
|
||||
protected SerializedProperty _interactionComplete;
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
// Controller Switch Settings
|
||||
_targetControllerName = serializedObject.FindProperty("targetControllerName");
|
||||
_cameraSwitchMode = serializedObject.FindProperty("cameraSwitchMode");
|
||||
_targetVirtualCamera = serializedObject.FindProperty("targetVirtualCamera");
|
||||
_targetCameraState = serializedObject.FindProperty("targetCameraState");
|
||||
_visualRepresentation = serializedObject.FindProperty("visualRepresentation");
|
||||
|
||||
// Base class properties
|
||||
_isOneTime = serializedObject.FindProperty("isOneTime");
|
||||
_cooldown = serializedObject.FindProperty("cooldown");
|
||||
_characterToInteract = serializedObject.FindProperty("characterToInteract");
|
||||
|
||||
// Base interactable events
|
||||
_interactionStarted = serializedObject.FindProperty("interactionStarted");
|
||||
_interactionInterrupted = serializedObject.FindProperty("interactionInterrupted");
|
||||
_characterArrived = serializedObject.FindProperty("characterArrived");
|
||||
_interactionComplete = serializedObject.FindProperty("interactionComplete");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
@@ -59,33 +65,9 @@ namespace Editor
|
||||
EditorGUILayout.LabelField("Controller Switch Settings", EditorStyles.boldLabel);
|
||||
EditorGUILayout.PropertyField(_targetControllerName);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
// Camera Settings
|
||||
EditorGUILayout.LabelField("Camera Settings", EditorStyles.boldLabel);
|
||||
EditorGUILayout.PropertyField(_cameraSwitchMode);
|
||||
|
||||
// Show relevant camera fields based on mode
|
||||
CameraSwitchMode mode = (CameraSwitchMode)_cameraSwitchMode.enumValueIndex;
|
||||
|
||||
switch (mode)
|
||||
if (string.IsNullOrEmpty(_targetControllerName.stringValue))
|
||||
{
|
||||
case CameraSwitchMode.None:
|
||||
EditorGUILayout.HelpBox("No camera switching will occur. Only the controller will be switched.", MessageType.Info);
|
||||
break;
|
||||
|
||||
case CameraSwitchMode.DirectReference:
|
||||
EditorGUILayout.PropertyField(_targetVirtualCamera);
|
||||
if (_targetVirtualCamera.objectReferenceValue == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Assign a Cinemachine camera to blend to when switching controllers.", MessageType.Warning);
|
||||
}
|
||||
break;
|
||||
|
||||
case CameraSwitchMode.TrashMazeCameraState:
|
||||
EditorGUILayout.PropertyField(_targetCameraState);
|
||||
EditorGUILayout.HelpBox("Uses TrashMazeCameraController to switch camera state. Make sure TrashMazeCameraController is present in the scene.", MessageType.Info);
|
||||
break;
|
||||
EditorGUILayout.HelpBox("Assign a target controller name (must match registration name in InputManager).", MessageType.Warning);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
@@ -94,8 +76,27 @@ namespace Editor
|
||||
EditorGUILayout.LabelField("Visual Feedback", EditorStyles.boldLabel);
|
||||
EditorGUILayout.PropertyField(_visualRepresentation);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
// Base Interactable Events
|
||||
EditorGUILayout.LabelField("Interaction Events", EditorStyles.boldLabel);
|
||||
EditorGUILayout.PropertyField(_interactionStarted);
|
||||
EditorGUILayout.PropertyField(_interactionInterrupted);
|
||||
EditorGUILayout.PropertyField(_characterArrived);
|
||||
EditorGUILayout.PropertyField(_interactionComplete);
|
||||
|
||||
DrawCustomFields();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override this in derived editors to add custom fields specific to derived classes
|
||||
/// </summary>
|
||||
protected virtual void DrawCustomFields()
|
||||
{
|
||||
// Base class has no additional custom fields
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
89
Assets/Editor/MazeExitEditor.cs
Normal file
89
Assets/Editor/MazeExitEditor.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Minigames.TrashMaze.Objects;
|
||||
|
||||
namespace Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom editor for MazeExit showing teleportation and camera settings
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(MazeExit))]
|
||||
public class MazeExitEditor : UnityEditor.Editor
|
||||
{
|
||||
private SerializedProperty _teleportTarget;
|
||||
private SerializedProperty _targetCameraState;
|
||||
|
||||
// Base class properties
|
||||
private SerializedProperty _isOneTime;
|
||||
private SerializedProperty _cooldown;
|
||||
private SerializedProperty _characterToInteract;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_teleportTarget = serializedObject.FindProperty("teleportTarget");
|
||||
_targetCameraState = serializedObject.FindProperty("targetCameraState");
|
||||
|
||||
// Base class properties
|
||||
_isOneTime = serializedObject.FindProperty("isOneTime");
|
||||
_cooldown = serializedObject.FindProperty("cooldown");
|
||||
_characterToInteract = serializedObject.FindProperty("characterToInteract");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
// Draw script field (read-only)
|
||||
EditorGUI.BeginDisabledGroup(true);
|
||||
EditorGUILayout.ObjectField("Script", MonoScript.FromMonoBehaviour((MonoBehaviour)target), GetType(), false);
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
// Interaction Settings (from base class)
|
||||
EditorGUILayout.LabelField("Interaction Settings", EditorStyles.boldLabel);
|
||||
EditorGUILayout.PropertyField(_isOneTime);
|
||||
EditorGUILayout.PropertyField(_cooldown);
|
||||
EditorGUILayout.PropertyField(_characterToInteract);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
// Maze Exit Settings
|
||||
EditorGUILayout.LabelField("Maze Exit Settings", EditorStyles.boldLabel);
|
||||
|
||||
EditorGUILayout.PropertyField(_teleportTarget);
|
||||
if (_teleportTarget.objectReferenceValue == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Assign a Transform where Pulver should be teleported to (maze exit position). Teleportation happens midway through camera blend.", MessageType.Warning);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.HelpBox("✓ Pulver will be teleported to this position halfway through the camera blend. Tracking target is set immediately.", MessageType.Info);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.PropertyField(_targetCameraState);
|
||||
EditorGUILayout.HelpBox("Camera state to blend to. Typically 'PulverGameplay' when exiting maze. Requires TrashMazeCameraController in scene.", MessageType.Info);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
// Info box about the behavior
|
||||
EditorGUILayout.HelpBox(
|
||||
"Maze Exit Behavior:\n" +
|
||||
"1. Find Pulver (player-controlled in maze)\n" +
|
||||
"2. Start camera blend to target state\n" +
|
||||
"3. ★ Teleport Pulver midway through blend ★\n" +
|
||||
"4. Set Pulver as tracking target immediately\n" +
|
||||
"5. Wait for blend to complete\n" +
|
||||
"6. Stop Pulver movement (clear cached input)\n" +
|
||||
"\n" +
|
||||
"Note: Does NOT switch controllers - Pulver remains player-controlled!",
|
||||
MessageType.None
|
||||
);
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
3
Assets/Editor/MazeExitEditor.cs.meta
Normal file
3
Assets/Editor/MazeExitEditor.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9bcc6ff619f74a88b899223936a66845
|
||||
timeCreated: 1766151279
|
||||
63
Assets/Editor/TrashMazeSwitchToPulverEditor.cs
Normal file
63
Assets/Editor/TrashMazeSwitchToPulverEditor.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using UnityEditor;
|
||||
using Minigames.TrashMaze.Objects;
|
||||
|
||||
namespace Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom editor for TrashMazeSwitchToPulver showing maze-specific settings
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(TrashMazeSwitchToPulver))]
|
||||
public class TrashMazeSwitchToPulverEditor : ControllerSwitchItemEditor
|
||||
{
|
||||
private SerializedProperty _teleportTarget;
|
||||
private SerializedProperty _targetCameraState;
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
|
||||
_teleportTarget = serializedObject.FindProperty("teleportTarget");
|
||||
_targetCameraState = serializedObject.FindProperty("targetCameraState");
|
||||
}
|
||||
|
||||
protected override void DrawCustomFields()
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
|
||||
// Trash Maze Specific Settings
|
||||
EditorGUILayout.LabelField("Trash Maze - To Pulver Settings", EditorStyles.boldLabel);
|
||||
|
||||
EditorGUILayout.PropertyField(_teleportTarget);
|
||||
if (_teleportTarget.objectReferenceValue == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Assign a Transform where Pulver should be teleported to (maze entrance position). Teleportation happens midway through camera blend.", MessageType.Warning);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.HelpBox("✓ Pulver will be teleported to this position halfway through the camera blend, creating a seamless 'entering maze' effect.", MessageType.Info);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.PropertyField(_targetCameraState);
|
||||
EditorGUILayout.HelpBox("Camera state to blend to. Typically 'Maze' when entering the maze. Requires TrashMazeCameraController in scene.", MessageType.Info);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
// Info box about the behavior
|
||||
EditorGUILayout.HelpBox(
|
||||
"Switch Behavior:\n" +
|
||||
"1. Deactivate current controller (Trafalgar)\n" +
|
||||
"2. Deactivate Pulver's follower mode\n" +
|
||||
"3. Start camera blend to Maze view\n" +
|
||||
"4. ★ Teleport Pulver midway through blend ★\n" +
|
||||
"5. Set Pulver as tracking target immediately\n" +
|
||||
"6. Wait for blend to complete\n" +
|
||||
"7. Activate PulverController for player control\n" +
|
||||
"8. Switch input to 'pulver'",
|
||||
MessageType.None
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
3
Assets/Editor/TrashMazeSwitchToPulverEditor.cs.meta
Normal file
3
Assets/Editor/TrashMazeSwitchToPulverEditor.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ded1ca7102b144a99d9e36a67d9054c0
|
||||
timeCreated: 1766149825
|
||||
50
Assets/Editor/TrashMazeSwitchToTrafalgarEditor.cs
Normal file
50
Assets/Editor/TrashMazeSwitchToTrafalgarEditor.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Minigames.TrashMaze.Objects;
|
||||
|
||||
namespace Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom editor for TrashMazeSwitchToTrafalgar showing maze-specific settings
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(TrashMazeSwitchToTrafalgar))]
|
||||
public class TrashMazeSwitchToTrafalgarEditor : ControllerSwitchItemEditor
|
||||
{
|
||||
private SerializedProperty _targetCameraState;
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
|
||||
_targetCameraState = serializedObject.FindProperty("targetCameraState");
|
||||
}
|
||||
|
||||
protected override void DrawCustomFields()
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
|
||||
// Trash Maze Specific Settings
|
||||
EditorGUILayout.LabelField("Trash Maze - To Trafalgar Settings", EditorStyles.boldLabel);
|
||||
|
||||
EditorGUILayout.PropertyField(_targetCameraState);
|
||||
EditorGUILayout.HelpBox("Camera state to blend to. Typically 'Gameplay' when exiting the maze. Requires TrashMazeCameraController in scene.", MessageType.Info);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
// Info box about the behavior
|
||||
EditorGUILayout.HelpBox(
|
||||
"Switch Behavior:\n" +
|
||||
"1. Deactivate PulverController (stops input)\n" +
|
||||
"2. Start camera blend to Gameplay view\n" +
|
||||
"3. Wait for blend to complete\n" +
|
||||
"4. Clear Pulver from maze camera tracking\n" +
|
||||
"5. Set Trafalgar as tracking target for gameplay camera\n" +
|
||||
"6. Activate Pulver's follower mode (follows Trafalgar)\n" +
|
||||
"7. Activate PlayerTouchController (Trafalgar)\n" +
|
||||
"8. Switch input to 'trafalgar'",
|
||||
MessageType.None
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
3
Assets/Editor/TrashMazeSwitchToTrafalgarEditor.cs.meta
Normal file
3
Assets/Editor/TrashMazeSwitchToTrafalgarEditor.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b58486fd20fd458ea14a508070a0f277
|
||||
timeCreated: 1766149834
|
||||
121
Assets/Editor/TriggerAnimationOnInteractionEditor.cs
Normal file
121
Assets/Editor/TriggerAnimationOnInteractionEditor.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Interactions;
|
||||
|
||||
namespace Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom editor for TriggerAnimationOnInteraction with helpful validation and feedback
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(TriggerAnimationOnInteraction))]
|
||||
public class TriggerAnimationOnInteractionEditor : UnityEditor.Editor
|
||||
{
|
||||
private SerializedProperty _interactable;
|
||||
private SerializedProperty _animator;
|
||||
private SerializedProperty _triggerName;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_interactable = serializedObject.FindProperty("interactable");
|
||||
_animator = serializedObject.FindProperty("animator");
|
||||
_triggerName = serializedObject.FindProperty("triggerName");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
// Draw script field (read-only)
|
||||
EditorGUI.BeginDisabledGroup(true);
|
||||
EditorGUILayout.ObjectField("Script", MonoScript.FromMonoBehaviour((MonoBehaviour)target), GetType(), false);
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
// Component References
|
||||
EditorGUILayout.LabelField("Component References (Optional)", EditorStyles.boldLabel);
|
||||
EditorGUILayout.PropertyField(_interactable);
|
||||
EditorGUILayout.PropertyField(_animator);
|
||||
|
||||
if (_interactable.objectReferenceValue == null || _animator.objectReferenceValue == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Leave fields empty to auto-discover components on this GameObject or children.", MessageType.Info);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
// Animation Settings
|
||||
EditorGUILayout.LabelField("Animation Settings", EditorStyles.boldLabel);
|
||||
EditorGUILayout.PropertyField(_triggerName);
|
||||
|
||||
if (string.IsNullOrEmpty(_triggerName.stringValue))
|
||||
{
|
||||
EditorGUILayout.HelpBox("Assign a trigger name that matches a trigger parameter in the Animator.", MessageType.Warning);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
// Component Discovery Info
|
||||
EditorGUILayout.LabelField("Component Discovery Status", EditorStyles.boldLabel);
|
||||
|
||||
var component = (TriggerAnimationOnInteraction)target;
|
||||
|
||||
// Check what will be used at runtime
|
||||
InteractableBase resolvedInteractable = _interactable.objectReferenceValue as InteractableBase;
|
||||
if (resolvedInteractable == null)
|
||||
{
|
||||
resolvedInteractable = component.GetComponent<InteractableBase>();
|
||||
}
|
||||
if (resolvedInteractable == null)
|
||||
{
|
||||
resolvedInteractable = component.GetComponentInChildren<InteractableBase>();
|
||||
}
|
||||
|
||||
Animator resolvedAnimator = _animator.objectReferenceValue as Animator;
|
||||
if (resolvedAnimator == null)
|
||||
{
|
||||
resolvedAnimator = component.GetComponent<Animator>();
|
||||
}
|
||||
if (resolvedAnimator == null)
|
||||
{
|
||||
resolvedAnimator = component.GetComponentInChildren<Animator>();
|
||||
}
|
||||
|
||||
// Show discovered components
|
||||
if (resolvedInteractable != null)
|
||||
{
|
||||
string source = _interactable.objectReferenceValue != null ? "Assigned" : "Auto-discovered";
|
||||
EditorGUILayout.HelpBox($"✓ Interactable: {resolvedInteractable.gameObject.name} ({source})", MessageType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.HelpBox("✗ No Interactable found! Assign one or ensure an Interactable exists on this GameObject or children.", MessageType.Error);
|
||||
}
|
||||
|
||||
if (resolvedAnimator != null)
|
||||
{
|
||||
string source = _animator.objectReferenceValue != null ? "Assigned" : "Auto-discovered";
|
||||
EditorGUILayout.HelpBox($"✓ Animator: {resolvedAnimator.gameObject.name} ({source})", MessageType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.HelpBox("✗ No Animator found! Assign one or ensure an Animator exists on this GameObject or children.", MessageType.Error);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
// Behavior explanation
|
||||
EditorGUILayout.HelpBox(
|
||||
"Behavior:\n" +
|
||||
"• Components can be manually assigned or auto-discovered\n" +
|
||||
"• Auto-discovery searches: this GameObject → children\n" +
|
||||
"• Listens to interactionComplete event from Interactable\n" +
|
||||
"• Triggers animation ONLY when interaction succeeds (success = true)\n" +
|
||||
"• Uses SetTrigger() with the specified trigger name",
|
||||
MessageType.None
|
||||
);
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cb5befe45d9c4f9ab10e20ee4c946cf4
|
||||
timeCreated: 1766153779
|
||||
@@ -19,6 +19,7 @@ GameObject:
|
||||
- component: {fileID: 4467608046243604209}
|
||||
- component: {fileID: 887004370483616855}
|
||||
- component: {fileID: 3342764969520326238}
|
||||
- component: {fileID: 3719568838531840149}
|
||||
m_Layer: 8
|
||||
m_Name: PulverCharacter
|
||||
m_TagString: Pulver
|
||||
@@ -379,6 +380,23 @@ MonoBehaviour:
|
||||
m_EditorClassIdentifier: AppleHillsScripts::UI.Tracking.TrackableTarget
|
||||
icon: {fileID: -4695408507704126972, guid: 31cfa2eea2b70af4b97a7a588fad0758, type: 3}
|
||||
trackDistance: 0
|
||||
--- !u!114 &3719568838531840149
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1102400833121127473}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: AppleHillsScripts::Minigames.TrashMaze.Core.PulverController
|
||||
moveSpeed: 5
|
||||
obstacleMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 64
|
||||
colliderRadius: 0.5
|
||||
--- !u!1 &5934518940303293264
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &1190045438452732069
|
||||
--- !u!1 &4288680281016853984
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
@@ -8,75 +8,40 @@ GameObject:
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1136290793271151494}
|
||||
- component: {fileID: 5320225058563658919}
|
||||
- component: {fileID: 7813271480623895155}
|
||||
- component: {fileID: 6196606079257550}
|
||||
- component: {fileID: 7174400527820218549}
|
||||
- component: {fileID: 2385482746242042445}
|
||||
- component: {fileID: 6654368395698888506}
|
||||
- component: {fileID: 6351228451172460299}
|
||||
m_Layer: 0
|
||||
m_Name: ControllerSwitchItem_To_pulver
|
||||
m_Name: TrashMazeSwitch_ToPulver
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &1136290793271151494
|
||||
--- !u!4 &7174400527820218549
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1190045438452732069}
|
||||
m_GameObject: {fileID: 4288680281016853984}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: -56, y: -38.8, z: 0}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 10, y: 10, z: 10}
|
||||
m_ConstrainProportionsScale: 1
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &5320225058563658919
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1190045438452732069}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 915abd653d714ea3ae11bbf14feafb1e, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: AppleHillsScripts::Items.ControllerSwitchItem
|
||||
isOneTime: 0
|
||||
cooldown: -1
|
||||
characterToInteract: 2
|
||||
interactionStarted:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
interactionInterrupted:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
characterArrived:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
interactionComplete:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
targetControllerName: pulver
|
||||
cameraSwitchMode: 2
|
||||
targetVirtualCamera: {fileID: 0}
|
||||
targetCameraState: 1
|
||||
visualRepresentation: {fileID: 0}
|
||||
OnCharacterSwitch:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
--- !u!212 &7813271480623895155
|
||||
--- !u!212 &2385482746242042445
|
||||
SpriteRenderer:
|
||||
serializedVersion: 2
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1190045438452732069}
|
||||
m_GameObject: {fileID: 4288680281016853984}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 0
|
||||
m_ReceiveShadows: 0
|
||||
@@ -128,13 +93,13 @@ SpriteRenderer:
|
||||
m_SpriteTileMode: 0
|
||||
m_WasSpriteAssigned: 1
|
||||
m_SpriteSortPoint: 0
|
||||
--- !u!61 &6196606079257550
|
||||
--- !u!61 &6654368395698888506
|
||||
BoxCollider2D:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1190045438452732069}
|
||||
m_GameObject: {fileID: 4288680281016853984}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 3
|
||||
m_Density: 1
|
||||
@@ -174,3 +139,37 @@ BoxCollider2D:
|
||||
m_AutoTiling: 0
|
||||
m_Size: {x: 0.44087836, y: 0.440879}
|
||||
m_EdgeRadius: 0
|
||||
--- !u!114 &6351228451172460299
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4288680281016853984}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe2d6200d0d54638adb61befd932228f, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: AppleHillsScripts::Minigames.TrashMaze.Objects.TrashMazeSwitchToPulver
|
||||
isOneTime: 0
|
||||
cooldown: -1
|
||||
characterToInteract: 2
|
||||
interactionStarted:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
interactionInterrupted:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
characterArrived:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
interactionComplete:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
targetControllerName: pulver
|
||||
visualRepresentation: {fileID: 0}
|
||||
OnCharacterSwitch:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
teleportTarget: {fileID: 0}
|
||||
targetCameraState: 1
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 67a60833f9f205940a2308bd74a2863e
|
||||
guid: 842cf175dd9fcfa438021df8b9868fed
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -406,6 +406,13 @@ namespace Input
|
||||
|
||||
while (!_interruptMoveTo)
|
||||
{
|
||||
// Use AIPath's built-in destination check if available
|
||||
if (_aiPath != null && _aiPath.reachedDestination)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Fallback to distance check
|
||||
Vector2 current2D = new Vector2(transform.position.x, transform.position.y);
|
||||
Vector2 target2D = new Vector2(target.x, target.y);
|
||||
float dist = Vector2.Distance(current2D, target2D);
|
||||
@@ -425,6 +432,74 @@ namespace Input
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Controller Lifecycle
|
||||
|
||||
/// <summary>
|
||||
/// Called when this controller is given input control.
|
||||
/// Default implementation cleans up any active movement state.
|
||||
/// Override to add controller-specific activation logic.
|
||||
/// </summary>
|
||||
public virtual void ActivateController()
|
||||
{
|
||||
// Stop any in-progress movement coroutines
|
||||
if (_moveToCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_moveToCoroutine);
|
||||
_moveToCoroutine = null;
|
||||
}
|
||||
|
||||
if (_pathfindingDragCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_pathfindingDragCoroutine);
|
||||
_pathfindingDragCoroutine = null;
|
||||
}
|
||||
|
||||
// Reset movement state
|
||||
_isHolding = false;
|
||||
_directMoveVelocity = Vector3.zero;
|
||||
_interruptMoveTo = false;
|
||||
|
||||
Logging.Debug($"[{GetType().Name}] Controller activated");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when this controller loses input control.
|
||||
/// Default implementation stops all movement and cleans up state.
|
||||
/// Override to add controller-specific deactivation logic.
|
||||
/// </summary>
|
||||
public virtual void DeactivateController()
|
||||
{
|
||||
// Stop all movement coroutines
|
||||
if (_moveToCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_moveToCoroutine);
|
||||
_moveToCoroutine = null;
|
||||
}
|
||||
|
||||
if (_pathfindingDragCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_pathfindingDragCoroutine);
|
||||
_pathfindingDragCoroutine = null;
|
||||
}
|
||||
|
||||
// Reset all movement state
|
||||
_isHolding = false;
|
||||
_directMoveVelocity = Vector3.zero;
|
||||
_interruptMoveTo = false;
|
||||
_isMoving = false;
|
||||
|
||||
// Stop AIPath movement
|
||||
if (_aiPath != null)
|
||||
{
|
||||
_aiPath.enabled = false;
|
||||
_aiPath.isStopped = true;
|
||||
}
|
||||
|
||||
Logging.Debug($"[{GetType().Name}] Controller deactivated");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using UnityEngine;
|
||||
using AppleHills.Core.Settings;
|
||||
using Core;
|
||||
using Core.Settings;
|
||||
|
||||
@@ -45,6 +44,10 @@ namespace Input
|
||||
InputManager.Instance.RegisterController("trafalgar", this, setAsDefaultConsumer: true);
|
||||
Logging.Debug($"[PlayerTouchController] Registered controller '{gameObject.name}' as default consumer");
|
||||
}
|
||||
|
||||
// Auto-activate as the default player controller
|
||||
ActivateController();
|
||||
Logging.Debug("[PlayerTouchController] Auto-activated as default player controller");
|
||||
}
|
||||
|
||||
#region IInteractingCharacter Override
|
||||
|
||||
@@ -3,9 +3,6 @@ using System.Collections;
|
||||
using Core;
|
||||
using Input;
|
||||
using Interactions;
|
||||
using Minigames.TrashMaze.Core;
|
||||
using Minigames.TrashMaze.Data;
|
||||
using Unity.Cinemachine;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
@@ -20,61 +17,27 @@ namespace Items
|
||||
public bool hasBeenUsed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Camera switching mode for controller switch items
|
||||
/// </summary>
|
||||
public enum CameraSwitchMode
|
||||
{
|
||||
/// <summary>
|
||||
/// No camera switching - controller switch only
|
||||
/// </summary>
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// Use a direct reference to a Cinemachine camera
|
||||
/// </summary>
|
||||
DirectReference,
|
||||
|
||||
/// <summary>
|
||||
/// Use TrashMazeCameraController state manager API
|
||||
/// </summary>
|
||||
TrashMazeCameraState
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An interactable item that switches control from one character controller to another.
|
||||
/// When clicked:
|
||||
/// 1. The selected character moves to this item's position
|
||||
/// 2. Upon arrival, the current controller is disabled
|
||||
/// 3. Camera blends to the target camera (based on camera mode)
|
||||
/// 4. Once the blend completes, control switches to the target controller
|
||||
/// Base interactable item that switches control from one character controller to another.
|
||||
/// Level-agnostic - handles only controller switching logic.
|
||||
/// Derive from this class for level-specific behavior (camera switching, teleportation, etc.)
|
||||
/// </summary>
|
||||
public class ControllerSwitchItem : SaveableInteractable
|
||||
{
|
||||
[Header("Controller Switch Settings")]
|
||||
[Tooltip("Name of the controller to switch to (must match GameObject name of the controller)")]
|
||||
[SerializeField] private string targetControllerName;
|
||||
|
||||
[Header("Camera Settings")]
|
||||
[Tooltip("How to switch the camera when changing controllers")]
|
||||
[SerializeField] private CameraSwitchMode cameraSwitchMode = CameraSwitchMode.None;
|
||||
|
||||
[Tooltip("Direct camera reference (only used if Camera Switch Mode is DirectReference)")]
|
||||
[SerializeField] private CinemachineCamera targetVirtualCamera;
|
||||
|
||||
[Tooltip("Target camera state (only used if Camera Switch Mode is TrashMazeCameraState)")]
|
||||
[SerializeField] private TrashMazeCameraState targetCameraState;
|
||||
[Tooltip("Name of the controller to switch to (must match registration name in InputManager)")]
|
||||
[SerializeField] protected string targetControllerName;
|
||||
|
||||
[Header("Visual Feedback")]
|
||||
[Tooltip("Visual representation to hide after use (optional)")]
|
||||
[SerializeField] private GameObject visualRepresentation;
|
||||
[SerializeField] protected GameObject visualRepresentation;
|
||||
|
||||
public UnityEvent OnCharacterSwitch;
|
||||
|
||||
// State
|
||||
private bool _hasBeenUsed;
|
||||
private PlayerTouchController _currentPlayerController;
|
||||
private bool _isSwitching;
|
||||
protected bool _hasBeenUsed;
|
||||
protected bool _isSwitching;
|
||||
|
||||
public override string SaveId => $"{gameObject.scene.name}/ControllerSwitchItem/{gameObject.name}";
|
||||
|
||||
@@ -123,68 +86,50 @@ namespace Items
|
||||
if (_isSwitching)
|
||||
return false;
|
||||
|
||||
// By the time this is called, the interacting character has already arrived at this item
|
||||
// We just need to perform the controller/camera switch
|
||||
|
||||
Logging.Debug("[ControllerSwitchItem] Starting controller switch sequence");
|
||||
|
||||
// Start the async switch sequence (camera blend + controller switch)
|
||||
StartCoroutine(SwitchControllerSequence());
|
||||
|
||||
// Return true immediately - interaction is considered successful
|
||||
// The coroutine will handle the actual switching asynchronously
|
||||
return true;
|
||||
}
|
||||
|
||||
private IEnumerator SwitchControllerSequence()
|
||||
protected virtual IEnumerator SwitchControllerSequence()
|
||||
{
|
||||
_isSwitching = true;
|
||||
|
||||
// Step 1: Get current player controller (the one we're switching FROM)
|
||||
_currentPlayerController = FindFirstObjectByType<PlayerTouchController>();
|
||||
if (_currentPlayerController == null)
|
||||
// Step 1: Get controllers
|
||||
var currentController = InputManager.Instance.GetActiveController();
|
||||
var targetController = InputManager.Instance.GetController(targetControllerName);
|
||||
|
||||
if (currentController == null || targetController == null)
|
||||
{
|
||||
Debug.LogError("[ControllerSwitchItem] Could not find PlayerTouchController in scene!");
|
||||
Debug.LogError($"[ControllerSwitchItem] Failed to get controllers! Current: {currentController}, Target: {targetController} (name: {targetControllerName})");
|
||||
_isSwitching = false;
|
||||
yield break;
|
||||
}
|
||||
|
||||
Logging.Debug("[ControllerSwitchItem] Character has arrived, beginning switch");
|
||||
GameObject currentGameObject = (currentController as MonoBehaviour)?.gameObject;
|
||||
GameObject targetGameObject = (targetController as MonoBehaviour)?.gameObject;
|
||||
|
||||
// Step 2: Disable current player controller
|
||||
_currentPlayerController.enabled = false;
|
||||
Logging.Debug("[ControllerSwitchItem] Disabled current player controller");
|
||||
Logging.Debug($"[ControllerSwitchItem] Switching from {currentGameObject?.name} to {targetGameObject?.name}");
|
||||
|
||||
// Step 3: Blend to target camera based on mode
|
||||
yield return SwitchCamera();
|
||||
// Step 2: Deactivate current controller
|
||||
DeactivateCurrentController(currentController, currentGameObject);
|
||||
|
||||
// Step 4: Switch to target controller
|
||||
ITouchInputConsumer targetController = InputManager.Instance.GetController(targetControllerName);
|
||||
if (targetController != null)
|
||||
// Step 3: Activate target controller
|
||||
ActivateTargetController(targetController, targetGameObject);
|
||||
|
||||
// Step 4: Switch InputManager to target controller
|
||||
bool switchSuccess = InputManager.Instance.SwitchToController(targetControllerName);
|
||||
|
||||
if (switchSuccess)
|
||||
{
|
||||
// Enable the target controller if it's a MonoBehaviour
|
||||
if (targetController is MonoBehaviour targetMono)
|
||||
{
|
||||
targetMono.enabled = true;
|
||||
Logging.Debug($"[ControllerSwitchItem] Enabled target controller: {targetControllerName}");
|
||||
}
|
||||
|
||||
// Switch input control to the target controller
|
||||
bool switchSuccess = InputManager.Instance.SwitchToController(targetControllerName);
|
||||
|
||||
if (switchSuccess)
|
||||
{
|
||||
Logging.Debug($"[ControllerSwitchItem] Successfully switched input to controller: {targetControllerName}");
|
||||
OnCharacterSwitch.Invoke();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"[ControllerSwitchItem] Failed to switch to controller: {targetControllerName}");
|
||||
}
|
||||
Logging.Debug($"[ControllerSwitchItem] Successfully switched input to controller: {targetControllerName}");
|
||||
OnCharacterSwitch.Invoke();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"[ControllerSwitchItem] Target controller '{targetControllerName}' not found!");
|
||||
Debug.LogError($"[ControllerSwitchItem] Failed to switch to controller: {targetControllerName}");
|
||||
}
|
||||
|
||||
// Step 5: Mark as used if one-time use
|
||||
@@ -197,79 +142,65 @@ namespace Items
|
||||
_isSwitching = false;
|
||||
}
|
||||
|
||||
private IEnumerator SwitchCamera()
|
||||
protected virtual void DeactivateCurrentController(ITouchInputConsumer currentController, GameObject currentGameObject)
|
||||
{
|
||||
switch (cameraSwitchMode)
|
||||
// If current is a player controller, deactivate it
|
||||
if (currentController is BasePlayerMovementController currentPlayerController)
|
||||
{
|
||||
case CameraSwitchMode.None:
|
||||
// No camera switching
|
||||
Logging.Debug("[ControllerSwitchItem] No camera switching configured");
|
||||
break;
|
||||
currentPlayerController.DeactivateController();
|
||||
}
|
||||
|
||||
case CameraSwitchMode.DirectReference:
|
||||
if (targetVirtualCamera != null)
|
||||
{
|
||||
Logging.Debug($"[ControllerSwitchItem] Blending to camera: {targetVirtualCamera.name}");
|
||||
|
||||
// Set the target camera as highest priority
|
||||
targetVirtualCamera.Priority = 100;
|
||||
|
||||
// Wait for camera blend to complete
|
||||
yield return WaitForCameraBlend();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("[ControllerSwitchItem] DirectReference mode selected but no camera assigned!");
|
||||
}
|
||||
break;
|
||||
|
||||
case CameraSwitchMode.TrashMazeCameraState:
|
||||
if (TrashMazeCameraController.Instance != null)
|
||||
{
|
||||
Logging.Debug($"[ControllerSwitchItem] Switching to camera state: {targetCameraState}");
|
||||
|
||||
// Use the state manager API
|
||||
if (targetCameraState == TrashMazeCameraState.Gameplay)
|
||||
{
|
||||
TrashMazeCameraController.Instance.SwitchToGameplay();
|
||||
}
|
||||
else if (targetCameraState == TrashMazeCameraState.Maze)
|
||||
{
|
||||
TrashMazeCameraController.Instance.SwitchToMaze();
|
||||
}
|
||||
|
||||
// Wait for camera blend to complete
|
||||
yield return WaitForCameraBlend();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("[ControllerSwitchItem] TrashMazeCameraController instance not found in scene!");
|
||||
}
|
||||
break;
|
||||
// If switching FROM follower mode, deactivate follower
|
||||
if (currentGameObject != null)
|
||||
{
|
||||
var currentFollower = currentGameObject.GetComponent<FollowerController>();
|
||||
if (currentFollower != null && currentFollower.IsFollowerActive)
|
||||
{
|
||||
currentFollower.DeactivateFollower();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator WaitForCameraBlend()
|
||||
protected virtual void ActivateTargetController(ITouchInputConsumer targetController, GameObject targetGameObject)
|
||||
{
|
||||
CinemachineBrain brain = Camera.main?.GetComponent<CinemachineBrain>();
|
||||
if (brain != null)
|
||||
// Check if target GameObject has FollowerController component
|
||||
FollowerController targetFollower = null;
|
||||
if (targetGameObject != null)
|
||||
{
|
||||
// Wait until blend is not active
|
||||
while (brain.IsBlending)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
targetFollower = targetGameObject.GetComponent<FollowerController>();
|
||||
}
|
||||
|
||||
Logging.Debug("[ControllerSwitchItem] Camera blend completed");
|
||||
// If switching TO a GameObject with FollowerController, we need special handling
|
||||
if (targetFollower != null)
|
||||
{
|
||||
// Switching TO Pulver player control (Pulver has both FollowerController and PulverController)
|
||||
// Deactivate follower mode, activate player control
|
||||
targetFollower.DeactivateFollower();
|
||||
|
||||
if (targetController is BasePlayerMovementController targetPlayerController)
|
||||
{
|
||||
targetPlayerController.ActivateController();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If no brain, just wait a brief moment
|
||||
yield return new WaitForSeconds(0.5f);
|
||||
// Switching TO Trafalgar (no FollowerController on Trafalgar)
|
||||
// If there's a Pulver in the scene, activate its follower mode
|
||||
var pulverFollower = FindFirstObjectByType<FollowerController>();
|
||||
if (pulverFollower != null)
|
||||
{
|
||||
pulverFollower.ActivateFollower();
|
||||
}
|
||||
|
||||
// Activate the target player controller
|
||||
if (targetController is BasePlayerMovementController targetPlayerController)
|
||||
{
|
||||
targetPlayerController.ActivateController();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DisableVisual()
|
||||
protected void DisableVisual()
|
||||
{
|
||||
if (visualRepresentation != null)
|
||||
{
|
||||
|
||||
136
Assets/Scripts/Interactions/TriggerAnimationOnInteraction.cs
Normal file
136
Assets/Scripts/Interactions/TriggerAnimationOnInteraction.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
using Core;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Interactions
|
||||
{
|
||||
/// <summary>
|
||||
/// Triggers an animation when an interactable interaction completes successfully.
|
||||
/// Auto-discovers Interactable and Animator components on the same GameObject or children.
|
||||
/// </summary>
|
||||
public class TriggerAnimationOnInteraction : MonoBehaviour
|
||||
{
|
||||
[Header("Component References (Optional)")]
|
||||
[Tooltip("Interactable to listen to. Leave empty to auto-discover on this GameObject or children.")]
|
||||
[SerializeField] private InteractableBase interactable;
|
||||
|
||||
[Tooltip("Animator to trigger. Leave empty to auto-discover on this GameObject or children.")]
|
||||
[SerializeField] private Animator animator;
|
||||
|
||||
[Header("Animation Settings")]
|
||||
[Tooltip("Name of the animation trigger to fire when interaction completes")]
|
||||
[SerializeField] private string triggerName;
|
||||
|
||||
private InteractableBase _interactable;
|
||||
private Animator _animator;
|
||||
private bool _isInitialized;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
DiscoverComponents();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (_isInitialized && _interactable != null)
|
||||
{
|
||||
_interactable.interactionComplete.AddListener(OnInteractionComplete);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (_interactable != null)
|
||||
{
|
||||
_interactable.interactionComplete.RemoveListener(OnInteractionComplete);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Auto-discover Interactable and Animator components if not manually assigned
|
||||
/// </summary>
|
||||
private void DiscoverComponents()
|
||||
{
|
||||
// Use assigned Interactable or try to find it
|
||||
_interactable = interactable;
|
||||
if (_interactable == null)
|
||||
{
|
||||
_interactable = GetComponent<InteractableBase>();
|
||||
}
|
||||
if (_interactable == null)
|
||||
{
|
||||
_interactable = GetComponentInChildren<InteractableBase>();
|
||||
}
|
||||
|
||||
if (_interactable == null)
|
||||
{
|
||||
Debug.LogError($"[TriggerAnimationOnInteraction] No InteractableBase found on {gameObject.name} or its children!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Use assigned Animator or try to find it
|
||||
_animator = animator;
|
||||
if (_animator == null)
|
||||
{
|
||||
_animator = GetComponent<Animator>();
|
||||
}
|
||||
if (_animator == null)
|
||||
{
|
||||
_animator = GetComponentInChildren<Animator>();
|
||||
}
|
||||
|
||||
if (_animator == null)
|
||||
{
|
||||
Debug.LogError($"[TriggerAnimationOnInteraction] No Animator found on {gameObject.name} or its children!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(triggerName))
|
||||
{
|
||||
Debug.LogWarning($"[TriggerAnimationOnInteraction] Trigger name is empty on {gameObject.name}!");
|
||||
}
|
||||
|
||||
_isInitialized = true;
|
||||
|
||||
string interactableSource = interactable != null ? "assigned" : "auto-discovered";
|
||||
string animatorSource = animator != null ? "assigned" : "auto-discovered";
|
||||
Logging.Debug($"[TriggerAnimationOnInteraction] Initialized on {gameObject.name} - Interactable: {_interactable.gameObject.name} ({interactableSource}), Animator: {_animator.gameObject.name} ({animatorSource})");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when interaction completes
|
||||
/// </summary>
|
||||
/// <param name="success">Whether the interaction was successful</param>
|
||||
private void OnInteractionComplete(bool success)
|
||||
{
|
||||
if (!success)
|
||||
{
|
||||
Logging.Debug($"[TriggerAnimationOnInteraction] Interaction failed, not triggering animation");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_animator == null || string.IsNullOrEmpty(triggerName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_animator.SetTrigger(triggerName);
|
||||
Logging.Debug($"[TriggerAnimationOnInteraction] Triggered animation: {triggerName}");
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void OnValidate()
|
||||
{
|
||||
// Validate in editor
|
||||
if (string.IsNullOrEmpty(triggerName))
|
||||
{
|
||||
name = "TriggerAnimationOnInteraction (NO TRIGGER)";
|
||||
}
|
||||
else
|
||||
{
|
||||
name = $"TriggerAnimationOnInteraction ({triggerName})";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f7da1b8703214c4e813e672ba8fc3b8e
|
||||
timeCreated: 1766153752
|
||||
@@ -23,6 +23,9 @@ namespace Minigames.TrashMaze.Core
|
||||
// Vision radius loaded from settings
|
||||
private float _visionRadius;
|
||||
|
||||
// Controller active state
|
||||
private bool _isControllerActive = false;
|
||||
|
||||
// Public accessors for other systems
|
||||
public static Vector2 PlayerPosition => Instance != null ? Instance.transform.position : Vector2.zero;
|
||||
public static float VisionRadius => Instance != null ? Instance._visionRadius : 8f;
|
||||
@@ -64,10 +67,18 @@ namespace Minigames.TrashMaze.Core
|
||||
InputManager.Instance.RegisterController("pulver", this, setAsDefaultConsumer: false);
|
||||
Logging.Debug($"[PulverController] Registered controller '{gameObject.name}'");
|
||||
}
|
||||
|
||||
// Start deactivated - PulverController only activates when explicitly switched to
|
||||
// This allows FollowerController to be the default mode for Pulver
|
||||
DeactivateController();
|
||||
Logging.Debug("[PulverController] Auto-deactivated - waiting for controller switch");
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
// Only process if this controller is active
|
||||
if (!_isControllerActive) return;
|
||||
|
||||
base.Update(); // Call base for movement and animation
|
||||
|
||||
// Update global shader properties for vision system
|
||||
@@ -127,6 +138,37 @@ namespace Minigames.TrashMaze.Core
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Controller Lifecycle Overrides
|
||||
|
||||
public override void ActivateController()
|
||||
{
|
||||
base.ActivateController();
|
||||
|
||||
_isControllerActive = true;
|
||||
|
||||
// Enable AIPath for player control
|
||||
if (_aiPath != null)
|
||||
{
|
||||
_aiPath.enabled = true;
|
||||
_aiPath.maxSpeed = Settings.MoveSpeed;
|
||||
}
|
||||
|
||||
Logging.Debug("[PulverController] Controller activated - shader updates enabled");
|
||||
}
|
||||
|
||||
public override void DeactivateController()
|
||||
{
|
||||
// DO NOT call base.DeactivateController() - it disables the shared AIPath
|
||||
// that FollowerController needs for pickup dispatch!
|
||||
// Just manage our own internal state instead
|
||||
|
||||
_isControllerActive = false;
|
||||
|
||||
Logging.Debug("[PulverController] Controller deactivated - shader updates paused (AIPath untouched for FollowerController)");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -84,6 +84,17 @@ namespace Minigames.TrashMaze.Core
|
||||
Logging.Debug("[TrashMazeCameraController] Switched to Maze camera");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Switch to Pulver gameplay camera (Pulver in main level, player-controlled)
|
||||
/// </summary>
|
||||
public void SwitchToPulverGameplay()
|
||||
{
|
||||
SwitchToState(TrashMazeCameraState.PulverGameplay);
|
||||
|
||||
if (showDebugLogs)
|
||||
Logging.Debug("[TrashMazeCameraController] Switched to PulverGameplay camera");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the gameplay camera
|
||||
/// </summary>
|
||||
@@ -100,6 +111,14 @@ namespace Minigames.TrashMaze.Core
|
||||
return GetCamera(TrashMazeCameraState.Maze);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the Pulver gameplay camera
|
||||
/// </summary>
|
||||
public CinemachineCamera GetPulverGameplayCamera()
|
||||
{
|
||||
return GetCamera(TrashMazeCameraState.PulverGameplay);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,6 @@ namespace Minigames.TrashMaze.Core
|
||||
{
|
||||
public static TrashMazeController Instance { get; private set; }
|
||||
|
||||
[Header("Player")]
|
||||
[SerializeField] private PulverController pulverController;
|
||||
|
||||
[Header("Background")]
|
||||
[Tooltip("Background sprite renderer - world size and center are inferred from its bounds")]
|
||||
[SerializeField] private SpriteRenderer backgroundRenderer;
|
||||
@@ -118,15 +115,6 @@ namespace Minigames.TrashMaze.Core
|
||||
|
||||
private void InitializePulver()
|
||||
{
|
||||
if (pulverController == null)
|
||||
{
|
||||
Logging.Error("[TrashMazeController] PulverController reference not assigned! Please assign it in the Inspector.");
|
||||
return;
|
||||
}
|
||||
|
||||
Logging.Debug($"[TrashMazeController] Pulver controller initialized at {pulverController.transform.position}");
|
||||
|
||||
// TODO: Implement proper events for maze start and finish
|
||||
pulverControllerSwitch.OnCharacterSwitch.AddListener(SwitchedToPulver);
|
||||
trafalgarControllerSwitch.OnCharacterSwitch.AddListener(SwitchedToTrafalgar);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,12 @@
|
||||
/// <summary>
|
||||
/// Maze camera following Pulver when exploring the maze alone
|
||||
/// </summary>
|
||||
Maze
|
||||
Maze,
|
||||
|
||||
/// <summary>
|
||||
/// Gameplay camera following Pulver (after exiting maze while still player-controlled)
|
||||
/// </summary>
|
||||
PulverGameplay
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
92
Assets/Scripts/Minigames/TrashMaze/Objects/MazeExit.cs
Normal file
92
Assets/Scripts/Minigames/TrashMaze/Objects/MazeExit.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using System.Collections;
|
||||
using Core;
|
||||
using Interactions;
|
||||
using Minigames.TrashMaze.Core;
|
||||
using Minigames.TrashMaze.Data;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Minigames.TrashMaze.Objects
|
||||
{
|
||||
/// <summary>
|
||||
/// Maze exit interactable that teleports Pulver out of the maze.
|
||||
/// Uses camera blend with midway teleportation to create seamless transition.
|
||||
/// Does NOT switch controllers - Pulver remains player-controlled.
|
||||
/// </summary>
|
||||
public class MazeExit : SaveableInteractable
|
||||
{
|
||||
[Header("Maze Exit Settings")]
|
||||
[Tooltip("Transform where Pulver should be teleported to (maze exit position)")]
|
||||
[SerializeField] private Transform teleportTarget;
|
||||
|
||||
[Tooltip("Camera state to blend to (typically PulverGameplay)")]
|
||||
[SerializeField] private TrashMazeCameraState targetCameraState = TrashMazeCameraState.PulverGameplay;
|
||||
|
||||
public override string SaveId => $"{gameObject.scene.name}/MazeExit/{gameObject.name}";
|
||||
|
||||
protected override object GetSerializableState()
|
||||
{
|
||||
// MazeExit doesn't need to save state - it's a simple trigger
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override void ApplySerializableState(string state)
|
||||
{
|
||||
// MazeExit doesn't need to restore state
|
||||
}
|
||||
|
||||
protected override bool DoInteraction()
|
||||
{
|
||||
Logging.Debug("[MazeExit] Starting maze exit sequence");
|
||||
|
||||
StartCoroutine(ExitMazeSequence());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private IEnumerator ExitMazeSequence()
|
||||
{
|
||||
// Step 1: Find Pulver (should be the active player-controlled character)
|
||||
var pulverController = FindFirstObjectByType<PulverController>();
|
||||
if (pulverController == null)
|
||||
{
|
||||
Debug.LogError("[MazeExit] PulverController not found in scene!");
|
||||
yield break;
|
||||
}
|
||||
|
||||
GameObject pulverGameObject = pulverController.gameObject;
|
||||
Logging.Debug($"[MazeExit] Found Pulver at {pulverGameObject.transform.position}");
|
||||
|
||||
// Step 2: Start camera blend to target state (PulverGameplay)
|
||||
TeleportationHelper.StartCameraBlend(targetCameraState);
|
||||
|
||||
// Step 3: Wait for halfway through blend, teleport Pulver, and set tracking target
|
||||
yield return TeleportationHelper.TeleportMidBlendAndSetTracking(pulverGameObject, teleportTarget, targetCameraState);
|
||||
|
||||
// Step 4: Wait for camera blend to complete
|
||||
yield return TeleportationHelper.WaitForCameraBlend();
|
||||
|
||||
// Step 5: Stop Pulver movement to prevent it from continuing with cached input
|
||||
if (pulverController != null)
|
||||
{
|
||||
pulverController.InterruptMoveTo();
|
||||
Logging.Debug("[MazeExit] Stopped Pulver movement after teleportation");
|
||||
}
|
||||
|
||||
Logging.Debug("[MazeExit] Maze exit sequence completed");
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void OnValidate()
|
||||
{
|
||||
name = "MazeExit";
|
||||
|
||||
// Default to PulverGameplay camera
|
||||
if (targetCameraState == TrashMazeCameraState.Gameplay)
|
||||
{
|
||||
targetCameraState = TrashMazeCameraState.PulverGameplay;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4543937f547b49ce8e506aac52442f73
|
||||
timeCreated: 1766151078
|
||||
@@ -0,0 +1,158 @@
|
||||
using System.Collections;
|
||||
using Core;
|
||||
using Minigames.TrashMaze.Core;
|
||||
using Minigames.TrashMaze.Data;
|
||||
using Unity.Cinemachine;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Minigames.TrashMaze.Objects
|
||||
{
|
||||
/// <summary>
|
||||
/// Static helper class for trash maze teleportation logic.
|
||||
/// Provides reusable methods for:
|
||||
/// - Starting camera blend to a target state
|
||||
/// - Teleporting a character midway through blend
|
||||
/// - Repositioning camera to teleported character
|
||||
/// - Setting up camera tracking after blend completes
|
||||
/// </summary>
|
||||
public static class TeleportationHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the camera for the target camera state
|
||||
/// </summary>
|
||||
private static CinemachineCamera GetTargetCamera(TrashMazeCameraState cameraState)
|
||||
{
|
||||
if (TrashMazeCameraController.Instance == null)
|
||||
return null;
|
||||
|
||||
return cameraState switch
|
||||
{
|
||||
TrashMazeCameraState.Gameplay => TrashMazeCameraController.Instance.GetGameplayCamera(),
|
||||
TrashMazeCameraState.Maze => TrashMazeCameraController.Instance.GetMazeCamera(),
|
||||
TrashMazeCameraState.PulverGameplay => TrashMazeCameraController.Instance.GetPulverGameplayCamera(),
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the camera blend to the target state
|
||||
/// </summary>
|
||||
public static void StartCameraBlend(TrashMazeCameraState targetState)
|
||||
{
|
||||
if (TrashMazeCameraController.Instance != null)
|
||||
{
|
||||
Logging.Debug($"[TeleportationHelper] Starting camera blend to {targetState}");
|
||||
|
||||
switch (targetState)
|
||||
{
|
||||
case TrashMazeCameraState.Gameplay:
|
||||
TrashMazeCameraController.Instance.SwitchToGameplay();
|
||||
break;
|
||||
case TrashMazeCameraState.Maze:
|
||||
TrashMazeCameraController.Instance.SwitchToMaze();
|
||||
break;
|
||||
case TrashMazeCameraState.PulverGameplay:
|
||||
TrashMazeCameraController.Instance.SwitchToPulverGameplay();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"[TeleportationHelper] TrashMazeCameraController instance not found!");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Coroutine that waits for halfway through camera blend, then teleports the character
|
||||
/// and immediately sets it as the tracking target for the camera
|
||||
/// </summary>
|
||||
public static IEnumerator TeleportMidBlendAndSetTracking(GameObject character, Transform teleportTarget, TrashMazeCameraState targetCameraState)
|
||||
{
|
||||
CinemachineBrain brain = Camera.main?.GetComponent<CinemachineBrain>();
|
||||
|
||||
if (brain != null && brain.IsBlending)
|
||||
{
|
||||
// Get blend duration from brain
|
||||
float blendDuration = brain.ActiveBlend != null ? brain.ActiveBlend.Duration : 1f;
|
||||
float halfBlendTime = blendDuration / 2f;
|
||||
|
||||
Logging.Debug($"[TeleportationHelper] Waiting {halfBlendTime:F2}s (half of {blendDuration:F2}s blend) before teleport");
|
||||
|
||||
// Wait for halfway through the blend
|
||||
yield return new WaitForSeconds(halfBlendTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback: wait a short moment if no blend is detected
|
||||
yield return new WaitForSeconds(0.25f);
|
||||
}
|
||||
|
||||
// Teleport character
|
||||
if (character != null && teleportTarget != null)
|
||||
{
|
||||
character.transform.position = teleportTarget.position;
|
||||
character.transform.rotation = teleportTarget.rotation;
|
||||
Logging.Debug($"[TeleportationHelper] Teleported {character.name} to {teleportTarget.position}");
|
||||
|
||||
// Immediately set as tracking target - let the blend finish naturally
|
||||
SetCameraTrackingTarget(character, targetCameraState);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (character == null)
|
||||
Debug.LogError($"[TeleportationHelper] Character GameObject is null!");
|
||||
if (teleportTarget == null)
|
||||
Debug.LogError($"[TeleportationHelper] Teleport target not assigned!");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wait for camera blend to complete
|
||||
/// </summary>
|
||||
public static IEnumerator WaitForCameraBlend()
|
||||
{
|
||||
CinemachineBrain brain = Camera.main?.GetComponent<CinemachineBrain>();
|
||||
|
||||
if (brain != null)
|
||||
{
|
||||
// Wait until blend is complete
|
||||
while (brain.IsBlending)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
Logging.Debug($"[TeleportationHelper] Camera blend completed");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback: wait a brief moment
|
||||
yield return new WaitForSeconds(0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set a character as the tracking target for the target camera
|
||||
/// </summary>
|
||||
public static void SetCameraTrackingTarget(GameObject character, TrashMazeCameraState targetCameraState)
|
||||
{
|
||||
if (character == null)
|
||||
{
|
||||
Debug.LogError($"[TeleportationHelper] Cannot set tracking target - character is null");
|
||||
return;
|
||||
}
|
||||
|
||||
var targetCamera = GetTargetCamera(targetCameraState);
|
||||
if (targetCamera != null)
|
||||
{
|
||||
targetCamera.Follow = character.transform;
|
||||
targetCamera.LookAt = character.transform;
|
||||
Logging.Debug($"[TeleportationHelper] Set {character.name} as tracking target for {targetCameraState} camera");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"[TeleportationHelper] Target camera for state {targetCameraState} not found!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1cf42e4c3a1e3c345aaef352bf84c762
|
||||
@@ -0,0 +1,109 @@
|
||||
using System.Collections;
|
||||
using Core;
|
||||
using Input;
|
||||
using Items;
|
||||
using Minigames.TrashMaze.Core;
|
||||
using Minigames.TrashMaze.Data;
|
||||
using Unity.Cinemachine;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Minigames.TrashMaze.Objects
|
||||
{
|
||||
/// <summary>
|
||||
/// Trash Maze specific controller switch that transitions TO Pulver (maze entrance).
|
||||
/// Handles camera blend with midway teleportation to create the illusion of entering the maze.
|
||||
/// </summary>
|
||||
public class TrashMazeSwitchToPulver : ControllerSwitchItem
|
||||
{
|
||||
[Header("Trash Maze - To Pulver Settings")]
|
||||
[Tooltip("Transform where Pulver should be teleported to (maze entrance)")]
|
||||
[SerializeField] private Transform teleportTarget;
|
||||
|
||||
[Tooltip("Camera state to blend to (Maze camera)")]
|
||||
[SerializeField] private TrashMazeCameraState targetCameraState = TrashMazeCameraState.Maze;
|
||||
|
||||
protected override IEnumerator SwitchControllerSequence()
|
||||
{
|
||||
_isSwitching = true;
|
||||
|
||||
// Step 1: Get controllers
|
||||
var currentController = InputManager.Instance.GetActiveController();
|
||||
var targetController = InputManager.Instance.GetController("pulver");
|
||||
|
||||
if (currentController == null || targetController == null)
|
||||
{
|
||||
Debug.LogError($"[TrashMazeSwitchToPulver] Failed to get controllers!");
|
||||
_isSwitching = false;
|
||||
yield break;
|
||||
}
|
||||
|
||||
GameObject currentGameObject = (currentController as MonoBehaviour)?.gameObject;
|
||||
GameObject targetGameObject = (targetController as MonoBehaviour)?.gameObject;
|
||||
|
||||
Logging.Debug($"[TrashMazeSwitchToPulver] Switching from {currentGameObject?.name} to Pulver");
|
||||
|
||||
// Step 2: Deactivate current controller (Trafalgar)
|
||||
DeactivateCurrentController(currentController, currentGameObject);
|
||||
|
||||
// Step 3: Deactivate Pulver's follower controller (will be teleported)
|
||||
if (targetGameObject != null)
|
||||
{
|
||||
var pulverFollower = targetGameObject.GetComponent<FollowerController>();
|
||||
if (pulverFollower != null)
|
||||
{
|
||||
pulverFollower.DeactivateFollower();
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4: Start camera blend to maze
|
||||
TeleportationHelper.StartCameraBlend(targetCameraState);
|
||||
|
||||
// Step 5: Wait for halfway through the blend, teleport Pulver, and set tracking target
|
||||
yield return TeleportationHelper.TeleportMidBlendAndSetTracking(targetGameObject, teleportTarget, targetCameraState);
|
||||
|
||||
// Step 6: Wait for camera blend to complete
|
||||
yield return TeleportationHelper.WaitForCameraBlend();
|
||||
|
||||
// Step 7: Activate Pulver controller
|
||||
if (targetController is BasePlayerMovementController targetPlayerController)
|
||||
{
|
||||
targetPlayerController.ActivateController();
|
||||
}
|
||||
|
||||
// Step 8: Switch InputManager to Pulver controller
|
||||
bool switchSuccess = InputManager.Instance.SwitchToController("pulver");
|
||||
|
||||
if (switchSuccess)
|
||||
{
|
||||
Logging.Debug($"[TrashMazeSwitchToPulver] Successfully switched to Pulver controller");
|
||||
OnCharacterSwitch.Invoke();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"[TrashMazeSwitchToPulver] Failed to switch to Pulver controller");
|
||||
}
|
||||
|
||||
// Step 9: Mark as used if one-time use
|
||||
if (isOneTime)
|
||||
{
|
||||
DisableVisual();
|
||||
}
|
||||
|
||||
_isSwitching = false;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void OnValidate()
|
||||
{
|
||||
name = "TrashMazeSwitch_ToPulver";
|
||||
|
||||
// Default to Maze camera
|
||||
if (targetCameraState != TrashMazeCameraState.Maze)
|
||||
{
|
||||
targetCameraState = TrashMazeCameraState.Maze;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fe2d6200d0d54638adb61befd932228f
|
||||
timeCreated: 1766149622
|
||||
@@ -0,0 +1,180 @@
|
||||
using System.Collections;
|
||||
using Core;
|
||||
using Input;
|
||||
using Items;
|
||||
using Minigames.TrashMaze.Core;
|
||||
using Minigames.TrashMaze.Data;
|
||||
using Unity.Cinemachine;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Minigames.TrashMaze.Objects
|
||||
{
|
||||
/// <summary>
|
||||
/// Trash Maze specific controller switch that transitions FROM Pulver back TO Trafalgar (maze exit).
|
||||
/// Handles camera blend back to gameplay view and re-enables follower mode.
|
||||
/// </summary>
|
||||
public class TrashMazeSwitchToTrafalgar : ControllerSwitchItem
|
||||
{
|
||||
[Header("Trash Maze - To Trafalgar Settings")]
|
||||
[Tooltip("Camera state to blend to (Gameplay camera)")]
|
||||
[SerializeField] private TrashMazeCameraState targetCameraState = TrashMazeCameraState.Gameplay;
|
||||
|
||||
protected override IEnumerator SwitchControllerSequence()
|
||||
{
|
||||
_isSwitching = true;
|
||||
|
||||
// Step 1: Get controllers
|
||||
var currentController = InputManager.Instance.GetActiveController();
|
||||
var targetController = InputManager.Instance.GetController("trafalgar");
|
||||
|
||||
if (currentController == null || targetController == null)
|
||||
{
|
||||
Debug.LogError($"[TrashMazeSwitchToTrafalgar] Failed to get controllers!");
|
||||
_isSwitching = false;
|
||||
yield break;
|
||||
}
|
||||
|
||||
GameObject currentGameObject = (currentController as MonoBehaviour)?.gameObject;
|
||||
GameObject targetGameObject = (targetController as MonoBehaviour)?.gameObject;
|
||||
|
||||
Logging.Debug($"[TrashMazeSwitchToTrafalgar] Switching from Pulver to {targetGameObject?.name}");
|
||||
|
||||
// Step 2: Deactivate current controller (Pulver)
|
||||
DeactivateCurrentController(currentController, currentGameObject);
|
||||
|
||||
// Explicitly deactivate PulverController to ensure it stops receiving input
|
||||
if (currentGameObject != null)
|
||||
{
|
||||
var pulverController = currentGameObject.GetComponent<PulverController>();
|
||||
if (pulverController != null)
|
||||
{
|
||||
pulverController.DeactivateController();
|
||||
Logging.Debug("[TrashMazeSwitchToTrafalgar] Explicitly deactivated PulverController");
|
||||
}
|
||||
}
|
||||
|
||||
// Step 3: Start camera blend back to gameplay
|
||||
StartCameraBlend();
|
||||
|
||||
// Step 4: Wait for camera blend to complete
|
||||
yield return WaitForCameraBlend();
|
||||
|
||||
// Step 5: Unset Pulver as tracking target and set Trafalgar for gameplay camera
|
||||
SetTrafalgarAsTrackingTarget(targetGameObject);
|
||||
|
||||
// Step 6: Activate Pulver's follower mode (so it follows Trafalgar)
|
||||
if (currentGameObject != null)
|
||||
{
|
||||
var pulverFollower = currentGameObject.GetComponent<FollowerController>();
|
||||
if (pulverFollower != null)
|
||||
{
|
||||
pulverFollower.ActivateFollower();
|
||||
}
|
||||
}
|
||||
|
||||
// Step 7: Activate Trafalgar controller
|
||||
if (targetController is BasePlayerMovementController targetPlayerController)
|
||||
{
|
||||
targetPlayerController.ActivateController();
|
||||
}
|
||||
|
||||
// Step 8: Switch InputManager to Trafalgar controller
|
||||
bool switchSuccess = InputManager.Instance.SwitchToController("trafalgar");
|
||||
|
||||
if (switchSuccess)
|
||||
{
|
||||
Logging.Debug($"[TrashMazeSwitchToTrafalgar] Successfully switched to Trafalgar controller");
|
||||
OnCharacterSwitch.Invoke();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"[TrashMazeSwitchToTrafalgar] Failed to switch to Trafalgar controller");
|
||||
}
|
||||
|
||||
// Step 8: Mark as used if one-time use
|
||||
if (isOneTime)
|
||||
{
|
||||
DisableVisual();
|
||||
}
|
||||
|
||||
_isSwitching = false;
|
||||
}
|
||||
|
||||
private void StartCameraBlend()
|
||||
{
|
||||
if (TrashMazeCameraController.Instance != null)
|
||||
{
|
||||
Logging.Debug($"[TrashMazeSwitchToTrafalgar] Starting camera blend to {targetCameraState}");
|
||||
|
||||
if (targetCameraState == TrashMazeCameraState.Gameplay)
|
||||
{
|
||||
TrashMazeCameraController.Instance.SwitchToGameplay();
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Warning($"[TrashMazeSwitchToTrafalgar] Unexpected camera state: {targetCameraState}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("[TrashMazeSwitchToTrafalgar] TrashMazeCameraController instance not found!");
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator WaitForCameraBlend()
|
||||
{
|
||||
CinemachineBrain brain = Camera.main?.GetComponent<CinemachineBrain>();
|
||||
|
||||
if (brain != null)
|
||||
{
|
||||
// Wait until blend is complete
|
||||
while (brain.IsBlending)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
Logging.Debug("[TrashMazeSwitchToTrafalgar] Camera blend completed");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback: wait a brief moment
|
||||
yield return new WaitForSeconds(0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetTrafalgarAsTrackingTarget(GameObject trafalgarGameObject)
|
||||
{
|
||||
if (TrashMazeCameraController.Instance != null)
|
||||
{
|
||||
// Clear maze camera tracking target
|
||||
var mazeCamera = TrashMazeCameraController.Instance.GetMazeCamera();
|
||||
if (mazeCamera != null)
|
||||
{
|
||||
mazeCamera.Follow = null;
|
||||
mazeCamera.LookAt = null;
|
||||
Logging.Debug($"[TrashMazeSwitchToTrafalgar] Cleared Pulver as tracking target from maze camera");
|
||||
}
|
||||
|
||||
// Set Trafalgar as tracking target for gameplay camera
|
||||
if (trafalgarGameObject != null)
|
||||
{
|
||||
var gameplayCamera = TrashMazeCameraController.Instance.GetGameplayCamera();
|
||||
if (gameplayCamera != null)
|
||||
{
|
||||
gameplayCamera.Follow = trafalgarGameObject.transform;
|
||||
gameplayCamera.LookAt = trafalgarGameObject.transform;
|
||||
Logging.Debug($"[TrashMazeSwitchToTrafalgar] Set Trafalgar as tracking target for gameplay camera");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void OnValidate()
|
||||
{
|
||||
name = "TrashMazeSwitch_ToTrafalgar";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 60a323cce5144fe9bae5dd3b313315a1
|
||||
timeCreated: 1766149639
|
||||
@@ -42,6 +42,9 @@ public class FollowerController : ManagedBehaviour
|
||||
private IFollowerSettings _settings;
|
||||
private IInteractionSettings _interactionSettings;
|
||||
|
||||
// Follower active state
|
||||
private bool _isFollowerActive = false;
|
||||
|
||||
private GameObject _playerRef;
|
||||
private Transform _playerTransform;
|
||||
private AIPath _playerAIPath;
|
||||
@@ -133,10 +136,18 @@ public class FollowerController : ManagedBehaviour
|
||||
{
|
||||
// Find player reference when scene is ready (called for every scene load)
|
||||
FindPlayerReference();
|
||||
|
||||
// Auto-activate follower mode when scene is ready
|
||||
// This ensures Pulver automatically follows Trafalgar in any scene by default
|
||||
ActivateFollower();
|
||||
Logging.Debug("[FollowerController] Auto-activated follower mode on scene ready");
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// Only process if follower is active
|
||||
if (!_isFollowerActive) return;
|
||||
|
||||
if (_playerTransform == null)
|
||||
{
|
||||
return;
|
||||
@@ -274,6 +285,118 @@ public class FollowerController : ManagedBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
#region Follower Lifecycle
|
||||
|
||||
/// <summary>
|
||||
/// Activate follower behavior - starts following the player.
|
||||
/// </summary>
|
||||
public void ActivateFollower()
|
||||
{
|
||||
_isFollowerActive = true;
|
||||
|
||||
// Find/refresh player reference
|
||||
FindPlayerReference();
|
||||
|
||||
// Check if a pickup is currently in progress
|
||||
bool pickupInProgress = _pickupCoroutine != null;
|
||||
|
||||
if (!pickupInProgress)
|
||||
{
|
||||
// Only reset to manual following mode if no pickup is active
|
||||
_isManualFollowing = true;
|
||||
_isReturningToPlayer = false;
|
||||
_isPlayingStationaryAnimation = false;
|
||||
_currentSpeed = 0f;
|
||||
_timer = 0f;
|
||||
|
||||
// Stop stationary animation coroutine if active
|
||||
if (_stationaryAnimationCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_stationaryAnimationCoroutine);
|
||||
_stationaryAnimationCoroutine = null;
|
||||
}
|
||||
|
||||
// Disable AIPath for manual following
|
||||
if (_aiPath != null)
|
||||
{
|
||||
_aiPath.enabled = false;
|
||||
}
|
||||
|
||||
// Initialize follow target position
|
||||
UpdateFollowTarget();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pickup in progress - don't interfere, just mark as active
|
||||
Logging.Debug("[FollowerController] Follower activated but pickup in progress - not resetting state");
|
||||
}
|
||||
|
||||
// Always enable TrackableTarget when follower is active
|
||||
var trackableTarget = GetComponent<UI.Tracking.TrackableTarget>();
|
||||
if (trackableTarget != null)
|
||||
{
|
||||
trackableTarget.enabled = true;
|
||||
}
|
||||
|
||||
Logging.Debug("[FollowerController] Follower activated");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deactivate follower behavior - stops all following and movement.
|
||||
/// </summary>
|
||||
public void DeactivateFollower()
|
||||
{
|
||||
_isFollowerActive = false;
|
||||
|
||||
// Stop all coroutines
|
||||
if (_pickupCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_pickupCoroutine);
|
||||
_pickupCoroutine = null;
|
||||
}
|
||||
|
||||
if (_stationaryAnimationCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_stationaryAnimationCoroutine);
|
||||
_stationaryAnimationCoroutine = null;
|
||||
}
|
||||
|
||||
// Reset movement state
|
||||
_isManualFollowing = false;
|
||||
_isReturningToPlayer = false;
|
||||
_isPlayingStationaryAnimation = false;
|
||||
_currentSpeed = 0f;
|
||||
|
||||
// Disable AIPath
|
||||
if (_aiPath != null)
|
||||
{
|
||||
_aiPath.enabled = false;
|
||||
_aiPath.isStopped = true;
|
||||
}
|
||||
|
||||
// Disable TrackableTarget component if present
|
||||
var trackableTarget = GetComponent<UI.Tracking.TrackableTarget>();
|
||||
if (trackableTarget != null)
|
||||
{
|
||||
trackableTarget.enabled = false;
|
||||
}
|
||||
|
||||
// Set animator to idle
|
||||
if (_animator != null)
|
||||
{
|
||||
_animator.SetFloat("Speed", 0f);
|
||||
}
|
||||
|
||||
Logging.Debug("[FollowerController] Follower deactivated");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if follower is currently active.
|
||||
/// </summary>
|
||||
public bool IsFollowerActive => _isFollowerActive;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Movement
|
||||
/// <summary>
|
||||
/// Updates the follower's target point to follow the player at a specified distance,
|
||||
|
||||
Reference in New Issue
Block a user