XML

Nov 21, 2010 13:25

Захотелось параметры сцены (количество и тип юнитов, описание и пр.) загружать из легко редактируемого файла. Без перекомпиляции.
Сначала решил использовать csv, как у Тодда Баррона в "Программировании стратегических игр с DX9", но испугало, что придется переделывать под себя вот это:

//-------------------------------------------------------
// Import unit defense, offense, move, and base types
// from a csv (comma delimited) file.
//-------------------------------------------------------
int CUnitManager::iLoadBaseTypes( char *szDefFileName,
char *szOffFileName,
char *szMovFileName,
char *szUnitFileName,
char *szAnimFileName )
{
FILE *fp;
char szTempBuffer[ 512 ];
char szValue[ 32 ][ 32 ];
//char szBitmapFileName[ 128 ];
int iStart, iEnd, iCurPos;
int iCurValue = 0;
CUnitDefense *ptrDefense;
CUnitOffense *ptrOffense1;
CUnitOffense *ptrOffense2;
CUnitOffense *ptrOffense3;
CUnitMovement *ptrMovement;
CUnitAnimation *ptrAnimation;

//------------------------------------------
//
// DEFENSE TYPES
//
//------------------------------------------
// Open the base type file
fp = fopen( szDefFileName, "r" );
if( fp == NULL ) {
return( -1 );
}

// Pull the header first and toss it out
fgets( szTempBuffer, 512, fp );
szTempBuffer[strlen(szTempBuffer)-1] = '\0';

// Set total objects to 0
m_iTotalDefObjs = 0;

// Loop through and read every line
while( !feof( fp ) ) {
// Get next line
fgets( szTempBuffer, 512, fp );

if( feof( fp ) ) {
break;
}

// Add terminator
szTempBuffer[strlen(szTempBuffer)-1] = '\0';
iStart = 0;
iEnd = 0;
iCurPos = 0;
iCurValue = 0;

// Pull out the values
while( szTempBuffer[ iCurPos ] != '\0' && iCurPos < 512 ) {
// Check for end of value
if( szTempBuffer[ iCurPos ] == ',' ) {
iEnd = iCurPos;
memset( &szValue[ iCurValue ][ 0 ], 0x00, 32 );
memcpy( &szValue[ iCurValue ], &szTempBuffer[ iStart ], iEnd-iStart );
iStart = iEnd+1;
iCurValue++;
}
iCurPos++;
};
// Import the last column
iEnd = iCurPos;
memset( &szValue[ iCurValue ][ 0 ], 0x00, 32 );
memcpy( &szValue[ iCurValue ], &szTempBuffer[ iStart ], iEnd-iStart );
iStart = iEnd+1;
iCurValue++;

//
// Store data
//

// ID Type
m_DefenseObjs[ m_iTotalDefObjs ].m_iType = m_iTotalDefObjs;
// Name
strcpy( m_DefenseObjs[ m_iTotalDefObjs ].m_szName, &szValue[ 0 ][ 0 ] );
// Bullet armor rating
m_DefenseObjs[ m_iTotalDefObjs ].m_iBulletArmorRating = atoi( &szValue[ 1 ][ 0 ] );
// Missile armor rating
m_DefenseObjs[ m_iTotalDefObjs ].m_iMissileArmorRating = atoi( &szValue[ 2 ][ 0 ] );
// Laser armor rating
m_DefenseObjs[ m_iTotalDefObjs ].m_iLaserArmorRating = atoi( &szValue[ 3 ][ 0 ] );
// Melee armor rating
m_DefenseObjs[ m_iTotalDefObjs ].m_iMeleeArmorRating = atoi( &szValue[ 4 ][ 0 ] );
// Hit points
m_DefenseObjs[ m_iTotalDefObjs ].m_iMeleeArmorRating = atoi( &szValue[ 5 ][ 0 ] );
// Regen rate
m_DefenseObjs[ m_iTotalDefObjs ].m_iMeleeArmorRating = atoi( &szValue[ 6 ][ 0 ] );

// Increment objects
m_iTotalDefObjs++;
}
fclose( fp );

//------------------------------------------
//
// OFFENSE TYPES
//
//------------------------------------------
// Open the base type file
fp = fopen( szOffFileName, "r" );
if( fp == NULL ) {
return( -1 );
}

// Pull the header first and toss it out
fgets( szTempBuffer, 512, fp );
szTempBuffer[strlen(szTempBuffer)-1] = '\0';

// Set total objects to 0
m_iTotalOffObjs = 0;

// Loop through and read every line
while( !feof( fp ) ) {
// Get next line
fgets( szTempBuffer, 512, fp );

if( feof( fp ) ) {
break;
}

// Add terminator
szTempBuffer[strlen(szTempBuffer)-1] = '\0';
iStart = 0;
iEnd = 0;
iCurPos = 0;
iCurValue = 0;

// Pull out the values
while( szTempBuffer[ iCurPos ] != '\0' && iCurPos < 512 ) {
// Check for end of value
if( szTempBuffer[ iCurPos ] == ',' ) {
iEnd = iCurPos;
memset( &szValue[ iCurValue ][ 0 ], 0x00, 32 );
memcpy( &szValue[ iCurValue ], &szTempBuffer[ iStart ], iEnd-iStart );
iStart = iEnd+1;
iCurValue++;
}
iCurPos++;
};
// Import the last column
iEnd = iCurPos;
memset( &szValue[ iCurValue ][ 0 ], 0x00, 32 );
memcpy( &szValue[ iCurValue ], &szTempBuffer[ iStart ], iEnd-iStart );
iStart = iEnd+1;
iCurValue++;

//
// Store data
//

// ID Type
m_OffenseObjs[ m_iTotalOffObjs ].m_iType = m_iTotalOffObjs;
// Name
memset( m_OffenseObjs[ m_iTotalOffObjs ].m_szName, 0x00, 64 );
strcpy( m_OffenseObjs[ m_iTotalOffObjs ].m_szName, &szValue[ 0 ][ 0 ] );
// Bullet damage rating
m_OffenseObjs[ m_iTotalOffObjs ].m_iBulletDamageRating = atoi( &szValue[ 1 ][ 0 ] );
// Missile damage rating
m_OffenseObjs[ m_iTotalOffObjs ].m_iMissileDamageRating = atoi( &szValue[ 2 ][ 0 ] );
// Laser damage rating
m_OffenseObjs[ m_iTotalOffObjs ].m_iLaserDamageRating = atoi( &szValue[ 3 ][ 0 ] );
// Melee damage rating
m_OffenseObjs[ m_iTotalOffObjs ].m_iMeleeDamageRating = atoi( &szValue[ 4 ][ 0 ] );
// Proj speed
m_OffenseObjs[ m_iTotalOffObjs ].m_fProjectileSpeed = (float)atof( &szValue[ 5 ][ 0 ] );
// Range
m_OffenseObjs[ m_iTotalOffObjs ].m_iRange = atoi( &szValue[ 6 ][ 0 ] );
// ROF
m_OffenseObjs[ m_iTotalOffObjs ].m_iRateOfFire = atoi( &szValue[ 7 ][ 0 ] );
// Splash Radius
m_OffenseObjs[ m_iTotalOffObjs ].m_iSplashRadius = atoi( &szValue[ 8 ][ 0 ] );

// Increment objects
m_iTotalOffObjs++;
}
fclose( fp );

//------------------------------------------
//
// MOVEMENT TYPES
//
//------------------------------------------
// Open the base type file
fp = fopen( szMovFileName, "r" );
if( fp == NULL ) {
return( -1 );
}

// Pull the header first and toss it out
fgets( szTempBuffer, 512, fp );
szTempBuffer[strlen(szTempBuffer)-1] = '\0';

// Set total objects to 0
m_iTotalMovObjs = 0;

// Loop through and read every line
while( !feof( fp ) ) {
// Get next line
fgets( szTempBuffer, 512, fp );

if( feof( fp ) ) {
break;
}

// Add terminator
szTempBuffer[strlen(szTempBuffer)-1] = '\0';
iStart = 0;
iEnd = 0;
iCurPos = 0;
iCurValue = 0;

// Pull out the values
while( szTempBuffer[ iCurPos ] != '\0' && iCurPos < 512 ) {
// Check for end of value
if( szTempBuffer[ iCurPos ] == ',' ) {
iEnd = iCurPos;
memset( &szValue[ iCurValue ][ 0 ], 0x00, 32 );
memcpy( &szValue[ iCurValue ], &szTempBuffer[ iStart ], iEnd-iStart );
iStart = iEnd+1;
iCurValue++;
}
iCurPos++;
};
// Import the last column
iEnd = iCurPos;
memset( &szValue[ iCurValue ][ 0 ], 0x00, 32 );
memcpy( &szValue[ iCurValue ], &szTempBuffer[ iStart ], iEnd-iStart );
iStart = iEnd+1;
iCurValue++;

//
// Store data
//

// ID Type
m_MovementObjs[ m_iTotalMovObjs ].m_iType = m_iTotalMovObjs;
// Name
memset( m_MovementObjs[ m_iTotalOffObjs ].m_szName, 0x00, 64 );
strcpy( m_MovementObjs[ m_iTotalMovObjs ].m_szName, &szValue[ 0 ][ 0 ] );
// Acceleration
m_MovementObjs[ m_iTotalMovObjs ].m_fAcceleration = (float)atof( &szValue[ 1 ][ 0 ] );
// Deacceleration
m_MovementObjs[ m_iTotalMovObjs ].m_fDeacceleration = (float)atof( &szValue[ 2 ][ 0 ] );
// Speed
m_MovementObjs[ m_iTotalMovObjs ].m_fMovementSpeed = (float)atof( &szValue[ 3 ][ 0 ] );
// Move type
m_MovementObjs[ m_iTotalMovObjs ].m_iMovementType = atoi( &szValue[ 4 ][ 0 ] );
// Turn speed
m_MovementObjs[ m_iTotalMovObjs ].m_fTurnSpeed = (float)atof( &szValue[ 5 ][ 0 ] );

// Increment objects
m_iTotalMovObjs++;
}
fclose( fp );

//------------------------------------------
//
// ANIMATION TYPES
//
//------------------------------------------
// Open the base type file
fp = fopen( szAnimFileName, "r" );
if( fp == NULL ) {
return( -1 );
}

// Pull the header first and toss it out
fgets( szTempBuffer, 512, fp );
szTempBuffer[strlen(szTempBuffer)-1] = '\0';

// Set total objects to 0
m_iTotalAnimationObjs = 0;

// Loop through and read every line
while( !feof( fp ) ) {
// Get next line
fgets( szTempBuffer, 512, fp );

if( feof( fp ) ) {
break;
}

// Add terminator
szTempBuffer[strlen(szTempBuffer)-1] = '\0';
iStart = 0;
iEnd = 0;
iCurPos = 0;
iCurValue = 0;

// Pull out the values
while( szTempBuffer[ iCurPos ] != '\0' && iCurPos < 512 ) {
// Check for end of value
if( szTempBuffer[ iCurPos ] == ',' ) {
iEnd = iCurPos;
memset( &szValue[ iCurValue ][ 0 ], 0x00, 32 );
memcpy( &szValue[ iCurValue ], &szTempBuffer[ iStart ], iEnd-iStart );
iStart = iEnd+1;
iCurValue++;
}
iCurPos++;
};
// Import the last column
iEnd = iCurPos;
memset( &szValue[ iCurValue ][ 0 ], 0x00, 32 );
memcpy( &szValue[ iCurValue ], &szTempBuffer[ iStart ], iEnd-iStart );
iStart = iEnd+1;
iCurValue++;

//
// Store data
//

// ID Type
m_AnimationObjs[ m_iTotalAnimationObjs ].m_iType = m_iTotalAnimationObjs;
// Name
memset( m_AnimationObjs[ m_iTotalAnimationObjs ].m_szName, 0x00, 64 );
strcpy( m_AnimationObjs[ m_iTotalAnimationObjs ].m_szName, &szValue[ 0 ][ 0 ] );
// Prefix
memset( m_AnimationObjs[ m_iTotalAnimationObjs ].m_szBitmapPrefix, 0x00, 64 );
strcpy( m_AnimationObjs[ m_iTotalAnimationObjs ].m_szBitmapPrefix, &szValue[ 1 ][ 0 ] );
// Number of still frames
m_AnimationObjs[ m_iTotalAnimationObjs ].m_iNumStillFrames = atoi( &szValue[ 2 ][ 0 ] );
// Number of move frames
m_AnimationObjs[ m_iTotalAnimationObjs ].m_iNumMoveFrames = atoi( &szValue[ 3 ][ 0 ] );
// Number of attack frames
m_AnimationObjs[ m_iTotalAnimationObjs ].m_iNumAttackFrames = atoi( &szValue[ 4 ][ 0 ] );
// Number of die frames
m_AnimationObjs[ m_iTotalAnimationObjs ].m_iNumDieFrames = atoi( &szValue[ 5 ][ 0 ] );
// Set the render device
m_AnimationObjs[ m_iTotalAnimationObjs ].vSetRenderDevice( m_pd3dDevice );
// Load the textures
m_AnimationObjs[ m_iTotalAnimationObjs ].vLoadTextures();

// Increment objects
m_iTotalAnimationObjs++;
}
fclose( fp );

//------------------------------------------
//
// UNIT TYPES
//
//------------------------------------------

// Open the base type file
fp = fopen( szUnitFileName, "r" );
if( fp == NULL ) {
return( -1 );
}

// Pull the header first and toss it out
fgets( szTempBuffer, 512, fp );
szTempBuffer[strlen(szTempBuffer)-1] = '\0';

// Set total objects to 0
m_iTotalUnitBaseObjs = 0;

// Loop through and read every line
while( !feof( fp ) ) {
// Get next line
fgets( szTempBuffer, 512, fp );

if( feof( fp ) ) {
break;
}

// Add terminator
szTempBuffer[strlen(szTempBuffer)-1] = '\0';
iStart = 0;
iEnd = 0;
iCurPos = 0;
iCurValue = 0;

// Pull out the values
while( szTempBuffer[ iCurPos ] != '\0' && iCurPos < 512 ) {
// Check for end of value
if( szTempBuffer[ iCurPos ] == ',' ) {
iEnd = iCurPos;
memset( &szValue[ iCurValue ][ 0 ], 0x00, 32 );
memcpy( &szValue[ iCurValue ], &szTempBuffer[ iStart ], iEnd-iStart );
iStart = iEnd+1;
iCurValue++;
}
iCurPos++;
};
// Import the last column
iEnd = iCurPos;
memset( &szValue[ iCurValue ][ 0 ], 0x00, 32 );
memcpy( &szValue[ iCurValue ], &szTempBuffer[ iStart ], iEnd-iStart );
iStart = iEnd+1;
iCurValue++;

//
// Store data
//

// ID Type
m_UnitBaseObjs[ m_iTotalUnitBaseObjs ].m_iType = m_iTotalUnitBaseObjs;
// Name
memset( m_UnitBaseObjs[ m_iTotalUnitBaseObjs ].m_szName, 0x00, 64 );
strcpy( m_UnitBaseObjs[ m_iTotalUnitBaseObjs ].m_szName, &szValue[ 0 ][ 0 ] );
// Defense Type
ptrDefense = ptrGetDefenseType( &szValue[ 1 ][ 0 ] );
// Offense Type1
ptrOffense1 = ptrGetOffenseType( &szValue[ 2 ][ 0 ] );
// Offense Type2
ptrOffense2 = ptrGetOffenseType( &szValue[ 3 ][ 0 ] );
// Offense Type3
ptrOffense3 = ptrGetOffenseType( &szValue[ 4 ][ 0 ] );
// Move Type
ptrMovement = ptrGetMoveType( &szValue[ 5 ][ 0 ] );
// Animation Type
ptrAnimation = ptrGetAnimType( &szValue[ 6 ][ 0 ] );
// Set the base types
m_UnitBaseObjs[ m_iTotalUnitBaseObjs ].vSetBaseValues(
ptrDefense,
ptrOffense1,
ptrOffense2,
ptrOffense3,
ptrMovement,
ptrAnimation );

// Increment objects
m_iTotalUnitBaseObjs++;
}
fclose( fp );

return( 1 );
}

