You need a delegate queue, then the other thread locks and adds to that queue, while Update locks and removes from it.
Then you would package up that little snippet of code above and pass it out for execution on the main thread via Update():
Something as simple as:
private Queue<System.Action> TODO = new Queue<System.Action>();
and then to fill it:
lock(TODO)
{
TODO.Enqueue( () => {
// your code here
playerObj.transform.position = new Vector3(0,0,27f);
});
}
and then in your Update():
lock(TODO)
{
// Warning: this is an ultra simple concept-only demo.
// This code will fail if any delegate executed in here
// causes a fresh attempt to enqueue something, which
// would then spin-lock against the locked queue.
//
// A proper professional solution requires you to:
// - copy all delegates out
// - release the queue lock
// - execute those copied out delegates.
//
while( TODO.Count > 0)
{
// NOT A TYPO: first paren pair is "get the action," second is "invoke it"
TODO.Dequeue()();
}
}
The dequeue could be snazzier and copy ALL items out of the queue at once, THEN execute them, especially to avoid spinlock situations where a dequeued item could in turn invoke code that would add to the queue, which it couldn’t do because it was locked.
There’s also this handy-dandy asset store package that might prove helpful: