Making 2 variables' value connected in c#

Is it possible to have 2 bools that store the same value? So if I changed one bool’s value, the other would have the same value.

private bool FieldBool = false;

void Start()
{
     bool localBool;
     localBool = true; // This would also makes the FieldBool true
}
 private bool bool1;
    private bool bool2;

    public bool Bool1
    {
        set
        {
            bool1 = value;
            bool2 = value;
        }
    }

I should have actually mentioned that the bool I’m changing is a not a member variable.

private bool Bool = false;
[*]

[*]

[]void Start()
[
]{
bool localBool;
[] localBool = true; // This would also makes the Bool true
[
]}

First question that comes to mind: What’s the purpose? Do you actually need 2 variables for that?

Anyway, yes. Use properties or setters if that’s possible.

Other ways would be dedicated reference types that you use instead or [warning] unsafe code. The latter is not recommended though, but can sometimes be the most efficient way, for instance for values such as dirty flags that otherwise take a long chain of setter/getters in complex and performance-critical hierarchies.

you can’t do that!!

So, what’s the purpose? If they’re not some kind of “state” of an object, why can’t you just use the boolean which is declared as member, as they stay the same all the time either way?
Why would you declare a local boolean just to update the member on assignement?

I have a Finite State Machine that has bools in it that reset automatically every time my entity goes into a new state. Since these bools can be for anyone they have generic names (like StateConditionA, StateConditionB, …).

So when I’m using them in my FSM for a specific case, like to say “You can now jump” setting StateConditionA to true is hard to keep track of, I need someway to be able to use a different name for that condition. Like canJumpNow = true; and it also changes the StateConditionA.

Tell me if that’s clear or not.

Here’s an example of the implementation of one of my state.

public class BomboShoot : State<BomboAI>
{
    public static BomboShoot Instance = new BomboShoot();
    public override void Enter(BomboAI _c)
    {
        _c.CurrDir = Vector2.zero;
    }

    public override void Execute(BomboAI _c)
    {
        // Set the condition's name to a more descriptive one
        bool isTheBomboFacingPlayer = _c.Fsm.StateConditionA;

        // Rotate towards target!
        var playerDir = _c.GetVectorToTarget(_c.transform.position);

        _c.CurrDir = Vector2.Lerp(_c.CurrDir, playerDir, _c.Fsm.TimeInState);

        if (_c.CurrDir == playerDir)
        {
            // start shooting
            isTheBomboFacingPlayer = true;
        }
    }

    public override void Exit(BomboAI _c)
    {
    }
}

It’s not 100% sure yet.

First of all, have you considered using enums or state objects? It’s appears to be much easier.
Either way, if you have some place to put specific “local” names, there’s also a way to have properly named properties/methods instead that get or set the state of the FSM accordingly.

I don’t think enum would work in this case but I’m not a c# pro, I could create a class that has both a string and a bool in it. That could make it a little clearer but doing it like that seems more unclear than if it the localBool was a pointer (like in C++) to the private Bool.

In regards to this, consider my post:

This might look like the following (edited in browser, sorry for potential typos/ syntax errors):

public class BomboShoot : State<BomboAI>
{
    public static BomboShoot Instance = new BomboShoot();
    public override void Enter(BomboAI _c)
    {
        _c.CurrDir = Vector2.zero;
    }
 
    // this is new and only used as implementation details, thus private is enough for now
    private bool IsFacingPlayer
    {
         get { return _c.Fsm.StateConditionA; }
         set { _c.Fsm.StateConditionA = value; }
    }

    public override void Execute(BomboAI _c)
    {
        // Set the condition's name to a more descriptive one
        // no longer needed here
        //bool isTheBomboFacingPlayer = _c.Fsm.StateConditionA;
     
        // Rotate towards target!
        var playerDir = _c.GetVectorToTarget(_c.transform.position);

        _c.CurrDir = Vector2.Lerp(_c.CurrDir, playerDir, _c.Fsm.TimeInState);

        if (_c.CurrDir == playerDir)
        {
            // start shooting
            // isTheBomboFacingPlayer= true;
            // replaced with
            IsFacingPlayer = true;
        }
    }

    public override void Exit(BomboAI _c)
    {
    }
}

@Suddoha Thanks!

That looks like it would work! Normally, that won’t make all my Bombo creatures share the same bools logically.

yes I think @Suddoha is right

other than that you cant compare 2 vectors with this “if (_c.CurrDir == playerDir)” use a dot product and check if it is near to 1f

1 Like

Oh actually it doesn’t work because I don’t have the variable _c outside of my methods.

Oh, didn’t check for that. My bad and personal confusion, since I use the underscore ‘_’ for members.
If this was C++, there would be other ways to solve this easily without changing the actual structure of your program. :S

1 Like

what State should contains ? it is not the same BomboAI in the parent class

Here’s the way my FSM works:

FSM.cs:

using System.Collections.Generic;
using UnityEngine;

public class FSM<TEntityType>
{
    public bool DebugActivated = false;

