This is one (big) bullet shot which went through the triangle out to the other side. It supports clipping against static geometry and fades at an angle.
Front side:
Back Side:
This is one (big) bullet shot which went through the triangle out to the other side. It supports clipping against static geometry and fades at an angle.
Front side:
Back Side:
I’ve been using CEGUI for a couple of weeks now. I’ve been trying to get a string to show up, with word wrap, for 5 days. Not actively, but on and off I’ve been pursuing this topic for that long.
My difficulty lies in that I don’t need to use their window system, with selectable text, etc. And I don’t want to define my text in an xml file, the preferred way to setup your interface. I simply want to do the equivalent of printing “Hello World” purely from code, including word wrap.
My first approach was to use the Font class. It seemed pretty good – there is a function to tell you how long a string was and how many lines it would span. I didn’t see a function to tell you where exactly the string was split but it’s a good start. The problem was that it didn’t work. So I asked about this on the forum. A day later I was essentially told not to use that class directly. It didn’t bother me too much, because I had a hunch of the technical reasons why this might be, but user classes should have clearly been delineated from internal classes and marked as such. As an aside, in RakNet all classes are independently functional and are documented as to their use, not just with Doxygen.
Anyway, to display text, you have to create a window and set the text for that window. How do you do this? There’s a Window class, a StaticText class, a DefaultWindow type, and a GUISheet class. GUISheet is the one to use although StaticText is the one you would think to use, with functions to set the text color, formatting, and other things. However, StaticText contains abstract functions, meaning you can’t use it directly, as I found out after I went to the trouble of trying to use it and then compiling. It turns out this is a class for internal use only. Arguably this was my fault for not looking closely enough to see that there were pure virtual functions. This is the same problem as before though – it should have been marked which classes were for the user and which not.
It’s definitely not obvious that GUISheet is the class you would use to display text. This is doubly the case because GUISheet does not contain functions related to text. It turns out the way it supports text operation is through a setProperty function which takes a string for the action to be performed and a string for the parameter. For example. “HorizFormatting” followed by “LeftAligned” (or something similar). I’m not sure how you are supposed to know this. In order to determine what properties were supported I had to search the source code for “: public Property”
Using strings as the native interface to set properties is a design mistake because it adds an unnecessary layer of abstraction between the user and the intended functionality. Rather than simply passing native types around (such as numbers) I have to convert them to strings. When I want to get the native type back from the string I have to do a reverse conversion, which I’m not sure is even supported. The reason they did this was to more easily support scripting. However, the proper way to architect this would have been to provide a translation layer from script strings to native types, such as numbers, with the reverse operation supported as well, rather than taking strings directly and hiding the native types.
CEGUI is very powerful if you stick to the mechanisms they give you. With almost no effort you can add tables, scroll bars, buttons, input windows, and other widgets. However, these widgets do not provide everything you might need. For example, my current difficulty comes from the fact that I’m trying to fade out and then delete text over time, a function not natively provided. It seems like cracks in the armor start to show through in those instances.
For API usability I’d give CEGUI a C-. It’s well documented at the level of Doxygen. They use Doxygen much better than RakNet does. Depreciated and non-user classes are not documented as such that I was able to see. The newer features seem to have worse architecture than the older features. However, the availability of the source code is a huge plus: it makes what would be otherwise insurmountable problems minor inconveniences.
For functionality I’d give it a B+. It does a lot and covers most of the common features. My favorite feature is input parsing, so it will natively understand double clicks. It also supports copy/paste, text highlighting, tables, and scroll bars. The GUI editor is a major benefit.
Here’s the problem:
Often in games when text shows up on the screen it doesn’t just pop in and pop out. Instead, it will fade in, display for some time, and fade out.
CEGUI (my GUI library) doesn’t support this. So I have to write something myself.
Solution:
Obviously the solution is to modify the alpha of the string.
My question for you:
“What is the best way to architect this?” Composition? Inheritance? Modify the string class? Write a string manager? Something else? This is non-trivial.
Think about your answer, then scroll down
.
.
.
.
.
If you’ve read my previous posts, the best architecture has small units of functionality that do the minimum possible while accomplishing the task at hand.
Classes which are well designed
A. Have loose coupling, which means that they have generic inputs and outputs.
B. Have tight cohesion, which mean they don’t rely on other systems to do the work they are responsible for.
Think again what you would do, then scroll down for what I did:
.
.
.
.
.
Header file:
#ifndef __FADE_CONTROLLER_H
#define __FADE_CONTROLLER_H
// Assumes the object being faded has an alpha.
// This handles the math of fading in and out.
// Just have an instance of this class composited with whatever you want faded. Then multiply GetAlpha by the alpha of the object.
// Call Update with the elapsed time since the last call to Update
// You can freely change the member variables of the class
struct FadeController
{
FadeController();
~FadeController();
float GetAlpha(void) const;
bool IsExpired(void) const;
void Update(unsigned elapsedTime);
// If fadeInTime < elapsedTime, the percentile elapsed will be used as alpha unsigned int fadeInTimeMS; // If lifeTime!=0 && lifeTime < elapsedTime then this string will be removed from AlphaTextList unsigned int lifeTimeMS; // Total MS elapsed unsigned int elapsedTimeMS; // Will calculate alpha as the remaining time unsigned int fadeOutTimeMS; }; #endif
Source file:
#include "FadeController.h"
FadeController::FadeController()
{
}
FadeController::~FadeController()
{
}
float FadeController::GetAlpha(void) const
{
if (elapsedTimeMS < fadeInTimeMS)
return (float) elapsedTimeMS / (float) fadeInTimeMS;
else if (lifeTimeMS!=0)
{
if (elapsedTimeMS < fadeOutTimeMS)
return 1.0f;
else if (elapsedTimeMS < lifeTimeMS)
return (float) (lifeTimeMS-fadeOutTimeMS) /(float) (lifeTimeMS-elapsedTimeMS);
return 0.0f;
}
else
return 1.0f;
}
void FadeController::Update(unsigned elapsedTime)
{
elapsedTimeMS+=elapsedTime;
}
bool FadeController::IsExpired(void) const
{
return lifeTimeMS!=0 && elapsedTimeMS > lifeTimeMS;
}
Seems very simple right? But consider that there are NO external dependencies. This will link fast, can work with any game, and in fact overengineers the problem beecause it can work with things other than strings. For example, shrapnel could fade out too.
Just composite this class with whatever you want faded and hook it in with two lines of code.
If you have come up with a better solution, post it in the comments.
I noticed that Visual Studio 2005 will frivolously ask you if you want to build out of date projects. For example, if I change a file in one project, build that project and its dependencies, and then try to run it will tell me that unrelated projects are out of date. Eventually I disabled that warning. Now I get a problem where, after building a project, it won’t take my changes or will tell me the source file is wrong.
So it seems like the warning was right and the real problem is even though you build your project sometimes you need to build it twice for no reason.
As in my last post I’m working on the GUI system for my engine. I’m using CEGUI and positively suprised me. I went to their forums and gave my requirements, which are non-trivial:
Scrolling chat window that splits text, with a per-line prefix
Line, bar graphs
Tables
Console input window.
While they couldn’t do everything I wanted (graphs were for a later version) everything else they claimed they could do directly and it was in their sample already.
I’m investigating now. If this is the case then it’ll save me a lot of time.
Combines Ogre3D, fmod, RakNet, OIS, and Crazy Eddie’s GUI system. OIS (the input system) and Crazy Eddie’s GUI system do not work together very well and OIS isn’t very well designed so I wrote an input manager which fixes that problem.
The majority of my work went into setting up the projects so they work together nicely. All the libraries go to one place, the output to another place, and so forth. There are includes and dependencies all over the place so I subdivided them among projects.
So now it’s tremendously easy to create a new game, with access to the functionality of all those systems, without having to write all kinds of setup crap.
One big plus is Ogre3D supports lots of content creation tools so the particles were made by me, as well as the GUI layout.
Here’s a screenshot which shows all the systems except RakNet in action. Everything you see was done in 231 lines of game code, which includes winmain()
*** EDIT ***
You can get it here: RakEngine .1
One thing I’ve learned from doing RakNet and am trying to do in RakEngine is to follow good systems design, which can be summarized as
1. Preserve generality
2. Preserve relevant information
This can be summarized in one sentence: Don’t make decisions that have exceptions – either in regard to processing or information hiding. Almost every time there is a case where someone says “This code is all over the place” it is because this rule was violated.
An example of this is a class that calculates and stores AI paths. Lets say you make a decision to limit updates to every 500 milliseconds. During later testing you find that the AI doesn’t respond fast enough when getting hit, and in that particular scenario you need to update the path right away. So now you have an exception to your rule of 500 milliseconds, which means it was a mistake to make that rule to begin with. Except that now when the AI gets hit a lot, you don’t want to recalculate the path again, so you have to add a special flag to disable this. Except for a third case when a path blocker comes up. And so forth. Now your code which simply finds AI paths has special flags for things it shouldn’t know about (blockers and getting hit).
It’s much harder to design systems that maintain generality as opposed to systems that are specific. You usually have less features. One way to tackle this is to define primitives, where a primitive is the minimum unit of functionality and information that anyone could ever care about. Then build up systems composed of those primitives. A good example of a primitive is the sin() function. A sin function is an expansion series. There is a certain amount of internal data going on there such as the nth term and how far the series is expanded. But you don’t care about that. So it’s not exposed and the sin function works well, without people having to rewrite it. Suppose instead the sin function calculated both the sin and the cosine at the same time, at a cheaper cost than calculating both separately but more expensive than individually. That would be a good thing, except in cases where you don’t care about the cosine. So you no longer have a primitive, which is why that is not done.
Sometimes designers think something is a primitive and it is not. For example, bytes. In network code I deal with bits all the time. The bit is actually the minimum computing unit. Because of the abstraction of bytes I had to write a bitstream class with a huge set of complicated functions to read and write bits. So defining bytes as the minimum memory unit was a bad abstraction. A better abstraction would have been to make a bit a native type, and to use that in composition, where you have a bit8 as another type, and so on.
The native C/C++ types are also bad abstractions. They try to hide the underlying type by representing the most efficient form for the compiler. So an int is the type you should usually use for numbers, a char is used for characters, and so on. But in practice a great deal of the time you don’t care about that – you care about how many bytes are used. So you end up with almost every library doing something like
typedef unsigned char UCHAR;
And when you use another library, you can’t just use UCHAR. You have to look at what type that actually was, and match it up with your own type. So people have proposed to do something like
typedef unsigned char u8;
typedef signed int s32;
And so forth. This is good, because it is more of a primitive than int or char. You are undoing the bad design work which shouldn’t have been done to begin with.
So a good rule of thumb when designing systems is “Is there any case where anyone would want to process something differently than I just wrote?” And “Is there any case where anyone would want to view this data I am setting as protected or private?” If yes, you need to think carefully about that because you will have to write exceptions, which multiplies the complexity of your system. It might be better to go to a lower level of granularity and compose the system instead.
I’m trying out Ogre3D now. So far I’m impressed!
I found a nice particle editor although it took some digging around in the forums. So that’s one big headache gone!
It has a GUI editor which could be easier to use but seems to do everything I want. Another headache gone.
It has exporters for every 3D modelling package. That’s great, because it frees me up from having to write one. If I do have to write one, I have the sources so I can do the modifications I need to.
It obviously supports shaders and enough graphics techniques for my game.
I made a project called RakEngine, which has Ogre3D, RakNet, and OpenAL. I’m going to screw around with it until I get some clickable buttons on the screen, showing some particles, and playing some sound. Then I will do a new state system. That’s pretty much it for the engine! I don’t need physics but if I do later turn out to need it there is a newton plugin for Ogre 🙂
In order to test the engine I can try writing something really simple, like multiplayer hangman. Although I don’t like taking the time away from my game, that covers all the basics so I can iron out the kinks.
I can then start over and do my real game 🙂
Thinking of taxes, I’m reminded of certain civilization style games where you can tax your civilizations between 0 and 100%. It depended on the game. Most games leveled off between 20% and 50% at which point the civilizations would be so unproductive and unhappy it didn’t make sense to go higher.
Did you know our own tax rate in the USA is about 60%? It’s just that most of it is hidden.
Suppose you go to get a job and you negotiate 80K with your employer. You actually negotiated 100K, it’s just that you only get 80K of that. The other 20K, which your employer pays, goes to taxes.
Of course you don’t actually get 80K. About 25% of that is taxed – social security, medicare, medicaid, straight up taxes, and various other things. So now, instead of 80K, you take home 60K.
Just having 60K doesn’t do you much good. You buy things with that 60K. A lot of that is subject to a sales tax (8.5% around here). If about half of what you buy is subject to a sales tax, that knocks us down to roughly 57K. That’s not bad. Now you have to pay the business, property, and employee taxes of those you buy from. Not directly, but they pass the charge on to you. Taxes account for about 20% of the cost of a good or service. So it brings our purchasing power down to 45K.
Do you own a house? Do you pay property taxes? Mello-Roos? That’s another 10K of taxes you pay.
So in the end, without a house a person actually earning 100K a year has a purchasing power of 45K. With a house, it’s 35K.
On average that’s a 60% tax rate.
I got a letter from Irvine today demanding $50 for a business license renewal and threatening various additional fees if I don’t pay up.
The federal government wants a piece of the pie too. Fork over their 30% cut or else they’ll come in with guns and shut you down.
Can anyone tell me how this differs from protection money for the mob?