How to do javascript-like object notation in unityscript or c# ?

I mainly do web stuff in javascript but trying to branch other to other languages. In my game I want to have many (perhaps hundreds) of action states for the character. If I were to do this in jscript I’d do.

ActionStates = {};

function AS(prop1, prop2) {
  this.prop1 = prop1;
  this.prop2 = prop2,
}

ActionStates.Dash = new AS(3,5);

then I’d add functions to the Dash actionstate like:

ActionStates.Dash.init = function(){
    do stuff...
}

ActionStates.Dash.main = function(){
    do stuff...
}

Then I’d have a variable string I’d use to call a particular function:

currentState = "Dash";

then in FixedUpdate(), I can put:

ActionState[currentState].main();

I think I understand classes and how to do structs, but how to call a function by using a variable string for it’s name or parent’s name? Thanks

Well, UnityScript as well as C# are compiled and static typed languages. That means you can’t create types on-the-fly at runtime. JScript (web-Javascript) is an interpreted scripting language. Interpreted / dynamic languages allow all sort of crazy stuff like altering the code in place or adding / removing variables / functions to objects. That’s not possible in static typed languages.

So in short a lot things you can do in JScript isn’t possible in .NET. However for some “features” there are workarounds or different approaches. For accessing different types in a common way you can use inheritance with either a baseclass or interfaces. To access instances of classes by name / id you can use a generic dictionary which behaves like an associative array / map.

Here’s an example written in C#. Note: I just tried to implement your abstract example with a bit of context.

using UnityEngine;
using System.Collections.Generic;

public abstract class ActionState
{
    protected GameObject owner;
    public int SomeCommonIntVariable = 5;
    
    public abstract string Name { get; } // abstract readonly property
    public abstract void Init(); // abstract method
    public abstract void Run(); // ...
    public ActionState(GameObject aOwner) // class constructor
    {
        owner = aOwner;
    }
}

public class Dash : ActionState
{
    public int DashSpecificVariable = 42;
    public override string Name
    {
        get {return "Dash";}
    }
    // class constructor
    public Dash(GameObject aOwner, int aSomeValue) : base(aOwner)
    {
        DashSpecificVariable = aSomeValue;
        SomeCommonIntVariable = 123;
    }
    public override void Init()
    {
        // ....
    }
    public override void Run()
    {
        // ....
    }
}

public class ActionStates
{
    private Dictionary<string, ActionState> states;
    public void AddState(ActionState aState)
    {
        if (aState != null && !states.ContainsKey(aState.Name))
            states.Add(aState.Name, aState);
    }
    public void InitState(string aName)
    {
        states[aName].Init();
    }
    public void RunState(string aName)
    {
        states[aName].Run();
    }
}


// inside a MonoBehaviour class:

private ActionStates actions = new ActionStates();
private string currentState = "Dash";

void Awake()
{
    actions.AddState(new Dash(gameObject, 555));
    //add other states here
    //  actions.AddState(new SomeOtherState(gameObject));
}

void FixedUpdate()
{
    actions.RunState(currentState);
}

Usually you don’t use a string variable to hold the current state. String variables are quite slow since they have to be compared character by character. It’s also easy to introduce errors when you have a typo in your string. Strings like "nonExistingState", "Dash " or "dash" won’t work and will throw an exception. Only "Dash" is valid.

For things like state machines you might want to use an enum to select the current state. An enum (enumeration) is a custom type which has a predefined number of possible values. The compiler will complain when you mistype an enum member name. Under the hood an enum is actually just an integer value. Each enum member behaves like a constant with a certain integer value.

public enum EState {Dash, Idle, Special1 = 25, Special2}

In this case EState.Dash equals to the value “0”, EState.Idle to the value “1”, EState.Special1 to “25” and EState.Special2 to “26”. Even though it’s just an integer type, it’s still type save. So you can’t simply assign “25” to a variable of that type.

An example variable with our enum type:

public EState currentState = EState.Idle;

The advantages of enums are:

  • They are fast since the underlying type is just an integer.
  • They are save to typing errors and ensure only valid values (unless someone bypasses it on purpose)
  • Most IDEs help you with autocompletion and suggests possible values.

So you could simply exchange “string” with EState in my example and it still works the same. Well, the “Name” property should be renamed to something like “StateId” since it doesn’t hold a name anymore ^^.

I deliberately implemented the statemachine in the example as “normal” classes. In Unity you will often see people implement each “state” as a seperate MonoBehaviour class. MonoBehaviours can be enabled / disabled and they receive notifications about that automatically.

In the end there’s no “right” way to do your business. It always depends on your knowledge / preference as well as the size and type of the project. I often saw people using a sledgehammer to crack a nut.