Sign in to follow this  

Level data exporting and loading

This topic is 2537 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm developing a C++ game for the iPhone which has recently started receiving low memory warnings from the kernel. I am very concerned about it and need to reduce the RAM usage as much as possible.

One area I can see this being improved is the way my C# level editor exports it's data. Currently it exports the data as a bunch of "C" structs.

Eg.

const GemDef g_DanjerReef_Gem_Actors[] =
{
{ "", 64.53f, -46.25f, 0.00f, 5.00f, 5.00f, GEMTYPE_DIAMOND, "chip1" },
};

const ChainDef g_DanjerReef_Chain_Actors[] =
{
{ "AnchorRope", 1.25f, 1.00f, 0.00f, 0.00f, "chain", 62.34f, 76.72f, 62.50f, 66.41f, 4, -0.50f, 1.00f, false, 0.00f, "Link", "Anchor", 2, 0, FILTERTYPE_ALL, FILTERTYPE_1 },
{ "", 1.88f, 1.00f, 0.00f, 0.00f, "seaweed2", 35.63f, -74.38f, 35.47f, -64.84f, 4, -0.60f, 1.15f, false, 0.00f, "v1", "", 1, 0, FILTERTYPE_ALL, FILTERTYPE_1 },
{ "", 1.88f, 1.00f, 0.00f, 0.00f, "seaweed1", 19.38f, -54.84f, 18.28f, -37.50f, 5, -0.60f, 1.13f, false, 0.00f, "V2", "", 1, 0, FILTERTYPE_ALL, FILTERTYPE_1 },
{ "", 1.88f, 1.00f, 0.00f, 0.00f, "seaweed3", 28.75f, 12.66f, 28.75f, 26.88f, 4, -0.60f, 1.13f, false, 0.00f, "V3", "", 1, 0, FILTERTYPE_ALL, FILTERTYPE_1 },
{ "", 1.88f, 1.00f, 0.00f, 0.00f, "seaweed4", -20.63f, 27.50f, -20.16f, 37.34f, 3, -0.60f, 1.14f, false, 0.00f, "V4", "", 1, 0, FILTERTYPE_ALL, FILTERTYPE_1 },
{ "", 1.88f, 1.00f, 0.00f, 0.00f, "seaweed4", 59.06f, -65.00f, 59.38f, -49.06f, 5, -0.60f, 1.14f, false, 0.00f, "V5", "", 1, 0, FILTERTYPE_ALL, FILTERTYPE_1 },
};

const LevelData g_DanjerReef_LevelData =
{
LEVELSTATUS_FINISHED, // Status
"Danjer Reef", // Name
"danjerreef.tmx", // MapFile
LEVEL_DANJERREEF, // Level
LEVEL_TO_THE_CANOPY, // NextLevel
LEVELTYPE_WORLDEND, // LevelType
1024, 1024, // Width, Height
WORLD_EASTERISLAND, // World
0, // EnterType
0, // ExitType
"Deep_Deep_Wallow.m4a", // Music
23, 26, // MinZoom, MaxZoom
LEVELFLAGS_COLLECT_SPECIAL_MASK, //Flags
-72.66f, 63.44f, // StartX, StartY
g_DanjerReef_Platforms, // PlatformData
86, // PlatformCount
g_DanjerReef_Actors, // ActorData
16, // ActorCount
50, // TotalActors
g_DanjerReef_Sounds, // SoundData
17, // SoundCount
};




I have considered exporting a binary format but can see some headaches like the fact the data needs to be compiled for both i386 (simulator) and armv6 (hardware) so I can imagine endianness, float formats, internal data structures etc. all causing potential problems here.

Another solution I had was to implement the GCC compiler to compile the "C" code into binary for loading directly into the game. Unfortunately I have no idea how I would go about this.

Finally I'm guessing something like xml would be a format to consider. I believe it would be quite slow and a tonne of code to process the xml for all the different actors in the game.

So now to my questions. What would be the best solution here and how would I implement it?

Share this post


Link to post
Share on other sites
The important thing isn't what your editor does on the development side, it's what your game engine does on the loading side. How do you load, parse, and then store the data from the excerpt you posted? What's the in-game representation of that data look like?

Share this post


Link to post
Share on other sites
To give you the idea of how the data is "loaded" I'll use the Actors' as an example. All Actor's are subclasses of the Actor class. Each one has it's own struct which is the basic data storage format for it's exported data from the level editor. Using the struct it's associated class is instanciated.

