playMaker

Author Topic: Turning a script into an action  (Read 2992 times)

troubleMaker

  • Playmaker Newbie
  • *
  • Posts: 25
Turning a script into an action
« on: February 16, 2015, 04:07:19 PM »
Hi, i need to test if a target object is on the left or right side of the forward axis of my fsm object. I found this super handy script on the internet that does just that, and now i'm kind of clumsily using set and get property on the script. I want to turn it into an action, but since i don't really understand the script i'm not sure how. The biggest issue for me is that part of the script seems to be outside of Update. I don't understand why, please help  :)

Here's the script:


Code: [Select]
using UnityEngine;
using System.Collections;


public class sidetest : MonoBehaviour {
public Transform target;
public float dirNum;


void Update () {
Vector3 heading = target.position - transform.position;
dirNum = AngleDir(transform.forward, heading, transform.up);
}


float AngleDir(Vector3 fwd, Vector3 targetDir, Vector3 up) {
Vector3 perp = Vector3.Cross(fwd, targetDir);
float dir = Vector3.Dot(perp, up);

if (dir > 0f) {
return 1f;
} else if (dir < 0f) {
return -1f;
} else {
return 0f;
}
}

}

Here's my attempt at the action:

Code: [Select]
// (c) Copyright HutongGames, LLC 2010-2013. All rights reserved.

using UnityEngine;

namespace HutongGames.PlayMaker.Actions
{
[ActionCategory(ActionCategory.Math)]
[Tooltip("Adds a value to a Float Variable.")]
public class sideTest : FsmStateAction
{

[RequiredField]
[Tooltip("Center object")]
public FsmOwnerDefault gameObject;
[RequiredField]

[UIHint(UIHint.Variable)]
[Tooltip("Direction")]
public FsmFloat direction;


[Tooltip("Repeat every frame while the state is active.")]
public bool everyFrame;

private float dirNum;



public override void Reset()
{
gameObject = null;
direction = null;
everyFrame = false;
dirNum = 0f;

}

public override void OnEnter()
{
DoSideTest();

if (!everyFrame)
{
Finish();
}
}

public override void OnUpdate()
{
DoSideTest();
}

void DoSideTest()
{
var target = Fsm.GetOwnerDefaultTarget(gameObject);

Vector3 heading = target.position - transform.position;
dirNum = AngleDir(transform.forward, heading, transform.up);
}


float AngleDir(Vector3 fwd, Vector3 targetDir, Vector3 up) {
Vector3 perp = Vector3.Cross(fwd, targetDir);
float dir = Vector3.Dot(perp, up);

if (dir > 0f) {
direction.Value = 1f;
} else if (dir < 0f) {
direction.Value = -1f;
} else {
direction.Value = 0f;
}
}
}
}


{mod edit: added code tags for readability}
« Last Edit: February 17, 2015, 07:56:05 AM by troubleMaker »

jeanfabre

  • Administrator
  • Hero Member
  • *****
  • Posts: 15500
  • Official Playmaker Support
Re: Turning a script into an action
« Reply #1 on: February 17, 2015, 02:20:07 AM »
Hi,

 This is a good start I would say.

 Typically, when you write an action, you shoudl also make a scene to test it. Have you done that yet?

from the Update() call, you can call other functions, your functions, and so, even if code is "outside" the update function it doesn't mean it's not going to be executed. typically, OnEnter and OnUpate both call DoSideTest() which is a very good technic, and necessary if you have this "everyframe" property.

 the important part is the "Finish()" call, when the action calls "Finish() it's not going to be exectued again ( the OnUpdate() will not be fired anymore).

 does that help a bit? or else can you point which line exactly isn't clear to you? Is it the way to declare the properties and how it relates to the action UI interface? the structure of the action script itself?

Bye,

 Jean

troubleMaker

  • Playmaker Newbie
  • *
  • Posts: 25
Re: Turning a script into an action
« Reply #2 on: February 17, 2015, 08:09:08 AM »
Thanks for the reply, Jean.

Well i haven't made a separate testing scene, i'm just using one of my level scenes where i want to use the action for real. But since i can't get the action to compile i haven't even gotten to testing.

Well, like i said my biggest problem is i don't understand where i should put everything, since in the original script the

Code: [Select]
Vector3 heading = target.position - transform.position;
dirNum = AngleDir(transform.forward, heading, transform.up);

