Skip to content

Pure MMCC vs. Split MMCC

Bryan Edds edited this page May 21, 2024 · 31 revisions

There are two general patterns of MMCC usage that we have discovered so far - Pure MMCC and Split MMCC. Which one you should use depends on the type of game you're making. Let's understand each.

Pure MMCC

Pure MMCC is a pattern of MMCC usage where most every interactive entity in a game has its life time and transform controlled completely by MMCC.

An example of this style is the tiles in the Twenty48 project -

https://github.com/bryanedds/Nu/blob/b63eda89903da8aed7b1d321a957af0a0a7feffc/Projects/Twenty48/GameplayDispatcher.fs#L112-L130

Notice how the board and all of its tiles have their existence and positioning dictated via MMCC model data. The tiles do not come from a scene authored in the editor - they're just placed there by the virtue of the Gameplay model's data and algorithms. Another example is OmniBlade's props -

https://github.com/bryanedds/Nu/blob/b63eda89903da8aed7b1d321a957af0a0a7feffc/Projects/OmniBlade/Field/FieldDispatcher.fs#L617-L620

...and its battles characters and their UI -

https://github.com/bryanedds/Nu/blob/b63eda89903da8aed7b1d321a957af0a0a7feffc/Projects/OmniBlade/Battle/BattleDispatcher.fs#L389-L440

Where individual interactive entities like tiles, props, characters have their lifetimes and transforms dictated completely by MMCC model data, this is what we term Pure MMCC. The exception would include static elements like Gui groups or Scene groups that have basically nothing but static entities. A pure MMCC game can and should still utilize these types of elements since they are easier to click together in the editor.

Pure MMCC is really great for games like puzzle games, strategy RPGs, shmups, fighting games, point-and-click adventure game, interactive novels, UI-driven RPGs like OmniBlade, and generally any game without a ton of complex physics-driven action. In fact, you can use Pure MMCC with heavily physics-based games so long as the physics are completely implemented in the MMCC model. Pure MMCC is particularly good for games whose content is also procedurally-generated since that lends toward direct representation in an MMCC model. However, Pure MMCC is not the best approach for every game.

Split MMCC

For games with physics-heavy gameplay that need to use the integrated behaviors provided by Aether Physics or Bullet Physics, such as action adventure games, first-person shooters, 3D racing games, VR games (tho Nu itself doesn't support VR yet), you will probably want an alternative usage pattern. This pattern, which we've termed Split MMCC, pushes much of the gameplay's MMCC usage down into individual entities, relying on events produced by said entities to be consumed by the gameplay screen to define its emergent behavior.

Examples include the EnemyDispatcher in Blaze Vector -

https://github.com/bryanedds/Nu/blob/b63eda89903da8aed7b1d321a957af0a0a7feffc/Projects/BlazeVector/Enemy.fs

The events these MMCC dispatcher produce are handled by the gameplay screen to update its MMCC model here -

https://github.com/bryanedds/Nu/blob/f2d46d91c7ca9067a3363dc3897e7b296d6b8dfd/Projects/BlazeVector/Gameplay.fs#L45-L50

Another example is from TerraFirma and its MMCC Character / CharacterDispatcher -

https://github.com/bryanedds/Nu/blob/f2d46d91c7ca9067a3363dc3897e7b296d6b8dfd/Projects/TerraFirma/Character.fs#L34-L47

https://github.com/bryanedds/Nu/blob/f2d46d91c7ca9067a3363dc3897e7b296d6b8dfd/Projects/TerraFirma/CharacterDispatcher.fs

What you'll notice about BlazeVector is that the interactive enemy entities are placed in the scene's section group files (Section0.nugroup, Section1.nugroup, etc.) via the editor. To achieve this in Pure MMCC, you either have to instead put in entity place holders in the .nugroup (or another file format) or implement a custom model editor by override the ScreenDispatcher.Edit method. In OmniBlade, for example, Props are read from the .tmx file format and inserted into the Field model at run-time.

Instead of having a monolithic MMCC model for the screen dispatcher to drive the life times and transforms of dynamic entities, we push down most of the MMCC implementation into individual MMCC entity dispatchers. Then emergent game behavior can be driven via events sent by these entities send and to which the screen dispatcher responds.

Also, mixing Pure MMCC with integrated Aether Physics or Bullet Physics can be a little less intuitive and has some general affordance trade-offs. While it is possible to configure entities with PhysicsMotion.ManualMotion and thereby update your model based on physics events, doing such a thing directly is not recommended. Handling one or more physics events per frame per entity in a Pure MMCC context will result in lots of transformations on a large MMCC model, which can make things performance-sensitive. It is intended for MMCC performance to never become a bottleneck in your game. Large MMCC models containing maps of many child models can cause the MMCC diff'ing and propagation processes to become performance-sensitive. So you wouldn't want to do it that way directly. Yet if you feel it appropriate to go the Pure MMCC route for a largely Aether Physics or Bullet Physics-driven game anyways, you should instead handle all the frame's physics messages via the single composite Game.IntegrationEvent. This event provides all of the current frame's physics messages, which can be handled in a fold expression. (EDIT: as of this writing, I'm not sure if this will include the implicit separation events that will also need to be handled. These may have to be handled individually, although they shouldn't cause quite as much performance sensitivity (tho there may be cases where they could).

None of these individual restriction should necessarily stop you from using Pure MMCC, but taken together, the affordance trade-off they impose may make them suboptimal for developing certain types of games. That's why for those types of games, we recommend the Split MMCC approach as used in BlazeVector and TerraFirma instead.

Clone this wiki locally