Here is a snippet of the loop and switch/case that instanciates the actors for a level

for(int i=0; i<g_levelData->ActorCount; i++)
{
switch(g_levelData->ActorData[i].Type)
{
case ACTORTYPE_PLATFORM:
{
break;
}
case ACTORTYPE_PLAYER:
{
break;
}
case ACTORTYPE_CRATE:
{
const CrateDef* crateDef = (const CrateDef*) g_levelData->ActorData[i].Data;

for(int j=0; j<g_levelData->ActorData[i].Count; j++)
g_actorArray.push_back(new Crate(crateDef[j].Name,
Vector3DMake(crateDef[j].X, crateDef[j].Y, crateDef[j].Z),
SizeFMake(crateDef[j].Width, crateDef[j].Height),
crateDef[j].Skin,
crateDef[j].DropEmit,
crateDef[j].Friction));
break;
}

}
}



In the above you can see if the level uses a "Crate" actor it will instanciate a Crate object and add it to the g_actorArray.

Here is part of the Crate class's header file

struct CrateDef
{
string Name;
float X;
float Y;
float Z;
float Width;
float Height;
string Skin;
MaskType DropEmit;
float Friction;
};

class Crate : public Actor
{
public:
Crate(const string& name, Vector3D position, SizeF size, string skin, MaskType dropemit, float friction);
~Crate();

void Update(float elapsedTime);
void Render();

private:
MaskType DropEmit;
int CrateBounce;
ParticleEmitter* CrumbleEmitter;
Actor* MaskActor;
};

Share this post


Link to post
Share on other sites
Have you pin-pointed where exactly during the execution of your program you run into the low-memory situation?

The first thing that strikes me about your approach is that it is highly wasteful; you duplicate all the information about an actor by storing it both in the struct and in the final instance that is loaded into game state. Why aren't you just deserializing the actors directly from the data stream? At the very least this should (roughly) halve your memory requirements during load-time.


I also notice that you pass some data by value into your Crate constructor, where you should at the very least be passing by const reference. This will bloat your memory requirements as well, not to mention increasing load times by invoking a lot of copy operations needlessly.

Share this post


Link to post
Share on other sites
Quote:
Original post by ApochPiQ
Have you pin-pointed where exactly during the execution of your program you run into the low-memory situation?


The iPhone has notoriously bad memory management and it seems to change based on what has been previously running in memory etc. So it's hard to tell but I am currently profiling to find out.

Quote:
Original post by ApochPiQ
The first thing that strikes me about your approach is that it is highly wasteful; you duplicate all the information about an actor by storing it both in the struct and in the final instance that is loaded into game state. Why aren't you just deserializing the actors directly from the data stream? At the very least this should (roughly) halve your memory requirements during load-time.


It does seem very wasteful I agree but it was the easiest way for me to export the data from a C# level editor running on an x86 PC to a C++ program compiling on ARM. I've measured the current total level data and it comes to 0.28 MB which does not seem to be an awful lot in the context of things considering I use about 5 MB for textures. I would have no idea how to deserialize data from a C# program into a C++ app. Any ideas on that?

Quote:
Original post by ApochPiQ
I also notice that you pass some data by value into your Crate constructor, where you should at the very least be passing by const reference. This will bloat your memory requirements as well, not to mention increasing load times by invoking a lot of copy operations needlessly.


Yes I see what you mean the "skin" parameter should be passed in as a "const string&"

Share this post


Link to post
Share on other sites
Before I get too far, let me clarify one thing: are you storing your "C struct format" stuff in a text file and reading that to load into the game, or are you actually saving the structs as code and compiling that into the game binary itself?

Share this post


Link to post
Share on other sites
Quote:
Original post by ApochPiQ
Before I get too far, let me clarify one thing: are you storing your "C struct format" stuff in a text file and reading that to load into the game, or are you actually saving the structs as code and compiling that into the game binary itself?


I'm saving it as code and compiling it into the game binary.

Share this post


Link to post
Share on other sites
Quote:
Original post by ApochPiQ
So... why not change your serializer to output calls to your class constructor directly? Eliminate the middle-man, so to speak [smile]


This sounds like a good option but how would I actually structure the output to do it? Seems like I would need to export a large switch/case and then "new" the appropriate class. Is this the only way?

Share this post


Link to post
Share on other sites

This topic is 2537 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this