Seems you do know why then
I know globals are bad only because people say so, but I didn't fully understand why they are bad, especially the public access part. With your explanation now I know how they are bad for cache coherency.
I still have some questions regarding your engine structure.
Different features might have data the flow through the subsystems in different order, and might go through the same subsystem multiple times. For example, we might need to do several consecutive raycasts that depends on each others result. How do we ensure all the works are done before we finish a single frame? Do we start by raising a update event and loop through all the subsystems until there are no more works queued for this frame?
By batching jobs subsystems will operate on a command pattern. I once used a engine whose rendering system is done like this, but debugging it was quite a headache. With procedural methods, if we received a segfault or other exceptions, all the inputs and callers down until main() is probably still on the stack so it is easier to track where it went wrong. But with a command pattern the information of who gave us this garbage is lost, unless we do some excessive logging. For the footstep example, suppose one of the many sound effects played is wrong, how would you suggest to track down where went wrong?
Thanks a lot!