design hiccups

Started by
6 comments, last by Telastyn 18 years ago
I'm having a little problem with the design of something. It's not a huge something, but then again most of my design problems are the small things. I've created a little class that will output messages in a bitmap font to the window, you know like in all the demos that we see here, it's got the little bit of text at the top of the window (NOT the title bar), that says the fps and other misc stuff? I've written that (not very big either). But I want to be able to specify the corner of the window where the text will appear. My problem isn't positioning, it's whether I should have a data structure (dynamic array) for each corner and keep all the messages for the top right corner together, all the messages for the bottom left, etc, etc. The advantages to keeping everything in a single array is that I don't have to have a bunch of 'if' statements containing almost all the same code depending on the corner of the screen, but then again, the disadvantage is that whenever I need to render it I have to keep different variables for each corner of the screen and it just seems inelegant (I seem to be using that word a lot these days). Has anyone else done anything like this, or have any ideas that could help?
[size="2"][size=2]Mort, Duke of Sto Helit: NON TIMETIS MESSOR -- Don't Fear The Reaper
Advertisement
I don't understand the problem, what's wrong with this implementation?
Message[] all_messages;for each message M in all_messages   if M is in top-left      print_topleft(M)   else if M is in top-right      print_topright(M)   ... and so on

print_xxx() can be classes that keeps track of the location where the next message should be printed at.
Well, since there can be more than 1 message in each corner, I'll have to keep track of the current position for drawing, so I'll need to keep 4 variables, one for each corner, which I suppose isn't that much of a problem. I just have a feeling that there's a better way of doing it.
[size="2"][size=2]Mort, Duke of Sto Helit: NON TIMETIS MESSOR -- Don't Fear The Reaper
There are some problems with "if-then-else" (or "switch") design, to name a few - its harder to extend, usually promotes copy-pasting, harder to edit in runtime (for example give a new "plugin" feature with a DLL), its slower O(n) instead of O(1) and Im sure there are more.

the object oriented way to do what you want is simply polymorphism -
some pseudo code:
abstract class text {void draw()=0;}class top_left_text : text {  static int number_of_texts_to_top_left=0;  int line_number; override constructor {  number_of_texts_to_top_left++;  line_number = number_of_texts_to_top_left; } override void draw() {  draw at top left at height "line_number" }}class top_right_text : text {  static number_of_texts_to_top_right=0;}...list <text  *> text_list;text_list.push_back( new top_left_text("hello from left") );text_list.push_back( new top_right_text("and from right") );foreach text in text_list do text->draw();


[Edited by - Iftah on April 1, 2006 9:43:17 PM]
Well to me, it doesn't matter how you design it, you need some location where a message should be printed at.
Personally, I don't like having each corner its own message array. Depending on the implementation of the array, transferring messages between corners can be a pain.

This is the way I would implement the corners:
class Corner{private:   int _x, int _y, int _dy;public:   Corner( int x, int y, int dy ) : _x(x), _y(y) : _dy(y) {}   Print( const char* c )   {      print(_x,_y,c);  // call your bitmap print class      _y += _dy;   }};

For example, for top corners, you would feed a positive number for dy, and a negative number for bottom corners. Now that I have done it, each message can have a Corner* member variable where it belongs, then you no longer need if-statements.
In my current implementation, text [even dynamic messages like that] are just renderable objects. Renderable objects contain a generator (a functor that takes 0 arguments and returns an object), which specifies their bounding rectangle. Making a corner 'tied' object is a simple matter of creating a generator object which returns a bounding rectangle based on the result of another.

[actually, it's much cleaner to simply return a cached bounding rectangle, which is then updated on any change to the one it's referenced from...]

Anyways, probably complete overkill for what you need, but another way to think about it.
I would personally make them objects as well. This syntax seems most natural to me:

MessageBox mb = new MessageBox("Hello Screen", x_pos, y_pos);
mb->Draw();
I think most people make them objects. Just to be clear, the key was the use of objects to determine a renderable's position. This is the sort of syntax that mine end up with [C# style psuedocode]:

TextRenderer FPS=FontManager.Load("FPSFont");FPS.TextSRC=new FPSTextGenerator("Frames Per Second: {0}");//// Now tie generated renderable to the Main Window, at the top-left corner,//  to the top-left corner.// The size is defined by FPS's "StringSize" function, and use the default//  offsets.//FPS.Rectangle=TiedRect.Tie(FPS, MainWindow, Tie.TopLeft, Tie.TopLeft, FPS.StringSize);//// The above actually would be a helper, which creates a generation functor//  (generator), which auto-magically moves FPS if the MainWindow moves, //  changes the size if the Font/Text changes...//


Like I said. Overkill if you just want text in your corners, but I hope you can see how this makes for some very useful constructs in certain scenarios.

This topic is closed to new replies.

Advertisement