简体   繁体   中英

Using C# Properties to Access Array Elements (Unity3D)

I am trying to figure out a good design pattern for a simple, generic input/controller system for a Unity game that can be used for the player, npcs, vehicles, etc. My current design uses a controller superclass that has a static array of "Actions", each of which has basic info about how the corresponding booleans in the "Action States" array should be triggered, key bindings, etc. I can then specify derived classes for specific controllers. My implementation of this design is shown below.

Controller superclass:

public class Controller : MonoBehaviour
{
    public class Action
    {
        public enum ActionType
        {
            Impulse,
            Hold,
            Toggle
        };

        public string name;
        public ActionType actionType;
        public KeyCode binding;
        ...
    }

    [HideInInspector]
    public static Action[] actions;
    public bool[] actionStates;
}

Example specific controller:

public class HumanController : Controller
{
    public bool sprint { get { return actionStates[0]; } set { actionStates[0] = value; } }
    public bool jump { get { return actionStates[1]; } set { actionStates[1] = value; } }
    ...
    public bool openInventory { get { return actionStates[13]; } set { actionStates[13] = value; } }

    public HumanController()
    {
        actions = new Action[]
        {
            new Action("Sprint", Action.InputType.Hold, KeyCode.LeftShift),
            new Action("Jump", Action.InputType.Impulse, KeyCode.Space),
            ...
            new Action("Open Inventory", Action.InputType.Toggle, KeyCode.Tab),
        };
        actionStates = new bool[actions.Length];
    }
}

This system works fairly well as I can easily view the actionStates array in the inspector, can easily access them in code via the properties as opposed to using a string indexed dictionary (which I would suspect would be slower and create more garbage), etc. The only part that is not ideal is manually setting up the properties and I wanted to know if there is a less verbose/more elegant way of mapping each of the properties in the derived classes to each of the elements of the actionStates array than doing the following for each action:

public bool action { get { return actionStates [0]; } set { actionStates[0] = value; } }

After taking this advice...

Surely it would be better to just have your array with the enums as your counters so myAction[JUMP] = ... etc

I came up with the following setup.

Controller Superclass:

public class Controller : MonoBehaviour
{

    public class Action
    {
        public enum InputType
        {
            Impulse,
            Hold,
            Toggle
        };

        public string name;
        public InputType inputType;
        public KeyCode binding;
                ...
            }

    public virtual Action[] actions { get; }
    public bool[] actionStates;

    public Controller()
    {
        actionStates = new bool[actions.Length];
    }

}

Indexable Derived Class (attempt at constraining T to be an enum):

public class Controller<T> : Controller where T : struct, System.IConvertible
{
    public bool this[T enumIndex]
    {
        get { return actionStates[System.Convert.ToInt32(enumIndex)]; }
        set { actionStates[System.Convert.ToInt32(enumIndex)] = value; }
    }
}

Example specific controller:

public enum HumanControls
{
    sprint,
    jump,
    ...
    openInventory
}

public class HumanController : Controller<HumanControls>
{

    public static Action[] actionList = new Action[]
    {
        // movement
        new Action("Sprint", Action.InputType.Hold, KeyCode.LeftShift),
        new Action("Jump", Action.InputType.Impulse, KeyCode.Space),
        ...
        new Action("Open Inventory", Action.InputType.Toggle, KeyCode.Tab),
    };

    public override Action[] actions { get; } = actionList;

}

I can then use the controller as follows:

using static HumanControls;
...
if(controller[sprint]) {
...

which does not involve as much redundancy, still allows me to easily access the array elements with simple typed names as before (as opposed to casting enum to int first, etc.), and works about as well as I could hope for my use cases.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM