وفي 03 ابريل 2008 02:44 م، قال وسام البهنسي متحمساً:
* تصفح كود اللعبة وبناؤه بشكل ناجح وتنفيذ اللعبة على جهازك.وفي 03 ابريل 2008 02:44 م، ظهر شبح ابتسامة على وجه وسام البهنسي وهو يقول:
* منع الأزرار من العمل عندما لا تكون اللعبة في الواجهة.if(uMsg == WM_ACTIVATE)
{
if(wParam != WA_INACTIVE)
{
// the app should now active, but may not have input focus
m_bAppActive = true;
}
else // app is being DeActivated
{
m_bAppActive = false;
// if our windows has focus, then discard it
/*if(GetFocus() == hWnd)
SetFocus(NULL);*/
}
// we handled the message of app activation
return 0;
}
//else // other messeages coming like input msg(s)
{
// check if app has focus and/or active
if(!m_bAppActive)
{
WaitMessage();
}
}
///////////////////////////////
اعتقد ان الموضوع بسيط لكنى بجد احترت - برجاء التوضيحأما في 03 ابريل 2008 02:44 م، فقد تنهد وسام البهنسي بارتياح وهو يرد:
* شرح مكونات الكود الأساسية./////// this code inside Main fucntion /////////////
const bool bFullScreen = false;
GameApp gameApp(hInstance,bFullScreen);
HICON hIcon = LoadIcon(hInstance,MAKEINTRESOURCE(IDI_GAME));
if (!CoreLib::LibInit(&gameApp,SCREEN_WIDTH,SCREEN_HEIGHT,bFullScreen,hIcon,GameApp::GameWndProc))
return -1;
gameApp.Init();
bool GameApp::Init(void)
{
if (!AudioInit())
return false;
if (!GameFont.Load("KonamiFont"))
return false;
if (!LoadConfig()) return false;
m_StateFlow.StartGame();
return true;
}
bool GameApp::LoadConfig(void)
{
char szFileName[MAX_PATH];
if (!GetGameFilePath(szFileName,"MainConfig.cfg",GameDir_Config))
return false;
CoreLib::ConfigDB db;
if (!CoreLib::XFerConfig(szFileName,db))
return false;
Config.pExplorerWalkArt = SpriteArt::GetOrLoadSpriteArt(db.szArtFile[0]);
Config.pExplorerAxeArt = SpriteArt::GetOrLoadSpriteArt(db.szArtFile[1]);
Config.pExplorerSwordArt = SpriteArt::GetOrLoadSpriteArt(db.szArtFile[2]);
Config.pExplorerDigArt = SpriteArt::GetOrLoadSpriteArt(db.szArtFile[3]);
Config.pExplorerShootArt = SpriteArt::GetOrLoadSpriteArt(db.szArtFile[4]);
if (!Config.pExplorerWalkArt || !Config.pExplorerAxeArt || !Config.pExplorerSwordArt ||
!Config.pExplorerDigArt || !Config.pExplorerShootArt)
return false;
(GameData::Config&)Config = db.data;
return true;
}
void StateFlow::StartGame(void)
{
m_eNextFlowAction = GameState::FlowTo_Intro1;
m_iTransitionTime = 0;
FlowData.eCurrentLevelStartMode = Pyramid::Starting_Intro;
STATS& stats = GameApp::Instance->Stats;
stats.iCurrentLevel = 0;
stats.iLevelCleared = -1;
stats.iScore = 0;
stats.iAttempts = 1;
}
enum FlowAction
{
FlowTo_Continue, // Keep updating the current state
FlowTo_Intro1, // Transition to the Intro1 state
FlowTo_Intro2, // Transition to the Intro2 state
FlowTo_Password, // Transition to the Password state
FlowTo_Play, // Transition to the Play state
FlowTo_Map, // Transition to the Map state
FlowTo_Outro, // Transition to the Outro state
};
/////////////////////////////////////////////////////////////////////////////////////////////
// Function Name : AudioManager::Update
//
// Purpose : Per-frame heart-beat function for updating sounds. Currently this function
// guarentees that conflicting sounds don't get played together.
// This function must be called once every game simulation frame.
//
// Params : None.
//
// Return Value : None.
/////////////////////////////////////////////////////////////////////////////////////////////
void AudioManager::Update(void)
{
// We only care about the background music. If it's already stopped then
// there's not really anything to do
if (!m_bBGMPlaying) return;
// See if any of the conflicting sounds are playing. If so, then silence the background music
static AudioSoundType aConflicts[] = { Sound_Door, Sound_RightDoor, Sound_CollectedAll };
for (DWORD i=0;i
{
if (CoreLib::AudioIsPlaying(aConflicts[i]))
{
CoreLib::AudioStop(Sound_BGMusic);
return;
}
}
// If we are here then it means that none of conflicting sounds are playing,
// so what we have to do is basically just re-activate the bg music if it was
// stopped before...
if (!CoreLib::AudioIsPlaying(Sound_BGMusic))
{
CoreLib::AudioRewind(Sound_BGMusic);
CoreLib::AudioPlay(Sound_BGMusic);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////
// Function Name : FontMonospace::Draw
//
// Purpose : Draws the specified text at the required position, starting from the bottom-left
// corner, and increasing to the right (only supports English, and not all characters).
//
// Params :
// int iScreenX : Screen pixel coordinate of text left.
// int iScreenY : Screen pixel coordinate of text bottom.
// const char *pszText : String to draw. No line-breaks allowed.
//
// Return Value : None.
/////////////////////////////////////////////////////////////////////////////////////////////
void FontMonospace::Draw(int iScreenX, int iScreenY, const char *pszText) const
{
RECT rcSource;
while (*pszText)
{
GetCharacterRect(*(pszText++),rcSource);
CoreLib::FontPutChar(iScreenX,iScreenY,rcSource);
iScreenX += TEXT_CHARACTER_WIDTH;
}
}
في 04 ابريل 2008 06:54 م، عقد ahmed ezz حاجبيه بتفكير وقال:
- نبدء بمفهوم المرحلة او ال pyramid وهى عبارة عن حجرة وا اكثر champer وكل حجرة مكونة من مجموعة BlockArtsوفي 04 ابريل 2008 06:03 م، قال ahmed ezz متحمساً:
ملاحظة : اذن المكتبة CoreLib كأنها Game Engine يوفر لنا وظائف هامة جدا مثل تشغيل الاصوات وتحميل ملفات المراحل والخطوط لكنوفي 04 ابريل 2008 06:03 م، ظهر شبح ابتسامة على وجه ahmed ezz وهو يقول:
نحمل البيانات من الملف بعد تهيئة مساره الفعلى ثم ننشأ متغير كأنه قاعدة بيانات لحفظ القيم المقروءة من الملف بالكلاس ConfigDB////////////////////////////////////////////////////////////////////////////////////////////
// Function Name
: Monster::Tick
//
// Purpose :
Monster's simulation update function. Processes all state machines for it.
//
// Params :
None.
//
// Return Value
: Irrelevant.
/////////////////////////////////////////////////////////////////////////////////////////////
bool
Monster::Tick(void)
{
// Try to follow explorer if visible
AttackExplorer();
// Tick him using base behavior...
bool bCreatureTick = Creature::Tick();
// If he is not in a base behavior,
then it is upon us to handle him
if (!bCreatureTick)
{
switch (m_State)
{
case State_Mon_Spawn: OnStateSpawn(); break;
case State_Mon_Think: OnStateThink(); break;
// Do AI
case State_Mon_Die: OnStateDie(); returntrue; // If dead, don't process anything else
}
}
// Decay of deflection amount
if (m_iDeflectionsAmount >
0)
m_iDeflectionsAmount--;
m_uInput &= ~Input_Action; //
Reset jump status
CollideWithChamber(); // Either jumps
or reflects off the wall if collides
CrossGap(); // Attempt to jump if
faced with a gap in front of him
// AI state machine update
switch (m_AIState)
{
case AIState_Chase: OnAIStateChase(); break;
case AIState_Wander: OnAIStateWander(); break;
case
AIState_ClimbNearestStairs: OnAIStateClimbNearestStairs();
break;
}
if ((m_State == State_Stand) ||
(m_State == State_Run))
{
if (m_iNextThinkCounter
<= 0)
SwitchToStateThink();
else
m_iNextThinkCounter--;
}
returntrue;
}
تستخدم هذه الوحدة لتحديث محاكاة الوحش و معالج/////////////////////////////////////////////////////////////////////////////////////////////
// Function Name
: Monster::SpawnAtCreationPoint
//
// Purpose :
Every pyramid has default locations for spawning monsters. Calling this
function
// will make the monster get
spawned from that position instead of where he was last
// killed.
//
// Params :
None.
//
// Return Value
: None.
/////////////////////////////////////////////////////////////////////////////////////////////
void
Monster::SpawnAtCreationPoint(void)
{
m_Pos.Chamber(m_Data.uSpawnChamber);
m_Pos.Init(m_Data.wSpawnCellX*CHAMBER_CELL,m_Data.wSpawnCellY*CHAMBER_CELL);
SwitchToStateSpawn(GameApp::Config.iMonsterSleepPeriod/2);
}
تستخدم هذه الوحدة لإنشاء وحش في نقطة معينة من/////////////////////////////////////////////////////////////////////////////////////////////
// Function Name
: Monster::Kill
//
// Purpose :
Kill the monster. This can happen by the sword of the explorer, or because we
// are kind-of stuck in a
situation that keeps bumping us against walls.
//
// Params :
// bool bSpawnFromCreationPoint : 'true' if it
was suicide and the monster should spawn
//
pyramid default spot. 'false' if not.
/////////////////////////////////////////////////////////////////////////////////////////////
void
Monster::Kill(bool bSpawnFromCreationPoint)
{
m_iDeflectionsAmount = 0;
SwitchToStateDie(bSpawnFromCreationPoint);
if (!bSpawnFromCreationPoint) // Increase score because he must have been killed by a
sword shot
GameApp::Instance->Stats.AddScore(GameApp::Config.iKillMonsterScore);
}
bool
Monster::IsAlive(void) const
{
switch (m_State)
{
case State_Hide:
case State_Mon_Spawn:
case State_Mon_Die:
returnfalse;
}
returntrue;
}
SpriteArt* Monster::GetArt(void) const
{
return m_pArtWalk;
}
fixed Monster::GetWalkSpeed(void) const
{
return m_Data.fWalkSpeed;
}
fixed
Monster::GetClimbSpeed(void) const
{
return m_Data.fClimbSpeed;
}
int
Monster::GetJumpFrame(void) const
{
return
GameApp::Config.uMonsterJumpFrame;
}
bool
Monster::RespondToAction(void)
{
if (!CanJumpAtPlace()) returnfalse;
SwitchToStateJump();
returntrue;
}
تستخدم هذه الوحدة لعملية معالجة قتل الوحش عنint CGameApp::BeginGame()
{
MSG msg;
// Start main loop
while (1)
{
// Did we receive a message, or are we idling ?
if ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
{
if (msg.message == WM_QUIT) break;
TranslateMessage( &msg );
DispatchMessage ( &msg );
}
else
{
FrameAdvance();
}
} // Until quit message is received
return 0;
}
الشكل السابق هو احدى الاشكال البسيطة لل Game loop وفى الدالة FrameAdvanceint WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
{
const bool bFullScreen = false;
GameApp gameApp(hInstance,bFullScreen);
HICON hIcon = LoadIcon(hInstance,MAKEINTRESOURCE(IDI_GAME));
if (!CoreLib::LibInit(&gameApp,SCREEN_WIDTH,SCREEN_HEIGHT,bFullScreen,hIcon,GameApp::GameWndProc))
return -1;
gameApp.Init();
CoreLib::LibRun(GAME_FPS);
CoreLib::LibShutdown();
return 0;
}
حيث بدأت اللعبة بعمل Initialize كما ذكرنا سابقاclass GameApp : public CoreLib::BaseApp
{
public:
// normal code here
// ...
// used to monitor game app activation
bool m_bAppActive;
// ...
// rest of the code here
}
الان نقوم بوضع قيمة ابتدائية للمتغير لتكون اللعبة نشطة وذلك فى ال GameApp Constructor وأيضا فى الدالة GameApp::Init كالتالى:// this line in GameApp::Init before returning from the func
m_bAppActive = true;
الان يبقى لنا تعديل حالة المتغير عندما تكون اللعبة نشطة أو غير نشطة وذلك كالتالىLRESULT CALLBACK GameApp::GameWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
// App is being Activated or Deactivated
if(uMsg == WM_ACTIVATE)
{
if(wParam != WA_INACTIVE)
{
// the app should now active, but may not have input focus
GameApp::Instance->m_bAppActive = true;
}
else // app is being DeActivated
{
GameApp::Instance->m_bAppActive = false;
// if our windows has focus, then discard it
/*if(GetFocus() == hWnd)
SetFocus(NULL);*/
}
// we handled the message of app activation
return 0;
}
// check if app has focus and/or active
if(!GameApp::Instance->m_bAppActive)
{
//OutputDebugString(TEXT("app is inactive\n"));
//WaitMessage();
return -1;
}
// here normal switch case message handling
}
كما نرى قمنا باضافة كود لتعديل حالة المتغير واللعبة اذا كانت نشطة او لاbool GameApp::OnIdle(void)
{
// only update if App is Active
if(m_bAppActive)
{
m_StateFlow.Update();
AudioUpdate();
return true;
}
return false;
}
بتاريخ 10 ابريل 2008 06:47 ص، قطب ahmed ezz حاجبيه بشدة وهو يقول:
والان للخطوة الاخيرة وهى منع تعديل عمل Update للعبة اذا كانت غير نشطة وذلك كما يلى:bool GameApp::OnIdle(void)
{
// only update if App is Active
if(m_bAppActive)
{
m_StateFlow.Update();
AudioUpdate();
return true;
}
return false;
}