SFML community forums
Help => General => Topic started by: s3rius on December 23, 2010, 04:27:15 am
-
Hey there, I've migrated to SFML not long ago and am an amateur programmer who is trying to make his own small game.
I'm doing good progress on the basic stuff, but as I'm looking forward and trying to decide how to best build my game I ran into a few things I'm insecure about.
I'd love some guidance on a few things:
1) How well does SFML handle multiple threads? Is there a limit as to how many threads can run at the same time or does it drastically impair performance, even if most threads are sleeping?
The reason why I'm asking is that I want to construct event-driven functions for certain things.
E.g. I want to be able to hook a certain function to a custom event like the player figure reaching a certain point on the map.
The called function could then send a radio message to the help, sleep for a few seconds and then send a second message. For that sleeping I'd need to thread all of these functions.
They'd generally not do a lot of stuff, as the performance-heavy chunk of the game is being taken care of in the main thread. They'd mostly serve to set-off in-game events and stuff.
2) I am already implementing a save/load function to store and read map files which contain the terrain data for each game level.
But I was wondering if there is a way to do the same for scripts.
Let's take the above example: In one level I want to send some messages to the player once he reaches a certain point. No problem. But when he plays a different level there are other things meant to happen.
The easiest way to manage this is to just create all the relevant functions for all levels in some cpp file and call them depending on the loaded level.
But in this case they'd clutter up the game.exe and I'd have to change the source code everytime I wanted to change any level's scripts.
So instead I'd like to be able to load the scripts from seperate files, like being able to dynamically load and unload cpp files (which probably won't work).
However, I have absolutely no idea how to do that.
The only thing that comes to my mind is creating a completely new small scripting language which is then read by the game and evaluated, but that's a HUGE amount of work.
3) My map has a tile-base terrain similar to a chess board with 19x25 squares. I noticed that, when drawing all these sprites, the game's frame rate goes down to about 23 (before that it was 60).
I'm running Win 7 x64 on a pretty decent computer and I updated my graphic drivers just a day ago - so at least this shouldn't be an issue.
However I can't believe that drawing a couple of small sprites is supposed to have such a high impact.
Are there any other things I can do to squeeze some better performance out of that?
Here's basically how I'm drawing it:
void draw(){
//This sprite array probably shouldn't be constructed everytime this function runs
//but only once - but I doubt that this alone is a great performance hit.
sf::Sprite sp[2] = { sf::Sprite(SomeTerrainImage),
sf::Sprite(SomeOtherTerrainImage) };
int i=0;
//map[][] is a char array containing the terrain type of each square.
//Depending on it's value the game should draw a different tile image.
for(short wi=0; wi < w; wi++){
for(short hi=0; hi < h; hi++){
i=map[hi][wi];
sp[i].SetPosition(hi*32.f, wi*32.f);
window->Draw(sp[i]);
}
}
}
4) Last but not least; I've asked a question in http://www.sfml-dev.org/forum/viewtopic.php?t=3718 which still baffles me. An answer to that would be great!
Many thanks in advance for some enlightenment!
~s3r
-
1) How well does SFML handle multiple threads? Is there a limit as to how many threads can run at the same time or does it drastically impair performance, even if most threads are sleeping?
SFML doesn't handle threads for you. It implements an interface to the operating system so that we get a generic way to handle threads on each platform.
So how many threads you can have depends on if the OS have a limit for it. But for Windows and Linux, I don't think that will be any problem.
And when it comes to threads, performance and sleeping. First a sleeping thread isn't really sleeping, it just tells the operating system that I got nothing to do for x amount of milliseconds, so it got nothing to do with performance directly. And then the operating system most often prioritize some other threads to run. And then the performance, it depends on the number of cores in the platform and how the threads "interface" with each others. For instance, a computer with 4 cores will never run more than 4 threads at the same time (unless it's Intel hyper-threading then it's 8 I think), so no matter how many threads you throw at it, it won't go faster, it will actually go slower. And if you share common data between the threads then in order to make use of the data safe you will have to make the threads wait on each others. And so on and so on.
The reason why I'm asking is that I want to construct event-driven functions for certain things.
E.g. I want to be able to hook a certain function to a custom event like the player figure reaching a certain point on the map.
The called function could then send a radio message to the help, sleep for a few seconds and then send a second message. For that sleeping I'd need to thread all of these functions.
They'd generally not do a lot of stuff, as the performance-heavy chunk of the game is being taken care of in the main thread. They'd mostly serve to set-off in-game events and stuff.
That's a very bad way to do it and is absolutely not suited for being put in an own thread. You're making it much more complicated than the problem actually is. I'll give you an example for how to do it properly and why it's bad idea to thread it and help you out with number 2 and 3(if nobody beats me to it) when I wake up. The clock is 04:53 here and I need to sleep. :)
-
I leave 1) to Groogy, but here is my opinion on the last two questions.
2) Using scripts is a very good idea, but you don't need to create your own language, just use one of the several that are available. The two most popular are Lua and Python. You'll then find C++ APIs that help you (more or less easily) communicate between C++ and the script language. The easiest (and which I recommend strongly) is Luabind (for Lua) and boost.python (for Python). They are both similar, the former is based on the latter.
3) Are you running in release mode, with all optimizations enabled?
-
I'll have to help you after christmas. I thought it was the 20th yesterday but apparently it's the 23th. Here in Sweden we celebrate Christmas on Christmas Eve, so I got a lot to do and can't help you until around 25-26th.
Hope you can wait. And merry Christmas everyone!
-
The easiest (and which I recommend strongly) is Luabind (for Lua) and boost.python (for Python).
Yeah! But... there are people who don't have an eternity or two only to wait for the code to compile. ;)
-
The easiest (and which I recommend strongly) is Luabind (for Lua) and boost.python (for Python).
Yeah! But... there are people who don't have an eternity or two only to wait for the code to compile. ;)
I use Google's V8 for my game engine.... :twisted:
-
Yeah! But... there are people who don't have an eternity or two only to wait for the code to compile
I prefer spending time waiting for the compiler to generate the code, rather than writing it myself ;)
-
That would be good, if the compilation weren't sooooooo slooooooow. Sure, it's C++, the code compiles slowly anyway, but all these boostisms make it compile incredibly slow even by C++ standards. I'd rather use some other library that does more or less the same thing without slowing down the compilation by several orders of magnitude.
-
If you don't got anything against Javascript, Danes or Google, then V8 is for you :D
-
That would be good, if the compilation weren't sooooooo slooooooow. Sure, it's C++, the code compiles slowly anyway, but all these boostisms make it compile incredibly slow even by C++ standards. I'd rather use some other library that does more or less the same thing without slowing down the compilation by several orders of magnitude.
It's not slow because it's boost ;)
It's slow because it makes the compiler create the code for you (heavy use of template metaprogramming). Faster would mean less code generated, which means more code written manually. You can't have both.
Moreover, class bindings are usually not the kind of stuff that changes often. So you don't have to suffer from the huge compile times often.
Of course you can use the plain C API of the script language, but then be prepared to write a huge amount of non-generic of low-level code.
-
If you don't got anything against Javascript, Danes or Google, then V8 is for you
How does it interfaces with C++?
-
It's not slow because it's boost ;)
It's slow because it makes the compiler create the code for you (heavy use of template metaprogramming).
Heavy use of templates is exactly one of these boostisms I'm talking about. I call them that way, because boost is perhaps the most widely-known library that makes use of them. Even when used by a library that has nothing to do with boost, they're still called boostisms. ;)
-
Heavy use of templates is exactly one of these boostisms I'm talking about. I call them that way, because boost is perhaps the most widely-known library that makes use of them. Even when used by a library that has nothing to do with boost, they're still called boostisms.
Ok, and I agree. But do you mean that they are useless? Or at least, that one could write a similar library with much less templates?
-
I'll have to help you after christmas. I thought it was the 20th yesterday but apparently it's the 23th. Here in Sweden we celebrate Christmas on Christmas Eve, so I got a lot to do and can't help you until around 25-26th.
Hope you can wait. And merry Christmas everyone!
No problem! I appreciate that you take the time to help me at all :)
About my second question:
I'll go with lua I think. I won't use LuaBind or any other library for now since I don't think the gain is worth it for now. I only need the external scripts for rather basic stuff.
About 3:
Nevermiiind~ with all optimizations I get the full 60fps.
Could someone take a look at question 4 (http://www.sfml-dev.org/forum/viewtopic.php?t=3718#24860)? Not a huge problem but it bugs me.
-
But do you mean that they are useless?
I mean that overusing and misusing the language features (most of boostisms qualify as either the former or the latter) is not the best way to program. Especially when they make so much pressure on the poor compiler as template voodoo does.
Or at least, that one could write a similar library with much less templates?
It depends. How much similar the new library should be to the library in question? Drop-in replacement probably would be very hard, if not impossible, but a thing that just lets me use C++ functions/classes as if they were Lua/Python ones and vice versa without requiring me to write boring details certainly is feasible.
-
If you don't got anything against Javascript, Danes or Google, then V8 is for you
How does it interfaces with C++?
It's made in C++ and designed to be used in C++. So pretty well. Their example for how to make your own Javascript shell with it is here: http://code.google.com/p/v8/source/browse/trunk/samples/shell.cc?r=6117
Here's a guide on how to embedd it: http://code.google.com/apis/v8/embed.html
Though documentation is pretty scarce but they got doxygen commentaries on their code.
But if you want to use Javascript in a object-oriented way(using objects in the actual scripts) I recommend that you steal my object and class objects. Since the default object-oriented system in Javascript is a mess.
*EDIT* Forgot to add link: https://github.com/Groogy/Javascript-Object
All it does is implement things that we expect, like being able to call the "super" method of the current called method and so on.
Hope you don't get confused s3rius :P
-
Laurent, some time ago you mentioned Lua and Python bindings in the context of your CAMP library. Have they been developped yet?
-
I mean that overusing and misusing the language features (most of boostisms qualify as either the former or the latter) is not the best way to program. Especially when they make so much pressure on the poor compiler as template voodoo does.
I don't think they misuse or overuse the language. But well... it's christmas and I don't feel like starting such a discussion -- we should rather focus on the OP's questions ;)
It's made in C++ and designed to be used in C++. So pretty well. Their example for how to make your own Javascript shell with it is here: http://code.google.com/p/v8/source/browse/trunk/samples/shell.cc?r=6117
Looks really cool.
Laurent, some time ago you mentioned Lua and Python bindings in the context of your CAMP library. Have they been developped yet?
The Lua binding is still in beta, but I think it's already working pretty well (you can check the "camp-lua" branch on github). There's no Python binding yet.
-
Aight I'm finally going to help you out :D Hope you had a great Christmas(If you celebrate it of course, otherwise it's just I hope you had a great day :D)
Okay, so let's first establish what you want to create. What you want in your game is that the player potentially triggers something and an action is accordingly taken. That's known as an action-trigger system. The system is basically that you have a trigger object that checks if it has been triggered, you can make this as advanced as you want, if it is triggered then you tell it's action object to run. This is just scratching the surface of the system but you'll learn more if you try and fail yourself first, I'll always be here to help you again.
Anyway let's say we do it like, when something is triggered, we run the action in it's own thread. Then what if two actions are run that both want to output some kind of messages to the player? Like a message box as this this (http://www.rpgmakervx.com/gallery/pictures/1_Screenshots/overworld_02.jpg) one. Then the two threads would start overriding each others text. Things like this is fixable but it gives much more headache than needed. If you want an action to wait 2 seconds but not lock the whole system then you can just simply have a trigger that takes a specific elapsed time. All it needs inside itself is a sf::Clock and a float telling it when to trigger. Looking something like this:
class TimedTrigger : public Trigger
{
public:
bool Update(Engine &engine)
{
if(myClock.GetElapsedTime() > myTimeToTrigger)
{
TriggerAction();
return true
}
return false;
}
private:
float myTimeToTrigger;
sf::Clock myClock;
};
Why I have the Engine argument there is because I think of the Update() of being a pure virtual method in the Trigger class. And we need some object to check against if we are supposed to trigger or not. A more complex way to do this(but it removes the virtual call) is to make the trigger receive signals that give various information and make it only trigger when it get's an interesting signal like in this case maybe: "Signal.Application.Update" and take the delta time passed with the signal. If we would like to know if some character moved, then it would be: "Signal.Entity.Moved" and use the coordinates passed to check if we want to trigger. This is just an example using the same system as me of course.
Aight, Like I said, try yourself and fail and then come back and tell me what you think you made wrong(reflect a little bit) and I'll give you a more in-depth view of how the action-trigger system should be built.
-
Thanks for the response!
Yes, a trigger-action system is basically what I want. I know the concept from the editors of Warcraft and Starcraft, but didn't know they're actually called like that.
However, with the implementation like you suggested wouldn't it look somewhat like this?
void SendMessage1(){
SendToPlayer("Enemies incoming!")
}
void SpawnEnemies(){
SpawnUnit(a,b);
SpawUnit(c,d);
}
void SendMessage2(){
SendToPlayer("Oh, they arrived already!")
}
void DoEffects(){
SpawnSFX(e,f);
}
void TimedTrigger(void (*ptr)(void), fixed timeDelay);
void WhenPlayerDoesStuff(Event &event){
//When this "trigger" is triggered we want to do the following things:
//1) Display some message to the player.
//2) Spawn some additional enemies.
//3) Display another message.
//4) Then add some explosion effects
//Between every action we want 2 seconds to pass.
TimedTrigger( &SendMessage1, 2.0);
TimedTrigger( &SpawnEnemies, 4.0);
TimedTrigger( &SendMessage2, 6.0);
TimedTrigger( &DoEffects, 8.0);
}
WhenPlayerDoesStuff() would be the function called by my event handler when event X happens.
But, especially when there's a few more things happening, this is pretty inconvenient - having to create a new function for every time I want a delay.
What'd be much better and easier to modify would be something like this:
void WhenPlayerDoesStuffConvenient(Event &event){
Wait(2.0); //Or Sleep(x)
SendToPlayer("Enemies incoming!")
Wait(2.0);
SpawnUnit(a,b);
SpawUnit(c,d);
Wait(2.0);
SendToPlayer("Oh, they arrived already!")
Wait(2.0);
SpawnSFX(e,f);
}
That's why I thought about using seperate threads in the first place.
Regarding your example with the message window being overwritten:
I could just lock the message window when one thread is using it and unlock it as soon as the message has been displayed for a certain time. I could even add debug output which informs me when a thread attempted to use the message window if it's still in use. Should be easy tracking the rest :)
So that's not really the issue - and your idea wouldn't really prevent this either, unless I overlooked something.
PS:
I was thinking and I guess I could make TimedTrigger class which basically works like a queue, where I can append all orders at once and it'll execute them one after another, waiting (like your example) when a sleep order is issued.
-
However, with the implementation like you suggested wouldn't it look somewhat like this?
Not really but works, I was thinking in more of the lines of classes and objects. Would make it much more advanced but simpler to extend.
That's why I thought about using seperate threads in the first place.
Regarding your example with the message window being overwritten:
I could just lock the message window when one thread is using it and unlock it as soon as the message has been displayed for a certain time. I could even add debug output which informs me when a thread attempted to use the message window if it's still in use. Should be easy tracking the rest :)
So that's not really the issue - and your idea wouldn't really prevent this either, unless I overlooked something.
Well you'll still have tons of problem, like I said, it adds more headache than solve the problem. For instance, you have to create these locks for EVERYTHING in the engine that any event/action might read, modify and so on and so on. You are bound to miss something somewhere, and the more locks you add the more likly that you create a deadlock somewhere which might even just come at what seems like random.
So more or less, it's a bad way to design any system and is a great misuse of parallel programming.
-
Here's a more complete example of Action-Trigger to get you going
Actions Example:
class Action
{
public:
protected:
friend class Trigger;
virtual void Run() = 0; /* The code to run */
};
class SpawnCreepAction : Action
{
public:
SpawnCreepAction(CreepType &aType, sf::Vector2f aPosition);
protected:
void Run(); /* Create the new creep */
private:
CreepType &myType;
sf::Vector2f aPosition;
};
Triggers Example:
class Trigger
{
public:
Trigger(Action *anAction);
virtual bool Update(Engine &anEngine) = 0;
protected:
Action *myAction;
};
class TimedTrigger : public Trigger
{
public:
TimedTrigger(Action * anAction, float someTime) : Trigger(anAction)
{
myTimeToTrigger = someTime;
}
bool Update(Engine &engine)
{
if(myClock.GetElapsedTime() > myTimeToTrigger)
{
myAction->Run();
return true
}
return false;
}
private:
float myTimeToTrigger;
sf::Clock myClock;
};
And in use:
SpawnCreepAction *action = new SpawnCreepAction(someCreepType, andSomePosition);
TimedTrigger *trigger = new TimedTrigger(action, 2);
Just forget everything I said about messaging/signals. That was more specific to my game engine and how I would personally do it.
This will result in less work than if you would have used threads actually. The threaded approach looks easier at a glance but will in practice be much harder to implement. The difference here is that this one isn't as straightforward and requires that you implement a system which will be capable of "creating" and "modifying" itself. Though in the long run, you'll gain more on this, both performance wise and in development.