www.pudn.com > GameEngine_src.rar > CSpriteFactory.cpp
#include "CSpriteFactory.h" #include "CEasyAudio.h" #include "CMagicFactory.h" #include "CMap.h" #include "normal.h" #include#include #include extern PEASYDRAW g_pEasyDraw; extern PEASYAUDIO g_pEasyAudio; extern CMap theMap; extern CMagicFactory theMagicFactory; ////////////////////////////////////////////////////////////// //SI文件中的EPG文件名数组 ////////////////////////////////////////////////////////////// struct EPG_NAME_ARRAY { union { struct { char epg_wait_name[32]; char epg_idle_name[32]; char epg_walk_name[32]; char epg_hurt_name[32]; char epg_dead_name[32]; char epg_melee_name[32]; char epg_spell_name[32]; }; char epg_name_array[7][32]; }; }; //////////////////////////////////////////////////////////////// //声音ID数组 //////////////////////////////////////////////////////////////// struct SOUND_ID_ARRAY { union { struct { int walk_sound_id; int hurt_sound_id; int dead_sound_id; int melee_sound_id; int spell_sound_id; }; int sound_id[5]; }; }; //si文件的文件头 struct SI_FILE_HEADER { union { struct { int siMask; //异或摭码,用于加密 int siFileType; //文件标识 SPRITE_TYPE siSpriteType; //精灵种类 bool siIsHaveES; //是否有脚本 char siName[16]; //精灵名字 int siNumMagic; //精灵魔法技能数量 int rev[3]; }; int siHeader[16]; }; }; const SI_FILE = 'SI'; ////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////// CSpriteFactory::CSpriteFactory() { m_MonsterCreateInterval = 3000; //5 seconds m_MaxNumOfMonster = 60; m_pEPK = NULL; } CSpriteFactory::~CSpriteFactory() { } ////////////////////////////////////////////////////////////////////// //初始化各个对象池,这只在程序开始时调用 ////////////////////////////////////////////////////////////////////// bool CSpriteFactory::Init() { if ( m_MonsterPool.Init( 128 ) == false ) return false; m_BloodBarWidth = g_pEasyDraw->GetCharWidth() * 8; //必被4整除 m_BloodBarHeight = g_pEasyDraw->GetCharHeight(); m_BloodBarSurface1 = g_pEasyDraw->CreateSurfaceEx( NULL, m_BloodBarWidth, m_BloodBarHeight, true, 0, 0 ); if ( m_BloodBarSurface1 == NULL ) return false; m_BloodBarSurface2 = g_pEasyDraw->CreateSurfaceEx( NULL, m_BloodBarWidth, m_BloodBarHeight, true, 0, 0 ); if ( m_BloodBarSurface2 == NULL ) return false; m_BloodBarSurface2->ClearSurface( 0x7bef, 0 ); return true; } ////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////// void CSpriteFactory::Free() { m_NpcArray.Free(); m_NpcClassArray.Free(); m_MonsterPool.Free(); m_MonsterClassArray.Free(); m_EPGDataArray.Free(); g_pEasyDraw->DeleteSurface( m_BloodBarSurface1 ); g_pEasyDraw->DeleteSurface( m_BloodBarSurface2 ); } ////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////// /*void CSpriteFactory::CreateNpc() { for ( int i = 0; i < m_NpcArray.GetLength(); ++i ) { CNpc &npc = m_NpcArray[i]; MONSTER_CLASS &mc = m_NpcClassArray[i]; npc.Init( &(mc.EPGArray), &(mc.SpriteInfo), m_NpcInfoArray[i].BasePoint, ST_N_B ); if ( theMap.AddAliveSprite( &npc ) == false ) { assert(false); } } }*/ ////////////////////////////////////////////////////////////////////// //随机的产生怪物 ////////////////////////////////////////////////////////////////////// void CSpriteFactory::CreateMonster() { unsigned int ThisTick = timeGetTime(); BYTE HoldMask = HOLD_MASK | SAVE_MASK; for ( int i = 0; i < m_MonsterInfoArray.GetLength(); ++i ) { MONSTER_INFO &mi = m_MonsterInfoArray[i]; if ( ThisTick - mi.LastTick > mi.Interval && mi.NumMonster <= mi.MaxNum ) { int max_row = theMap.GetHeight() * 4; int max_col = theMap.GetWidth() * 4; srand( ThisTick ); int row = ( rand() + m_LastCell.col ) % max_row; //随机产生怪物位置 int col = ( rand() + m_LastCell.row ) % max_col; if ( theMap.IsCellHold( row, col, HoldMask ) == false ) { CAliveSprite *monster = m_MonsterPool.Alloc(); if ( monster != NULL ) { MONSTER_CLASS &mc= m_MonsterClassArray[i]; CELL cell(row, col); POINT base; theMap.CellToPoint( cell, base ); monster->Init( &mc, base, ST_MONSTER ); monster->SetDirection( ThisTick % 8 + 1 ); //随机设置怪物方向 monster->SetClassIndex( i ); //设置怪物的种类索引 if ( theMap.AddAliveSprite( monster ) == false ) m_MonsterPool.Free( monster ); else { mi.NumMonster++; mi.LastTick = ThisTick; } } } } } } ////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////// void CSpriteFactory::DeleteMonster( CAliveSprite *monster ) { int i = monster->GetClassIndex(); m_MonsterInfoArray[i].NumMonster -= 1; m_MonsterPool.Free( monster ); } ////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////// void CSpriteFactory::DrawBloodBar( int x, int y, int hp, int max_hp, PSURFACE nameSurf ) { float f = float(hp) / float(max_hp) * float(m_BloodBarWidth); RECT rc = { 0, 0, int(f), m_BloodBarHeight }; m_BloodBarSurface1->ClearSurface( 0x0000, 0 ); m_BloodBarSurface2->BltTo( 0, 0, m_BloodBarSurface1, &rc ); #ifdef ALPHA_SHADOW m_BloodBarSurface1->DrawAlphaMMX( x, y ); #else m_BloodBarSurface1->DrawAutoClip( x, y ); #endif nameSurf->DrawAutoClip( x, y ); } ////////////////////////////////////////////////////////////////////// //载入SI文件,获取要载入的EPG文件名 ////////////////////////////////////////////////////////////////////// void CSpriteFactory::OnFreeLvl() { for ( int i = 0; i < m_MonsterClassArray.GetLength(); ++i ) { AS_SOUND_ARRAY &sound = m_MonsterClassArray[i].SoundArray; for ( int j = 0; j < 5; ++j ) { if ( sound.asSound[j] != NULL ) g_pEasyAudio->DeleteSoundBuffer( sound.asSound[j] ); } } SaveTmp(); m_MonsterPool.Clear(); m_MonsterClassArray.Clear(); m_MonsterInfoArray.Clear(); m_NpcArray.Clear(); m_NpcClassArray.Clear(); m_EPGDataArray.Clear(); } ////////////////////////////////////////////////////////////////////// //从地图文件中载入NPC和怪物的信息 ////////////////////////////////////////////////////////////////////// void CSpriteFactory::OnLoadMap( FILE *fp, int NumNpc, int NumMonster ) { for ( int i = 0; i < NumNpc; ++i ) { NPC_INFO *pni = m_NpcInfoArray.CreateOneElement(); fread( pni, sizeof(NPC_INFO), 1, fp ); } for ( i = 0; i < NumMonster; ++i ) { MONSTER_INFO *pmi = m_MonsterInfoArray.CreateOneElement(); fread( pmi, sizeof(MONSTER_INFO), 1, fp ); } } ////////////////////////////////////////////////////////////////////// //载入SI文件,并获取EPG文件名 //SI文件结构: //文件头+基本属性结构+EPG名数组+声音ID数组+魔法ID数组+脚本 ////////////////////////////////////////////////////////////////////// void CSpriteFactory::LoadSIHelp( unsigned char *buf ) { SI_FILE_HEADER sfh; EPG_NAME_ARRAY epgName; sfh = READ_MEMORY( buf, SI_FILE_HEADER ); //读取文件头 buf += sizeof(SI_FILE_HEADER); for ( int i = 1; i < 16; ++i ) sfh.siHeader[i] ^= sfh.siMask; //解密文件头 debug_assert( sfh.siFileType == SI_FILE ); MONSTER_CLASS *pMonsterClass = 0; if ( sfh.siSpriteType == ST_N_B ) pMonsterClass = m_NpcClassArray.CreateOneElement(); else if ( sfh.siSpriteType == ST_MONSTER ) pMonsterClass = m_MonsterClassArray.CreateOneElement(); else assert(false); ZeroMemory( pMonsterClass, sizeof(MONSTER_CLASS) ); pMonsterClass->NameSurface = g_pEasyDraw->CreateSurfaceEx( NULL, m_BloodBarWidth, m_BloodBarHeight, true, true, 0 ); unsigned int color = 0xff; if ( sfh.siSpriteType == ST_N_B ) color = 0xff00; pMonsterClass->NameSurface->WriteTextCenter( sfh.siName, color ); //创建名字页面,并写上名字 pMonsterClass->SpriteInfo = READ_MEMORY( buf, AS_BASE_INFO ); //读取基本属性 buf += sizeof(AS_BASE_INFO); for ( i = 0; i < 6; ++i ) pMonsterClass->SpriteInfo.IntInfo[i] ^= sfh.siMask; //解密基本属性 epgName = READ_MEMORY( buf, EPG_NAME_ARRAY ); //读取EPG文件名 buf += sizeof(EPG_NAME_ARRAY); for ( i = 0; i < 7; ++i ) { if ( epgName.epg_name_array[i][0] != '\0' ) { string str = epgName.epg_name_array[i]; m_EPGNameArray.Add( str ); //EPG文件名存入列表,而EPG数组存放索引,索引从1开始 pMonsterClass->EPGArray.epg_array[i].NameIndex = m_EPGNameArray.GetLength(); } } pMonsterClass->SoundArray = READ_MEMORY( buf, AS_SOUND_ARRAY ); //读取精灵的声音 buf += sizeof(AS_SOUND_ARRAY); if ( sfh.siNumMagic > 0 ) { pMonsterClass->MagicIDArray = new AS_MAGIC[sfh.siNumMagic]; assert( pMonsterClass->MagicIDArray != NULL ); memcpy( pMonsterClass->MagicIDArray, buf, sfh.siNumMagic * 4 );//读取魔法ID pMonsterClass->NumMagic = sfh.siNumMagic; buf += sfh.siNumMagic * 4; for ( int j = 0; j < sfh.siNumMagic; ++j ) theMagicFactory.OnLoadSI( pMonsterClass->MagicIDArray[j].magicID );//将魔法ID提交给魔法工厂 } if ( sfh.siSpriteType == ST_N_B && sfh.siIsHaveES ) { CNpc *pNpc = m_NpcArray.CreateOneElement(); //创建一个NPC对象 pNpc->LoadESFromMemory( (char *)buf, 0 ); //载入脚本 } } ////////////////////////////////////////////////////////////////////// //载入关卡所有需要的SI文件 ////////////////////////////////////////////////////////////////////// bool CSpriteFactory::OnLoadLvl() { CEPKFile epk; if ( false == epk.Open( "..\\data\\si.epk", EPK_IN ) ) assert(false); CDynamicArray magicIDArray; bool re = true; for ( int i = 0; i < m_NpcInfoArray.GetLength(); ++i ) { BYTE *buf = epk.Read( m_NpcInfoArray[i].siFileName ); if ( buf == 0 ) { re = false; goto _exit; } LoadSIHelp( buf ); } for ( i = 0; i < m_MonsterInfoArray.GetLength(); ++i ) { BYTE *buf = epk.Read( m_MonsterInfoArray[i].siFileName ); if ( buf == NULL ) { re = false; goto _exit; } LoadSIHelp( buf ); } _exit: epk.Close(); if ( re ) { SafeDelete( m_pEPK ); m_pEPK = new CEPKFile; //创建EPK对象 assert( m_pEPK != NULL ); if ( false == m_pEPK->Open( "..\\data\\animation.epk", EPK_IN ) ) re = false; m_IndexEPGLoading = 0; } return re; } ////////////////////////////////////////////////////////////////////// //载入关卡中所需要的EPG //一次游戏循环中载入一个,如果全部载入完,返回true ////////////////////////////////////////////////////////////////////// bool CSpriteFactory::OnLoadingLvl() { if ( m_IndexEPGLoading < m_EPGNameArray.GetLength() ) { BYTE *data = m_pEPK->Read( m_EPGNameArray[m_IndexEPGLoading].c_str() ); debug_assert( data != NULL ); //如果找不到所要的EPG,则是游戏设计的错误 EPG_DATA *pEPGData = m_EPGDataArray.CreateOneElement(); if ( false == pEPGData->LoadEPGFromMemory( (char *)data ) ) { debug_assert( false ); return false; } m_IndexEPGLoading++; return false; } else { m_pEPK->Close(); //载入声音: if ( m_pEPK->Open( "..\\data\\sound.epk", EPK_IN ) == false ) assert(false); for ( int i = 0; i < m_MonsterClassArray.GetLength(); ++i ) { AS_SOUND_ARRAY &sound = m_MonsterClassArray[i].SoundArray; for ( int j = 0; j < 5; ++j ) { if ( sound.soundId[j] > 0 ) { char sz[8]; wsprintf( sz, "%d.wav", sound.soundId[j] ); BYTE *buf = m_pEPK->Read( sz ); debug_assert( buf != NULL ); sound.asSound[j] = g_pEasyAudio->CreateSoundBuffer( (char *)buf, false, 4 ); } } } m_pEPK->Close(); delete m_pEPK; m_pEPK = NULL; return true; } } ////////////////////////////////////////////////////////////////////// //初始化关卡 ////////////////////////////////////////////////////////////////////// void CSpriteFactory::InitClassHelp( CDynamicArray &classArray ) { for ( int i = 0; i < classArray.GetLength(); ++i ) { //按EPG索引获取EPG指针,如果索引为0则没有指针 MONSTER_CLASS &monsterClass = classArray[i]; for ( int j = 0; j < 7; ++j ) { ALIVE_SPRITE_EPG &asEPG = monsterClass.EPGArray.epg_array[j]; int index = asEPG.NameIndex; if ( index > 0 ) { asEPG.pPG = m_EPGDataArray[index-1].GetAnimation(); asEPG.pSPG= m_EPGDataArray[index-1].GetShadow(); int h = asEPG.pPG->GetMaxHeight(); //计算最大高度值,用于绘制血条 if ( h > monsterClass.MaxHeight ) monsterClass.MaxHeight = h; } } //按魔法ID向魔法工厂索要魔法指针 for ( j = 0; j < monsterClass.NumMagic; ++j ) { monsterClass.MagicIDArray[j].pMagic = theMagicFactory.FindMagic(monsterClass.MagicIDArray[j].magicID); debug_assert( monsterClass.MagicIDArray[j].pMagic != NULL ); } } } ////////////////////////////////////////////////////////////////////// //初始化关卡 ////////////////////////////////////////////////////////////////////// void CSpriteFactory::OnInitLvl() { InitClassHelp( m_NpcClassArray ); InitClassHelp( m_MonsterClassArray ); //创建NPC: for ( int i = 0; i < m_NpcArray.GetLength(); ++i ) { CNpc &npc = m_NpcArray[i]; MONSTER_CLASS &mc = m_NpcClassArray[i]; npc.Init( &mc, m_NpcInfoArray[i].BasePoint, ST_N_B ); theMap.AddAliveSprite( &npc ); } //初始化怪物信息 for ( i = 0; i < m_MonsterInfoArray.GetLength(); ++i ) { m_MonsterInfoArray[i].LastTick = 0; m_MonsterInfoArray[i].NumMonster = 0; } m_NpcInfoArray.Free(); //npc info数组已经没用,释放内存 m_EPGNameArray.Free(); //EPG名字数组释放 LoadTmp(); } ////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////// void CSpriteFactory::SaveTmp() { if ( m_MonsterPool.IsEmpty() ) return; char *fileName = new char[64]; if ( fileName == NULL ) return; memset( fileName, 0, 64 ); strcpy( fileName, "..\\data\\" ); strcat( fileName, theMap.GetCurMapName() ); strcat( fileName, ".tmp" ); FILE *fp = fopen( fileName, "wb+" ); if ( fp == NULL ) { delete [] fileName; return; } int sum = 0; fseek( fp, 4, SEEK_SET ); for ( m_MonsterPool.Begin(); m_MonsterPool.IsNotNull(); m_MonsterPool.MoveNext() ) { CAliveSprite *monster = m_MonsterPool.GetCur(); if ( monster->IsAlive() ) { int n = monster->GetClassIndex(); fwrite( &n, 4, 1, fp ); n = monster->GetLife(); fwrite( &n, 4, 1, fp ); POINT p = monster->GetBasePoint(); fwrite( &p, 8, 1, fp ); sum++; } } fseek( fp, 0, SEEK_SET ); fwrite( &sum, 4, 1, fp ); fclose(fp); delete [] fileName; } ////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////// void CSpriteFactory::LoadTmp() { char *fileName = new char[64]; if ( fileName == NULL ) return; memset( fileName, 0, 64 ); strcpy( fileName, theMap.GetNextMapName() ); strcat( fileName, ".tmp" ); FILE *fp = fopen( fileName, "rb" ); if ( fp == NULL ) { delete [] fileName; return; } int sum, index, life; POINT point; BYTE HoldMask = HOLD_MASK | SAVE_MASK; DWORD ThisTick = timeGetTime(); fread( &sum, 4, 1, fp ); for ( int i = 0; i < sum; ++i ) { fread( &index, 4, 1, fp ); fread( &life, 4, 1, fp ); fread( &point, 8, 1, fp ); CAliveSprite *monster = m_MonsterPool.Alloc(); if ( monster != NULL ) { MONSTER_CLASS &mc= m_MonsterClassArray[index]; monster->Init( &mc, point, ST_MONSTER ); monster->SetClassIndex( index ); //设置怪物的种类索引 monster->SetLife( life ); if ( theMap.AddAliveSprite( monster ) == false ) m_MonsterPool.Free( monster ); else { MONSTER_INFO &mi = m_MonsterInfoArray[index]; mi.NumMonster++; mi.LastTick = ThisTick; } } } fclose( fp ); delete [] fileName; }