    /// <summary>
    /// Conditions that are reset to false every time the FSM state changes.
    /// </summary>
    public bool StateConditionA;
    public bool StateConditionB;
    public bool StateConditionC;
    public bool StateConditionD;
    public bool StateConditionE;

    public float StateAccuTimeA;
    public float StateAccuTimeB;

    public FSM (TEntityType _owner)
    {
        Owner = _owner;
    }

    public TEntityType Owner;

    public List<KeyValuePair<string, float>> FinishedStates = new List<KeyValuePair<string, float>>(10);

    public State<TEntityType> CurrentState { get; private set; }
    public State<TEntityType> PreviousState { get; private set; }
    public State<TEntityType> GlobalState { get; private set; }

    public float TimeInState { get; private set; }

    public void SetCurrentState(State<TEntityType> _s) { CurrentState = _s; }

    public void SetCurrentStateWithEnterExecute(State<TEntityType> _s)
    {
        CurrentState = _s;
        CurrentState.Enter(Owner);
    }
    public void SetPreviousState(State<TEntityType> _s) { PreviousState = _s; }
    public void SetGlobalState(State<TEntityType> _s) { GlobalState = _s; }

    public void UpdateFsm()
    {
        if (GlobalState != null) GlobalState.Execute(Owner);
        if (CurrentState != null) CurrentState.Execute(Owner);
        TimeInState += Time.deltaTime;
    }

    public void ChangeState(State<TEntityType> _s)
    {
        Debug.Assert(_s != null);

        // TODO: Create event that notifies the state is changing!

        ResetStateVariables();

        if (DebugActivated) Debug.Log("Exiting: " + CurrentState);
        CurrentState.Exit(Owner);
        PreviousState = CurrentState;
        CurrentState = _s;
        CurrentState.Enter(Owner);
        if (DebugActivated) Debug.Log("Entering: " + CurrentState);
    }

    private void ResetStateVariables()
    {
        TimeInState = 0;

        StateConditionA = false;
        StateConditionB = false;
        StateConditionC = false;
        StateConditionD = false;
        StateConditionE = false;

        FinishedStates.Insert(0, new KeyValuePair<string, float>(CurrentState.ToString(), TimeInState));
        if (FinishedStates.Count > 10)
        {
            FinishedStates.RemoveAt(10);
        }

        StateAccuTimeA = 0;
        StateAccuTimeB = 0;
    }

    public void RevertToPreviousState()
    {
        ChangeState(PreviousState);
    }

    public bool IsInState(State<TEntityType> _s)
    {
        return CurrentState.Equals(_s);
    }
}

Here are the states:
State.cs

public abstract class State<T>
{
    // _c for character
    public abstract void Enter(T _c);
    public abstract void Execute(T _c);
    public abstract void Exit(T _c);
}

Here’s BomboAI.cs:

public class BomboAI : AIAgent
{
    public FSM<BomboAI> Fsm;
    [Header("Bombo Attributes"), Space]
    public float AggroRange;
    public float PatrolChangeDirectionTime;

    [HideInInspector] public RotateAccordingToMovement RotateAccordingToMovement;

    protected override void Start ()
    {
       base.Start();
        Fsm = new FSM<BomboAI>(this);
        Fsm.SetCurrentStateWithEnterExecute(BomboPatrol.Instance);
       RotateAccordingToMovement = GetComponentInChildren<RotateAccordingToMovement>();

    }
   
    protected override void Update ()
    {
       base.Update();
        Fsm.UpdateFsm();
   
        // ABSORB FIRE DAMAGE + GROW ONCE
        Move.SetDirectionalInputForAi(CurrDir);
        Move.FlyVelocity();
        Move.Move(false);
    }

    private void OnGUI()
    {
        var result = Fsm.GetStateDebug(5, "Bombo");
        JeyGUI.OnGuiDraw(result, Move.Col, Vector2.down, 14);
    }
}

It’s just the type parameter that defines which type of AI is passed into the Execute, Enter and Exit.

I think the issue you’re encountering now is just a trade-off for the architectural design in combination with the high abstraction that you’ve chosen. The idea seems good, though it’s a common trade-off of such an approach when dealing with different domains.

One thing though.

Your state class could as well be an interface, if it only defines abstract methods.

Other than that, in regards to your actual problem:
Looking at it again, your BomboAI class can provide the properly named properties that forward execution to the FSM. You could even split that up into interfaces, so that it’s not a BomboAI, but a more general interface for similar entities.
The state itself should not care about the BomboAI’s internal management either way, i.e. should not care about how to set the FSM states. To the state itself, this can be considered an implementation details.

Long story short, move the property to your BomboAI or an abstraction, so that you can access it with ease and via proper names.

So the only way left is something of that sort? It’s not really convenient.

public class FSMBool
{
    private string Name;
    private bool Value;

    public bool Get(string _name)
    {
        if (Name == _name) return Value;
        Debug.LogError("Bad name");
        return false;
    }

    public void Set(string _name, bool _active)
    {
        if (Name == _name) Value = _active;
        Debug.LogError("Bad name");
    }
}