📄 winmain.cpp
字号:
/**************************************************
WinMain.cpp
Chapter 16 Character Controller Demo
Programming Role-Playing Games with DirectX
by Jim Adams (01 Jan 2002)
Required libraries:
D3D8.LIB, D3DX8.LIB, and DINPUT8.LIB
**************************************************/
#include "Core_Global.h"
#include "Window.h"
#include "Chars.h"
#include "Script.h"
#include "WinMain.h"
// Global names of character meshes
char *g_CharMeshNames[] = {
{ "..\\Data\\Warrior.x" }, // Mesh # 0
{ "..\\Data\\Yodan.x" } // Mesh # 1
};
sCharAnimationInfo g_CharAnimations[] = {
{ "Idle", TRUE },
{ "Walk", TRUE },
{ "Swing", FALSE },
{ "Spell", FALSE },
{ "Swing", FALSE },
{ "Hurt", FALSE },
{ "Die", FALSE },
{ "Idle", TRUE }
};
char *g_SpellMeshNames[] = {
{ "..\\Data\\Fireball.x" },
{ "..\\Data\\Explosion.x" },
{ "..\\Data\\Groundball.x" },
{ "..\\Data\\ice.x" },
{ "..\\Data\\bomb.x" },
};
///////////////////////////////////////////////////////////
// Overloaded application class functions
//////////////////////////////////////////////////////////
cApp::cApp()
{
m_Width = 640;
m_Height = 480;
m_Style = WS_BORDER|WS_CAPTION|WS_MINIMIZEBOX|WS_SYSMENU;
strcpy(m_Class, "CharClass");
strcpy(m_Caption, "Characters Demo by Jim Adams");
}
BOOL cApp::Init()
{
long i;
FILE *fp;
// Initialize the graphics device and set display mode
m_Graphics.Init();
m_Graphics.SetMode(GethWnd(), TRUE, TRUE);
m_Graphics.SetPerspective(D3DX_PI/4, 1.3333f, 1.0f, 10000.0f);
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);
// Load the terrain mesh and set object
m_TerrainMesh.Load(&m_Graphics, "..\\Data\\World.x", \
"..\\Data\\");
m_TerrainObject.Create(&m_Graphics, &m_TerrainMesh);
// Load the master item list
for(i=0;i<1024;i++)
ZeroMemory(&m_MIL[i], sizeof(sItem));
if((fp=fopen("..\\Data\\Default.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\\Default.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.Init(&m_Graphics, \
"..\\Data\\Default.msl", \
sizeof(g_SpellMeshNames)/sizeof(char*),g_SpellMeshNames, \
"..\\Data\\", &m_CharController);
// Add the character player
m_CharController.Add(0, 0, CHAR_PC, CHAR_STAND, \
0.0f, 0.0f, 0.0f, 3.14f);
// Process the startup script
m_Script.SetData(this, &m_Graphics, &m_Font, &m_Keyboard, \
&m_CharController);
m_Script.Execute("..\\Data\\Startup.mls");
return TRUE;
}
BOOL cApp::Shutdown()
{
// Free controllers
m_CharController.Free();
m_SpellController.Free();
// Free script object
m_Script.Free();
// Free objects and meshes
m_TerrainMesh.Free();
m_TerrainObject.Free();
// 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 UpdateCounter = timeGetTime();
char Stats[128];
static sCharacter *CharPtr=m_CharController.GetCharacter(0);
// Lock to 30 fps
if(timeGetTime() < UpdateCounter + 33)
return TRUE;
UpdateCounter = timeGetTime();
// Read in keyboard
m_Keyboard.Acquire(TRUE);
m_Keyboard.Read();
// Exit if ESC pressed
if(m_Keyboard.GetKeyState(KEY_ESC) == TRUE)
return FALSE;
// Update controllers
m_CharController.Update(33);
m_SpellController.Update(33);
// Set the camera
m_Camera.Point(0.0f, 700.0f, -700.0f, 0.0f, 0.0f, 0.0f);
m_Graphics.SetCamera(&m_Camera);
// Render everything
m_Graphics.Clear();
if(m_Graphics.BeginScene() == TRUE) {
// Render terrain
m_Graphics.EnableZBuffer(TRUE);
m_TerrainObject.Render();
// Render all characters
m_CharController.Render();
// Render spells
m_SpellController.Render();
// Display stats
sprintf(Stats, "HP: %ld / %ld\r\nMP: %ld / %ld", \
CharPtr->HealthPoints, CharPtr->Def.HealthPoints,
CharPtr->ManaPoints, CharPtr->Def.ManaPoints);
m_Font.Print(Stats, 2, 2);
m_Graphics.EndScene();
}
m_Graphics.Display();
return TRUE;
}
long cApp::GetInput()
{
long Action = 0;
if(m_Keyboard.GetKeyState(KEY_UP) == TRUE)
Action |= 1;
if(m_Keyboard.GetKeyState(KEY_RIGHT) == TRUE)
Action |= 2;
if(m_Keyboard.GetKeyState(KEY_DOWN) == TRUE)
Action |= 4;
if(m_Keyboard.GetKeyState(KEY_LEFT) == TRUE)
Action |= 8;
if(m_Keyboard.GetKeyState(KEY_SPACE) == TRUE) {
Action |= 16;
m_Keyboard.SetLock(KEY_SPACE, TRUE);
m_Keyboard.SetKeyState(KEY_SPACE, FALSE);
}
if(m_Keyboard.GetKeyState(KEY_1) == TRUE) {
Action |= 32;
m_Keyboard.SetLock(KEY_1, TRUE);
m_Keyboard.SetKeyState(KEY_1, FALSE);
}
if(m_Keyboard.GetKeyState(KEY_2) == TRUE) {
Action |= 64;
m_Keyboard.SetLock(KEY_2, TRUE);
m_Keyboard.SetKeyState(KEY_2, FALSE);
}
if(m_Keyboard.GetKeyState(KEY_3) == TRUE) {
Action |= 128;
m_Keyboard.SetLock(KEY_3, TRUE);
m_Keyboard.SetKeyState(KEY_3, FALSE);
}
return Action;
}
BOOL cApp::CheckIntersect( \
float XStart, float YStart, float ZStart, \
float XEnd, float YEnd, float ZEnd)
{
sMesh *MeshPtr;
BOOL Hit;
float u, v, Dist;
float XDiff, YDiff, ZDiff, Size;
DWORD FaceIndex;
D3DXVECTOR3 vecDir;
// Start with parent mesh
if((MeshPtr = m_TerrainMesh.GetParentMesh()) == NULL)
return FALSE; // No polygons hit
// Calculate ray
XDiff = XEnd - XStart;
YDiff = YEnd - YStart;
ZDiff = ZEnd - ZStart;
Size = (float)sqrt(XDiff*XDiff+YDiff*YDiff+ZDiff*ZDiff);
D3DXVec3Normalize(&vecDir, &D3DXVECTOR3(XDiff, YDiff, ZDiff));
// Go through each mesh looking for intersection
while(MeshPtr != NULL) {
D3DXIntersect(MeshPtr->m_Mesh, \
&D3DXVECTOR3(XStart,YStart,ZStart), &vecDir, \
&Hit, &FaceIndex, &u, &v, &Dist);
if(Hit == TRUE) {
if(Dist <= Size)
return TRUE; // Hit a polygon
}
MeshPtr = MeshPtr->m_Next;
}
return FALSE; // No polygons hit
}
int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, \
LPSTR szCmdLine, int nCmdShow)
{
cApp App;
return App.Run();
}
///////////////////////////////////////////////////////////
// Overloaded character controller class functions
///////////////////////////////////////////////////////////
BOOL cChars::SetData(cApp *App)
{
if((m_App = App) == FALSE)
return FALSE;
return TRUE;
}
BOOL cChars::PCUpdate(sCharacter *Character, long Elapsed, \
float *XMove, float *YMove, float *ZMove)
{
sCharacter *CharPtr;
float XDiff, YDiff, ZDiff, Dist;
long Action = 0;
float Speed;
long SpellNum;
float SpellRadius;
// If not PC, then let controller handle movement
if(Character->ID != 0)
return TRUE;
Speed = (float)Elapsed / 1000.0f * GetSpeed(Character);
// Get the input flags
if(m_App != NULL)
Action = m_App->GetInput();
// Rotate character
if(Action & 2) {
Character->Direction += ((float)Elapsed / 1000.0f * 4);
Character->Action = CHAR_MOVE;
}
if(Action & 8) {
Character->Direction -= ((float)Elapsed / 1000.0f * 4);
Character->Action = CHAR_MOVE;
}
// Walk forward
if(Action & 1) {
*XMove = (float)sin(Character->Direction) * Speed;
*ZMove = (float)cos(Character->Direction) * Speed;
Character->Action = CHAR_MOVE;
}
// Attack a nearby monster or process NPC script
if(Action & 16) {
CharPtr = GetParentCharacter();
while(CharPtr != NULL) {
// Only check other characters
if(CharPtr->ID != Character->ID) {
XDiff = (float)fabs(CharPtr->XPos - Character->XPos);
YDiff = (float)fabs(CharPtr->YPos - Character->YPos);
ZDiff = (float)fabs(CharPtr->ZPos - Character->ZPos);
Dist = XDiff*XDiff+YDiff*YDiff+ZDiff*ZDiff;
// Only check characters within 100.0 units distance
if(Dist <= 10000.0f) {
// Process script or attack?
if(CharPtr->ScriptFilename[0])
m_App->m_Script.Execute(CharPtr->ScriptFilename);
else {
// Turn toward victim
XDiff = (CharPtr->XPos - Character->XPos);
ZDiff = (CharPtr->ZPos - Character->ZPos);
Character->Direction = (float)atan2(XDiff, ZDiff);
// Set attack data
Character->Victim = CharPtr;
CharPtr->Attacker = Character;
// Set attack action
m_App->m_CharController.SetAction(Character, \
CHAR_ATTACK);
}
break;
}
}
CharPtr = CharPtr->Next;
}
}
// Cast spells
if(Action & 32 || Action & 64 || Action & 128) {
// Get spell number to cast
if(Action & 32)
SpellNum = 0;
if(Action & 64)
SpellNum = 1;
if(Action & 128)
SpellNum = 2;
// Get spell distance
SpellRadius = \
m_App->m_SpellController.GetSpell(SpellNum)->Distance;
// Search for closest monster
CharPtr = GetParentCharacter();
while(CharPtr != NULL) {
// Only check other characters
if(CharPtr->Type == CHAR_MONSTER) {
XDiff = (float)fabs(CharPtr->XPos - Character->XPos);
YDiff = (float)fabs(CharPtr->YPos - Character->YPos);
ZDiff = (float)fabs(CharPtr->ZPos - Character->ZPos);
Dist = XDiff*XDiff+YDiff*YDiff+ZDiff*ZDiff;
// Only check characters within 100.0 units distance
if(Dist <= (SpellRadius * SpellRadius)) {
Character->SpellNum = SpellNum;
Character->SpellTarget = CHAR_MONSTER;
Character->TargetX = CharPtr->XPos;
Character->TargetY = CharPtr->YPos;
Character->TargetZ = CharPtr->ZPos;
// Turn toward victim
XDiff = (CharPtr->XPos - Character->XPos);
ZDiff = (CharPtr->ZPos - Character->ZPos);
Character->Direction = (float)atan2(XDiff, ZDiff);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -