Immediate Mode and Model-view-controller

Immediate Mode and model-view-controller architectures in different forms seems to come up more and more often here. After reading what johno wrote in his book so far i got curious. Since that wasn't complete and without examples it would be nice to discuss how you use it and if you could show a couple of simple pseudo code examples where you use it.

I've just made the kind of entity management johno dislikes in his book and i've started to think about how my code could be more direct. As i understand it, instead of having a single class for state data, input management and update/drawing of an entity you should divide this up and have a model that communicates with its associated view and controller objects, perhaps via pointers?

Well a simple pseudo code example of an entity kind of thing with your system would be cool to see. Say for something like a "player" entity with user input, positioning data and drawing functions.

users avatar

real fast...

Here's a really quick analysis...

For your "player entity" example, I would say that the entity itself is the Model, the code that maps keyboard / mouse / gamepad input to changes in Model is the Controller (not the same class as the Model), and the code that draws the Model in some way is the View.

There are a number of variants on this; sometimes Controller and View get lumped together. Personally I don't do this.

Here's some pseudo:

void main()
{
Model m;
View v;
Controller c;

c.doInput(m);
m.update();
c.doOutput(m, v);
v.present();
}

void Controller::doInput(Model& aModel)
{
aModel.setInput(keyIsDown(VK_LEFT),
keyIsDown(VK_RIGHT),
keyIsDown(VK_UP),
keyIsDown(VK_DOWN));
}

void Model::setInput(const bool aLeft, const bool aRight, const bool anUp, const bool aDown)
{
myLeft = aLeft;
myRight = aRight;
myUp = anUp;
myDown = aDown;
}

void Model::update()
{
//move according to input (left, right, up, down, etc...)
}

void Controller::doOutput(const Model& aModel, View& aView)
{
aView.drawSprite(aModel.myPosition);
}

void View::present()
{
//begin scene
//draw sprites
//end scene
}

Extremely simple, but here are some notes:

Model (in my games) is not just a single player entity, but basically the entire game state, including all possible entities. The setInput() would typically pass input stuff to the player entity, which would be a member of Model.

Exactly how Controller and View work together to render output is very API-dependent; the example above assumes the need for some kind of per-frame caching and / or "flip to video memory" pass (View::present()) at the end.

The main thing is that the Model doesn't "know how to draw itself", but rather there is some external process (Controller and / or View) that traverses the state in Model and "presents it in some way".

Again, this is just my personal style. I have seen a lot of implementations where the delineation between Controller and View isn't as clear. I personally have lots of Controllers (for the game, for editors, etc) and only one View, which is basically a passive renderer, the place where the visual assets go with methods to render them. I basically see Controllers as "using the View to procedurally program the output for a single frame".

I was in Oslo last November visiting Trygve Reenskaug (the man behind the original MVC stuff back in 1978), but he was very careful to not explain to me what his original ideas were in any detail. We are obviously on the same level concerning that Model is the state of the system, and it seems fitting that any AI or "per tick" logic fits within the Model concept (in a typical OOP manner, i.e. classes with state and behaviour).

What Trygve basically said to me was "do whatever works for you", and I have found that for real time stuff the idea of a "passive view that is programmable" works well - hence my use of Controllers as a separate thing that handles both input and programs resulting output for any given frame.

All my games use basically this same MVC pattern, plus the whole IEventTarget thing that I describe in my book. This is really a preparation for multiplayer, but I tend to use it all the time because it makes the whole application flow much clearer (writes to Model state are much more formalized).

I know this is tons of info to take in all at once, but I would be happy to answer any questions that come to mind either here or via email (johno at johno dot se).

/johno
"you can't stop the change"

users avatar

thanks for all the info!

thanks for all the info! i'll read it a few times and post back any questions. i feel this is my last chance if i want to change anything in the current game. the last few weeks of code is pretty ugly because i wanted to experiment with different things. which means that i want to clean it up after the first iteration anyway to get a good foundation to the real game. i might as well see if this is something that works for me and try it out because if i get any further into the game now it will be too much to change and i probably can't be arsed to change the fundamentals until the next game.

---------------
Solid Core Entertainment
Developer of Roadclub

users avatar

Ah, good old MVC. I seem to

Ah, good old MVC. I seem to recall something about that in school. hObbe, do you have anything to say in your defense? =)

Joking aside though, MVC is a design pattern that is commonly used for games, have a look at gamedev.net and you'll see what I mean. Some more I suggest you look at are Flyweight, Adapter and Observer. In fact, most of the original GOF design patterns are quite handy. There are two you should avoid though, Visitor and Singleton. Visitor is just ugly in my opinion, and Singleton is just about always overused.

A good way to think of MVC for me is to imagine a complete game in 3d. Then imagine you would want to present the game in 2d instead of 3d, for this all you need to do it write a new view that displays the game data (the model) in 2d in the way you want. Controller would be input of all kinds, one could also argue that the controller would handle AI and other decision making aspects from the games perspective, although this is probably an invitation for a flame war.. =)

______________________________________________________________
There's no kill like an overkill!

users avatar

Guilty as charged Actually

Guilty as charged Smiling Actually since MVC is a big fad in the web dev community now (ASP .NET MVC, Zend, et al) we'll be hammering more MVC. I personally find this really interesting that games and web (indeed any interactive system benefits from MVC) is starting to converge...

The "Entity" thingy is actually a big misunderstanding of OO practices. OO actually says objects should be as cohesive as possible and have as low coupling as possible. To then go and make a "Player"-entity that has dependencies on input, graphics, sound, and game play mechanics is indeed a violation of OO guidelines.

Anyway back on topic Sticking out tongue

Our approach to MVC in games have diverged towards pretty much the same actual implementation as Johno described. This also makes it quite easy for us to understand each others code and we can communicate really efficiently. The biggest "confusion" in MVC is mostly what is the View and what is the Controller. The model is mostly clear (ie gameplay mechanics and rules anything not doing with presentation or interaction).

Malice's idea of imagining another presentation for your game is quite good. Though you should probably not diverge into speculation when coding your view. Keep it focused Sticking out tongue

users avatar

Here's a good one

http://martinfowler.com/eaaDev/PassiveScreen.html

This is pretty close to what I'm doing. The only thing that I violently disagree with is the implication that View MUST be stateful, which is what Fowler is talking about regarding "synchronization" and "updating the widgets".

That in itself is the Immediate Mode aspect of all of this; you don't want to have any caches of state in the View. This means, contrary to what Fowler writes, that View probably will have to depend on Model (in order to visualize it) but then only in a constant fashion (reads not writes).

I'm tempted to put a minimal game up on my website in order to be uber-clear in what I mean.

/johno
"you can't stop the change"

users avatar

Great info guys. I'll read

Great info guys. I'll read up on it. A game would of course help too Smiling I'm starting to realize this is where i need to go. I've locked out myself too much already. I've kinda just teached myself and looked up what i needed. I haven't used any other patterns than monostate and singleton so far. So this is a needed lesson indeed Smiling

---------------
Solid Core Entertainment
Developer of Roadclub

users avatar

MVC

Okay. I've read your post several times and I think i understand the general concept. Fowlers example just made me confused. I think i'd prefer more examples in code for games Smiling It's hard to come up with any specific questions. I think i'll just have to experiment and see what comes up.

All i know is i have some very annoying problems in my current code but i guess its no use asking about them until i tried this approach to see if it solves my problems. Most problems have to do with inheritance and not knowing which type pointers to base classes really are though.

All problems are also related to visual effects (guns, explosions) and entities (players, enemies and objects) since there are so many complex communications between these.

I just ended up with using singletons to trigger effects and playing sounds because the pointer passing involved otherwise would be horrendous.

---------------
Solid Core Entertainment
Developer of Roadclub and Sense: Survival Prelude (Developer blog)

users avatar

The RTTI trap

Sounds like you have fallen in the poymorphism/RTTI trap, otherwise known as "is you a can of coke?"

http://www.johno.se/book/oops.html

/johno
"you can't stop the change"

users avatar

Yeah, that's a part of your

Yeah, that's a part of your book that really spoke to me. I felt right at home Smiling

Would it be possible for you to explain how this is solved in your way of working without writing another book?

EDIT: Hmm well your separate lists idea probably fixes some things but i'm not sure it applies all to my problems. Let's take some concrete examples.

The physics system calls a callback with two colliding object's names as parameters. This is the best solution i found to get information about which objects interact with what in the Chipmunk library because all i get from chipmunk is the two shapes involved. The shapes DO have a void* data that i can use to provide "who am I"-info and I guess I COULD put a struct there with a pointer to my object and what type it is. But is that any easier than what I do? I also remember storing the real pointers caused me some trouble (don't remember what) so I went with the names.

Well, this means i now need to find the entities with these names in the entity list and cast them to their subclass to access their specific data. I probably could have several lists with Objects, Players, Enemies, Particles and so on but that would mean querying each list with the name i'm looking for rather than just having a map.

I guess there's lots of room for improvement but i found this usable for now.

My current inter-module communication problems usually consist of particles in a particlesystem wanting to play sounds or trigger other visual effects at emission time or when they hit something. This means that when something calls particlesystem->emit the particlesystem needs access to the engine's audio module and effect module (to trigger another effect at the same time). Is the best way really to provide pointers to the engine modules to the particle system when it is created? I hate having to do that to every object needing engine access... I assume you use some kind of messagebased system or similar? Is that what IEventTarget is about?

---------------
Solid Core Entertainment
Developer of Roadclub and Sense: Survival Prelude (Developer blog)

users avatar

Intermixing a separate

Intermixing a separate physics "engine" of course complicates tings a bit. I guess the physics engine is residing on the model side of things, that is it manages some game play aspects. Unfortunately most physics engines use the "retained mode" approach as you describe, making the physics engine much of a cache duplicating much of the real model data. As it seems the physics engine of your choice seem to mess things up for you regarding your actual game play Sticking out tongue But that is a whole other discussion.

Anyway, my first thought is if you can query for collisions for the specific pairs you want to handle? For example "Player Bullets" v.s. "Enemy Fighter Ship". If you can you can then directly generate an event (function call over IEventTarget) to the view (PlayerBulletEnemyFighter(...)) possibly with pointers/ids to the concrete model object for further investigation by the view (for example checking if the enemy died)

Secondly, I've started to grow fond of using immediate mode techniques for doing effects like particles. In TWTPB all effects are immediate mode, this means they are recreated from scratch each frame and rendering a particle system becomes as easy as calling a function with some parameters.

In my view I mostly had some extra timers for these effects that where started when an event occurred. The view also started any sound effects needed as the event occurred.

This all worked very well in TWTPB...

users avatar

yeah i actually started this

yeah i actually started this project last summer and when I chose the libraries to use i already had the retained approach in mind and had only heard of imgui but didn't really know what it implied. so that's some old choices. i like the library though and it solves a lot of things for me so i don't think its too bad. i can still make the other stuff as good as i want like you suggest.

I noticed i didn't read the MVC chapter yet in johnos book so i'm still a little new on the eventtarget thing.

I really is a mind bender to try to think immediate mode suddenly Smiling

hmm is the view really the right place for logic such as who died?

---------------
Solid Core Entertainment
Developer of Roadclub and Sense: Survival Prelude (Developer blog)

users avatar

There is no rule against

There is no rule against putting rules in the controller/view as long as they are for controller/view logic. In the case of TWTPB and bullet hits there was no model side representation of a dead enemy, so the controller/view simply checked if the enemy was dead and if so started the explosion timer otherwise another effect was triggered.

In my current MVC implementation this logic would reside in the controller. As it seems we(?) have seen that immediate mode techniques tend to make the view a very slim collection of utility functions, the controllers become a bit fatter with responsibilities as described above and layout (i.e. calling view functions in some kind of order)

According to Johno (who actually went to Oslo to talk with the man behind MVC) it seems not even Trygve Reenskaug exactly knows the division between Controller and View. I guess it's very much up to the application and developer to find this out for themselves Smiling

users avatar

heh okay. i guess. johno

heh okay. i guess. johno proposed in his book that he felt it was beneficial if the view was minimal and passive and only had presentation functionality.

---------------
Solid Core Entertainment
Developer of Roadclub and Sense: Survival Prelude (Developer blog)

users avatar

Controller vs View

I would say that the main thing that drove me towards a Passive View was having lots of different "modes" in my app; typical would be to have a "game mode" and at least one "edit mode".

In that kind of scenario I found that it was beneficial to have an object that was shared amongst all "modes" and encapsulated common rendering methods (and not least common assets like bitmaps/textures, meshes, sounds, etc).

Also, there was a "mode master" that controlled switching between the various "modes".

Initially I called the "modes" Views, the "mode master" ViewManager, and the "common rendering object" ViewCore.

The more I worked with this architecture I started thinking that maybe the my Views were really Controllers and my ViewCore was really View (speculating as to what the intended distinction between Controller and View was in the original envisioning of MVC).

These days I would say that each "mode" is a specific Controller, and everything that is common in terms of assets and rendering stuff is View, and there is also a MetaController that encapsulates all Controllers and controls switching between them.

Having things this way allows to basically switch between almost completely different apps by pressing for example the F keys (F1 for game, F2 for level editor, etc) really quickly with no setup or teardown overhead.

Each Controller is responsible for both reacting to user input (doInput()) and composing output (doOutput()) for each frame. There is no significant reason to splitting this up into two methods, but this is just what I tend to do.

At the top Application level loop I do:

metaController.doInput();
model.update();
metaController.doOutput();

MetaController::doInput() handles controller switching as mentioned and then delegates to the current Controller.

Model::update() is a "game logic tick"; AI and stuff goes here.

MetaController::doOutput() delegates drawing to the current controller as well as perhaps drawing top level stuff.

Again, you could do both output and input in MetaController::doOutput() (call it update() or whatever) as you conceivably need to have drawn something for the user to react to it, and it's all a fast realtime loop anyway. I believe hObbE's stuff is more in this style.

I really need to put up a reference game somewhere with full src... Smiling

/johno
"you can't stop the change"

users avatar

Re: controller vs view

Yeah you do Laughing out loud

This sounds like a very reasonable and logical way of splitting things up. So for a simple game with editor you usually only have one model, two controllers and one view?

So far i don't see a reason for several models but you both say you have lots of controllers. What are all these other controllers?

Several views are only necessary if you have very separate things to draw with nothing in common then?

I'd also like someone to elaborate on the two types of ieventtargets used. A pseudo code basic setup summary for what you're talking about on this page http://www.johno.se/book/mvc.html would be really helpful because then i would get a better overview of how things communicate and the eventtargets are used. If you don't feel like it i can try to make one myself and you could comment on that.

Heh the more i read about this the more i start to realize i've already kinda semi-made it like this already so a conversion to real MVC shouldn't be too bad actually. Lots of mistakes roadclub taught me has pushed me in this direction without knowing it.

---------------
Solid Core Entertainment
Developer of Roadclub and Sense: Survival Prelude (Developer blog)

users avatar

Indeed one model, several

Indeed one model, several controllers and one view Smiling I tend to have several tiny editors (in TWTPB there where three I think; one sprite editor, one wave editor and one level editor)

And yes, there should only be the need for one model (as it is the representation of the game).

BTW the smooth rotation in Project L is done on the controller/view side of things on the model side of things the change of up is instant making the world movements much less complicated Smiling When the model changes the up direction it simply sends an event (function call) to the controller and it starts an interpolation timer to interpolate between it's own up direction and the up direction in the model.

users avatar

Todo list

ah cool. well my next thing on the todo list is to make sense (hihi) use MVC architecture. i'll see about pure immediate mode but i'll try IMGUI for sure.

btw will i see it on hub today? sooo looking forward to it.

---------------
Solid Core Entertainment
Developer of Roadclub and Sense: Survival Prelude (Developer blog)

users avatar

MVC summary

Okay, i took some time puzzling together summarizing text and made pseudo code dependency/inheritance summary to get some kind of overview here. I extended johnos first example to include a metacontroller with two child controllers and IEventTarget setup. Have i made any mistakes here?

Model = gamestate and logic which operates on this state (i.e. objects)
Model holds state and logic. I.e data that give substance to all the game's objects. If you have a spaceship, its position and velocity etc is part of Model. Any bullets it shoots is also part of Model.
Model may not depend on View or Controller. Model may be global (i.e only a single Model in the system).

MetaController::doInput() handles controller switching as mentioned and then delegates to the current Controller.
Model::update() is a "game logic tick"; AI and stuff goes here.
MetaController::doOutput() delegates drawing to the current controller as well as perhaps drawing top level stuff.

Controller = based on the state of the Model, Controller orchestrates the presentation of the application using View
Controller will look at (i.e. traverse) Model's state and "program" View to visualize this state in some way.
it is typical to have a "MetaController?" at the top level. This logically replaces the main "Controller" in the MVC pattern, and allows for switching between the various Controllers.

