Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411990 Posts in 69441 Topics- by 58486 Members - Latest Member: Fuimus

June 17, 2024, 12:19:08 AM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)Multiple levels -- how is it typically done using C++?
Pages: [1]
Print
Author Topic: Multiple levels -- how is it typically done using C++?  (Read 2601 times)
HannesP
Level 0
***


View Profile WWW
« on: January 07, 2009, 02:57:40 AM »

I mainly do application programming, but now I consider writing a game. In order to make it easily portable (I'm on a Mac) I guess I have to use C++, which I know a little but not well. Before even starting, I want to get some things straight, and first out is:

If I want to make a game with several levels, like Metroid, SMB, Commander Keen etc, how is one level typically represented in the code? My first thought was to make each level inherit from a common ancestor, and then subclass when required in order to add new behaviour to certain levels. However, C++'s static nature makes me ask myself if this is a good way to do it. With ObjC, the language with which I'm most familiar, I'd create som sort of array and then store the class for each level in it, which is possible since ObjC classes are treated like normal objects (a feature shared with Ruby, Python etc). If I remember the little C++ I know correctly, this isn't nearly as easy using C++, since classes are just type names and cannot be treated like objects.

Experienced C++ programmers, help! Is this an impossible/stupid way to do it in C++ (or even in games generally), and if it is, how would you solve the same situation?

Thanks in advance!
Logged
Javilop
Level 2
**



View Profile
« Reply #1 on: January 07, 2009, 03:14:51 AM »

I usually like to store leves in files.

For the maps, and while debugging, I like to use XML files (I use TinyXML framework), because I can edit them directly. For the release, depending on the size of the level, I convert dose XML files to binarie files, for speeding up loading / saving. I only do that if the leves are really huge, like thousand of polygons for a 3d map. For smaller maps, like storing the positions of pieces in a game like Aquaria, I prefer to let them as XML files.

In the same map file, you can also store other type of entities, like spawn places for the players, position of the particle systems, path points, etc.

All these information should be correctly stored into classes in your sourcecode. And you can code the game logic of each entity (its behaviour in the world, for example the actions of a monster) in an scripting language, like lua.

Them, when you want to load a new level, you just free all the memory from the previous one, parses the XML file and load all the map and entities nodes. I usually store these nodes (that are in fact classes) inside STL vectors. Then you can run the game logic lua scripts.

These are just really general words.

If you are a bit patient, I'm currently working on a tutorial about how to load and edit maps. That is the first part of what I described. Maybe it would be helpful for you.

Logged
increpare
Guest
« Reply #2 on: January 07, 2009, 03:28:17 AM »

I'm in agreement with loover.  That is to say, an OO approach isn't really what people tend to do.  I have a 'level data' struct in most games, but it's more or less a stand-alone thing.  Reading and writing to files is generally considered the way to go.  I've grown rather fond of Boost::Serialization, but if you can store your levels in vectors/arrays (better still if they're fixed length ;P), then you should be able to parse files by hand pretty easily.
Logged
HannesP
Level 0
***


View Profile WWW
« Reply #3 on: January 07, 2009, 03:46:21 AM »

Thanks, both of you! Your replies cleared it up a little, but there's still one thing I'm missing, and that is how logic that is strictly separate to one level is implemented.

For example, lets say that I have one level, in which I want it to rain comets from the sky. With my class approach, I'd just make a subclass with a "comets" array, and in the update hook of the level object I'd throw in comets at random positions at given times. How would you solve a such problem?
Logged
Javilop
Level 2
**



View Profile
« Reply #4 on: January 07, 2009, 03:57:41 AM »

I would do that with a particle system entity.

In my map file I would create a particle spawn. In the map file it should be something like:

[On map file]

Code:
[...]
<particle_spawn pos_x="400" pos_y="600" layer="3" particle_system_file="resources/particles/comets.xml" />
[...]

[On comets.xml file]

Code:
[...]
<particle_system life="200" speed="500" gravity="1" ... etc />
[...]

So, in the map file, I choose the position of the particle system, and in another file, I define the specific particle system attributes for the comets.

In you sourcecode you need a particle system class, containing a vector of particle node classes, a map class and a map node class.

Once again, really general words. I hope are aclaratory enough.
« Last Edit: January 07, 2009, 04:01:05 AM by Loover » Logged
Eclipse
Level 10
*****


0xDEADC0DE


View Profile WWW
« Reply #5 on: January 07, 2009, 04:03:24 AM »

I mainly do application programming, but now I consider writing a game. In order to make it easily portable (I'm on a Mac) I guess I have to use C++, which I know a little but not well. Before even starting, I want to get some things straight, and first out is:

If I want to make a game with several levels, like Metroid, SMB, Commander Keen etc, how is one level typically represented in the code? My first thought was to make each level inherit from a common ancestor, and then subclass when required in order to add new behaviour to certain levels. However, C++'s static nature makes me ask myself if this is a good way to do it. With ObjC, the language with which I'm most familiar, I'd create som sort of array and then store the class for each level in it, which is possible since ObjC classes are treated like normal objects (a feature shared with Ruby, Python etc). If I remember the little C++ I know correctly, this isn't nearly as easy using C++, since classes are just type names and cannot be treated like objects.

Experienced C++ programmers, help! Is this an impossible/stupid way to do it in C++ (or even in games generally), and if it is, how would you solve the same situation?

Thanks in advance!

WAT?!?  Shocked

... anyway yes, you can and should do a class Level and then you can inherit from it if you really want to change a lot of stuff for each level, if not it would be a lot clean to simply have a single Level class.

In my games i usually store the levels in files too (of course) but it's a lot cleaner having that Level class loading it from file...

something like   currentLevel = new Level("level1.lv"); is imo the best way
Logged

<Powergloved_Andy> I once fapped to Dora the Explorer
HannesP
Level 0
***


View Profile WWW
« Reply #6 on: January 07, 2009, 04:11:41 AM »

WAT?!?  Shocked

What I mean, is that in ObjC I'd do something like this:

[levelRegistry setLevelClass:[CometLevel class] atX:7 y:2]; (provided that my game orders its levels in a grid)

Is that possible using C++?


To Loover:

Many thanks for your explanation. If I understand you right, the best general way is to make the game engine as customizable and reusable as possible, then most cases can be solved without custom code.
Logged
BorisTheBrave
Level 10
*****


View Profile WWW
« Reply #7 on: January 07, 2009, 04:21:21 AM »

What I mean, is that in ObjC I'd do something like this:

[levelRegistry setLevelClass:[CometLevel class] atX:7 y:2]; (provided that my game orders its levels in a grid)

Is that possible using C++?

I'd second Loover's approach (though if you have one off effects like comet storms, you don't need create a full particle system, a simple flag would do.

But what you described is possible in C++, but the syntax you have above doesn't work. You cannot pass references to classes around, and then instantiate them, but you can pass function pointers around. So each subclass could have a static method Create that creates a subclass level and returns in. Level registry just maps strings to those functions, and each subclass needs to be manually registered. This is actually an example of the factory pattern. The magic of creating levels is hidden behind the registry object, which does it for you. Whether it internally uses Create methods, or a bigass switch statement, is not really important.
Logged
HannesP
Level 0
***


View Profile WWW
« Reply #8 on: January 07, 2009, 04:34:13 AM »

To BorisTheBrave:

I've always wondered how C++ solves that kind of problems, without being able to store references to classes. Your explanation made it perfectly clear to me. Thanks!

(Though I still prefer the ObjC way to do it Wink)
Logged
increpare
Guest
« Reply #9 on: January 07, 2009, 04:55:26 AM »

I've always wondered how C++ solves that kind of problems, without being able to store references to classes.
You can reference classes in C++, though it's not considere very idiomatic, if you enable RTTI.
Logged
BorisTheBrave
Level 10
*****


View Profile WWW
« Reply #10 on: January 07, 2009, 06:42:46 AM »

I've never used RTTI, but the reference you linked says that the resulting type_info class has a private copy constructor and assignment operator, meaning you cannot actually pass it around, or do very much at all. In fact, the whole things seems pretty useless, what's the point?
Logged
increpare
Guest
« Reply #11 on: January 07, 2009, 06:52:56 AM »

I've never used RTTI, but the reference you linked says that the resulting type_info class has a private copy constructor and assignment operator, meaning you cannot actually pass it around, or do very much at all.
type_info yeah, but type_info has functions like name() that return strings which identify objects (I have a recollection of there being some int somewhere as well that did the same job, but can't find it now), which can be passed about.  I haven't used this stuff too much, so there might be a better way of doing it in C++, though.
Logged
David Pittman
Level 2
**


MAEK GAEM


View Profile WWW
« Reply #12 on: January 07, 2009, 02:18:57 PM »

C++'s RTTI is no substitute for actual first-class citizen classes. It's really only intended to provide information for the type of an existing object (e.g., for dynamic casts). But yeah, the map of class names to factory functions works fine for me to create objects by name. I've also implemented a custom RTTI system that's much faster for dynamic casts than the usual MSVC string-based implementation, and I can use it in conjunction with the factory system to get a type info object by name. That pretty much covers every practical use I've ever had for classes as first-class citizens.

More on topic, I only ever instantiate one level object in my engine, because I only ever have one level active at a time. Everything about the level is described in a level file (actually, the level file only contains the static information about the world; the initial game state is stored separately as a "default saved game" and so can be ignored when loading a saved game in that level.) When I transition to a new level or load a saved game, I just destroy everything and unload assets from the current level and load static content from the new level file into the existing object, then load the game state, which uses the factory stuff to actually instantiate all the game entities.
Logged

Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic