playMaker

Author Topic: Get Component  (Read 9056 times)

Talon

  • Playmaker Newbie
  • *
  • Posts: 6
    • View Profile
Get Component
« on: April 11, 2011, 12:53:29 AM »
Well I've tried figuring this one out. I'm trying to get a value from a java script variable and just can't get it working in a custom action. On my last project I used get component a lot of the time. 1.1 even has a "has component" action, why not a get component action?
For me this is the biggest thing Play Maker is lacking. I really enjoy everything else about this package, I just wish it interfaced with external scripts easier.
I'm not very good with C# so maybe I'm missing something. Anyway here's what I have so far, I tried hacking apart the Has Component action... Unity isn't liking looking for the variable name.



using UnityEngine;
using System.Collections;

namespace HutongGames.PlayMaker.Actions
{
   [ActionCategory(ActionCategory.GameLogic)]
   [Tooltip("Gets the amount of money the player has from the logic script.")]
   public class GetMoney : FsmStateAction
   {
      [RequiredField]
      public FsmOwnerDefault gameObject;
      public FsmFloat floatStore;
      public bool everyFrame;

      Component aComponent;

      public override void Reset()
      {
         aComponent = null;
         gameObject = null;
         floatStore = null;
         everyFrame = false;
      }

      public override void OnEnter()
      {
         DoHasComponent(gameObject.OwnerOption == OwnerDefaultOption.UseOwner ? Owner : gameObject.GameObject.Value);
         if (!everyFrame)
            Finish();
      }
      
      public override void OnUpdate()
      {
         DoHasComponent(gameObject.OwnerOption == OwnerDefaultOption.UseOwner ? Owner : gameObject.GameObject.Value);
      }

      public override void OnExit()
      {

      }

      void DoHasComponent(GameObject go)
      {
         floatStore = go.GetComponent("Logic").money;
      }
   }
}

jeanfabre

  • Administrator
  • Hero Member
  • *****
  • Posts: 12342
  • Official Playmaker Support
    • View Profile
Re: Get Component
« Reply #1 on: April 11, 2011, 03:31:13 AM »
Hi,

 I have the same feeling about how playmaker interfaces with scripts. I have too much boiler plate code and composition to build for my liking, tho I can live with it since I found a solution that I like :)

 My approach when trying to solve exactly what you are willing to do is to create special functions within my existing script that accepts a fsm variable as parameter, and modify the parameter instead of simply sending the value via return

 So it works like that:

in your script build/override a function so that it receives a fsm variable ( don't forget to add "using HutongGames.PlayMaker;" at the top of your script) :

Code: [Select]
void GetMoney(FsmFloat outFloat){
   outFloat.Value = money;
}// GetMoney

in fsm, simply use the "sendMessage" action and select your fsm variable to pass as a parameter to the message. And there you have your money value transferred from a script to a fsm variable in one step without custom action.

I totally avoid making a custom action for each and every information I want to pass from existing script to fsm, that's a lot of work for nothing I feel, and it doesn't scale at all. Each time something new come out, you'll need to write yet a gain a custom action, that will be difficult to access amongst so many unrelated actions.

Now, there is another approach using eventsData I think. I haven't yet tested it fully, when I do I will edit this post, cause I think it's better because basically, script can send an event to playmaker and pass data with that event, which is very good practice. So instead of querying when needed the money value, it's when the money value changes that the script sends an event to the fsm with eventsData, so that in the fsm, you simply catch that event in a state and get the EventsData which is the money value.

 Either way, I don't see yet a way to access script from fsm as we normally do with script-script access, so either way, with my current humble knowledge of things, your scripts needs to adapt and accommodate the playmaker factor or you need to write custom actions which is a lot of work.
 
 I might over thinking and over complicating it and maybe there is a much much easier/nicer solution to this problem we have :)

 Bye,

 Jean



MaDDoX

  • 1.2 Beta
  • Full Member
  • *
  • Posts: 165
    • View Profile
    • FluidPlay Studios
Re: Get Component
« Reply #2 on: April 11, 2011, 04:50:52 AM »
Maybe that's related to the order in which Unity compiles scripts, by default .js scripts can't access c# data. Try moving the Playmaker-related scripts to the "standard assets" folder, making sure your .js files are out of it. Supposing Playmaker works when moved out of the default folders, that should work things out. Read the following for more information:

http://unity3d.com/support/documentation/ScriptReference/index.Script_compilation_28Advanced29.html
--
Breno "MaDDoX" Azevedo
@brenoazevedo

Alex Chouls

  • Administrator
  • Hero Member
  • *****
  • Posts: 3202
  • Official Playmaker Support
    • View Profile
    • LinkedIn
Re: Get Component
« Reply #3 on: April 12, 2011, 01:49:04 AM »
@Talon - You need to cast the component to your component type to access its properties/methods. You also need to use floatStore.Value.

Example (untested):

floatStore.Value = ((MyScript)go.GetComponent<MyScript>()).money;

It's also a good idea to get the component in OnEnter and cache it. I'll try to write up a more complete example tomorrow...

Jean's solution is certainly a good suggestion. You can also use Send Message and Invoke Method actions to interface with your scripts.

However, I agree it would be nice to have a simpler way to access component properties within Playmaker.

I'm playing around with some ideas:

1. A custom action wizard that basically writes boilerplate actions for you. It would use reflection to give you a nice UI to access MonoBehaviour properties but would generate c# code that you then use like any other action. I'm wary of the number of extra actions this might make...

2. Get/Set actions that access named MonoBehaviour properties at runtime. I'm wary of the runtime reflection here...

3. A combination of the above, where the Get/Set actions create c# code behind the scenes, but you don't need to really worry about.

Still thinking it through... thoughts?


jeanfabre

  • Administrator
  • Hero Member
  • *****
  • Posts: 12342
  • Official Playmaker Support
    • View Profile
Re: Get Component
« Reply #4 on: April 12, 2011, 02:44:29 AM »
Hi Alex,

 If boiler plates code could be avoided, that would be cool. If one action per script access could be avoided, again cool.

 I think that's where global events and variables in playmaker would be very helpful cause we would then only really need one broker script if we wanted to keep existing code base playmaker agnostic as much as possible.

Is it not also a case of having the ability to have script that intercepts events, and States. Very much like we create actions, why not be able to create a script that simply catch Events, and scripts that catch States status at a global level.

public class PlaymakerEvents : FsmEventsBroker
{
   //Here we would catch any events being fired within playmaker like OnEventFired
}

public class PlaymakerState : FsmStatesBroker{
  //Here we would catch any States Status. that is OnEnter and OnExit
  // And we should be able to know from what Status and action it comes from.
}

FsmEventsBroker and FsmStatesBroker are very creative names, but your get the idea I think, it's just so that the script gets informed about Events and States activity globally. I see in this a lot of possibilities. Like being able to log trace or playmaker activity at a global level. Have a central place for linking existing code base and playmaker.

Hopefully, I am not talking crap here :)

 Bye,

 Jean

 

Talon

  • Playmaker Newbie
  • *
  • Posts: 6
    • View Profile
Re: Get Component
« Reply #5 on: April 18, 2011, 12:24:17 PM »
Well I went about fixing this probably half an hour after posting this topic.  :P
My solution was similar to how Jean Fabre suggested.
On my game logic script (java) that contains the player's money, lives, ect. I added a FSM object that has variables that are updated from the game logic script whenever the java script is updated. All of the variables are updated via a function so it wasn't hard to just add in a update for the FSM Float values. Then my playmaker objects that need to access the money amount can just get the value from the FSM component. When they spend money it sends a message to the java script that then updates the FSM value as well.

It's just an extra layer to go through, but there's only a couple of variables that I need to do this with so it's not a big deal.