0

I am making a Finite State Machine (FSM) in C# for a game. The goal is to make it as independant of traditional control flow as possible. I am currently trying to create a gun behaviour with it. When the gun enters an "Out of ammo" state it should start listening for when ammo is added and automatically change state to reloading, but i am having some trouble with the C# language.

I basically want to pass an Action to another function. In that function I would like to subscribe to it:

  var outOfAmmo = new ListenerState<GunState>(GunState.OUT_OF_AMMO);
  outOfAmmo.AddTrigger(currentAmmo.OnAdded, GunState.RELOAD);

The function:

public class ListenerState<TStateID> : State<TStateID>

    ...

    public void AddTrigger(Action trigger, TStateID next)
    {
        Action setState = () => fsm.SetState(next);
        OnEnter += () => trigger += setState; //When we enter "Out of ammo" start listening for when ammo is added.
        OnExit += () => trigger -= setState; //When we exit "Out of ammo" we don't want to change state to reloading when ammo is added anymore
    }

When OnEnter and later the trigger is invoked, I expect setState to be called but its not.

Pulling out the content of AddTrigger makes everything work as expected:

  outOfAmmo.AddTrigger(currentAmmo.OnAdded, GunState.RELOAD);
  Action setReload = () => fsm.SetState(GunState.RELOAD);
  outOfAmmo.OnEnter += () => currentAmmo.OnAdded += setReload;
  outOfAmmo.OnExit += () => currentAmmo.OnAdded -= setReload;

I have made a smaller example of the problem here: https://dotnetfiddle.net/MG1tve

I am not sure what is going on here.

Is the action by default passed by value :O? because passing as ref solves the problem (https://dotnetfiddle.net/XNresg)

Tagor
  • 937
  • 10
  • 30
  • Delegates are immutable. Your `trigger` parameter variable is modified by the lambda handlers, but that has no effect except where the `trigger` variable itself is used, and it's not used for anything other than those handlers that modify its value. See duplicates. Assuming `OnAdded` is a field and not a property, you could pass it by-reference (i.e. with `ref`); it's not ideal -- there are probably better ways to implement what you're trying to do -- but it would work. – Peter Duniho Jun 21 '21 at 20:48
  • Thanks, yeah OnAdded is a field. But since i am using trigger in an anonymous method can i really use ref though? @PeterDuniho – Tagor Jun 21 '21 at 21:00
  • No, you're right...you can't capture the by-reference parameter in an anonymous method. I guess "it's not ideal" is an understatement. :) – Peter Duniho Jun 21 '21 at 21:05
  • @PeterDuniho yeahh i completely redesigned everything – Tagor Jun 21 '21 at 22:22

0 Answers0