Потом подумал переписать хге-шный парсер, но там все еще страшнее.

void RScript::Parse(hgeResourceManager *rm, RScriptParser *sp, const char *sname, const char *sbasename)
{
RScriptParser *np;
RScript *res_script;
void *data;
DWORD size;
char *script, name[MAXRESCHARS], basename[MAXRESCHARS];
int restype;

if(!FindRes(rm, RES_SCRIPT, sname))
{
res_script = new RScript(); // hack! we need an instance of RScript to access hge
// if all ok, this object is used later to keep the script

data=hge->Resource_Load(sname, &size);
if(!data)
{
if(sp) sp->ScriptPostError("Script "," not found.");
else hge->System_Log("Script '%s' not found.",sname);
delete res_script;
return;
}
else
{
script= new char[size+1];
memcpy(script, data, size);
script[size]=0;
hge->Resource_Free(data);

strcpy(res_script->name, sname);
AddRes(rm, RES_SCRIPT, res_script);
np = new RScriptParser(res_script->name, script);

for(;;)
{
np->get_token();
if(np->tokentype == TTEND) break;

else if(np->tokentype == TTRES_INCLUDE)
{
np->get_token();
RScript::Parse(rm, np, np->tkn_string(), NULL);
}

else if(np->tokentype > TTRES__FIRST && np->tokentype < TTRES__LAST)
{
restype=np->tokentype-TTRES__FIRST-1;
name[0]=basename[0]=0;

np->get_token();
if(FindRes(rm, restype, np->tkn_string()))
{
np->ScriptPostError("Resource "," of the same type already has been defined.");
while((np->tokentype <= TTRES__FIRST || np->tokentype >= TTRES__LAST) && np->tokentype != TTEND) np->get_token();
np->put_back();
continue;
}
strcpy(name, np->tkn_string());

np->get_token();

if(np->tokentype == TTBASED)
{
np->get_token();
if(!FindRes(rm, restype, np->tkn_string())) np->ScriptPostError("Base resource "," is not defined.");
else strcpy(basename, np->tkn_string());
np->get_token();
}

if(np->tokentype == TTOPENBLOCK)
{
switch(restype)
{
case RES_RESOURCE: RResource::Parse(rm, np, name, basename); break;
case RES_TEXTURE: RTexture::Parse(rm, np, name, basename); break;
case RES_EFFECT: REffect::Parse(rm, np, name, basename); break;
case RES_MUSIC: RMusic::Parse(rm, np, name, basename); break;
case RES_STREAM: RStream::Parse(rm, np, name, basename); break;
case RES_TARGET: RTarget::Parse(rm, np, name, basename); break;
case RES_SPRITE: RSprite::Parse(rm, np, name, basename); break;
case RES_ANIMATION: RAnimation::Parse(rm, np, name, basename); break;
case RES_FONT: RFont::Parse(rm, np, name, basename); break;
case RES_PARTICLE: RParticle::Parse(rm, np, name, basename); break;
case RES_DISTORT: RDistort::Parse(rm, np, name, basename); break;
case RES_STRTABLE: RStringTable::Parse(rm, np, name, basename); break;
}
}
else
{
np->ScriptPostError("Illegal resource syntax, "," found; '{' expected.");
while((np->tokentype <= TTRES__FIRST || np->tokentype >= TTRES__LAST) && np->tokentype != TTEND) np->get_token();
np->put_back();
}
}

else
{
np->ScriptPostError("Unrecognized resource specificator ",".");
while((np->tokentype <= TTRES__FIRST || np->tokentype >= TTRES__LAST) && np->tokentype != TTEND) np->get_token();
np->put_back();
}
}

delete np;
delete[] script;
}
}
else sp->ScriptPostError("Script "," already has been parsed.");
}

Тогда я вспомнил, что на hge форуме часто упоминается xml и заточенный под игры парсер pugixml (созданный, кстати, zeux). Изучил, внедрил - остался очень доволен. Можно продалжать писать игру, не отвлекаясь на детали.
Спасибо, zeux!

tools

Previous post Next post
Up