View = the "input/output" layer, including the renderer and also all user interface windows and widgets
View. All interfaces for querying for user input (gamepad/key/mouse stuff) is here, and output/sound/drawing stuff is here, including user interface widgets.
View may depend on Model (in order to visualize it), but may not depend on Controller. View may be global.

Dependencies
* App owns a Model, a View and a MetaController
* View has a const& to Model
* MetaController has a & to View, and passes this to each IController implementation

void main()
{
Model m;
View v;
MetaController c;
m.setEventTarget((IEventTarget)c);

while(loop)
{
c.setEventTarget((IEventTarget)m);
c.doInput(m);
m.update();
c.doOutput(m, v);
v.present();
}
}

class IEventTarget
{
virtual void Event() = 0;

virtual void StartExplosion();
virtual void PlaySound();
};

class IController : public IEventTarget
{
virtual void doInput(Model& aModel) = 0;
virtual void doOutput(const Model& aModel, View& aView) = 0;

virtual void StartExplosion();
virtual void PlaySound();

IEventTarget& frameEventTarget;
};

class MetaController : public IController
{
void SwitchController();

// From icontroller
void doInput(Model& aModel);
void doOutput(const Model& aModel, View& aView);

// From ieventtarget
void StartExplosion();
void PlaySound();

Controller* currentController;
GameController gc;
EditController ec;
}

void MetaController::doOutput(const Model& aModel, View& aView)
{
currentController->doOutput(aModel, aView);
}

class GameController : public IController
{
void doInput(Model& aModel);
void doOutput(const Model& aModel, View& aView);

// From ieventtarget
void StartExplosion();
void PlaySound();
};

void GameController::doInput(Model& aModel)
{
// set input state to model so it can act according to input
}

void GameController::doOutput(const Model& aModel, View& aView)
{
// draw model using model state with views functionality
aView.drawSprite(aModel.myPosition);
}

class EditController : public Controller
{
void doInput(Model& aModel);
void doOutput(const Model& aModel, View& aView);

// From ieventtarget
void StartExplosion();
void PlaySound();
};

void EditController::doInput(Model& aModel)
{
// set editor input state to model so it can act according to input
}

void EditController::doOutput(const Model& aModel, View& aView)
{
// draw model in edit mode using model state with views functionality
aView.drawSprite(aModel.myPosition);
}

class Model : public IEventTarget
{
void setEventTarget(IEventTarget& eventTarget);

void setInput(inputstate);
void update();

IEventTarget& eventTarget;
};

void Model::setInput(inputstate)
{
// store inputstate for use in update
}

void Model::update()
{
//act according to input (move left, right, up, down, etc...)
}

class View
{
void drawSprite(vector position);
void present();
};

void View::present()
{
//begin scene
//draw sprites
//end scene
}

---------------
Solid Core Entertainment
Developer of Roadclub and Sense: Survival Prelude (Developer blog)

users avatar

yes, that pretty much sums it up

Looking at all your pseudo-code I would say it wouldn't be really obvious to a beginner exactly WHY this is beneficial, but maybe that's beside the point here... Smiling

Your wrote this:

void main()
{
Model m;
View v;
MetaController c;
m.setEventTarget((IEventTarget)c);

while(loop)
{
c.setEventTarget((IEventTarget)m);
c.doInput(m);
m.update();
c.doOutput(m, v);
v.present();
}
}

I would change it to:

void main()
{
Model m;
View v(m);
MetaController c(v);

m.setEventTarget(c);

while(loop)
{
c.doInput(m);
m.update();
c.doOutput();
v.present();
}
}

Notes on that:

  • View gets a const & to Model which is stored as a public member
  • Top level Controller (i.e. MetaController) gets a & to View, and thereby const & access to Model since View has a public const & to Model (as per above). Each IController implementation that MetaController encapsulates gets this same & to View at construction time.
  • The m.setEventTarget(IEventTarget& t) in which the MetaController is passed to the Model is for construction order reasons. Note that the Model sees and stores the passed MetaController as an IEventTarget.
  • In the main loop, the only thing you need to pass as a parameter is the IEventTarget (which is the model) to the MetaController in doInput(). The main reason for this is that the actual object you pass may change during program execution, for example if you switch to multiplayer mode, in which case the object being passed will be a remote proxy to the servers-side Model.
  • You could very reasonably get away with having both View and Model as singletons, but in that case it is important that Model does not use View, and that singleton access to Model is const& ONLY.

