Creating a Playmaker action

It is time to translate our script to C#. Create a new C# script the same way you created the JS one. Call it PushPuckAction. Open the script and find the line starting with the public class keywords. Make sure that the name of the class is the same as the name of the script, then press command + S (Ctrl + S in Windows) to save your changes if you made any.

As you can see, the default template for a C# script looks different from that of JS. This is because more things are shown to you. For instance, in JS it is implied that everything inside a script is, in fact, in a class with the same name, but you do not see the class declaration anywhere. Component classes in Unity have to inherit from MonoBehaviour, and it is shown in C#, while JS hides it from you. Then you have the two lines with the using keyword. All JS scripts use these namespaces, but JS hides it from you as well. The following script is the same one that we had before, but this time translated to C#. Replace the template with it.

using UnityEngine;
using System.Collections;
[RequireComponent (typeof (CharacterController))]

public class PushPuckAction : MonoBehaviour 
{
  // Global variables available from Inspector
  public float pushMag = 20f;

  public string collisionTag = string.Empty;

  // Function that will detect the collision with 
  // controller and apply force in point of the collision
  void OnControllerColliderHit (ControllerColliderHit hit) 
  {
    if (hit.gameObject.tag == collisionTag)
    {
      // Get the position of the object we collided with
      Vector3 hitObjectPos = hit.transform.position;

      // Get the position of the collision
      Vector3 hitPointPos = hit.point;

      // Calculate the direction of the force, 
      // multiply it by magnitude
      Vector3 pushForce = Vector3.Normalize(hitObjectPos - hitPointPos) * pushMag;

      // Finally, apply force in position
      hit.rigidbody.AddForceAtPosition(pushForce, hitPointPos);

      // Print a message in Console saying that 
      //the collision did happen and force was indeed applied
      Debug.Log("Detected hit with " + collisionTag + ", applying force of " + pushForce + " in " + hitPointPos + ".");
    }
  }
}

Press command + S (Ctrl + S in Windows), and let us look at what has changed apart from the things already mentioned. The syntax of the component requirement is different in C#. On top of that, the RequireComponent attribute has to be placed before the class declaration.

The #pragma strict directive is gone. C# is explicit by nature and requires that you specify types of everything, so it is not needed.

Tip

In C#, the following are quite useful: #region [Name]/#endregion, which is a good way of dividing your code into regions that you can fold. For example, writing #region Variables will create a region called Variables. Then you will be able to press a minus in a rectangle on the left of the MonoDevelop window to fold the code region, the end of which you have to mark with #endregion.

The function keyword is not used. Instead, function declarations are preceded by return types. You can specify a return type in JS as well, but this is done with the : operator after the brackets, for example, function Update() : void.

Finally, all variable declarations are preceded with types of variables instead of the var keyword. There are more differences in syntax that we cannot see in this example because of the relative simplicity of our script, but these are the main ones.

Now, if you replace your JS script with the C# one on the Mallets, they will act exactly the same way as before. Try doing this, then remove the Push Puck Action component from the mallets. It is time to modify the script and transform PushPuckAction.cs into an actual Playmaker action. Replace the contents of PushPuckAction.cs with the following code:

using UnityEngine;
using System.Collections;

namespace HutongGames.PlayMaker.Actions
{
  [ActionCategory(ActionCategory.Character)]
  [Tooltip("Detect collision with CharacterController, then push the other object into the opposite direction.")]
  public class PushPuckAction : FsmStateAction 
  {
    [Tooltip("Push magnitude")]
    public FsmFloat pushMag;

    [Tooltip("Object with this tag will be pushed")]
    public FsmString collisionTag;

    public override void Reset ()
    {
      pushMag = 20f;
      collisionTag = string.Empty;
    }

    public override void DoControllerColliderHit(ControllerColliderHit hit)
    {
      if (hit.gameObject.tag == collisionTag.Value)
      {
        FsmVector3 hitObjectPos = hit.transform.position;

        FsmVector3 hitPointPos = hit.point;

        FsmVector3 pushForce = (hitObjectPos.Value - hitPointPos.Value).normalized * pushMag.Value;

        hit.rigidbody.AddForceAtPosition(pushForce.Value, hitPointPos.Value);

        Debug.Log("Detected hit with " + collisionTag.Value + ", applying force of " + pushForce.Value + " in " + hitPointPos.Value + ".");
      }
    }
  }
}

Press command + S (Ctrl + S in Windows) to save the script. As you can see, this time more things have changed, although you can still see the same structure. Let us go through the code line-by-line and examine it.

The using directives are the same, but the difference begins right after them. The line namespace HutongGames.PlayMaker.Actions is obligatory for all Playmaker actions. Without it Playmaker will not know that the script that you are writing is, in fact, an action.

The [ActionCategory(ActionCategory.Character)] line puts your new action into a category. In this case, we are putting it into the Character category, because the action is about things colliding with the Character Controller. It could also go into the Physics category. To move it there, the line would have to be [ActionCategory(ActionCategory.Physics)].

After that there is [Tooltip("...")], which is quite self-explanatory. It shows a short description when you select the action from the list in the Actions panel.

The PushPuckAction class now inherits from FsmStateAction instead of MonoBehavior. You still have access to all the standard Unity classes, but Playmaker-specific ones are added now.

Then there is another Tooltip, this time for a variable rather that a whole action. The text within this tooltip will appear when you hover your mouse pointer over the variable in the State tab of the playMaker panel or in the Actions panel.

Note that the type of the pushMag variable has changed from float to FsmFloat, and the same goes for the string variable collisionTag—it is FsmString now. These are Playmaker types of variables. The same operations can be performed on them as before, but to access their value you now have to use the dot operator with the word Value, so, for example, pushMag.Value will return a float, the value of the Playmaker variable.

Tip

If you do not want to be able to assign a value directly in the State tab of the playMaker panel and force choosing from existing variables, you can write [UIHint(UIHint.Variable)] in the line before the variable declaration, the same way we did for the tooltips.

A Reset function was added. This is what happens when a new action is added to a state or when you right-click on the header of the action and press Reset. In it, we reinitialize the variables.

Then there is the DoControllerColliderHit function. Its name has changed from the standard Unity OnControllerColliderHit. Inside the function everything has stayed more or less the same with the only difference that types of Vector3 variables have changed to FsmVector3, so to access their values .Value is used. Also, instead of Vector3.Normalize, we used .nomalized, which does exactly the same thing.

Tip

While it is clear that in order to find examples and standard Unity classes' API one has to go to Unity Script Reference, it may be less clear about Playmaker-specific things. The easiest way to find examples is opening the script files of existing Playmaker actions that are located under the PlayMaker/Actions path, in your project. For example, if you are not quite sure how to detect mouse input and you want to do it via a Playmaker custom action, you can open PlayMaker/Actions/MousePick.cs and look at how the creators of Playmaker solved this problem.

Note that both Reset and DoControllerColliderHit have override preceding their types. This means that we are replacing a base function defined in the Playmaker with our own function. As a general rule, you will need to override all of the Playmaker standard functions using this keyword.

Now that we are done writing a custom Playmaker action, we can try using it. Remove the Push Puck and/or Push Puck Action components from MalletLeft and MalletRight. In their Move state, remove the Collision Event action. Then locate the newly created Push Puck Action in the Actions panel and add it to the state. Set the properties as shown in the following screenshot. Finally, delete the Push Puck state from the FSM as well as the Push event and transition. To delete a transition, you just need to right-click on the event in the FSM view and press Delete Transition.

Creating a Playmaker action
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.221.58.143