📄 winmain.cpp
字号:
/**************************************************
WinMain.cpp
Chapter 20 Full Game Demo - The Tower
Programming Role-Playing Games with DirectX
by Jim Adams (01 Jan 2002)
Required libraries:
D3D8.LIB, D3DX8.LIB, D3DXOF.LIB, DXGUID.LIB,
DINPUT8.LIB, DSOUND.LIB, and WINMM.LIB
**************************************************/
//#define FULLSCREENMODE
#include "Global.h"
///////////////////////////////////////////////////////////
// Global declarations
///////////////////////////////////////////////////////////
#define MENU_BACK 1
#define MENU_LOAD 2
#define MENU_SAVE 4
long g_MenuOptions = 0;
// Global names of character meshes
char *g_CharMeshNames[] = {
{ "..\\Data\\Warrior1.x" }, // Mesh # 0
{ "..\\Data\\Warrior2.x" }, // Mesh # 1
{ "..\\Data\\Yodan1.x" }, // Mesh # 2
{ "..\\Data\\Yodan2.x" }, // Mesh # 3
{ "..\\Data\\Yodan3.x" }, // Mesh # 4
{ "..\\Data\\Yodan4.x" } // Mesh # 5
};
// Global character animation information
sCharAnimationInfo g_CharAnimations[] = {
{ "Idle", TRUE },
{ "Walk", TRUE },
{ "Swing", FALSE },
{ "Spell", FALSE },
{ "Swing", FALSE },
{ "Hurt", FALSE },
{ "Die", FALSE },
{ "Idle", TRUE }
};
// Global spell mesh information
char *g_SpellMeshNames[] = {
{ "..\\Data\\Fireball.x" },
{ "..\\Data\\Explosion.x" },
{ "..\\Data\\Ice.x" },
{ "..\\Data\\Heal.x" },
{ "..\\Data\\Teleport.x" },
{ "..\\Data\\Groundball.x" },
{ "..\\Data\\Bomb.x" },
{ "..\\Data\\Force.x" }
};
// Global sound effect filenames
#define NUM_SOUNDS 9
char *g_SoundFilenames[NUM_SOUNDS] = {
{ "..\\Data\\Attack1.wav" },
{ "..\\Data\\Attack2.wav" },
{ "..\\Data\\Spell.wav" },
{ "..\\Data\\Roar.wav" },
{ "..\\Data\\Hurt1.wav" },
{ "..\\Data\\Hurt2.wav" },
{ "..\\Data\\Die1.wav" },
{ "..\\Data\\Die2.wav" },
{ "..\\Data\\Beep.wav" }
};
// Global music filenames
long g_CurrentMusic = -1;
char *g_MusicFilenames[] = {
{ "..\\Data\\Cathedral_Sunrise.mid" },
{ "..\\Data\\Distant_tribe.mid" },
{ "..\\Data\\Escape.mid" },
{ "..\\Data\\Jungle1.mid" },
{ "..\\Data\\Magic_Harp.mid" },
{ "..\\Data\\Medi_Strings.mid" },
{ "..\\Data\\Medi_techno.mid" },
{ "..\\Data\\Song_of_the_sea.mid" },
{ "..\\Data\\Storm.mid" }
};
// Global character pointer to PC, bartering NPC, and barter ICS
sCharacter *g_PCChar = NULL;
sCharacter *g_BarterChar = NULL;
char g_BarterICS[MAX_PATH];
///////////////////////////////////////////////////////////
// cApp function code
///////////////////////////////////////////////////////////
cApp::cApp()
{
m_Width = 640;
m_Height = 480;
m_Style = WS_BORDER | WS_CAPTION | \
WS_MINIMIZEBOX | WS_SYSMENU;
strcpy(m_Class, "GameClass");
strcpy(m_Caption, "The Tower by Jim Adams");
}
BOOL cApp::Init()
{
// Initialize the graphics device
m_Graphics.Init();
// Determine to use fullscreen mode or not
#ifdef FULLSCREENMODE
m_Graphics.SetMode(GethWnd(), FALSE, TRUE, 640, 480);
#else
m_Graphics.SetMode(GethWnd(), TRUE, TRUE);
#endif
// Set perspective
m_Graphics.SetPerspective(0.6021124f,1.33333f,1.0f,20000.0f);
// Enable cursor
ShowMouse(TRUE);
// Create a font
m_Font.Create(&m_Graphics, "Arial", 16, TRUE);
// Initialize input and input devices
m_Input.Init(GethWnd(), GethInst());
m_Keyboard.Create(&m_Input, KEYBOARD);
m_Mouse.Create(&m_Input, MOUSE, TRUE);
// Initialize the sound system and channels
m_Sound.Init(GethWnd(), 22050, 1, 16);
m_SoundChannel.Create(&m_Sound, 22050, 1, 16);
m_MusicChannel.Create(&m_Sound);
// Load the master item list
FILE *fp;
for(long i=0;i<1024;i++)
ZeroMemory(&m_MIL[i], sizeof(sItem));
if((fp=fopen("..\\Data\\Game.mil", "rb")) != NULL) {
for(i=0;i<1024;i++)
fread(&m_MIL[i], 1, sizeof(sItem), fp);
fclose(fp);
}
// Initialize the character controller
m_CharController.SetData(this);
m_CharController.Init(&m_Graphics, &m_Font, \
"..\\Data\\Game.mcl", (sItem*)&m_MIL, \
m_SpellController.GetSpell(0), \
sizeof(g_CharMeshNames)/sizeof(char*), g_CharMeshNames, \
"..\\Data\\", "..\\Data\\", \
sizeof(g_CharAnimations) / sizeof(sCharAnimationInfo), \
(sCharAnimationInfo*)&g_CharAnimations, \
&m_SpellController);
// Initialize the spell controller
m_SpellController.SetData(this);
m_SpellController.Init(&m_Graphics, \
"..\\Data\\Game.msl", \
sizeof(g_SpellMeshNames)/sizeof(char*),g_SpellMeshNames, \
"..\\Data\\", &m_CharController);
// Get the options bitmap
m_Options.Load(&m_Graphics, "..\\Data\\Options.bmp");
// Create the main, header, and stats windows
m_Window.Create(&m_Graphics, &m_Font);
m_Header.Create(&m_Graphics, &m_Font);
m_Stats.Create(&m_Graphics, &m_Font);
// Position all windows
m_Window.Move(2,2, 636, 476);
m_Header.Move(2,2,128,32,-1,-1,D3DCOLOR_RGBA(128,16,16,255));
m_Stats.Move(2,2,128,48);
// Set script application pointer
m_Script.SetData(this);
// Push the main menu state, setting menu options first
g_MenuOptions = MENU_LOAD;
m_StateManager.Push(MenuFrame, this);
return TRUE;
}
BOOL cApp::Shutdown()
{
// Pop all states
m_StateManager.PopAll(this);
// Free controllers
m_CharController.Free();
m_SpellController.Free();
// Free script object
m_Script.Free();
// Free level data
FreeLevel();
// Free the options texture
m_Options.Free();
// Free the text windows
m_Window.Free();
m_Header.Free();
m_Stats.Free();
// Shutdown sound
m_MusicChannel.Free();
m_SoundChannel.Free();
m_Sound.Shutdown();
// Shutdown input
m_Keyboard.Free();
m_Mouse.Free();
m_Input.Shutdown();
// Shutdown graphics
m_Font.Free();
m_Graphics.Shutdown();
return TRUE;
}
BOOL cApp::Frame()
{
static DWORD UpdateTimer = timeGetTime();
// Limit all frame updates to 30 fps
if(timeGetTime() < UpdateTimer + 33)
return TRUE;
UpdateTimer = timeGetTime();
// Acquire input devices and read input for all states
m_Keyboard.Acquire(TRUE); // Read keyboard
m_Keyboard.Read();
m_Mouse.Acquire(TRUE); // Read mouse
m_Mouse.Read();
// Process state, returning result
return m_StateManager.Process(this);
}
BOOL cApp::RenderFrame(long Elapsed)
{
long i, j;
// Render simplified mesh for z-values
m_Graphics.EnableZBuffer(TRUE);
m_SceneObject.Render();
// Draw the backdrop (composed of six textures)
m_Graphics.EnableZBuffer(FALSE);
m_Graphics.BeginSprite();
for(i=0;i<2;i++) {
for(j=0;j<3;j++)
m_SceneTextures[i*3+j].Blit(j*256,i*256);
}
m_Graphics.EndSprite();
// Draw the 3-D objects
m_Graphics.EnableZBuffer(TRUE);
m_CharController.Render(Elapsed);
m_SpellController.Render();
return TRUE;
}
float cApp::GetHeightBelow(float XPos, float YPos, float ZPos)
{
BOOL Hit;
float u, v, Dist;
DWORD FaceIndex;
D3DXIntersect(m_SceneMesh.GetParentMesh()->m_Mesh,
&D3DXVECTOR3(XPos,YPos,ZPos),
&D3DXVECTOR3(0.0f, -1.0f, 0.0f),
&Hit, &FaceIndex, &u, &v, &Dist);
if(Hit == TRUE)
return YPos-Dist;
return YPos;
}
BOOL cApp::CheckIntersect( \
float XStart, float YStart, float ZStart, \
float XEnd, float YEnd, float ZEnd, \
float *Length)
{
BOOL Hit;
float u, v, Dist;
float XDiff, YDiff, ZDiff, Size;
DWORD FaceIndex;
D3DXVECTOR3 vecDir;
XDiff = XEnd - XStart;
YDiff = YEnd - YStart;
ZDiff = ZEnd - ZStart;
D3DXVec3Normalize(&vecDir, &D3DXVECTOR3(XDiff, YDiff, ZDiff));
D3DXIntersect(m_SceneMesh.GetParentMesh()->m_Mesh, \
&D3DXVECTOR3(XStart,YStart,ZStart), &vecDir, \
&Hit, &FaceIndex, &u, &v, &Dist);
if(Hit == TRUE) {
Size = (float)sqrt(XDiff*XDiff+YDiff*YDiff+ZDiff*ZDiff);
if(Dist > Size)
Hit = FALSE;
else {
if(Length != NULL)
*Length = Dist;
}
}
return Hit;
}
float cApp::GetNextFloat(FILE *fp)
{
char Buf[1024];
long Pos = 0;
int c;
// Read until EOF or EOL
while(1) {
if((c = fgetc(fp)) == EOF)
break;
if(c == 0x0a || c == ' ')
break;
if((c >= '0' && c <= '9') || c == '.' || c == '-')
Buf[Pos++] = c;
}
Buf[Pos] = 0;
return (float)atof(Buf);
}
BOOL cApp::LoadLevel(long Num)
{
char Filename[MAX_PATH];
FILE *fp;
long i;
float XPos, YPos, ZPos, XAt, YAt, ZAt;
FreeLevel(); // Free a prior level
// Record scene number
m_SceneNum = Num;
// Load the backdrop textures
for(i=0;i<6;i++) {
sprintf(Filename, "..\\Data\\Scene%u%u.bmp", Num, i+1);
if(m_SceneTextures[i].Load(&m_Graphics, Filename) == FALSE)
return FALSE;
}
// Load the scene mesh and configure object
sprintf(Filename, "..\\Data\\Scene%u.x", Num);
if(m_SceneMesh.Load(&m_Graphics, Filename) == FALSE)
return FALSE;
m_SceneObject.Create(&m_Graphics, &m_SceneMesh);
// Load the camera data
sprintf(Filename, "..\\Data\\Cam%u.txt", Num);
if((fp=fopen(Filename, "rb"))==NULL)
return FALSE;
XPos = GetNextFloat(fp);
YPos = GetNextFloat(fp);
ZPos = GetNextFloat(fp);
XAt = GetNextFloat(fp);
YAt = GetNextFloat(fp);
ZAt = GetNextFloat(fp);
fclose(fp);
m_Camera.Point(XPos, YPos, ZPos, XAt, YAt, ZAt);
// Position the camera for the scene
m_Graphics.SetCamera(&m_Camera);
// Set no monsters in last frame
m_MonstersLastFrame = FALSE;
// Execute the script for loading this scene
sprintf(Filename, "..\\Data\\Scene%lu.mls", Num);
m_Script.Execute(Filename);
return TRUE;
}
BOOL cApp::FreeLevel()
{
sCharacter *CharPtr, *NextChar;
long i;
// Free scene mesh and textures
m_SceneMesh.Free();
m_SceneObject.Free();
for(i=0;i<6;i++)
m_SceneTextures[i].Free();
// Free triggers and barriers
m_Barrier.Free();
m_Trigger.Free();
// Free all non-pc characters
if((CharPtr=m_CharController.GetParentCharacter()) != NULL) {
while(CharPtr != NULL) {
// Remember next character
NextChar = CharPtr->Next;
// Remove non-PC character
if(CharPtr->Type != CHAR_PC)
m_CharController.Remove(CharPtr);
// Go to next character
CharPtr = NextChar;
}
}
// Free all spell effects
m_SpellController.Free();
return TRUE;
}
BOOL cApp::PlaySound(long Num)
{
if(Num >=0 && Num < NUM_SOUNDS) {
m_SoundData.Free();
if(m_SoundData.LoadWAV(g_SoundFilenames[Num]) == TRUE)
m_SoundChannel.Play(&m_SoundData);
return TRUE;
}
return FALSE;
}
BOOL cApp::PlayMusic(long Num)
{
// Don't bother changing song if same already playing
if(g_CurrentMusic == Num)
return TRUE;
// Stop and free current song
m_MusicChannel.Stop();
m_MusicChannel.Free();
// Fade music out, giving DirectMusic enough time
// to finish up last song (or else new song doesn't
// play correctly. The 700 is based on play volume
// of music, so adjust ahead.
DWORD Timer = timeGetTime() + 700;
while(timeGetTime() < Timer) {
DWORD Level = (Timer - timeGetTime()) / 10;
m_MusicChannel.SetVolume(Level);
}
// Load and play new song
m_MusicChannel.Load(g_MusicFilenames[Num]);
m_MusicChannel.Play(70,0);
// Remember new song #
g_CurrentMusic = Num;
return TRUE;
}
BOOL cApp::StopMusic()
{
// Stop and free music, marking current song as none
m_MusicChannel.Stop();
m_MusicChannel.Free();
g_CurrentMusic = -1;
return TRUE;
}
BOOL cApp::WinGame()
{
m_StateManager.PopAll(this);
g_MenuOptions = MENU_LOAD;
m_StateManager.Push(MenuFrame, this);
return TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -