4 ms·
> When you're separating out the model/essence from the view/representation portions of a system, the most important distinction is: the essence carries all the
by archagon 8y ago
> When you're separating out the model/essence from the view/representation portions of a system, the most important distinction is: the essence carries all the information necessary to determine (a configuration of) the representation. In this case, you can set up a mapping from the essence to the representation once; after that, you can stop thinking about the view/representation because changes to the model/essence already cover everything.
How does this work when you have to deal with animations, or state that you don't want to commit until the user completes a gesture or activity, or complex transitions between screens? It's not necessarily a good idea to shove all that stuff directly into the model.
I think if you treat the Controller as a mere implementation detail, your interfaces will lack liveliness. Simulation time and running user input are just as essential to the view as any changes to the model. That's (IMO) what the Controller is there for: to encapsulate that sort of temporal complexity.
- westoncb 8y agoTL;DR: I'm experimenting with that problem now. Currently I'm trying out this idea of 'transient state' described more below. ------- I've actually been working on something that deals a lot with that problem. It's a game with all the rendering done in a single pixel shader. All the gameplay logic is in a class called GameStateTransformer. The idea was to treat the game like a dynamical system where the state evolves as a function of 1) time 2) a sequence of 'events'. The core of it is a loop that runs 60 times per second, evolving state via time-dependent logic and by grabbing/processing any events in the queue at that time. The rendering (i.e. view) is connected to the state (i.e. model) by executing a function `mapStateToUniforms()`[0] every frame. It always works the same way regardless of whether there is an animation going on or whatever; animation logic just updates parts of the state that will get mapped to GLSL uniforms (mostly it's things like `deathAnimRatio` taking on values between 0 and 1.) The situation with events taking place over time was certainly the most complex architectural aspect I had to deal with. There were two main things I used: 1) 'transient state'; I would set up a bit of temporary/transient state by making a call like `runTransientState('player.dying', {deathPosition: blah}, 1.5)` —first arg is a path into the state object, second is a 'data' object, third is the amount of time it should remain in the state. After that call my state object would contain something like `{..., player: {..., dying: {position: blah}}}` So other code could check `if (state.player.dying)` and access related sub-data (e.g. `state.player.dying.position`); and that part of the state would be deleted after 1.5 seconds. 2) Emitting events at key points during animations/transitions (generally when they finish). Also the 'transient state' system always emits an "[transientStatePath]_finished" event when a bit of transient state's time runs out (e.g. "player.dying_finished"). There was another subsystem I put in place related to this which I haven't had to use much so far though: 'contingent evolvers', which are objects that define a `condition(state)` function and an `evolve(state, deltaTime)` function, and are automatically only executed while their condition is met. Not positive how well this would scale to larger applications, but it has worked well for the game so far. Source is here if you're curious: https://github.com/westoncb/under-game https://github.com/westoncb/under-game [0] For those unfamiliar with GLSL 'uniforms' they are variables passed into your shader from the application code. Since all of my rendering is in a pixel shader, the code there is function of the current values of the uniforms + x,y coordinate of some pixel.