I will post an example of an IEventTarget to show what kinds of events typically go there.

/johno
"you can't stop the change"

users avatar

The IEventTarget from UfoPilot : Astro-Creeps

http://www.johno.se/software/AstroCreeps_IEventTarget.h

The ordering is methods slightly bad, but here are the ones that the Controller calls:

  • togglePause()
  • setShipInput()
  • resetGame()
  • submitScore()
  • togglePowerup()

The main one is of course setShipInput() which is called every frame once the game is running.

My typical style is that Model implements each of these methods in some way, and then calls back its stored IEventTarget reference (which is the MetaController) to let the "other side" do anything it needs to do as a result of an event.

A good example is asteroidHit(), which is triggered by:

  • A Bullet instance detects intersections with Asteroids, and if one is hit the Bullet calls IEventTarget::asteroidHit() and terminates. Note that this is all single threaded, so technically the bullet dies right after everything that happens as a result of IEventTarget::asteroidHit() is complete. Also note that most things within the Model (the ship, bullets, asteroids) all use the paradigm of const& to Model and a normal & to IEventarget, usually as parameters to their update() methods. This is for clarity, so that when some bit of code wants to change something in the Model, IEventTarget is used to "formalize" that change.
  • Models implementation of asteroidHit() finds the asteroid that is referenced, calls its hit() method (which in turn can result in calls to IEventTarget::makeAsteroid()), and then handles all score and multiplier related stuff for the player.
  • Finally, Model calls back its stored IEventTarget (again, this is the MetaController) to allow for explosion visuals and sound effects, depending on the type of the asteroid (all rocks and creeps use the class Asteroid).

This might feel kind of strange to you, especially since I use the style that logic elements within the Model (asteroids, bullets, the player's ship) all use the formal interfaces to Model (reads are free via const Model &, writes are via IEventTarget &). However, I find that this really cleans up the code and makes all intents very clear, and you have a really good way to make sure that things happen in the right order.

One other thing to note is that a big part of the design of a game like Astro-Creeps is that you have to decide what party is active and what party is passive in each interaction. In my game:

  • Bullets actively detect collisions with Asteroids, and if one occurs they decide to terminate.
  • Ship fires projectiles via IEventTarget::makeBullet() and IEventTarget::makeLaser().
  • Asteroids create new asteroids via IEventTarget::makeAsteroid() (when Asteroid::hit() is called), and also powerups via IEventTarget::makePowerup().

Finally, sometimes "events" are simply for the sake of the visualisation. For example, a bouncing Bullet calls IEventTarget::bulletBounced() when a bounce occurs, and Model implements this with an empty method and then the usual forward to the MetaController, which handles the playing of the bounce sound.

I hope this example helps.

/johno
"you can't stop the change"

users avatar

I've already seen how this

I've already seen how this solves several of my current issues so like you said maybe i don't see all the benefits now but if it works out i'll be happy as they start to unveal themselves as the project evolves. Plus you've already said this is a good start for a network-enabled game (if i ever get to that).

I'm learning a lot here and having SOME kind of architecture must be better than having no idea which architecture you're using.

I've also already realized long ago that i need some kind of event-based system but i didn't know what to look for. and here it's included already Smiling

It helps a lot thanks! It seems a very clean way of doing it. I like having events like that.

Interesting that you don't need more events than that. I'd thought IEventTarget would grow HUGE. I expect it to grow exponentially depending on the size of the project though Smiling

Now on to convert Sense to use something similar to this Smiling

---------------
Solid Core Entertainment
Developer of Roadclub and Sense: Survival Prelude (Developer blog)

users avatar

Happy to help :)

I will be following the development of Sense closely! And btw, I forgot to say that I really liked your glowy yellow "blood" particles... Smiling

/johno
"you can't stop the change"

users avatar

Appreciated!

Yeah really appreciate you taking the time to explain all this!

Great to hear!

Cool, i love playing and creating those effects Sticking out tongue Actually the intention was for the "blood" to actually be those spokes of the "wheel" in the shot particle. the hit behind the monsters is the real hit effect. but it doesn't matter. As long as it's liked Laughing out loud

---------------
Solid Core Entertainment
Developer of Roadclub and Sense: Survival Prelude (Developer blog)

users avatar

Another MVC Q

