ArgumentNullException: Value cannot be null.

Ohhh boy… you’re gonna be studying my code for ages! I threw in a whole mix of different ways to do stuff. :smile:

public class CubeXOtest : MonoBehaviour
{
    public List<PanelTest> allPanels = new List<PanelTest>();
    public List<List<PanelTest>> sides = new List<List<PanelTest>>();
    int player = 1; // debug one player for now

    private void Awake()
    {
        Application.targetFrameRate = 30; // save CPU
        allPanels.AddRange(GetComponentsInChildren<PanelTest>());
        for (int i = 0; i < 6; i++) { sides.Add(new List<PanelTest>()); }
    }

    private void Update()
    {
        if (Input.GetMouseButtonDown(0)) { HandleClick(); }
    }

    void HandleClick()
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        if (Physics.Raycast(ray, out RaycastHit hit, 500f))
        {
            PanelTest panel = GetPanel(hit.collider);
            if (panel != null && panel.stateValue == 0)
            {
                panel.stateValue = player;
                CheckWin(player, panel.side);
            }
        }
    }

    PanelTest GetPanel(Collider collider)
    {
        for (int i = 0; i < allPanels.Count; i++)
        {
            if (allPanels[i].coll == collider)
            { return allPanels[i]; }
        }
        return null;
    }

    void CheckWin(int p, int s)
    {
        if (ConditionalWin(s, p, 0, 1, 2)) { WinGame(); return; }
        if (ConditionalWin(s, p, 3, 4, 5)) { WinGame(); return; }
        if (ConditionalWin(s, p, 6, 7, 8)) { WinGame(); return; }
        if (ConditionalWin(s, p, 0, 3, 6)) { WinGame(); return; }
        if (ConditionalWin(s, p, 1, 4, 7)) { WinGame(); return; }
        if (ConditionalWin(s, p, 2, 5, 8)) { WinGame(); return; }
        if (ConditionalWin(s, p, 0, 4, 8)) { WinGame(); return; }
        if (ConditionalWin(s, p, 2, 4, 6)) { WinGame(); return; }
    }

    bool ConditionalWin(int side, int p, int a, int b, int c)
    {
        bool aa = false; bool bb = false; bool cc = false;
        for (int i = 0; i < 9; i++)
        {
            PanelTest pp = sides[side][i];
            if (pp.sideIndex == a && pp.stateValue == p) { aa = true; }
            if (pp.sideIndex == b && pp.stateValue == p) { bb = true; }
            if (pp.sideIndex == c && pp.stateValue == p) { cc = true; }
        }
        if (aa && bb && cc) { return true; }
        return false;
    }

    void WinGame()
    {
        print("GAME WON!!!");
    }
}
public class PanelTest : MonoBehaviour
{
    public Collider coll;
    public Renderer rend;
    public CubeXOtest owner;
    public int stateValue;
    private int lastValue;
    public int side;
    public int sideIndex;

    private void Awake()
    {
        coll = GetComponent<Collider>();
        rend = GetComponent<Renderer>();
        owner = transform.root.GetComponent<CubeXOtest>();
    }

    private void Start()
    {
        SetSide();
        SetSideIndex();
    }

    private void Update()
    {
        if (stateValue != lastValue)
        {
            if (stateValue== 0) { rend.material.color = Color.white; }
            if (stateValue== 1) { rend.material.color = Color.blue; }
            if (stateValue== 2) { rend.material.color = Color.green; }
            lastValue = stateValue;
        }
    }

    void SetSide()
    {
        Vector3 sidePos = transform.forward;
        if (sidePos == Vector3.back)
        { side = 0; owner.sides[side].Add(this); return; }
        if (sidePos == Vector3.forward) { side = 1; return; }
        if (sidePos == Vector3.up) { side = 2; return; }
        if (sidePos == Vector3.down) { side = 3; return; }
        if (sidePos == Vector3.left) { side = 4; return; }
        if (sidePos == Vector3.right) { side = 5; return; }
    }

    void SetSideIndex()
    {
        if (string.Equals(name, "Panel BL")) { sideIndex = 0; }
        if (string.Equals(name, "Panel BM")) { sideIndex = 1; }
        if (string.Equals(name, "Panel BR")) { sideIndex = 2; }
        if (string.Equals(name, "Panel ML")) { sideIndex = 3; }
        if (string.Equals(name, "Panel Mid")) { sideIndex = 4; }
        if (string.Equals(name, "Panel MR")) { sideIndex = 5; }
        if (string.Equals(name, "Panel TL")) { sideIndex = 6; }
        if (string.Equals(name, "Panel TM")) { sideIndex = 7; }
        if (string.Equals(name, "Panel TR")) { sideIndex = 8; }
    }
}

Since I only did one side, the SetSide() method just needs filled in. And I only set one player for just testing. But I child-ed all adjacent panels to the middle panel, so just need to duplicate and rotate in the editor, for the remaining sides:


But I thought of testing several different ways of doing things, especially a list within a list, which I’ve never done before. But took it as a challenge, so I had fun with this. :sunglasses: