in a nutshell:
non-OO c++ syntax
ADTs (abstract data types) composed of:
* PODs (plain old data)
* standalone functions
the use of data structures statically allocated in the data segment vs dynamically allocated on the heap
procedural code calling hierarchy used to define flow control
this avoids some of the headaches related to OO game coding.
and many of the advantages of OO game coding do not apply to a small team or single developer in control of their own project, which makes this a viable alternative - but only in such cases.
if you need true inheritance and polymorphism in your code, you're going to have to do the OO thing (at least a little bit).
however i've found this method perfectly satisfactory for writing games both large and small. and I have yet to require OO syntax in my code for any game i've made, am working on now, or plan to make in the future. surely those who didn't learn programming until after OO syntax was added to c++ will find this shocking. but yes, its true. games were being written for computers long before OO syntax existed. OO was invented as a means to handle the difficulties of software development in general, with no special regard to games or their special needs. so it was a dual edged blade, OO power, but with OO issues and OO overhead. Non OO syntax if done correctly (basically in an OO style) could get the job done just fine without the issues or overhead. it was only in the "OO syntax only" capabilities that it showed advantage. and those capabilities are largely related to modification of large code bases by multiple coders over long periods of time. Almost the opposite of the single developer on a single version of a single game.
so how does one do this?
well, instead of an object, you'd have a data structure (most likely a struct) for its member variables, and a number of standalone functions that accessed the data structure (IE implement the methods as stand alone functions). you take all that and put it together along with your struct definition and any related #defines, and any other variable declarations you need, and you have the non-OO equivalent of an object - an ADT (abstract data type). then if you want to, you can put it in its own source file, with it own header, thereby turning it into a code module. other code will only be able to use the exposed API in the header file. variables declared in the module will essentially be private to the module, unless exposed through the header API. so you have nice clean APIs and data hiding, with no OO syntax, no object hierarchy headaches, no memory leaks (as the variables in the module are static, allocated at load time in the data segment, not at runtime on the heap), etc.
however, you will need to write explicit init and shutdown routines to replace any custom constructors and destructors. the nice thing about explicit init and shutdown routines is you have complete control over initialization and shutdown order of all your modules in the game.
note that there's nothing wrong with using the heap when called for. if you need a big temporary buffer, the heap is obviously the way to go. but the key word there is temporary. there's no real reason to keep permanent data structures on the heap. its adds allocation and de-allocation overhead, and introduces the possibility of memory leaks. sure, one malloc or new at game start isn't a biggie, but constantly newing and disposing every little data structure in the game is just inefficient. another place where the heap is useful/required is when you simply don't know how big the data structure must be, or want it to use all available ram. but there are very few places in a game where the maximum possible number is not known or at least estimate-able, and static data structures can be declared appropriately large to handle the worst case anticipated scenario, then either degrade gracefully, or perhaps fall back to using supplemental memory from the heap to enlarge the structure, if you want to get fancy. the trade off is some unused memory at the end of the slightly oversize static data structure, vs the overhead, possible extra code work, and possibility of introducing memory leaks using dynamic allocation and reallocation.
what it boils down to is that the heap has allocation and deallocation overhead that the data segment doesn't. and its possible to make coding errors using the heap which are not possible using the data segment. so the heap can be used, but not like a madman due to overhead, and you have to make sure you dot your i's and cross your t's.
the use of procedural code implicitly defines flow control in the program, so "game states" for flow control purposes is unnecessary. game states are then only required for the more fitting purpose of making the game run in multiple modes, such as fps mode vs rts mode in a fps/rts hybrid.
further topics:
relational databases
shared resources
use of globals
level based vs non level based game code - the differences between shooter and simulator code
gameplay vs realism, the differences between shooter and simulator game design
"generic" routines
What you are describing is often called 'object oriented C'.