Quote:What I mean by a "message based" engine is that parts of the program submit "messages" into a queue. ... Each frame the engine (if you can call it that) goes through the queue and looks at each message. Depending on the nature of the message, the engine makes calls to methods in other parts of the program.
The first time I started this project, I actually tried the idea of keeping a message queue, then dispatching the messages by allowing each object to know what message to start at, so it can iterate though and process the messages. The main problem with this approach is first the overhead of storing messages in your queue. When do you remove them? What if a message needs to go to several different classes?
From what I saw, storing all of the messages then passing them to the objects could also create desynchronization. For example, if I passed two messages, one side effect would be that one object would "catch" up by processing the events in the message queue until there were no more and then the next object would do the same. What resulted was some objects doing messages out of order, which was bad. Now I could have made it so objects only processed messages one at a time, but then I was thinking, what's the point of that?
Next I saw if I was just going to be passing messages as they occured, why store them? If they only need to go to a specific object, then message processing could just send it as it is received, thus eliminating any desyncing as well as the additional overhead. With that in mind, I then based the rest of the design in terms of an "instant feedback" approach. Now, as you may be wonder, and as wa asked, "what about delayed events". At first I was thinking that was the only thing my approach could not accommodate for, but then I thought about it.
A delayed event is an event that is sent at some time, to which it actually happens a later time. More specifically in real life, it's some 'cause' that triggers some 'effect' in the future. Now, with the old version of storing messages in a queue, you could allow that system to track the time and dispatch messages only when some delay reaches 0, but I did not think that was realistic. My whole idea fo this "delayed event" is that an event is sent to some object, and the object itself handles the delaying.
For example, if you set an alarm clock to go off at some time, the object itself controls when the "effect" actually happens. If that object was turned off, then the event would not happen at all, which is more realistic with my model than that of the conventioanl message queue, which would still dispatch that message to the object. In addition, the actual messaging system would have to be some centralized component that received messages anddispatched them while keeping track of time and who it can send to and all of that. I opted for something much different.
Quote:I thought about creating a generic base class for a message. It would contain a few simple variables, such as a name, a boolean value to see if it has been taken care of and can be discarded, and perhaps a few other basic things like that. Now I would derive other classes from this, depending on what the message needs to contain.
Good start with the idea of a generic base class for a message, that is what I do currently. However, I left it at that. Simple and easy to use, there is only one message class that stores 3 things, who sent it, data of the message, as well as the names of the message. The reason I did this was to minimize the dependecies that would otherwise be created with your proposal. For example, if you have 3 different classes with 3 different messages, all 3 would have to know about each other's format of the message if they want to interact.
I took the approach of "void* message passing". Yes, this of course seems more dangerous and unsafe, but, it's one of those things that is fine to do when you know exactly what you are trying to do. In my system, I pass a 1:1 ratio of named messages with void* data. This way, any object that receives a message can parse the message name and if it implements it, then it can process the data accordingly. My approach does rely on more of a "you know the data being passed around", so it is more error prone, but with a reasonable amount of checking, it is very flexible.
Quote:The problem I am having is, how would the engine be able to distinguish between the different types of messages? How would the engine 'know' that a message contains variables specific to that kind of message?
As mentioned in the previous paragraph, the message name will let the object know what the message is. "What is done" with the message is specifically up to the object itself. If it does not handle the named message, then it will naturally just ignore that message. If it does handle it though, then it can process the data if any. Since each data will have a name with it, the end user can handle data in any order it comes. What I was going after with this approach is that of more a life-like representation. For example, let's say I pass a "kick" message to a boulder. Naturally, the boulder will not handle that message since it will not be affected by it.
Now I just said if I pass a "kick" message to a boulder, it would not handle it. With my design, all messages are sent to all objects! So if the player "kicks", all messages will receive the message as well as the data associted with it, such as where it took place, how hard was it and so on. If an object does not handle the kick message, it will simply ignore it. If it does handle it though, then it can see if it is actually affected by it.
Next comes the whole aspect of knowing what messages to pass and all of that. At first I just typed in the messages using strings and handled the handling of them doing the same. The problem that I saw was if that I needed to change a message one place, I'd have to change it in the other place, so what I did was make one header file that defined all of the messages being used. Of course each time I made a new message, I'd have to recompile, but it was a lot clearned and easier to use.
With my current design, I will be finding another way to do this, something that involves a map to which I can just register events and use them without having to worry about inconsistances. The idea would be that I can register messages and track them, so at any time, if a message is used that is not registered I can stop execution and warn myself that a typo was made or something was used that needs to actually be handling. That will make debugging a lot easier as well.
One last response on the idea of the actual messages being used. My main goal is to define a set of engine specific messages that are used to denote common events, such as when a key is pressed, what key it is will be passed as well. By doing this, I can then tie in any framework or library to use my system which would make integrating it a lot easier. In that case, all you would have to do is add in the specific message broad casting of events that corerlate to the engines defined ones and you are all set.
Ok, now I have covered pretty much the basics of my system. Time for demos! As I went along developing this system, I needed a way to test it in application to see where any problems were. What resulted was me making a SDL Selection Box demo. I have screenshots of the demos, the demos themselves, as well as screenshots of code to give you the idea of what is going on.
After I got to version 8 of that last example, I felt it was time to move on, so I hacked together an example, but this time using 3D and Opengl . OpenGL Selection Box. In that example, I implemented my messaging architecture and saw a few things had to be changed. Ok for controls:
Left mouse - Select or draw drag rectangle
Arrow Keys - When an object/objects are selected, change their rotation
Pg Up/Down - When object(s) are selected, will change their Z values.
That's about it for that demo, the hardest part for me was actually getting the OpenGL stuff to work correctly (one little thing I was doing wrong in my picking that threw me off for hours).
That's about it for now, I am working on integrating this system into a new engine that will use it. By doing this, I can see where some problems might occur or additional functionality I might need. For example, I always had the ability to send a message to a specific object, based on it's guid, but with the logics I had, it was being done incorrectly. Final note on this system are that it is decentralized -- there is no main message component. As to what I do, you should be able to figure it out though the code screenshots.
If you have any questions on this (Yes I see that I kinda wrote a lot [grin]), feel free to ask! I'm not giving away any code right now though, but I can show certain specific parts. On a final note, you can take aa look at my old threads at attempts to this as well: Void* Messaging for Classes, Self Managing Objects - Part 2, Self Tracking Object Design
Phew, that took a while [smile] Good luck!