Cursor.SetCursor() not working inside Start()

I have this script:

    public Texture2D defaultCursor;
    public Texture2D attackCursor;

    void Start() {
        SetCursor(defaultCursor);
    }

    public void SetAttackCursor() {
        SetCursor(attackCursor);
    }

    public void SetMoveCursor() {
        SetCursor(defaultCursor);
    }

    private void SetCursor(Texture2D cursor) {
        Debug.Log("changing state");
        Cursor.SetCursor(cursor, Vector2.zero, CursorMode.Auto);
    }

It works when the functions SetAttackCursor and SetMoveCursor are called from mouse clicking scripts elsewhere. But the cursor is not set at the start of the game when the Start function is called (the debug text is printed but the cursor remains the default cursor from operating system)

Anyone knows why?

It’s documented under “Web Player” here: (Not that this covers everything - keep reading)

OSX Webplayer note: Due to sandboxing, Hardware Cursors can only be updated intermittently (when the cursor is moving) the best way to ensure correct behavior if to use OnMouseEnter and OnMouseExit to set the hardware cursors. This is not an issue for software cursors.

It probably has similar restrictions on other platforms.

It’s the best I can find.

As an aside, there is a pretty interesting read here:

Finally, here’s confirmation that someone else who’s at least experinced in the field ran in to your problem:

Therefore, following the MonoBehaviour class logic, if the Cusor.SetCursor() method is called at the Start() or Awake() methods, this should replace the current cursor with the one specified by the Texture2D passed as the first parameter. Although this is the most straightforward approach, it doesn’t work by the time this tutorial is being written.

While he’s using a 2 second Invoke to delay and set the cursor, I wonder if you could just use a coroutine with a one frame yield to get the same result.

Sample:

void Start() {
    StartCoroutine(SetInitialCursor());
}

private IEnumerator SetInitialCursor() {
    yield return null;
    SetCursor(defaultCursor);
}

Try doing it in the first execution of the Update, or OnGUI function:

private bool isInitialCursorSet = false;

void Update() {
    if(!isInitialCursorSet)
    {
        isInitialCursorSet = true;
        SetCursor(defaultCursor);
    }
}

I’m doing it with Invoke and 0.1 sec delay, that indeed works, but feels somewhat superfluous.