is in Update, then Update seems to be closed off and the rest just seems to float there without being part of any function. If i try to ape this, by putting the same bit into my doSideTest function and leave the rest of the code outside of any function like in the action attempt i posted i get an error : Assets/PlayMaker/Actions/sideTest.cs(57,50): error CS1061: Type `UnityEngine.GameObject' does not contain a definition for `position' and no extension method `position' of type `UnityEngine.GameObject' could be found (are you missing a using directive or an assembly reference?)

If i try to include everything in doSideTest, like here:

      
Code: [Select]
void DoSideTest()
{
var target = Fsm.GetOwnerDefaultTarget(gameObject);

Vector3 heading = target.position - transform.position;
dirNum = AngleDir(transform.forward, heading, transform.up);



float AngleDir(Vector3 fwd, Vector3 targetDir, Vector3 up) {
Vector3 perp = Vector3.Cross(fwd, targetDir);
float dir = Vector3.Dot(perp, up);

if (dir > 0f) {
direction.Value = 1f;
} else if (dir < 0f) {
direction.Value = -1f;
} else {
direction.Value = 0f;
}
}
}

Then i get parsing errors about missing semicolons.

jeanfabre

  • Administrator
  • Hero Member
  • *****
  • Posts: 15500
  • Official Playmaker Support
Re: Turning a script into an action
« Reply #3 on: February 19, 2015, 03:36:26 AM »
hi,

 ok, Allow me one or two days, I'll clean up that action.

 Bye,

 Jean

troubleMaker

  • Playmaker Newbie
  • *
  • Posts: 25
Re: Turning a script into an action
« Reply #4 on: February 25, 2015, 06:31:10 AM »
Ok, thanks a lot Jean! Looking forward to it.

jeanfabre

  • Administrator
  • Hero Member
  • *****
  • Posts: 15500
  • Official Playmaker Support
Re: Turning a script into an action
« Reply #5 on: March 02, 2015, 06:07:03 AM »
Hi,

 here it is:

Code: [Select]
// (c) Copyright HutongGames, LLC 2010-2015. All rights reserved.

using UnityEngine;

namespace HutongGames.PlayMaker.Actions
{
[ActionCategory(ActionCategory.Math)]
[Tooltip("Adds a value to a Float Variable.")]
public class sideTest : FsmStateAction
{

[RequiredField]
[Tooltip("The GameObject")]
public FsmOwnerDefault gameObject;

[RequiredField]
[Tooltip("Reference GameObject. If null, will use the center of the world")]
public FsmGameObject reference;

[RequiredField]
[UIHint(UIHint.Variable)]
[Tooltip("Direction")]
public FsmFloat direction;

[Tooltip("Repeat every frame while the state is active.")]
public bool everyFrame;

private float dirNum;

public override void Reset()
{
gameObject = null;
reference = null;
direction = null;
everyFrame = false;
}

public override void OnEnter()
{
DoSideTest();

if (!everyFrame)
{
Finish();
}
}

public override void OnUpdate()
{
DoSideTest();
}

void DoSideTest()
{
GameObject target = Fsm.GetOwnerDefaultTarget(gameObject);
GameObject _reference = reference.Value;

Vector3 Center = _reference!=null?_reference.transform.position:Vector3.zero;
Vector3 Up = _reference!=null?_reference.transform.up:Vector3.up;
Vector3 Forward = _reference!=null?_reference.transform.forward:Vector3.forward;

if (target!=null)
{
Vector3 heading = target.transform.position - Center;

direction.Value = AngleDir(Forward, heading, Up);
}
}


float AngleDir(Vector3 fwd, Vector3 targetDir, Vector3 up)
{
Vector3 perp = Vector3.Cross(fwd, targetDir);
float dir = Vector3.Dot(perp, up);

if (dir > 0f) {
return 1f;
} else if (dir < 0f) {
return -1f;
}

return 0f;
}
}
}

few things. you got very confused I think with how an action work, you should not access the transform of the gamoebject of the fsm of that action ( be it what you want), you should have this FsmOwerDefault for this, ALWAYS. this allows your logic to behave as expected when dropped, yet allows flexibility if you need an fsm that checks a different gameobject, happens a lot.

then, your function whas returning a float you did not used ( and your code was wrong because when you declare a function that returns a float, you must return a float within that method, in all cases, else c# will complain).

 so study the differences, you'll see you were not that far at all :)

 Bye,

 Jean

troubleMaker

  • Playmaker Newbie
  • *
  • Posts: 25
Re: Turning a script into an action
« Reply #6 on: March 06, 2015, 04:27:24 PM »
Hey,

Thank you ever so much, Jean! Tested and it works perfectly.

I've had some experience in making actions by combining existing actions into one, but this is the first one where i tried to to do it with only a script as reference, and well... like you said, i got quite confused :)

But this is confusion is precisely why i use Playmaker after all :D

Anyway, i hope that if i need to try this again and make a new action i can use your solution as a guide to how to turn a script into something Playmaker can understand. Thanks again for your help!




siumanchunandy

  • Playmaker Newbie
  • *
  • Posts: 27
Re: Turning a script into an action
« Reply #7 on: December 16, 2021, 05:36:50 PM »
Help !

How To Check Forward And Back ?

Thank You