From 5cc618cb37da88eadb2159c8ac342a24c18c6139 Mon Sep 17 00:00:00 2001 From: nemethi Date: Fri, 20 Nov 2020 06:42:28 +0100 Subject: [PATCH 1/5] Added MultiTagSwitch for be able to iterate over the multi tags given to the specified GameObject. --- .../Logic/MultiTagSwitch.cs | 68 +++++++++++++++++++ .../Logic/MultiTagSwitch.cs.meta | 11 +++ 2 files changed, 79 insertions(+) create mode 100644 Assets/PlayMaker Custom Actions/Logic/MultiTagSwitch.cs create mode 100644 Assets/PlayMaker Custom Actions/Logic/MultiTagSwitch.cs.meta diff --git a/Assets/PlayMaker Custom Actions/Logic/MultiTagSwitch.cs b/Assets/PlayMaker Custom Actions/Logic/MultiTagSwitch.cs new file mode 100644 index 0000000..0ac0da9 --- /dev/null +++ b/Assets/PlayMaker Custom Actions/Logic/MultiTagSwitch.cs @@ -0,0 +1,68 @@ +using UnityEngine; + +namespace HutongGames.PlayMaker.Actions +{ + + [ActionCategory(ActionCategory.Logic)] + [Tooltip("Iterate over the tags on the given gameobject. Defines for each an exit point as a switch flow control statement.")] + public class MultiTagSwitch : FsmStateAction + { + [RequiredField] + [UIHint(UIHint.Variable)] + [Tooltip("The GameObject to be tested.")] + public FsmGameObject gameObject; + + [UIHint(UIHint.Tag)] + [Tooltip("The Tag to check for.")] + [CompoundArray("Tag switches", "Compare Tag", "Send Event")] + public FsmString[] compareTo; + + [Tooltip("On compare success, the event to be sent.")] + public FsmEvent[] sendEvent; + + [Tooltip("Repeat every frame.")] + public bool everyFrame; + + [Tooltip("Store the matching Tag in a String variable.")] + public FsmString storeTag; + + public override void Reset() + { + gameObject = null; + compareTo = new FsmString[1]; + sendEvent = new FsmEvent[1]; + everyFrame = false; + storeTag = null; + } + + // Code that runs on entering the state. + public override void OnEnter() + { + CompareAllTags(); + + if (!everyFrame) + Finish(); + } + + // Code that runs every frame. + public override void OnUpdate() + { + CompareAllTags(); + } + + void CompareAllTags() + { + for (int i=0; i Date: Mon, 22 Feb 2021 06:08:07 +0100 Subject: [PATCH 2/5] New classes for Playmaker --- .../Logic/FloatAndBoolDecision.cs | 102 +++++++++++++++ .../Logic/IntAndBoolDecision.cs | 101 +++++++++++++++ .../StateMachine/MultiFsmEnabler.cs | 73 +++++++++++ .../StateMachine/MultiFsmEnabler.cs.meta | 11 ++ .../Time/TimeDiffCalculator.cs | 44 +++++++ .../Time/TimeDiffCalculator.cs.meta | 11 ++ .../Transform/GearGameObjectsEachOther.cs | 116 ++++++++++++++++++ 7 files changed, 458 insertions(+) create mode 100644 Assets/PlayMaker Custom Actions/Logic/FloatAndBoolDecision.cs create mode 100644 Assets/PlayMaker Custom Actions/Logic/IntAndBoolDecision.cs create mode 100644 Assets/PlayMaker Custom Actions/StateMachine/MultiFsmEnabler.cs create mode 100644 Assets/PlayMaker Custom Actions/StateMachine/MultiFsmEnabler.cs.meta create mode 100644 Assets/PlayMaker Custom Actions/Time/TimeDiffCalculator.cs create mode 100644 Assets/PlayMaker Custom Actions/Time/TimeDiffCalculator.cs.meta create mode 100644 Assets/PlayMaker Custom Actions/Transform/GearGameObjectsEachOther.cs diff --git a/Assets/PlayMaker Custom Actions/Logic/FloatAndBoolDecision.cs b/Assets/PlayMaker Custom Actions/Logic/FloatAndBoolDecision.cs new file mode 100644 index 0000000..ecc660f --- /dev/null +++ b/Assets/PlayMaker Custom Actions/Logic/FloatAndBoolDecision.cs @@ -0,0 +1,102 @@ +using System; + +namespace HutongGames.PlayMaker.Actions +{ + [ActionCategory(ActionCategory.Logic)] + [Tooltip("Make decision by accepting multiple data types. Returns a bool.")] + public class FloatAndBoolDecision : FsmStateAction + { + public enum Operation + { + Greater, + Lower, + Equals, + GreaterThenEquals, + LowerThenEquals + } + + [RequiredField] [UIHint(UIHint.Variable)] [Tooltip("The float variable should be tested.")] + public FsmFloat targetFloat; + + [RequiredField] [UIHint(UIHint.Variable)] [Tooltip("The tester float variable.")] + public FsmFloat testerFloat; + + [RequiredField] [Tooltip("Operation which is used between the target and tester.")] + public Operation operation = Operation.Equals; + + [RequiredField] + [UIHint(UIHint.Variable)] + [Tooltip("Boolean to be tested, which is used with short circuit and statement.")] + public FsmBool targetBool; + + [Tooltip("Event to send if the Bool variable is True.")] + public FsmEvent isTrue; + + [Tooltip("Event to send if the Bool variable is False.")] + public FsmEvent isFalse; + + public bool everyFrame; + + // Code that runs on entering the state. + public override void OnEnter() + { + Fsm.Event(areTheyTrue().Value ? isTrue : isFalse); + + if (!everyFrame) + Finish(); + } + + // Code that runs every frame. + public override void OnUpdate() + { + Fsm.Event(areTheyTrue().Value ? isTrue : isFalse); + } + + public override void Reset() + { + targetFloat = null; + testerFloat = null; + targetBool = false; + isTrue = null; + isFalse = null; + everyFrame = false; + } + + // Perform custom error checking here. + public override string ErrorCheck() + { + return null; + } + + + private FsmBool areTheyTrue() + { + FsmBool result = new FsmBool(); + + switch (operation) + { + case Operation.Equals: + result = targetFloat.Value.Equals(testerFloat.Value) && targetBool.Value; + break; + + case Operation.Greater: + result = targetFloat.Value > testerFloat.Value && targetBool.Value; + break; + + case Operation.Lower: + result = targetFloat.Value < testerFloat.Value && targetBool.Value; + break; + + case Operation.GreaterThenEquals: + result = targetFloat.Value >= testerFloat.Value && targetBool.Value; + break; + + case Operation.LowerThenEquals: + result = targetFloat.Value <= testerFloat.Value && targetBool.Value; + break; + } + + return result; + } + } +} \ No newline at end of file diff --git a/Assets/PlayMaker Custom Actions/Logic/IntAndBoolDecision.cs b/Assets/PlayMaker Custom Actions/Logic/IntAndBoolDecision.cs new file mode 100644 index 0000000..66f92ab --- /dev/null +++ b/Assets/PlayMaker Custom Actions/Logic/IntAndBoolDecision.cs @@ -0,0 +1,101 @@ +namespace HutongGames.PlayMaker.Actions +{ + + [ActionCategory(ActionCategory.Logic)] + [Tooltip("Make decision by accepting multiple data types. Returns a bool.")] + public class IntAndBoolDecision: FsmStateAction + { + public enum Operation + { + Greater, + Lower, + Equals, + GreaterThenEquals, + LowerThenEquals + } + + [RequiredField] [UIHint(UIHint.Variable)] [Tooltip("The float variable should be tested.")] + public FsmInt targetVariable; + + [RequiredField] [Tooltip("The tester float variable.")] + public FsmInt testerVariable; + + [RequiredField] [Tooltip("Operation which is used between the target and tester.")] + public Operation operation = Operation.Equals; + + [RequiredField] + [UIHint(UIHint.Variable)] + [Tooltip("Boolean to be tested, which is used with short circuit and statement.")] + public FsmBool targetBool; + + [Tooltip("Event to send if the Bool variable is True.")] + public FsmEvent isTrue; + + [Tooltip("Event to send if the Bool variable is False.")] + public FsmEvent isFalse; + + public bool everyFrame; + + // Code that runs on entering the state. + public override void OnEnter() + { + Fsm.Event(areTheyTrue().Value ? isTrue : isFalse); + + if (!everyFrame) + Finish(); + } + + // Code that runs every frame. + public override void OnUpdate() + { + Fsm.Event(areTheyTrue().Value ? isTrue : isFalse); + } + + public override void Reset() + { + targetVariable = null; + testerVariable = null; + targetBool = false; + isTrue = null; + isFalse = null; + everyFrame = false; + } + + // Perform custom error checking here. + public override string ErrorCheck() + { + return null; + } + + + private FsmBool areTheyTrue() + { + FsmBool result = new FsmBool(); + + switch (operation) + { + case Operation.Equals: + result = targetVariable.Value.Equals(testerVariable.Value) && targetBool.Value; + break; + + case Operation.Greater: + result = targetVariable.Value > testerVariable.Value && targetBool.Value; + break; + + case Operation.Lower: + result = targetVariable.Value < testerVariable.Value && targetBool.Value; + break; + + case Operation.GreaterThenEquals: + result = targetVariable.Value >= testerVariable.Value && targetBool.Value; + break; + + case Operation.LowerThenEquals: + result = targetVariable.Value <= testerVariable.Value && targetBool.Value; + break; + } + + return result; + } + } +} \ No newline at end of file diff --git a/Assets/PlayMaker Custom Actions/StateMachine/MultiFsmEnabler.cs b/Assets/PlayMaker Custom Actions/StateMachine/MultiFsmEnabler.cs new file mode 100644 index 0000000..fb23977 --- /dev/null +++ b/Assets/PlayMaker Custom Actions/StateMachine/MultiFsmEnabler.cs @@ -0,0 +1,73 @@ +using UnityEngine; + +namespace HutongGames.PlayMaker.Actions +{ + + [ActionCategory(ActionCategory.StateMachine)] + [Tooltip("Accepts a list of fsm names, the gameobject contains the specified fsms and the corresponding bools -> fsms to be enabled or not.")] + public class MultiFsmEnabler : FsmStateAction + { + + [RequiredField] + [Tooltip("The GameObject which contains the defined fsms.")] + public FsmOwnerDefault gameObject; + + [Tooltip("List of FSMs to be enabled/disabled.")] + public FsmString[] fsmNames; + + [Tooltip("Turn all of the defined fsms to enabled/disabled.")] + public FsmBool toBeEnabled; + + private PlayMakerFSM fsmComponent; + + public override void Reset() + { + gameObject = null; + fsmNames = null; + toBeEnabled = null; + } + + // Code that runs on entering the state. + public override void OnEnter() + { + DoEnableFSM(); + + Finish(); + } + + void DoEnableFSM() + { + GameObject go = gameObject.OwnerOption == OwnerDefaultOption.UseOwner ? Owner : gameObject.GameObject.Value; + + if (go == null) return; + + foreach (var currFsmName in fsmNames) + { + string fsmName = currFsmName.Value; + if (!string.IsNullOrEmpty(fsmName)) + { + var fsmComponents = go.GetComponents(); + foreach (var component in fsmComponents) + { + if (component.FsmName.Equals(fsmName)) + { + fsmComponent = component; + break; + } + } + } + else + { + fsmComponent = go.GetComponent(); + } + + if (fsmComponent == null) + { + return; + } + + fsmComponent.enabled = toBeEnabled.Value; + } + } + } +} diff --git a/Assets/PlayMaker Custom Actions/StateMachine/MultiFsmEnabler.cs.meta b/Assets/PlayMaker Custom Actions/StateMachine/MultiFsmEnabler.cs.meta new file mode 100644 index 0000000..714c736 --- /dev/null +++ b/Assets/PlayMaker Custom Actions/StateMachine/MultiFsmEnabler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 52e9ceaa2851ed044bd7c72ea10ff3fe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/PlayMaker Custom Actions/Time/TimeDiffCalculator.cs b/Assets/PlayMaker Custom Actions/Time/TimeDiffCalculator.cs new file mode 100644 index 0000000..9bfa754 --- /dev/null +++ b/Assets/PlayMaker Custom Actions/Time/TimeDiffCalculator.cs @@ -0,0 +1,44 @@ +using System; +using UnityEngine; + +namespace HutongGames.PlayMaker.Actions +{ + [ActionCategory(ActionCategory.Time)] + [Tooltip("Compares two time values (given in String datatype in HH:mm:ss format) and gives back its difference converted into Float datatype.")] + public class TimeDiffCalculator : FsmStateAction + { + [Tooltip("Starting time")] + public FsmString StartTime; + + [Tooltip("Ending time")] + public FsmString EndTime; + + [Tooltip("The difference of ending time subtracting starting time, stored in seconds (float datatype).")] + public FsmFloat Result; + + public override void OnEnter() + { + if (FsmString.IsNullOrEmpty(StartTime)) + { + if (FsmString.IsNullOrEmpty(EndTime)) + { + var start = DateTime.Parse(StartTime.ToString()); + var end = DateTime.Parse(EndTime.ToString()); + + Debug.Log("start is " + start + " and end is " + end); + + Result = end.Subtract(start).Seconds; + Debug.Log("Result is " + Result); + } + } + Finish(); + } + + public override void Reset() + { + StartTime = string.Empty; + EndTime = string.Empty; + Result = float.NaN; + } + } +} diff --git a/Assets/PlayMaker Custom Actions/Time/TimeDiffCalculator.cs.meta b/Assets/PlayMaker Custom Actions/Time/TimeDiffCalculator.cs.meta new file mode 100644 index 0000000..5e5a6fe --- /dev/null +++ b/Assets/PlayMaker Custom Actions/Time/TimeDiffCalculator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e32bc1633b6c08a4296ce4b89d26b3a8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/PlayMaker Custom Actions/Transform/GearGameObjectsEachOther.cs b/Assets/PlayMaker Custom Actions/Transform/GearGameObjectsEachOther.cs new file mode 100644 index 0000000..e5d27aa --- /dev/null +++ b/Assets/PlayMaker Custom Actions/Transform/GearGameObjectsEachOther.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections; +using UnityEngine; + +namespace HutongGames.PlayMaker.Actions +{ + /* + * This Action is useful if the target gameobject is looking in the Z axis direction. + */ + [ActionCategory(ActionCategory.Transform)] + [Tooltip("Gears two gameobjects to each other, using by their 'Y' rotation. ")] + public class GearGameObjectsEachOther : FsmStateAction + { + private const float ONE_CIRCLE = 360; + private const float RIGHT_ANGLE = 90; + + private static ILogger LOGGER = Debug.unityLogger; + private static string loggerName = "GearGameObjectsEachOther"; + + [RequiredField] + [UIHint(UIHint.Variable)] + [Tooltip("Base GameObject which 'Y' rotation's value is taken as base value.")] + public FsmGameObject baseGameObject; + + [RequiredField] + [Tooltip("Target GameObject which 'Y' rotation's value equals with base gameobject's Y rotation value.")] + public FsmOwnerDefault targetGameObject; + + [RequiredField] + [UIHint(UIHint.Variable)] + [Tooltip( + "Turning speed of the target gameobject. How much time will the target game object will before it takes the next turning portion. Negative value will be turned to its absolute value.")] + public FsmFloat turningSpeed; + + [RequiredField] + [UIHint(UIHint.Variable)] + [Tooltip("Turning degree of the target gameobject. How much value will be added to the previous rotation value? Negative value will be turned to its absolute value.")] + public FsmFloat turningDegree; + + + public override void Reset() + { + baseGameObject = null; + targetGameObject = null; + turningSpeed = null; + turningDegree = null; + } + + public override void OnEnter() + { + gearEachOther(); + + } + + void gearEachOther() + { + LOGGER.Log(loggerName, "Base game object's transform.rotation is " + baseGameObject.Value.transform.rotation); + + float base_Y = Mathf.Ceil(baseGameObject.Value.transform.rotation.y); + + switch (Math.Sign(base_Y)) + { + case -1: + negativeBranch(); + break; + + case 0: + zeroBranch(); + break; + + case 1: + positiveBranch(base_Y); + break; + } + } + + private void positiveBranch(float base_Y) + { + int rounds = (int) (base_Y / ONE_CIRCLE); + + float baseNormalisedYRotation = base_Y - (ONE_CIRCLE * rounds) + RIGHT_ANGLE; + + Quaternion targetQuaternion = Fsm.GetOwnerDefaultTarget(targetGameObject).gameObject.transform.rotation; + + float x = Mathf.Ceil(targetQuaternion.x); + float z = Mathf.Ceil(targetQuaternion.z); + + float targetRotationToBe = baseNormalisedYRotation - Mathf.Ceil(targetQuaternion.y); + + float targetY = 0.0f; + for (float k = 0; k < targetRotationToBe; k = (k + Math.Abs(turningDegree.Value))) + { + targetY = targetY + targetQuaternion.y + k; + StartCoroutine(wait(x, targetY, z)); + } + LOGGER.Log(loggerName, "time after iteration is " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.SS")); + } + + private void zeroBranch() + { + throw new NotImplementedException(); + } + + private void negativeBranch() + { + throw new NotImplementedException(); + } + + + private IEnumerator wait(float x, float y, float z) + { + yield return new WaitForSecondsRealtime(Math.Abs(turningSpeed.Value)); + Fsm.GetOwnerDefaultTarget(targetGameObject).gameObject.transform.rotation = Quaternion.Euler(x, y, z); + } + } +} \ No newline at end of file From 2afb6d32d6816aa384d5be84905f43a35bb94298 Mon Sep 17 00:00:00 2001 From: Istvan Nemeth Date: Mon, 22 Feb 2021 06:27:41 +0100 Subject: [PATCH 3/5] Some more extension. --- .../Logic/IntAndFloatAndBoolDecision.cs | 111 ++++++++++++++++++ .../Logic/IntAndFloatAndBoolDecision.cs.meta | 3 + 2 files changed, 114 insertions(+) create mode 100644 Assets/PlayMaker Custom Actions/Logic/IntAndFloatAndBoolDecision.cs create mode 100644 Assets/PlayMaker Custom Actions/Logic/IntAndFloatAndBoolDecision.cs.meta diff --git a/Assets/PlayMaker Custom Actions/Logic/IntAndFloatAndBoolDecision.cs b/Assets/PlayMaker Custom Actions/Logic/IntAndFloatAndBoolDecision.cs new file mode 100644 index 0000000..8e5d7bb --- /dev/null +++ b/Assets/PlayMaker Custom Actions/Logic/IntAndFloatAndBoolDecision.cs @@ -0,0 +1,111 @@ +using static HutongGames.PlayMaker.Actions.FloatAndBoolDecision; + +namespace HutongGames.PlayMaker.Actions.Logic +{ + + /// + /// Author is Istvan Nemeth. + /// + [ActionCategory(ActionCategory.Logic)] + [Tooltip("Make decision by accepting multiple data types. Returns a bool.")] + public class IntAndFloatAndBoolDecision : FsmStateAction + { + [RequiredField] [UIHint(UIHint.Variable)] [Tooltip("The int variable should be tested.")] + public FsmInt targetInt; + + [RequiredField] [UIHint(UIHint.Variable)] [Tooltip("The tester int variable.")] + public FsmInt testerInt; + + [RequiredField] + [Tooltip("Operation which is used between the target and tester.")] + public Operation intOperation = Operation.Equals; + + [RequiredField] [UIHint(UIHint.Variable)] [Tooltip("The float variable should be tested.")] + public FsmFloat targetFloat; + + [RequiredField] [UIHint(UIHint.Variable)] [Tooltip("The tester float variable.")] + public FsmFloat testerFloat; + + [RequiredField] + [Tooltip("Operation which is used between the target and tester.")] + public Operation floatOperation = Operation.Equals; + + [RequiredField] + [UIHint(UIHint.Variable)] + [Tooltip("Boolean to be tested, which is used with short circuit and statement.")] + public FsmBool targetBool; + + [Tooltip("Event to send if the Bool variable is True.")] + public FsmEvent isTrue; + + [Tooltip("Event to send if the Bool variable is False.")] + public FsmEvent isFalse; + + public bool everyFrame; + + // Code that runs on entering the state. + public override void OnEnter() + { + Fsm.Event(areTheyTrue().Value ? isTrue : isFalse); + + if (!everyFrame) + Finish(); + } + + // Code that runs every frame. + public override void OnUpdate() + { + Fsm.Event(areTheyTrue().Value ? isTrue : isFalse); + } + + public override void Reset() + { + targetFloat = null; + testerFloat = null; + targetBool = false; + isTrue = null; + isFalse = null; + everyFrame = false; + } + + private FsmBool areTheyTrue() + { + FsmBool result = new FsmBool(); + + if (intOperation == Operation.Equals) + { + result = targetInt.Value.Equals(testerInt.Value); + if (floatOperation == Operation.Equals) + { + result = result.Value && targetFloat.Value.Equals(testerFloat.Value) && targetBool.Value; + } + } + + + switch (floatOperation) + { + case Operation.Equals: + result = targetFloat.Value.Equals(testerFloat.Value) && targetBool.Value; + break; + + case Operation.Greater: + result = targetFloat.Value > testerFloat.Value && targetBool.Value; + break; + + case Operation.Lower: + result = targetFloat.Value < testerFloat.Value && targetBool.Value; + break; + + case Operation.GreaterThenEquals: + result = targetFloat.Value >= testerFloat.Value && targetBool.Value; + break; + + case Operation.LowerThenEquals: + result = targetFloat.Value <= testerFloat.Value && targetBool.Value; + break; + } + + return result; + } + } +} \ No newline at end of file diff --git a/Assets/PlayMaker Custom Actions/Logic/IntAndFloatAndBoolDecision.cs.meta b/Assets/PlayMaker Custom Actions/Logic/IntAndFloatAndBoolDecision.cs.meta new file mode 100644 index 0000000..93ba7ec --- /dev/null +++ b/Assets/PlayMaker Custom Actions/Logic/IntAndFloatAndBoolDecision.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 55403f4e06ef4d7b8cca6843fba1ad10 +timeCreated: 1613971230 \ No newline at end of file From 6de346ec81b52bcc1efd761b0ac88a82e4f229c6 Mon Sep 17 00:00:00 2001 From: Istvan Nemeth Date: Mon, 1 Mar 2021 06:31:55 +0100 Subject: [PATCH 4/5] Some completion - Gear game object - Turn towards --- .../StateMachine/MultiFsmEnabler.cs | 132 ++++++++--------- .../Transform/GearGameObjectsEachOther.cs | 135 +++++++++--------- .../Transform/TurnTowardsGameObject.cs | 128 +++++++++++++++++ .../Transform/TurnTowardsGameObject.cs.meta | 3 + 4 files changed, 269 insertions(+), 129 deletions(-) create mode 100644 Assets/PlayMaker Custom Actions/Transform/TurnTowardsGameObject.cs create mode 100644 Assets/PlayMaker Custom Actions/Transform/TurnTowardsGameObject.cs.meta diff --git a/Assets/PlayMaker Custom Actions/StateMachine/MultiFsmEnabler.cs b/Assets/PlayMaker Custom Actions/StateMachine/MultiFsmEnabler.cs index fb23977..131ba07 100644 --- a/Assets/PlayMaker Custom Actions/StateMachine/MultiFsmEnabler.cs +++ b/Assets/PlayMaker Custom Actions/StateMachine/MultiFsmEnabler.cs @@ -1,73 +1,75 @@ -using UnityEngine; - namespace HutongGames.PlayMaker.Actions { + /// + /// Author is Istvan Nemeth. + /// + [ActionCategory(ActionCategory.StateMachine)] + [Tooltip( + "Accepts a list of fsm names, the gameobject contains the specified fsms and the corresponding bools -> fsms to be enabled or not.")] + public class MultiFsmEnabler : FsmStateAction + { + [RequiredField] [Tooltip("The GameObject which contains the defined fsms.")] + public FsmOwnerDefault FsmGameObject; + + [Tooltip("List of FSMs to be enabled/disabled.")] + [CompoundArray("Tag switches", "Fsm Name", "Enable/Disable")] + public FsmString[] FsmNames; + + [Tooltip("Turn all of the defined fsms to enabled/disabled.")] + public FsmBool[] ToBeEnabled; + + private PlayMakerFSM _fsmComponent; + + public override void Reset() + { + FsmGameObject = null; + FsmNames = null; + ToBeEnabled = null; + } - [ActionCategory(ActionCategory.StateMachine)] - [Tooltip("Accepts a list of fsm names, the gameobject contains the specified fsms and the corresponding bools -> fsms to be enabled or not.")] - public class MultiFsmEnabler : FsmStateAction - { - - [RequiredField] - [Tooltip("The GameObject which contains the defined fsms.")] - public FsmOwnerDefault gameObject; + // Code that runs on entering the state. + public override void OnEnter() + { + DoEnableFsm(); - [Tooltip("List of FSMs to be enabled/disabled.")] - public FsmString[] fsmNames; - - [Tooltip("Turn all of the defined fsms to enabled/disabled.")] - public FsmBool toBeEnabled; - - private PlayMakerFSM fsmComponent; - - public override void Reset() - { - gameObject = null; - fsmNames = null; - toBeEnabled = null; - } + Finish(); + } - // Code that runs on entering the state. - public override void OnEnter() - { - DoEnableFSM(); + private void DoEnableFsm() + { + var ownerGameObject = FsmGameObject.OwnerOption == OwnerDefaultOption.UseOwner + ? Owner + : FsmGameObject.GameObject.Value; + + if (ownerGameObject == null) return; - Finish(); - } - - void DoEnableFSM() - { - GameObject go = gameObject.OwnerOption == OwnerDefaultOption.UseOwner ? Owner : gameObject.GameObject.Value; + var i = 0; + foreach (var currentFsmName in FsmNames) + { + var fsmName = currentFsmName.Value; + if (!string.IsNullOrEmpty(fsmName)) + { + var fsmComponents = ownerGameObject.GetComponents(); + foreach (var component in fsmComponents) + { + if (component.FsmName.Equals(fsmName)) + { + _fsmComponent = component; + _fsmComponent.enabled = ToBeEnabled[i].Value; + break; + } + } + } + else + { + _fsmComponent = ownerGameObject.GetComponent(); + } - if (go == null) return; + + if (_fsmComponent == null) return; - foreach (var currFsmName in fsmNames) - { - string fsmName = currFsmName.Value; - if (!string.IsNullOrEmpty(fsmName)) - { - var fsmComponents = go.GetComponents(); - foreach (var component in fsmComponents) - { - if (component.FsmName.Equals(fsmName)) - { - fsmComponent = component; - break; - } - } - } - else - { - fsmComponent = go.GetComponent(); - } - - if (fsmComponent == null) - { - return; - } - - fsmComponent.enabled = toBeEnabled.Value; - } - } - } -} + i++; + } + } + } +} \ No newline at end of file diff --git a/Assets/PlayMaker Custom Actions/Transform/GearGameObjectsEachOther.cs b/Assets/PlayMaker Custom Actions/Transform/GearGameObjectsEachOther.cs index e5d27aa..78a3684 100644 --- a/Assets/PlayMaker Custom Actions/Transform/GearGameObjectsEachOther.cs +++ b/Assets/PlayMaker Custom Actions/Transform/GearGameObjectsEachOther.cs @@ -8,109 +8,116 @@ namespace HutongGames.PlayMaker.Actions * This Action is useful if the target gameobject is looking in the Z axis direction. */ [ActionCategory(ActionCategory.Transform)] - [Tooltip("Gears two gameobjects to each other, using by their 'Y' rotation. ")] + [Tooltip("Gears two gameobjects to each other, using by their 'Y' rotation. This Action is useful if the target gameobject is looking in the Z axis direction.")] public class GearGameObjectsEachOther : FsmStateAction { - private const float ONE_CIRCLE = 360; - private const float RIGHT_ANGLE = 90; - - private static ILogger LOGGER = Debug.unityLogger; - private static string loggerName = "GearGameObjectsEachOther"; + private const float OneCircleConst = 360; + private const float RightAngleConst = 90; + + private const string RightConst = "Right"; [RequiredField] [UIHint(UIHint.Variable)] [Tooltip("Base GameObject which 'Y' rotation's value is taken as base value.")] - public FsmGameObject baseGameObject; + public FsmGameObject BaseGameObject; [RequiredField] [Tooltip("Target GameObject which 'Y' rotation's value equals with base gameobject's Y rotation value.")] - public FsmOwnerDefault targetGameObject; + public FsmOwnerDefault TargetGameObject; [RequiredField] [UIHint(UIHint.Variable)] - [Tooltip( - "Turning speed of the target gameobject. How much time will the target game object will before it takes the next turning portion. Negative value will be turned to its absolute value.")] - public FsmFloat turningSpeed; + [Tooltip("Turning speed of the target gameobject. How much time will the target game object will before it takes the next turning portion. Negative value will be turned to its absolute value.")] + public FsmFloat TurningSpeed; [RequiredField] [UIHint(UIHint.Variable)] [Tooltip("Turning degree of the target gameobject. How much value will be added to the previous rotation value? Negative value will be turned to its absolute value.")] - public FsmFloat turningDegree; - + public FsmFloat TurningDegree; public override void Reset() { - baseGameObject = null; - targetGameObject = null; - turningSpeed = null; - turningDegree = null; + BaseGameObject = null; + TargetGameObject = null; + TurningSpeed = null; + TurningDegree = null; } public override void OnEnter() { - gearEachOther(); - + if(GearEachOther()) + Fsm.Event(FsmEvent.Finished); } - void gearEachOther() + private bool GearEachOther() { - LOGGER.Log(loggerName, "Base game object's transform.rotation is " + baseGameObject.Value.transform.rotation); + var targetGameObjectVector = Fsm.GetOwnerDefaultTarget(TargetGameObject).gameObject.transform.eulerAngles; + + var baseGameObjectVector = BaseGameObject.Value.transform.eulerAngles; + + var baseGameObjectY = baseGameObjectVector.y; - float base_Y = Mathf.Ceil(baseGameObject.Value.transform.rotation.y); + if (BaseGameObject.Value.HasTag(RightConst)) + baseGameObjectY -= OneCircleConst; - switch (Math.Sign(base_Y)) - { - case -1: - negativeBranch(); - break; + StartCoroutine(TurnTargetToBaseYRotation(NormalisedYRotation(baseGameObjectY), targetGameObjectVector)); - case 0: - zeroBranch(); - break; + return baseGameObjectY.Equals(targetGameObjectVector.y); + } - case 1: - positiveBranch(base_Y); - break; + private float NormalisedYRotation(float baseY) + { + if (baseY >= OneCircleConst) + { + return baseY - (OneCircleConst * ((int) (baseY / OneCircleConst))); } + return baseY; } - private void positiveBranch(float base_Y) + private IEnumerator TurnTargetToBaseYRotation(float baseY, Vector3 target) { - int rounds = (int) (base_Y / ONE_CIRCLE); + var x = target.x; + var z = target.z; - float baseNormalisedYRotation = base_Y - (ONE_CIRCLE * rounds) + RIGHT_ANGLE; - - Quaternion targetQuaternion = Fsm.GetOwnerDefaultTarget(targetGameObject).gameObject.transform.rotation; - - float x = Mathf.Ceil(targetQuaternion.x); - float z = Mathf.Ceil(targetQuaternion.z); - - float targetRotationToBe = baseNormalisedYRotation - Mathf.Ceil(targetQuaternion.y); + float targetRotationToBe; + float targetY = NormalisedYRotation(target.y); - float targetY = 0.0f; - for (float k = 0; k < targetRotationToBe; k = (k + Math.Abs(turningDegree.Value))) + switch (Math.Sign(baseY)) { - targetY = targetY + targetQuaternion.y + k; - StartCoroutine(wait(x, targetY, z)); - } - LOGGER.Log(loggerName, "time after iteration is " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.SS")); - } + // NEGATIVE CASE + case -1: - private void zeroBranch() - { - throw new NotImplementedException(); - } + targetRotationToBe = baseY - RightAngleConst; - private void negativeBranch() - { - throw new NotImplementedException(); - } - - - private IEnumerator wait(float x, float y, float z) - { - yield return new WaitForSecondsRealtime(Math.Abs(turningSpeed.Value)); - Fsm.GetOwnerDefaultTarget(targetGameObject).gameObject.transform.rotation = Quaternion.Euler(x, y, z); + for (float k = 0; k > targetRotationToBe; k = (k - Math.Abs(TurningDegree.Value))) + { + var y = Mathf.Abs(targetY - k) * -1; + + Fsm.GetOwnerDefaultTarget(TargetGameObject).gameObject.transform.eulerAngles = + new Vector3(x, y, z); + //Quaternion.Euler(x, y, z); + yield return new WaitForSeconds(Math.Abs(TurningSpeed.Value)); + } + + break; + + case 0: + break; + + + // POSITIVE CASE + case 1: + targetRotationToBe = baseY + RightAngleConst; + + for (float k = 0; k < targetRotationToBe; k = (k + Math.Abs(TurningDegree.Value))) + { + Fsm.GetOwnerDefaultTarget(TargetGameObject).gameObject.transform.rotation = + Quaternion.Euler(x, (targetY + k), z); + yield return new WaitForSeconds(Math.Abs(TurningSpeed.Value)); + } + + break; + } } } } \ No newline at end of file diff --git a/Assets/PlayMaker Custom Actions/Transform/TurnTowardsGameObject.cs b/Assets/PlayMaker Custom Actions/Transform/TurnTowardsGameObject.cs new file mode 100644 index 0000000..fc6e431 --- /dev/null +++ b/Assets/PlayMaker Custom Actions/Transform/TurnTowardsGameObject.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace HutongGames.PlayMaker.Actions +{ + /// + /// Author is Istvan Nemeth. + /// + public class TurnTowardsGameObject: FsmStateAction + { + private const float HalfCircle = 180; + private const float WholeCircle = 360; + + [RequiredField] + [Tooltip("The gameobject what will be rotated toward the target gameobject.")] + public FsmOwnerDefault Myself; + + [RequiredField] + [UIHint(UIHint.FsmGameObject)] + [Tooltip( + "Target gameobject, where I will turn. So my Z axis will points towards the target gameobject's Z direct.")] + public FsmGameObject TargetGameObject; + + [RequiredField] + [UIHint(UIHint.Variable)] + [Tooltip("Turning speed of the target gameobject." + + " How much time will the target game object will before it takes the next turning portion." + + " Negative value will be turned to its absolute value.")] + public FsmFloat TurningSpeed; + + [RequiredField] + [UIHint(UIHint.Variable)] + [Tooltip( + "Turning degree of the target gameobject." + + " How much value will be added to the previous rotation value?" + + " Negative value will be turned to its absolute value.")] + public FsmFloat TurningDegree; + + [UIHint(UIHint.Variable)] public FsmFloat yAngle; + + private Vector3 _rotation; + + + public override void Reset() + { + TargetGameObject = null; + TurningSpeed = null; + TurningDegree = null; + } + + public override void OnEnter() + { + var turnDegree = ChangeSign(TurningDegree.Value); + TurningDegree.Value = turnDegree; + + var turnSpeed = ChangeSign(TurningSpeed.Value); + TurningSpeed.Value = turnSpeed; + + var targetObject = TargetGameObject.Value; + var myself = Fsm.GetOwnerDefaultTarget(Myself); + + if (null == targetObject) + return; + + if (null == myself) + return; + + if (!yAngle.IsNone) + StartCoroutine(TurnVehicleTowardsTarget(myself, targetObject, turnDegree, turnSpeed)); + + //Fsm.Event(FsmEvent.Finished); + } + + private float ChangeSign(float toBeChanged) + { + return Math.Sign(toBeChanged) == -1 ? toBeChanged *= -1 : toBeChanged; + } + private IEnumerator TurnVehicleTowardsTarget(GameObject myself, GameObject target, float degree, float speed) + { + _rotation = myself.transform.localEulerAngles; + + var x = _rotation.x; + var z = _rotation.z; + var mySignedCurrYRot = SignedCurrentYRotation(_rotation.y); + + switch (Math.Sign(mySignedCurrYRot)) + { + case -1: + for (var i = 0f; i < mySignedCurrYRot; i = (i + Math.Abs(degree))) + { + yield return SetMyAngles(myself, speed, x, i, z); + } + break; + + // if mySignedCurrYRot = 120; + case 1: + for (var i = mySignedCurrYRot; i > 0; i = (i - Math.Abs(degree))) + { + yield return SetMyAngles(myself, speed, x, i, z); + } + break; + + case 0: break; + } + } + private static object SetMyAngles(GameObject myself, float speed, float x, float y, float z) + { + myself.transform.eulerAngles = new Vector3(x, y, z); + return new WaitForSeconds(Math.Abs(speed)); + } + private static float SignedCurrentYRotation(float y) + { + float myCurrentYRotation; + if (y > HalfCircle) + { + myCurrentYRotation = -(WholeCircle - y); + } + else + { + myCurrentYRotation = y; + } + + return myCurrentYRotation; + } + } +} \ No newline at end of file diff --git a/Assets/PlayMaker Custom Actions/Transform/TurnTowardsGameObject.cs.meta b/Assets/PlayMaker Custom Actions/Transform/TurnTowardsGameObject.cs.meta new file mode 100644 index 0000000..282d637 --- /dev/null +++ b/Assets/PlayMaker Custom Actions/Transform/TurnTowardsGameObject.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 19bec6a4ac264b198edfaed22539b10f +timeCreated: 1614574461 \ No newline at end of file From 5c3d5f8d13430b92edcb60c48808f83ee2e4dee2 Mon Sep 17 00:00:00 2001 From: Istvan Nemeth Date: Thu, 5 Aug 2021 05:47:10 +0200 Subject: [PATCH 5/5] Added some extra functionality especially in Logic and Time sections. --- .../Logic/TimeDiffCalculator.cs | 44 +++++++++++++++++++ .../Logic/TimeDiffCalculator.cs.meta | 11 +++++ 2 files changed, 55 insertions(+) create mode 100644 Assets/PlayMaker Custom Actions/Logic/TimeDiffCalculator.cs create mode 100644 Assets/PlayMaker Custom Actions/Logic/TimeDiffCalculator.cs.meta diff --git a/Assets/PlayMaker Custom Actions/Logic/TimeDiffCalculator.cs b/Assets/PlayMaker Custom Actions/Logic/TimeDiffCalculator.cs new file mode 100644 index 0000000..9bfa754 --- /dev/null +++ b/Assets/PlayMaker Custom Actions/Logic/TimeDiffCalculator.cs @@ -0,0 +1,44 @@ +using System; +using UnityEngine; + +namespace HutongGames.PlayMaker.Actions +{ + [ActionCategory(ActionCategory.Time)] + [Tooltip("Compares two time values (given in String datatype in HH:mm:ss format) and gives back its difference converted into Float datatype.")] + public class TimeDiffCalculator : FsmStateAction + { + [Tooltip("Starting time")] + public FsmString StartTime; + + [Tooltip("Ending time")] + public FsmString EndTime; + + [Tooltip("The difference of ending time subtracting starting time, stored in seconds (float datatype).")] + public FsmFloat Result; + + public override void OnEnter() + { + if (FsmString.IsNullOrEmpty(StartTime)) + { + if (FsmString.IsNullOrEmpty(EndTime)) + { + var start = DateTime.Parse(StartTime.ToString()); + var end = DateTime.Parse(EndTime.ToString()); + + Debug.Log("start is " + start + " and end is " + end); + + Result = end.Subtract(start).Seconds; + Debug.Log("Result is " + Result); + } + } + Finish(); + } + + public override void Reset() + { + StartTime = string.Empty; + EndTime = string.Empty; + Result = float.NaN; + } + } +} diff --git a/Assets/PlayMaker Custom Actions/Logic/TimeDiffCalculator.cs.meta b/Assets/PlayMaker Custom Actions/Logic/TimeDiffCalculator.cs.meta new file mode 100644 index 0000000..bd67fc2 --- /dev/null +++ b/Assets/PlayMaker Custom Actions/Logic/TimeDiffCalculator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cea88560d5cc698428c0ba7215ce8d6a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: