You might take look at the Model-View-Controller design specification. Basically you separate out the data (Model) from the visual representation of it (View), and mediate between the two with a Controller. This way you can act on the data with a controller and only render it to view based on the state of the controller.
To make this a bit more concrete:
Suppose you have a racing game. You have a list of cars, with their stats and records. You have a list of tracks, conditions on those tracks, and their length. This is all data held in the Model.
Now you also have models, textures and animations for cars, tracks, and drivers along with UI for a player to drive an actual car. This is all view stuff.
There would be a number of controllers, to control different kinds of gameplay. To start you would have a RaceController which picks cars and driver from the roster, selects a track, and starts the race. It would have assigned CarControllers to every single car, which control how the car moves around the track and handle physics between cars (I’d abstract out the AI code. If you do, you can just plug the PlayerController in later to take control of a car). They would have the ability to pass their position, state and other necessary variables to a CarView which would update the model position and visual data on the track. When the race is over, the RaceController could update a file containing season data, which could in turn be used to update car stats and future races (ie if there is a bracket).
Finally the RaceController could be called up by a GameView script that would instantiate all the Cars, the Track and pull data from the RaceController to update the view. At this point you have the ability to run games invisibly, or watch one. Its here that I’d build in the ability for the player to take control of a specific car, or for the player’s car to be inserted into a race. You’d have build all the functionality for moving a car, and just be providing inputs to it from a different source than the AI.
The big problem I see here is the physics. I don’t know how I’d go about abstracting out Unity’s physics engine for cars (or a football). As for putting them on separate threads, basically if you create a static function in RaceController called PlayRace(data), you can tell that to run on its own thread.
A much simpler way of doing all this could just be to run games the player isn’t watching purely statistically, and only play out games the player actually plays in/watches.
These are ways I’d go about it. Might be someone has a better answer. Hope this helps though!