when the model calls its stored eventtarget with requests for visual effects/sound, who maintains the state after that? say you activate an explosion. the view starts showing it but it will take 3 seconds for the effect to be done. does the view handle this itself or does the controller or model feed the view with the integrated positions/sizes etc every frame (thus not requiring any state in view and holding all state data itself)?

I also have to ask how you handle the classic "engine" thinking. I assume you have SOME kind of utility tools for access to hardware. how does the controller and view access them and where are they created?

I currently have a "framework" to which i register a "game" and callbacks from the framework give me some access to hardware and some parts i can access through a monostate pattern. This is probably what i need to change first.. so answers on the previous paragraph would put me in the right direction.

---------------
Solid Core Entertainment
Developer of Roadclub and Sense: Survival Prelude (Developer blog)

users avatar

If the state is purely an

If the state is purely an effect with no gameplay aspects then this information should be handled by the controller. As I described in twtpb using immediate mode particle systems require only a simple timer (float) for things such as explosions, smoke etc.

In your case an explosion could have an gameplay aspect (explosion grows, ignites other objects etc) then the state should obviously be handled on the model side of things and the view should be able to visualize the state of an explosion directly. Again having an immediate mode type effect makes this much easier.

IMHO the big no no is duplication of state between the model and the controller(s).

Regarding the engine my views depend directly on DirectX, i.e. they initialize, store textures, models etc. I have some utility classes to help me along, but I'm trying to break free from the "engine" principle. Also I have no ambition of making something cross compatible over several apis.

If that was the case the idea of (our) MVC is that you simply write a new set of view classes.

users avatar

Ok as i suspected. I've

Ok as i suspected. I've spent so much time on the framework i'm beginning to think i need to compromise if i'm not to spend a year on rewriting everything. I couldn't make it perfect the first try anyway so maybe it's better to do as much as i can and move on and start with a clear mind on the next project. the framework is pretty nicely divided regarding updates/draws and kinda low-level so it shouldn't be too bad. I should be able to utilize most of the benefits of mvc anyway if i try to wrap what i have inside the mvc classes and use eventtargets for communication.

---------------
Solid Core Entertainment
Developer of Roadclub and Sense: Survival Prelude (Developer blog)

users avatar

State

I'm sorry for bombarding you with questions but your precise answers are usually all i need to know.

This question is about state management. How do you handle different menus and transitions between them? I assume everything goes in the model. Which would make it huge.

Well say i want a constant background and then transition between the main menu and the options menu over it. I'd need to show two states at once in the view while they transition and one constant behind them. The controller should make this happen somehow as i understand it.

In johnos imgui example he had a controller for each window. Maybe i should have a backgroundcontroller, and store a controller for current and next menu and let them do their thing to send to view.. well i'm just rambling here. but maybe it'll give you an idea what i want to discuss.

Also, if i understand this correctly. If you divide work into classes in a model or controller you still need to pass around that eventtarget variable to all children for them to be able to generate events?

---------------
Solid Core Entertainment
Developer of Roadclub and Sense: Survival Prelude (Developer blog)

users avatar

About "state"

There is no call for being totally purist about state. To be fair, a D3D texture interface handle is "state" (it occupies memory). I agree with hObbE that a singular concept that is part of the domain model (i.e. Model) should only be represented once.

A counter-example: back in my days at Massive (I'm thinking Ground Control II in 2003-2004) we had for example the 3d-space position of any given unit represented once on the server, once on the client, once in the 3d engine, once in the script api, and once in the AI module... Sticking out tongue

Concerning "menu states"; in Bloom, which is a pretty recent architecture, I have these controllers:

  • IdleController: this controller is active when the game is not being played, and handles all the different "screens" (highscores, credits). There is a piece of state inside IdleController called myScreen, which is a simple enum variable that represents the current screen, and everything is IMGUI style from there.
  • PlayController: this controller is active when the game is being played, and handles user input for the little dude and of course renders the game world, plays music, etc.
  • ReplayController: very much like PlayController, this controller is active when a replay is being shown. However here the IEventTarget method setHeroInput() is being fed not from user input, but from prerecorded input from the current replay.

In the version of Bloom that is on hUb right now, the current controller is selected each frame by MetaController depending entirely on Model state, like this:

IController& MetaController::controller()
{
if(myView.myModel.gameActive())
{
if(myReplayer.isPlaying())
return myReplay;
else
return *myController;
}
else
{
return myIdle;
}
}

The Controllers are the variables myReplay, myIdle, and whatever myController is pointing at at that moment (Bloom has an integrated EditController that you never see when you play the game).

So my point is basically that what many people consider to be "application states", i.e. frontend vs ingame, is in my mind just a number of different Controllers handling input and composing output. The Model is always there and encapsulates the same state, but since it in itself doesn't know or care about visualization what the user is seeing is purely dictated by Controllers.

This drastically contrasts what we used to do back at Massive with "application states", where when the user saw the frontend the entire "model / server" didn't exist at all (was dynamically allocated later). This gave us all kinds of headaches concerning things like displaying stats from the last mission in the frontend, since that memory belonged to the server that we just deallocated.

I very much strive to be able to have every single thing I need for the Model in memory at the same time, because if I can't things get complicated very fast. Remember, even if you have several maps or levels in your game, you still only need to have one loaded at once. Also, because of the non-cached / immediate nature of View and Controller, they really couldn't care less about when the internal representation of Model changes, even on a per frame basis.

/johno
"you can't stop the change"

users avatar

The "razor"...

Reading all of this back I think that one thing is worth mentioning.

A good way to get your head around "which state goes where?" is to think about what the domain model actually is and cares about. Really force yourself to think about what the game really IS, and how that can be represented by state.

As hObbE mentioned, if an explosion or a sound or a texture is purely "visualization / eye candy / decoration" and has no real effect on anything that happens within Model, than it belongs in Controller or View. From there it's a matter of personal preference, but here at SoP we pretty much all agree on the strengths of having a passive View, so the explosion example does indeed go in the "Controller section".

I've almost become fetichistic about reducing the amount of state required to represent something; recently in Sentry's menu system I removed the need for a variable that tracks the current selection in a given menu. Now I barely understand the code though, so maybe that's a bad thing... Sticking out tongue

One thing that is really great about MVC however is that even though DirectX "requires" that you express transforms in matrix form, that doesn't mean that your Model has to use that format; you can still use 3d points and euler angles if you want to.

Again, I find the split to be really helpful in concentrating on what the domain model really IS, and face it; stripped of everything presentation-oriented games really aren't all that complicated. I haven't made a game yet where the Model (I tend to have Model in a separate library) is more code than the View or Controller stuff.

/johno
"you can't stop the change"

users avatar

State 2

Thanks again for elaborated but to-the-point answers. It's really helpful to see how you've actually implemented something even though i think i understand the basic concept pretty well by now. MVC can be interpreted in a few ways and you can place stuff in different places depending on your position.

I spent a few hours today morphing sense code into MVC. I gotta say, it was like laying a puzzle. Things just fall into place and it feels right. It's great to see that what I've done isn't so bad and it's nice to see the benefits of the new architecture kinda remove unnecessary code and dependencies as well as links to singletons.

The eventtarget approach is really nice. I had to make SOME modifications to the original plan but generally it was pretty painless and stays true to the discussion we've had. The framework does some things i merged with the mvc layout but nothing major and i think it fits nicely. There's still some work to do but i think the eventtarget actually removes most of my communication issues and the feeling of need for singletons "because it's too hard to find objects". Now i just call on the eventtarget what i want to happen and the model or a controller somewhere takes care of it.

The hardest bit will be separating drawing code from objects that previously had both update and draw functions and make the controllers tell the view what to do instead. but i really think it will be nicer and easier to work with when its done.

Now that i know that "input goes here" and "drawing goes here" it's much easier to design the code and know where to put it and similar code is automatically brought together.

Hehe i would be careful going too far though like with your sentry example there. I think at some point you're just complicating for yourself by trying to make the nicest code according to your Plans of Purity Smiling Sometimes you just have to move on because you have a working setup that already does what you need and there's no need putting more time into architecture design at the moment.

The last bit is interesting. From what i can see now it looks as if the eventtarget and model will grow really large while controller and view stay smaller. Well, we'll see as the game grows, things are still too much in the wrong place for a final judgement.

---------------
Solid Core Entertainment
Developer of Roadclub and Sense: Survival Prelude (Developer blog)

users avatar

Post new comment

Please solve the math problem above and type in the result. e.g. for 1+1, type 2.
The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <h1> <h2> <h3> <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • Textual smileys will be replaced with graphical ones.
  • Images can be added to this post.

More information about formatting options