Jump to content

MVC and physics


Laurens
 Share

Recommended Posts

Hi everyone,

 

I have been rewriting my project to apply Model-View-Controller. I like the idea of seperating game logic from rendering and input but I have hit a snag.

 

In the engine, a TEntity is both a mesh and a physics body. The TEntity is contained within the view because it serves the rendering purpose. Now let's say a collision occurs in the game world that bounces the TEntity to a different location. There is no way to tell this to the model because the view is not allowed to change the state of the model and I do wish to keep this seperated.

 

Now I though of a different solution and that is to contain the actual physics mesh (through LoadBody) in the Model, and the mesh (through LoadMesh) in the view, making the body the parent of the TEntity. My question is now, is it possible to set collisions callbacks and such on a Body? Is a Body also a TEntity?

 

And will I run into any other snags I have overlooked right now using this method?

 

Many thanks!

Link to comment
Share on other sites

TEntity is just a general pointer to any kind of entity (camera, source, mesh, body, model, etc...).

TModel is TBody+TMesh (mesh is the first child of TModel, body is the root, same as the model).

You can also keep TBody and TMesh seperate and use PositionEntity/RotateEntity/SetEntityMatrix on the mesh to place it where the body is. I use this for additional models, like trousers, boots, etc... since if you parent them to the model, the animated main model gets bugged (at least in LE 2.22).

Ryzen 9 RX 6800M ■ 16GB XF8 Windows 11 ■
Ultra ■ LE 2.53DWS 5.6  Reaper ■ C/C++ C# ■ Fortran 2008 ■ Story ■
■ Homepage: https://canardia.com ■

Link to comment
Share on other sites

Look over here: http://www.leadwerks.com/wiki/index.php?title=Entities#SetEntityUserData

You can create your own custom class and circle reference this class in userdata, like (Bmax code):

 

Type TCharacter
Field Body:TBody
Field Mesh:TMesh
Field Health:Int = 100
Field State:String = "hostile"
End Type

myChar:TCharacter = New TCharacter
myChar.Entity = LoadMesh("mychar.gmf")
myChar.Body = CreateBodyBox(1, 1, 1)
EntityParent(mychar.Mesh, mychar.Body)

myChar.Body.userdata = myChar

 

Funny enough, this will not crash and is very useful.

desktop: Quad core Q6600 + 4GB + ATI HD4890 + XP

laptop: Dual core T6400 + 4 GB + NVidia 9600M GT + Vista 32

Link to comment
Share on other sites

In the engine, a TEntity is both a mesh and a physics body. The TEntity is contained within the view because it serves the rendering purpose.

 

I don't know if that really has to be the case. Looking at the wiki of MVC let's take some information from that and see if we can't relate it to LE.

 

The model is used to manage information and notify observers when that information changes.

 

When a model changes its state, it notifies its associated views so they can be refreshed.

 

The way I see it, the TEntity is the means on how you notify the view of changes (in LE the views are hidden from the programmer). So by using TEntity and calling PositionEntity() you are telling that view the change you want.

 

LE handles the view for you already and so you really only have to handle the model and controller.

Link to comment
Share on other sites

TEntity is just a general pointer to any kind of entity (camera, source, mesh, body, model, etc...).

TModel is TBody+TMesh (mesh is the first child of TModel, body is the root, same as the model).

You can also keep TBody and TMesh seperate and use PositionEntity/RotateEntity/SetEntityMatrix on the mesh to place it where the body is. I use this for additional models, like trousers, boots, etc... since if you parent them to the model, the animated main model gets bugged (at least in LE 2.22).

 

Thats good to hear. I'll perform some tests before I fully implement it to see how animations behave though.

 

You can create your own custom class and circle reference this class in userdata, like (Bmax code):

 

Had not yet thought of that and deserves some looking into!

 

The way I see it, the TEntity is the means on how you notify the view of changes (in LE the views are hidden from the programmer). So by using TEntity and calling PositionEntity() you are telling that view the change you want.

 

LE handles the view for you already and so you really only have to handle the model and controller.

 

That's an interesting perspective and had not yet looked at it that way. The downside to having the TEntity contained in the model is that view-specific code (even though hidden) has to be contained in the model as well.

 

For example, let's say I am creating an RTS and want to tint selected units green. By having the TEntity contained the model I would have to go through the model to change the color while the model has entirely no interest in knowing what color it is. By having the mesh in the view it would simply query the model and if it is selected, tint it green. In an ideal world the model would simply enforce the game rules and nothing else.

 

I do understand that all suggested approaches will most likely work though and it mostely is just me nitpicking, but I am trying to keep the reliance of the model on the engine to a bare minimum. If I ever need to change the engine to for instance LE 3.0 I can leave the model untouched. Secondly I feel it gives much cleaner code, having game rules, input and rendering neatly seperated.

 

Anyway, thanks for all the insights so far :)

Link to comment
Share on other sites

That's an interesting perspective and had not yet looked at it that way. The downside to having the TEntity contained in the model is that view-specific code (even though hidden) has to be contained in the model as well.

 

It seems to me from the wiki description, that the model tells the view of the changes. The view doesn't query the model for the changes. So if the model portion of the code has to tell your 3D models in the view to change, how can it ID those 3D models in the view? It seems you would want to use the TEntity for that ID. No reason to create your own. So that's why it seems like it would make sense that the model hold these ID's of all the views, so it can tell the views what to do.

 

That's just my understanding of it, and honestly the MVC model isn't something I've used before but from reading the description of it this is what my take on it is.

 

In your example, selecting the units would be the Controller potion. That input would them populate the Model portion (SelectUnits logic) with the TEntities that were selected. Running the Model logic would then set their tints, which is telling the View portion of the change you need. Then LE draws the View for you with the changes.

 

 

So it seems you are trying to have the View query the Model instead of having the Model update the View?

Link to comment
Share on other sites

It seems to me from the wiki description, that the model tells the view of the changes. The view doesn't query the model for the changes. So if the model portion of the code has to tell your 3D models in the view to change, how can it ID those 3D models in the view? It seems you would want to use the TEntity for that ID. No reason to create your own. So that's why it seems like it would make sense that the model hold these ID's of all the views, so it can tell the views what to do.

 

That's just my understanding of it, and honestly the MVC model isn't something I've used before but from reading the description of it this is what my take on it is.

 

In your example, selecting the units would be the Controller potion. That input would them populate the Model portion (SelectUnits logic) with the TEntities that were selected. Running the Model logic would then set their tints, which is telling the View portion of the change you need. Then LE draws the View for you with the changes.

 

 

So it seems you are trying to have the View query the Model instead of having the Model update the View?

 

I believe everyone has a different take on the pattern just like any other theory. What we were taught in college was that the Model has an indirect association to the view, and the view has a direct association with the model. So what we did was this: the model is repositioned and then tells the view through an observer or event "Hey, I was moved!". Then the view would call model.GetPosition() and move the mesh it contains.

 

I think that also answers your question as to how the model would ID the view it is associated with. It doesn't. The view would subscribe to events the model raises and update itself to represent the state the model is in after the event was raised. Let's say the model fires the "Moved" event. The view would then GetPosition() on the model and SetPosition() on the mesh it contains.

 

Typing that I realize that I may be creating a giant performance bottleneck. Perhaps it is indeed best to contain the TEntity in the model and cut out the view, regardless of whether it is violating the pattern or not.

Link to comment
Share on other sites

Ah, events. Yeah that makes sense now. I was trying to figure out how the Model would tell the View without storing ID's to it, but events solves that. I like that idea. You can use that event system I posted a few times on here. That would work very nice with this because the View methods that you bind to events can be private and not exposed to the View objects if you want, creating a nice and tight object that is controlled by the Model logic.

 

Seems you think I opened your eyes, but I think you opened mine :)

 

Then the view would call model.GetPosition() and move the mesh it contains.

 

The only strange thing about this with LE is that the way it's setup the assets already know their positions and other values. So storing them off again in the Model section would be duplicating things. Like in the Model section you'll have Vec3's for positions of assets when in reality you can get that from the View side because it has the TEntity and when you have that you can query anything about that like position/rotation etc.

 

That was one of the reasons LE is slightly different than other none entity based engines where it's up to you to store the position and other attributes yourself. LE already does that.

Link to comment
Share on other sites

I'm curious on how you are going about Views also. Are you taking everything in the scene and putting them into 1 View or are you breaking them out based on some criteria or are you dynamically making/destroying Views as the game goes along? This is interesting stuff :)

Link to comment
Share on other sites

You can use that event system I posted a few times on here.

 

I have been using that extensively for some time now. It's awesome :)

 

Seems you think I opened your eyes, but I think you opened mine

 

Good to hear we both had benefit from this thread then :(

 

The only strange thing about this with LE is that the way it's setup the assets already know their positions and other values. So storing them off again in the Model section would be duplicating things. Like in the Model section you'll have Vec3's for positions of assets when in reality you can get that from the View side because it has the TEntity and when you have that you can query anything about that like position/rotation etc.

 

You're right. I wrote it down like that more for the purpose of explaining what I was taught about MVC. I'll admit that wasn't entirely clear :)

Link to comment
Share on other sites

I'm curious on how you are going about Views also. Are you taking everything in the scene and putting them into 1 View or are you breaking them out based on some criteria or are you dynamically making/destroying Views as the game goes along? This is interesting stuff :)

 

Basically every entity has a view that displays it. I have an EntityManager that stores and updates all entities it contains and for every entity that is added to or deleted from the manager, an event is raised that is picked up by a RepresentationManager that will create the appropriate view.

 

What I have right now is mostly based on what I read in this article over at Gamasutra: http://www.gamasutra.com/features/20050414/rouwe_01.shtml

 

Mind that the view we have been talking about is called an EntityRepresentation in that article. Otherwise you might be confused :)

Link to comment
Share on other sites

But duplication of things LE already stores might not be all that bad. I'm reading more about this and it seems at some level the Model doesn't need to know about the View or Controller at all. This would be huge in being able to port all your game logic over to multiple engines. You wouldn't need to change your game logic at all. Just the Controller and Views which would help same time and reduce bugs when porting a game.

 

At first glance anyone using LE would say you are wasting memory and processing time, but you are gaining the ability to port your game much faster and easier. This could be huge if you plan on making things on consoles.

Link to comment
Share on other sites

But duplication of things LE already stores might not be all that bad. I'm reading more about this and it seems at some level the Model doesn't need to know about the View or Controller at all. This would be huge in being able to port all your game logic over to multiple engines. You wouldn't need to change your game logic at all. Just the Controller and Views which would help same time and reduce bugs when porting a game.

 

At first glance anyone using LE would say you are wasting memory and processing time, but you are gaining the ability to port your game much faster and easier. This could be huge if you plan on making things on consoles.

 

This is indeed a bit of a trade-off but the benefits gained in terms of maintenance and porting to other platforms can be huge.

 

And it doesn't have to be limited to 3D engines. Say I want to use SDL. The model can be untouched, all that would require updating is the controller and the view. The game rules would still be enforced because it doesn't rely on a certain technology.

Link to comment
Share on other sites

Then the view would call model.GetPosition() and move the mesh it contains.

 

I wonder if it would be better to just fire events from the Model to the View and pass in the information required for the event instead of having the View query the Model for data. That way the views wouldn't need to hold onto a reference to the Model. It would just need it at startup to subscribe to it's events. Basically you would have events for every kind of thing that could happen to a View(Entity).

Link to comment
Share on other sites

I wonder if it would be better to just fire events from the Model to the View and pass in the information required for the event instead of having the View query the Model for data. That way the views wouldn't need to hold onto a reference to the Model. It would just need it at startup to subscribe to it's events. Basically you would have events for every kind of thing that could happen to a View(Entity).

 

Good point. The View is never meant to manipulate the Model anyway so there is no reason for it I can think of right now to hold a reference. It can just wait for an event and have the Model pass it as an argument.

Link to comment
Share on other sites

Then this is where you can borrow from .NET with events and have an EventArgs class that you derive from for specific events so it can store specific variables about that event. This would allow you to define all event variables as Event1<EventArgs*> OnPositionChange, and still be able to pass different data based on the event. Derive from EventArgs to make PositionChangeEventArgs that has an x, y, z variable, and when you fire OnPositionChange create an obejct of PositionChangeEventArgs and fill in x, y, z and pass it to the event when the Model fires it.

Link to comment
Share on other sites

So where does the actual storage of data go? I can't imagine it goes in the View or Controller so that leaves the Model. If it goes in the Model that would mean that each instance of a View has it's own instance of the Model so that it can have it's own data? I was originally thinking the Model would just be the logic alone, but then I wouldn't know where the data would be stored so now it seems the Model needs the data for that specific instance of the View it's working on.

Link to comment
Share on other sites

The Model does indeed hold all the data the View needs to work with. For example:

 

I need to represent a spaceship. The Model would keep all data relating to the spaceship it needs to enforce the rules. This includes speed, hitpoints, mounted weapons, shield strength and so on. It also defines how the spaceship behaves and thus has methods such as FireWeapon(), BoostShields() and AddThrust().

 

Each Model is associated with one View so if I instantiated ten spaceships, there would be ten Models and ten Views.

 

Now let's say the players hits the W key and the controller calls AddThrust() on the ships it's controlling. The Model will then raise the Moved event that the View is subscribed to. The method it is bound to in the View will be called and it can then update the actual position of the TEntity, passed through the EventArgs.

Link to comment
Share on other sites

That makes sense. Seems like you can also have a separate GUIView then, that also subscribes to your spaceship Model so it could update the UI too when certain events are fired. That's cool.

 

This method seems like it also gives you a good networking approach once you are able to run LE on a server without a graphics card, since all the game data and logic is in Models, you just send the data to the clients and they update their visuals. With remote procedure call you can even fire events on those client machines to update their Views.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...