From 6152ba102a4970e64b4417a76b5eac9a0472b763 Mon Sep 17 00:00:00 2001 From: rowan Date: Wed, 16 Jul 2025 23:35:29 -0400 Subject: [PATCH] timer --- Assets/Animation/Door.controller | 211 +++++++++++++++ Assets/Animation/Door.controller.meta | 8 + Assets/Animation/Slide.anim | 177 +++++++++++++ Assets/Animation/Slide.anim.meta | 8 + Assets/SOAP/UI/New Modal Element.asset | 2 +- Assets/Scenes/SampleScene.unity | 242 +++++++++--------- Assets/Scripts/Entity/EntityAnimator.cs | 2 +- Assets/Scripts/Environment.meta | 8 + .../Scripts/Environment/TriggerAnimation.cs | 34 +++ .../Environment/TriggerAnimation.cs.meta | 2 + Assets/Scripts/Extension/Func.cs | 6 + Assets/Scripts/Extension/Func.cs.meta | 2 + Assets/Scripts/Extension/Math.cs | 148 ++++++++++- Assets/Scripts/Extension/Observable.cs | 28 +- Assets/Scripts/Extension/R3.cs | 46 +++- Assets/Scripts/Interaction/Interactor.cs | 2 +- Assets/Scripts/System/Duration.cs | 134 ++++++++++ Assets/Scripts/System/Duration.cs.meta | 2 + Assets/Scripts/System/Func.cs | 10 + Assets/Scripts/System/Func.cs.meta | 2 + Assets/Scripts/System/Timer.cs | 181 +++++++++++++ Assets/Scripts/System/Timer.cs.meta | 2 + Assets/Scripts/UI/TestThing.cs | 2 +- 23 files changed, 1129 insertions(+), 130 deletions(-) create mode 100644 Assets/Animation/Door.controller create mode 100644 Assets/Animation/Door.controller.meta create mode 100644 Assets/Animation/Slide.anim create mode 100644 Assets/Animation/Slide.anim.meta create mode 100644 Assets/Scripts/Environment.meta create mode 100644 Assets/Scripts/Environment/TriggerAnimation.cs create mode 100644 Assets/Scripts/Environment/TriggerAnimation.cs.meta create mode 100644 Assets/Scripts/Extension/Func.cs create mode 100644 Assets/Scripts/Extension/Func.cs.meta create mode 100644 Assets/Scripts/System/Duration.cs create mode 100644 Assets/Scripts/System/Duration.cs.meta create mode 100644 Assets/Scripts/System/Func.cs create mode 100644 Assets/Scripts/System/Func.cs.meta create mode 100644 Assets/Scripts/System/Timer.cs create mode 100644 Assets/Scripts/System/Timer.cs.meta diff --git a/Assets/Animation/Door.controller b/Assets/Animation/Door.controller new file mode 100644 index 0000000..6366806 --- /dev/null +++ b/Assets/Animation/Door.controller @@ -0,0 +1,211 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!91 &9100000 +AnimatorController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Door + serializedVersion: 5 + m_AnimatorParameters: + - m_Name: Slide + m_Type: 9 + m_DefaultFloat: 0 + m_DefaultInt: 0 + m_DefaultBool: 0 + m_Controller: {fileID: 9100000} + m_AnimatorLayers: + - serializedVersion: 5 + m_Name: Base Layer + m_StateMachine: {fileID: 3520680776111234515} + m_Mask: {fileID: 0} + m_Motions: [] + m_Behaviours: [] + m_BlendingMode: 0 + m_SyncedLayerIndex: -1 + m_DefaultWeight: 0 + m_IKPass: 0 + m_SyncedLayerAffectsTiming: 0 + m_Controller: {fileID: 9100000} +--- !u!1102 &38950273917977174 +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: 5473826971642451200} + 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: 0} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: +--- !u!1102 &671522036267396356 +AnimatorState: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Slide Open + m_Speed: 1 + m_CycleOffset: 0 + m_Transitions: + - {fileID: 3513482884697136127} + 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: 89b2252e24ece1dcba57da2e30b659fd, type: 2} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: +--- !u!1101 &3513482884697136127 +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: Slide + m_EventTreshold: 0 + m_DstStateMachine: {fileID: 0} + m_DstState: {fileID: 6558265478478358952} + 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!1107 &3520680776111234515 +AnimatorStateMachine: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Base Layer + m_ChildStates: + - serializedVersion: 1 + m_State: {fileID: 671522036267396356} + m_Position: {x: 200, y: 180, z: 0} + - serializedVersion: 1 + m_State: {fileID: 38950273917977174} + m_Position: {x: 330, y: 80, z: 0} + - serializedVersion: 1 + m_State: {fileID: 6558265478478358952} + m_Position: {x: 420, y: 180, 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_ExitPosition: {x: 800, y: 120, z: 0} + m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} + m_DefaultState: {fileID: 38950273917977174} +--- !u!1101 &5473826971642451200 +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: Slide + m_EventTreshold: 0 + m_DstStateMachine: {fileID: 0} + m_DstState: {fileID: 671522036267396356} + 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!1101 &6296192238611738469 +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: 38950273917977174} + 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!1102 &6558265478478358952 +AnimatorState: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Slide Closed + m_Speed: -1 + m_CycleOffset: 0 + m_Transitions: + - {fileID: 6296192238611738469} + 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: 89b2252e24ece1dcba57da2e30b659fd, type: 2} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: diff --git a/Assets/Animation/Door.controller.meta b/Assets/Animation/Door.controller.meta new file mode 100644 index 0000000..56b9ed7 --- /dev/null +++ b/Assets/Animation/Door.controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 88201f823a141e345ab1799d0c715448 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 9100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Animation/Slide.anim b/Assets/Animation/Slide.anim new file mode 100644 index 0000000..5624dbd --- /dev/null +++ b/Assets/Animation/Slide.anim @@ -0,0 +1,177 @@ +%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: Slide + serializedVersion: 7 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: {x: 0, y: 0, z: 0} + inSlope: {x: 0, y: 0, z: 0} + outSlope: {x: 0, y: 0, z: 0} + tangentMode: 0 + weightedMode: 0 + inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + - serializedVersion: 3 + time: 1 + value: {x: -2, y: 0, z: 0} + inSlope: {x: 0, y: 0, z: 0} + outSlope: {x: 0, y: 0, z: 0} + tangentMode: 0 + weightedMode: 0 + inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + path: + m_ScaleCurves: [] + m_FloatCurves: [] + m_PPtrCurves: [] + m_SampleRate: 60 + 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: 1 + script: {fileID: 0} + typeID: 4 + customType: 0 + isPPtrCurve: 0 + isIntCurve: 0 + isSerializeReferenceCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 1 + 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: + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: -2 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_LocalPosition.x + path: + classID: 4 + script: {fileID: 0} + flags: 0 + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_LocalPosition.y + path: + classID: 4 + script: {fileID: 0} + flags: 0 + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_LocalPosition.z + path: + classID: 4 + script: {fileID: 0} + flags: 0 + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 1 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Assets/Animation/Slide.anim.meta b/Assets/Animation/Slide.anim.meta new file mode 100644 index 0000000..94b3615 --- /dev/null +++ b/Assets/Animation/Slide.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 89b2252e24ece1dcba57da2e30b659fd +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/SOAP/UI/New Modal Element.asset b/Assets/SOAP/UI/New Modal Element.asset index 508de42..9f325f3 100644 --- a/Assets/SOAP/UI/New Modal Element.asset +++ b/Assets/SOAP/UI/New Modal Element.asset @@ -12,6 +12,6 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 0b01085379e9a10319622dd3dd23f4bd, type: 3} m_Name: New Modal Element m_EditorClassIdentifier: - visualTreeAsset: {fileID: 0} + visualTreeAsset: {fileID: 9197481963319205126, guid: bc70bdaaf37609283aac14435c5441a2, type: 3} titleId: title contentId: content diff --git a/Assets/Scenes/SampleScene.unity b/Assets/Scenes/SampleScene.unity index 4c28f76..43bfe69 100644 --- a/Assets/Scenes/SampleScene.unity +++ b/Assets/Scenes/SampleScene.unity @@ -938,6 +938,9 @@ GameObject: - component: {fileID: 1190731369} - component: {fileID: 1190731368} - component: {fileID: 1190731367} + - component: {fileID: 1190731373} + - component: {fileID: 1190731371} + - component: {fileID: 1190731372} m_Layer: 0 m_Name: Cube m_TagString: Untagged @@ -954,7 +957,7 @@ Transform: m_GameObject: {fileID: 1190731365} serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 5, y: 1, z: 5} + m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 2, y: 2, z: 0.25} m_ConstrainProportionsScale: 0 m_Children: [] @@ -980,10 +983,22 @@ MonoBehaviour: opened: m_PersistentCalls: m_Calls: - - m_Target: {fileID: 1632951287} - m_TargetAssemblyTypeName: UnityEngine.GameObject, UnityEngine - m_MethodName: SetActive - m_Mode: 6 + - m_Target: {fileID: 1190731372} + m_TargetAssemblyTypeName: KitsuneCafe.Animation.TriggerAnimation, Assembly-CSharp + m_MethodName: Trigger + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 + - m_Target: {fileID: 1190731373} + m_TargetAssemblyTypeName: KitsuneCafe.Timer, Assembly-CSharp + m_MethodName: StartTimer + m_Mode: 1 m_Arguments: m_ObjectArgument: {fileID: 0} m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine @@ -1066,6 +1081,75 @@ MeshFilter: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1190731365} m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!95 &1190731371 +Animator: + serializedVersion: 7 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1190731365} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 88201f823a141e345ab1799d0c715448, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_AnimatePhysics: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 + m_WriteDefaultValuesOnDisable: 0 +--- !u!114 &1190731372 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1190731365} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ea23cf01a7e3191299601c9494661c37, type: 3} + m_Name: + m_EditorClassIdentifier: + animator: {fileID: 1190731371} + parameter: -1288781466 +--- !u!114 &1190731373 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1190731365} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1eeeac25dfbfdf4cf8a8d231c5296c00, type: 3} + m_Name: + m_EditorClassIdentifier: + duration: 3 + unit: 2 + timing: 4 + timeKind: 0 + autostart: 0 + oneShot: 1 + onComplete: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1190731372} + m_TargetAssemblyTypeName: KitsuneCafe.Animation.TriggerAnimation, Assembly-CSharp + m_MethodName: Trigger + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 --- !u!1 &1281046467 GameObject: m_ObjectHideFlags: 0 @@ -1096,8 +1180,7 @@ Transform: m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 1520555326} + m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!114 &1281046469 @@ -1634,117 +1717,6 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1520555325 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1520555326} - - component: {fileID: 1520555327} - - component: {fileID: 1520555328} - - component: {fileID: 1520555329} - m_Layer: 5 - m_Name: UIDocument - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &1520555326 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1520555325} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: -2, y: 1, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1281046468} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &1520555327 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1520555325} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0} - m_Name: - m_EditorClassIdentifier: - m_PanelSettings: {fileID: 11400000, guid: 2bc58aab5867867e5b0feeae2df42fd0, type: 2} - m_ParentUI: {fileID: 0} - sourceAsset: {fileID: 9197481963319205126, guid: bc70bdaaf37609283aac14435c5441a2, type: 3} - m_SortingOrder: 0 - m_WorldSpaceSizeMode: 1 - m_WorldSpaceWidth: 1920 - m_WorldSpaceHeight: 1080 ---- !u!1931382933 &1520555328 -UIRenderer: - m_ObjectHideFlags: 2 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1520555325} - m_Enabled: 1 - m_CastShadows: 0 - m_ReceiveShadows: 0 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 0 - m_ReflectionProbeUsage: 0 - m_RayTracingMode: 0 - m_RayTraceProcedural: 0 - m_RayTracingAccelStructBuildFlagsOverride: 0 - m_RayTracingAccelStructBuildFlags: 1 - m_SmallMeshCulling: 1 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 0} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 ---- !u!114 &1520555329 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1520555325} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: d11d59e048d068de9a36d02d67cfd1ad, type: 3} - m_Name: - m_EditorClassIdentifier: - doc: {fileID: 1520555327} - value: test --- !u!1001 &1574173917 PrefabInstance: m_ObjectHideFlags: 0 @@ -1835,13 +1807,32 @@ Transform: m_GameObject: {fileID: 1632951287} serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalPosition: {x: 5, y: 1, z: 5} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: - {fileID: 1190731366} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1740748256 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 2892703864492016621, guid: 51202e3c62c3d3e1c9bb0ff9c09a608f, type: 3} + m_PrefabInstance: {fileID: 7547016027398857338} + m_PrefabAsset: {fileID: 0} +--- !u!114 &1740748263 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1740748256} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d11d59e048d068de9a36d02d67cfd1ad, type: 3} + m_Name: + m_EditorClassIdentifier: + orchestrator: {fileID: 11400000, guid: 994ab04db2c2004abb8272830cb16b26, type: 2} + modal: {fileID: 11400000, guid: 71a6f29fae4392a4f97870a52b6adf1e, type: 2} --- !u!1 &1782112144 stripped GameObject: m_CorrespondingSourceObject: {fileID: 919132149155446097, guid: 39499efe4f068c9f1aa32d2ea7e17fa9, type: 3} @@ -1882,7 +1873,7 @@ GameObject: m_Layer: 0 m_Name: Interaction Collider m_TagString: Untagged - m_Icon: {fileID: 0} + m_Icon: {fileID: -5397416234189338067, guid: 0000000000000000d000000000000000, type: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 @@ -1920,7 +1911,7 @@ CapsuleCollider: m_ProvidesContacts: 0 m_Enabled: 1 serializedVersion: 2 - m_Radius: 1.25 + m_Radius: 1 m_Height: 2.5 m_Direction: 1 m_Center: {x: 0, y: 0, z: 0} @@ -2041,6 +2032,10 @@ PrefabInstance: serializedVersion: 3 m_TransformParent: {fileID: 0} m_Modifications: + - target: {fileID: 2022912019066975223, guid: 51202e3c62c3d3e1c9bb0ff9c09a608f, type: 3} + propertyPath: oneTimeUse + value: 1 + objectReference: {fileID: 0} - target: {fileID: 2368094401510200604, guid: 51202e3c62c3d3e1c9bb0ff9c09a608f, type: 3} propertyPath: m_LocalPosition.x value: -2 @@ -2088,7 +2083,10 @@ PrefabInstance: m_RemovedComponents: [] m_RemovedGameObjects: [] m_AddedGameObjects: [] - m_AddedComponents: [] + m_AddedComponents: + - targetCorrespondingSourceObject: {fileID: 2892703864492016621, guid: 51202e3c62c3d3e1c9bb0ff9c09a608f, type: 3} + insertIndex: -1 + addedObject: {fileID: 1740748263} m_SourcePrefab: {fileID: 100100000, guid: 51202e3c62c3d3e1c9bb0ff9c09a608f, type: 3} --- !u!1660057539 &9223372036854775807 SceneRoots: diff --git a/Assets/Scripts/Entity/EntityAnimator.cs b/Assets/Scripts/Entity/EntityAnimator.cs index 4127f5d..9a61128 100644 --- a/Assets/Scripts/Entity/EntityAnimator.cs +++ b/Assets/Scripts/Entity/EntityAnimator.cs @@ -90,7 +90,7 @@ namespace KitsuneCafe.Entity return speedSource .CombineLatest(motor.MaxSpeedSource, scaleFactor, NormalizeSpeed) - .DistinctUntilChanged(FEqualityComparer.Create(MathExtension.IsApproxEqual)); + .DistinctUntilChanged(FEqualityComparer.Create(KMath.IsApproxEqual)); } private float NormalizationFactor(float maxSpeed, float defaultMaxSpeed) diff --git a/Assets/Scripts/Environment.meta b/Assets/Scripts/Environment.meta new file mode 100644 index 0000000..f6b09c5 --- /dev/null +++ b/Assets/Scripts/Environment.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: af0ee52c05fe2ee4d90143efa7204a07 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Environment/TriggerAnimation.cs b/Assets/Scripts/Environment/TriggerAnimation.cs new file mode 100644 index 0000000..7ef1d80 --- /dev/null +++ b/Assets/Scripts/Environment/TriggerAnimation.cs @@ -0,0 +1,34 @@ +using NaughtyAttributes; +using UnityEngine; + +namespace KitsuneCafe.Animation +{ + public class TriggerAnimation : MonoBehaviour + { + [SerializeField] + private Animator animator; + + [SerializeField, AnimatorParam("animator")] + private int parameter; + + private void Reset() + { + animator = GetComponent(); + } + + public void Trigger(string parameter) + { + animator.SetTrigger(parameter); + } + + public void Trigger(int parameter) + { + animator.SetTrigger(parameter); + } + + public void Trigger() + { + animator.SetTrigger(parameter); + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Environment/TriggerAnimation.cs.meta b/Assets/Scripts/Environment/TriggerAnimation.cs.meta new file mode 100644 index 0000000..47db7e9 --- /dev/null +++ b/Assets/Scripts/Environment/TriggerAnimation.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ea23cf01a7e3191299601c9494661c37 \ No newline at end of file diff --git a/Assets/Scripts/Extension/Func.cs b/Assets/Scripts/Extension/Func.cs new file mode 100644 index 0000000..d82f306 --- /dev/null +++ b/Assets/Scripts/Extension/Func.cs @@ -0,0 +1,6 @@ +namespace KitsuneCafe.Extension +{ + public static class FuncExtension + { + } +} diff --git a/Assets/Scripts/Extension/Func.cs.meta b/Assets/Scripts/Extension/Func.cs.meta new file mode 100644 index 0000000..fc72529 --- /dev/null +++ b/Assets/Scripts/Extension/Func.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ac81a630011ddabde99f8cd851dfbacd \ No newline at end of file diff --git a/Assets/Scripts/Extension/Math.cs b/Assets/Scripts/Extension/Math.cs index 8a87993..5b53934 100644 --- a/Assets/Scripts/Extension/Math.cs +++ b/Assets/Scripts/Extension/Math.cs @@ -2,7 +2,7 @@ using System; namespace KitsuneCafe.Extension { - public static class MathExtension + public static class KMath { public static bool IsApproxEqual(this float value, float other) { @@ -13,5 +13,151 @@ namespace KitsuneCafe.Extension { return Math.Abs(value - other) < epsilon; } + + public static bool And(bool a, bool b) + { + return a && b; + } + + public static bool Or(bool a, bool b) + { + return a || b; + } + + public static bool Not(bool value) + { + return !value; + } + + public static int Add(sbyte a, sbyte b) + { + return a + b; + } + + public static int Add(byte a, byte b) + { + return a + b; + } + + public static int Add(short a, short b) + { + return a + b; + } + + public static int Add(ushort a, ushort b) + { + return a + b; + } + + public static int Add(int a, int b) + { + return a + b; + } + + public static uint Add(uint a, uint b) + { + return a + b; + } + + public static long Add(long a, long b) + { + return a + b; + } + + public static ulong Add(ulong a, ulong b) + { + return a + b; + } + + public static nint Add(nint a, nint b) + { + return a + b; + } + + public static nuint Add(nuint a, nuint b) + { + return a + b; + } + + public static float Add(float a, float b) + { + return a + b; + } + + public static double Add(double a, double b) + { + return a + b; + } + + public static decimal Add(decimal a, decimal b) + { + return a + b; + } + + public static int Sub(sbyte a, sbyte b) + { + return a - b; + } + + public static int Sub(byte a, byte b) + { + return a - b; + } + + public static int Sub(short a, short b) + { + return a - b; + } + + public static int Sub(ushort a, ushort b) + { + return a - b; + } + + public static int Sub(int a, int b) + { + return a - b; + } + + public static uint Sub(uint a, uint b) + { + return a - b; + } + + public static long Sub(long a, long b) + { + return a - b; + } + + public static ulong Sub(ulong a, ulong b) + { + return a - b; + } + + public static nint Sub(nint a, nint b) + { + return a - b; + } + + public static nuint Sub(nuint a, nuint b) + { + return a - b; + } + + public static float Sub(float a, float b) + { + return a - b; + } + + public static double Sub(double a, double b) + { + return a - b; + } + + public static decimal Sub(decimal a, decimal b) + { + return a - b; + } + } } diff --git a/Assets/Scripts/Extension/Observable.cs b/Assets/Scripts/Extension/Observable.cs index acd68a1..517660a 100644 --- a/Assets/Scripts/Extension/Observable.cs +++ b/Assets/Scripts/Extension/Observable.cs @@ -3,6 +3,7 @@ using UnityEngine; using System; using KitsuneCafe.System; using System.Collections.Generic; +using System.Threading; namespace KitsuneCafe.Extension { @@ -55,7 +56,7 @@ namespace KitsuneCafe.Extension TimeProvider provider) { return source - .DistinctUntilChanged(FEqualityComparer.Create(MathExtension.IsApproxEqual)) + .DistinctUntilChanged(FEqualityComparer.Create(KMath.IsApproxEqual)) .Select(target => { float initialCurrentValue = valueGetter(); @@ -151,6 +152,31 @@ namespace KitsuneCafe.Extension return minElement; } } + + public static Observable SelectSwitch(this Observable source, Func> selector) + { + return source.Select(selector).Switch(); + } + + public static Observable SwitchIf(this Observable source, Observable selectionSource, Observable other) + { + return selectionSource.SelectSwitch(value => value ? other : source); + } + + public static Observable SwitchIf(this Observable source, Observable selectionSource, Func> other) + { + return selectionSource.SelectSwitch(value => value ? other() : source); + } + + public static Observable WhereEquals(this Observable source, T value) where T : IEquatable + { + return source.Where(value.Equals); + } + + public static Observable WhereTrue(this Observable source) + { + return source.Where(Func.Identity); + } } } diff --git a/Assets/Scripts/Extension/R3.cs b/Assets/Scripts/Extension/R3.cs index 3097397..7c50dfa 100644 --- a/Assets/Scripts/Extension/R3.cs +++ b/Assets/Scripts/Extension/R3.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using R3; using UnityEngine; @@ -20,7 +21,7 @@ namespace KitsuneCafe.Extension } } - private static readonly Dictionary timeProviderInfo = new Dictionary() + private static readonly Dictionary timeProviderInfo = new() { { UnityTimeProvider.Initialization, new (UnityFrameProvider.Initialization, TimeKind.Time) }, { UnityTimeProvider.EarlyUpdate, new (UnityFrameProvider.EarlyUpdate, TimeKind.Time) }, @@ -63,7 +64,7 @@ namespace KitsuneCafe.Extension PostFixedUpdate } - private static readonly Dictionary frameProviderTiming = new Dictionary() + private static readonly Dictionary frameProviderTiming = new() { { UnityFrameProvider.Initialization, PlayerLoopTiming.Initialization }, { UnityFrameProvider.EarlyUpdate, PlayerLoopTiming.EarlyUpdate }, @@ -77,6 +78,7 @@ namespace KitsuneCafe.Extension }; + public static bool TryGetFrameProvider(this TimeProvider provider, out FrameProvider frameProvider) { if (timeProviderInfo.TryGetValue(provider, out var info)) @@ -136,5 +138,45 @@ namespace KitsuneCafe.Extension { return provider.TryGetFrameTiming(out var timing) ? timing : null; } + + public static TimeProvider GetTimeProvider(PlayerLoopTiming timing, TimeKind kind) + { + return (timing, kind) switch + { + (PlayerLoopTiming.Initialization, TimeKind.Time) => UnityTimeProvider.Initialization, + (PlayerLoopTiming.Initialization, TimeKind.UnscaledTime) => UnityTimeProvider.InitializationIgnoreTimeScale, + (PlayerLoopTiming.Initialization, TimeKind.Realtime) => UnityTimeProvider.InitializationRealtime, + + (PlayerLoopTiming.EarlyUpdate, TimeKind.Time) => UnityTimeProvider.EarlyUpdate, + (PlayerLoopTiming.EarlyUpdate, TimeKind.UnscaledTime) => UnityTimeProvider.EarlyUpdate, + (PlayerLoopTiming.EarlyUpdate, TimeKind.Realtime) => UnityTimeProvider.EarlyUpdate, + + (PlayerLoopTiming.FixedUpdate, TimeKind.Time) => UnityTimeProvider.FixedUpdate, + (PlayerLoopTiming.FixedUpdate, TimeKind.UnscaledTime) => UnityTimeProvider.FixedUpdate, + (PlayerLoopTiming.FixedUpdate, TimeKind.Realtime) => UnityTimeProvider.FixedUpdate, + + (PlayerLoopTiming.PreUpdate, TimeKind.Time) => UnityTimeProvider.PreUpdate, + (PlayerLoopTiming.PreUpdate, TimeKind.UnscaledTime) => UnityTimeProvider.PreUpdate, + (PlayerLoopTiming.PreUpdate, TimeKind.Realtime) => UnityTimeProvider.PreUpdate, + + (PlayerLoopTiming.Update, TimeKind.Time) => UnityTimeProvider.Update, + (PlayerLoopTiming.Update, TimeKind.UnscaledTime) => UnityTimeProvider.Update, + (PlayerLoopTiming.Update, TimeKind.Realtime) => UnityTimeProvider.Update, + + (PlayerLoopTiming.PreLateUpdate, TimeKind.Time) => UnityTimeProvider.PreLateUpdate, + (PlayerLoopTiming.PreLateUpdate, TimeKind.UnscaledTime) => UnityTimeProvider.PreLateUpdate, + (PlayerLoopTiming.PreLateUpdate, TimeKind.Realtime) => UnityTimeProvider.PreLateUpdate, + + (PlayerLoopTiming.PostLateUpdate, TimeKind.Time) => UnityTimeProvider.PostLateUpdate, + (PlayerLoopTiming.PostLateUpdate, TimeKind.UnscaledTime) => UnityTimeProvider.PostLateUpdate, + (PlayerLoopTiming.PostLateUpdate, TimeKind.Realtime) => UnityTimeProvider.PostLateUpdate, + + (PlayerLoopTiming.TimeUpdate, TimeKind.Time) => UnityTimeProvider.TimeUpdate, + (PlayerLoopTiming.TimeUpdate, TimeKind.UnscaledTime) => UnityTimeProvider.TimeUpdate, + (PlayerLoopTiming.TimeUpdate, TimeKind.Realtime) => UnityTimeProvider.TimeUpdate, + + (var t, var k) => throw new ArgumentException("({t}, {k}) are not valid values.") + }; + } } } \ No newline at end of file diff --git a/Assets/Scripts/Interaction/Interactor.cs b/Assets/Scripts/Interaction/Interactor.cs index a7d08dc..61b2bf6 100644 --- a/Assets/Scripts/Interaction/Interactor.cs +++ b/Assets/Scripts/Interaction/Interactor.cs @@ -113,7 +113,7 @@ namespace KitsuneCafe.Player { var highlighted = interactables .Where(x => x.IsInteractable) - .MinBy(x => gameObject.transform.position.SqrDistance(x.gameObject.transform.position)); + .MinBy(x => collider.transform.position.SqrDistance(x.gameObject.transform.position)); if (CurrentHighlightedInteractable.Value != highlighted) { diff --git a/Assets/Scripts/System/Duration.cs b/Assets/Scripts/System/Duration.cs new file mode 100644 index 0000000..73874fd --- /dev/null +++ b/Assets/Scripts/System/Duration.cs @@ -0,0 +1,134 @@ +using System; + +namespace KitsuneCafe.System +{ + public enum TimeUnit : byte + { + Ticks, + Milliseconds, + Seconds, + Minutes, + Hours, + Days + } + + public readonly struct Duration : IComparable, IComparable, IComparable, IEquatable, IEquatable + { + public readonly long Value; + private readonly TimeUnit unit; + + public Duration(long ticks, TimeUnit unit) + { + Value = ticks; + this.unit = unit; + } + + public Duration(long ticks) : this(ticks, TimeUnit.Ticks) { } + + public static implicit operator TimeSpan(Duration duration) => duration.AsTimeSpan(); + + public readonly TimeSpan AsTimeSpan() => new(Value); + + public static Duration From(long value, TimeUnit unit) + { + var ticks = unit switch + { + TimeUnit.Ticks => value, + TimeUnit.Milliseconds => TimeSpan.TicksPerMillisecond * value, + TimeUnit.Seconds => TimeSpan.TicksPerSecond * value, + TimeUnit.Minutes => TimeSpan.TicksPerMinute * value, + TimeUnit.Hours => TimeSpan.TicksPerHour * value, + TimeUnit.Days => TimeSpan.TicksPerHour * value, + var x => throw new ArgumentException($"{x} is not a valid TimeUnit.") + }; + + return new Duration(ticks, unit); + } + + public static Duration From(double value, TimeUnit unit) + { + var ticks = unit switch + { + TimeUnit.Ticks => value, + TimeUnit.Milliseconds => TimeSpan.TicksPerMillisecond * value, + TimeUnit.Seconds => TimeSpan.TicksPerSecond * value, + TimeUnit.Minutes => TimeSpan.TicksPerMinute * value, + TimeUnit.Hours => TimeSpan.TicksPerHour * value, + TimeUnit.Days => TimeSpan.TicksPerHour * value, + var x => throw new ArgumentException($"{x} is not a valid TimeUnit.") + }; + + return new Duration(Convert.ToInt64(ticks), unit); + } + + public long Into(TimeUnit unit) + { + return unit switch + { + TimeUnit.Ticks => Value, + TimeUnit.Milliseconds => Value / TimeSpan.TicksPerMillisecond, + TimeUnit.Seconds => Value / TimeSpan.TicksPerSecond, + TimeUnit.Minutes => Value / TimeSpan.TicksPerMinute, + TimeUnit.Hours => Value / TimeSpan.TicksPerHour, + TimeUnit.Days => Value / TimeSpan.TicksPerHour, + var x => throw new ArgumentException($"{x} is not a valid TimeUnit.") + }; + } + + public int CompareTo(object obj) + { + return obj switch + { + Duration d => CompareTo(d), + TimeSpan ts => CompareTo(ts), + var value => throw new ArgumentException($"{value} is not a Duration or TimeSpan") + }; + } + + public static bool Equals(Duration a, Duration b) + { + return a.Value == b.Value; + } + + public static int Compare(Duration a, Duration b) + { + return a.Value.CompareTo(b.Value); + } + + public int CompareTo(Duration other) + { + return Compare(this, other); + } + + public int CompareTo(TimeSpan other) + { + return TimeSpan.Compare(this, other); + } + + public bool Equals(Duration other) + { + return Equals(this, other); + } + + public bool Equals(TimeSpan other) + { + return other.Equals(this); + } + + public override bool Equals(object obj) + { + return (obj is Duration d && Equals(this, d)) + || (obj is TimeSpan ts && Equals(this, ts)); + } + + public override int GetHashCode() + { + return HashCode.Combine(Value); + } + + public override string ToString() + { + return $"{Value} {nameof(unit)}"; + } + } +} diff --git a/Assets/Scripts/System/Duration.cs.meta b/Assets/Scripts/System/Duration.cs.meta new file mode 100644 index 0000000..ab41329 --- /dev/null +++ b/Assets/Scripts/System/Duration.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e9121eab7f3a85e14bb366b2bdad86e6 \ No newline at end of file diff --git a/Assets/Scripts/System/Func.cs b/Assets/Scripts/System/Func.cs new file mode 100644 index 0000000..31dd7b2 --- /dev/null +++ b/Assets/Scripts/System/Func.cs @@ -0,0 +1,10 @@ +namespace KitsuneCafe.System +{ + public static class Func + { + public static T Identity(T value) + { + return value; + } + } +} diff --git a/Assets/Scripts/System/Func.cs.meta b/Assets/Scripts/System/Func.cs.meta new file mode 100644 index 0000000..8497e19 --- /dev/null +++ b/Assets/Scripts/System/Func.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: dbecc1a160f64dbaf94e8344363e921f \ No newline at end of file diff --git a/Assets/Scripts/System/Timer.cs b/Assets/Scripts/System/Timer.cs new file mode 100644 index 0000000..3d38743 --- /dev/null +++ b/Assets/Scripts/System/Timer.cs @@ -0,0 +1,181 @@ +using System; +using System.Threading; +using KitsuneCafe.Extension; +using R3; +using UnityEditor; +using UnityEngine; +using UnityEngine.Events; +using static KitsuneCafe.Extension.R3Extensions; +using TimeUnit = KitsuneCafe.System.TimeUnit; + +namespace KitsuneCafe +{ + public class Timer : MonoBehaviour + { + [SerializeField] + private float duration = 1; + public float Duration + { + get => duration; + set => duration = value; + } + + [SerializeField] + private TimeUnit unit = TimeUnit.Seconds; + public TimeUnit Unit + { + get => unit; + set => unit = value; + } + + [SerializeField] + private PlayerLoopTiming timing = PlayerLoopTiming.Update; + + [SerializeField] + private TimeKind timeKind = TimeKind.Time; + + [SerializeField] + private bool autostart = false; + + [SerializeField] + private bool oneShot = false; + + [SerializeField] + private UnityEvent onComplete = default; + + private readonly ReactiveProperty started = new(false); + private readonly ReactiveProperty paused = new(false); + private Observable stopped => started.Where(KMath.Not).Skip(1); + + public bool Started => started.Value; + public bool Paused => paused.Value; + + public IDisposable source; + + public event EventHandler Completed; + + private void Awake() + { + SubscribeToTimer(); + } + + private void SubscribeToTimer() + { + source?.Dispose(); + + var counting = Observable.Merge( + started.Compose(WhereTrue).Select(_ => true), + paused.Compose(WhereTrue).Select(_ => false) + ); + + var timeProvider = GetTimeProvider(timing, timeKind); + var totalDuration = GetDuration(); + + source = CreateTimer(GetDuration(), counting, timeProvider) + .TakeUntil(stopped) + // add onNext handler if remaining time is required + .Do(onCompleted: OnCompleted) + .Subscribe() + .AddTo(this); + } + + private void Start() + { + if (autostart) + { + StartTimer(); + } + } + + private void OnEnable() + { + if (Started && Paused) + { + Resume(); + } + } + + private void OnDisable() + { + if (Started) + { + Pause(); + } + } + + public void StartTimer() + { + if (source == null) + { + SubscribeToTimer(); + } + + paused.Value = false; + started.Value = true; + } + + public void StopTimer() + { + source?.Dispose(); + source = null; + paused.Value = false; + started.Value = false; + } + + public void Pause() + { + paused.Value = true; + } + + public void Resume() + { + paused.Value = false; + } + + private void OnCompleted(Result result) + { + StopTimer(); + + if (result.IsSuccess) + { + Finish(); + + if (!oneShot) + { + StartTimer(); + } + } + } + + private void Finish() + { + Completed?.Invoke(this, EventArgs.Empty); + onComplete.Invoke(); + } + + private Observable CreateTimer(TimeSpan duration, Observable isCounting, TimeProvider timeProvider) + { + return Observable.Empty() + .SwitchIf(isCounting, Observable.EveryUpdate(timeProvider.GetFrameProvider())) + .Select(_ => DeltaTime(timeProvider)) + .Scan(duration, (acc, dt) => acc.Subtract(dt)) + .TakeWhile(ts => ts > TimeSpan.Zero) + .DefaultIfEmpty(duration); + } + + private Observable WhereTrue(Observable source) + { + return source.WhereTrue().AsUnitObservable(); + } + + private TimeSpan GetDuration() + { + return System.Duration.From(duration, unit); + } + + private TimeSpan DeltaTime(TimeProvider timeProvider) + { + return TimeSpan.FromSeconds(timeProvider.GetDeltaTime()); + } + } +} diff --git a/Assets/Scripts/System/Timer.cs.meta b/Assets/Scripts/System/Timer.cs.meta new file mode 100644 index 0000000..efbcfd9 --- /dev/null +++ b/Assets/Scripts/System/Timer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 1eeeac25dfbfdf4cf8a8d231c5296c00 \ No newline at end of file diff --git a/Assets/Scripts/UI/TestThing.cs b/Assets/Scripts/UI/TestThing.cs index 5a6862d..7ed056b 100644 --- a/Assets/Scripts/UI/TestThing.cs +++ b/Assets/Scripts/UI/TestThing.cs @@ -12,7 +12,7 @@ namespace KitsuneCafe.UI private void Start() { - orchestrator.SpawnElement(modal.Create("Test", "Fuck"), transform.position); + orchestrator.SpawnElement(modal.Create("test", "fuck !!!! :3"), transform.position + Vector3.up); } } }