⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 spell.cpp

📁 [游戏开发参考书-用DirectX编写RPG游戏]这是一个系列的丛书如果你都看并且懂的话你就可以你工作啦!
💻 CPP
字号:
#include "Core_Global.h"
#include "Frustum.h"

#include "MCL.h"
#include "MSL.h"

#include "Chars.h"
#include "Spell.h"

cSpellController::cSpellController()
{
  m_Graphics       = NULL;  // Clear cGraphics pointer
  m_Frustum        = NULL;  // Clear frustum pointer

  m_Chars          = NULL;  // Clear character controller
  
  m_SpellParent    = NULL;

  m_NumMeshes      = 0;     // Clear mesh data
  m_Meshes         = NULL;
  m_TexturePath[0] = 0;
}

cSpellController::~cSpellController()
{
  Shutdown();
}

BOOL cSpellController::Init(cGraphics *Graphics,              \
          char *DefinitionFile,                               \
          long NumSpellMeshes, char **MeshNames,              \
          char *TexturePath,                                  \
          cCharacterController *Controller)
{
  FILE *fp;
  long i;

  Free();  // Free prior init

  // Get parent graphics object
  if((m_Graphics = Graphics) == NULL || MeshNames == NULL ||  \
     DefinitionFile == NULL)
    return FALSE;

  // Load the spells
  if((fp=fopen(DefinitionFile, "rb"))==NULL)
    return FALSE;
  for(i=0;i<NUM_SPELL_DEFINITIONS;i++)
    fread(&m_Spells[i], 1, sizeof(sSpell), fp);
  fclose(fp);

  m_Chars = Controller;  // Store controller pointer

  // Copy over texture name
  if(TexturePath != NULL)
    strcpy(m_TexturePath, TexturePath);

  // Get mesh names
  if((m_NumMeshes = NumSpellMeshes)) {
    m_Meshes = new sSpellMeshList[NumSpellMeshes]();
    for(i=0;i<m_NumMeshes;i++)
      strcpy(m_Meshes[i].Filename, MeshNames[i]);
  }

  return TRUE;
}

BOOL cSpellController::Shutdown()
{
  Free();  // Free class data

  m_Graphics = NULL;

  // Release mesh list  
  delete [] m_Meshes;
  m_Meshes = NULL;
  m_NumMeshes = 0;

  return TRUE;
}

BOOL cSpellController::Free()
{
  long i;

  // Release spell list
  delete m_SpellParent;
  m_SpellParent = NULL;

  // Release spell meshes
  if(m_NumMeshes && m_Meshes != NULL) {
    for(i=0;i<m_NumMeshes;i++) {
      m_Meshes[i].Animation.Free();
      m_Meshes[i].Mesh.Free();
      m_Meshes[i].Count = 0;
    }
  }

  return TRUE;
}

sSpell *cSpellController::GetSpell(long SpellNum)
{
  return &m_Spells[SpellNum];
}

BOOL cSpellController::Add(long SpellNum,                     \
             sCharacter *Caster, long TargetType,             \
             float SourceX, float SourceY, float SourceZ,     \
             float TargetX, float TargetY, float TargetZ)
{
  sSpellTracker *SpellPtr;

  // Error checking
  if(m_Graphics == NULL || m_Meshes == NULL)
    return FALSE;

  // Make sure character is allowed to cast spell
  if(Caster != NULL) {
    if(!(Caster->Def.MagicSpells[SpellNum/32] &               \
                                      (1 << (SpellNum & 31))))
      return FALSE;

    // Make sure caster has enough MP to cast and reduce MP
    if(Caster != NULL) {
      // Return if not enough mana
      if(Caster->ManaPoints < m_Spells[SpellNum].Cost)
        return FALSE;
    }
  }

  // Allocate a new structure and link in to head of list
  SpellPtr = new sSpellTracker();
  if(m_SpellParent != NULL)
    m_SpellParent->Prev = SpellPtr;
  SpellPtr->Next = m_SpellParent;
  m_SpellParent = SpellPtr;

  // Set structure data
  SpellPtr->SpellNum = SpellNum;
  SpellPtr->Caster   = Caster;
  SpellPtr->Type     = TargetType;
  SpellPtr->SourceX  = SourceX;
  SpellPtr->SourceY  = SourceY;
  SpellPtr->SourceZ  = SourceZ;
  SpellPtr->TargetX  = TargetX;
  SpellPtr->TargetY  = TargetY;
  SpellPtr->TargetZ  = TargetZ;

  // Setup the mesh and movement data
  SetAnimData(SpellPtr, 0);

  return TRUE;
}

BOOL cSpellController::Update(long Elapsed)
{
  sSpellTracker *SpellPtr, *NextSpell;
  long SpellNum, Anim;
  BOOL GotoNextAnim;
  float Speed;

  if((SpellPtr = m_SpellParent) == NULL)
    return FALSE;

  // Scan through all spells in use
  while(SpellPtr != NULL) {

    // Remember next spell in list
    NextSpell = SpellPtr->Next;

    // Get local data
    SpellNum = SpellPtr->SpellNum;
    Anim     = SpellPtr->CurrentAnimation;

    // Update/move/countdown spell object
    GotoNextAnim = FALSE;
    switch(m_Spells[SpellNum].MeshPos[Anim]) {
      case POSITION_NONE:
        // Go to next animation
        GotoNextAnim = TRUE;
        break;

      case POSITION_CASTER:
      case POSITION_TARGET:
      case POSITION_SCALE:
        SpellPtr->Time -= Elapsed;
        if(SpellPtr->Time <= 0)
          GotoNextAnim = TRUE;
        break;

      case POSITION_TOTARGET:
      case POSITION_TOCASTER:
        Speed = (float)Elapsed / 1000.0f * SpellPtr->Speed;

        // Decrease distance amount
        SpellPtr->Distance -= Speed;
        if(SpellPtr->Distance <= 0.0f)
          GotoNextAnim = TRUE;
        else {
          SpellPtr->XPos += (SpellPtr->XAdd * Speed);
          SpellPtr->YPos += (SpellPtr->YAdd * Speed);
          SpellPtr->ZPos += (SpellPtr->ZAdd * Speed);
        }
        break;
    }

    // Update to next animation
    if(GotoNextAnim == TRUE)
      SetAnimData(SpellPtr, Anim+1);
   
    // Go to next spell
    SpellPtr = NextSpell;
  }

  return TRUE;
}

BOOL cSpellController::SetAnimData(sSpellTracker *SpellPtr,   \
                                  long Num)
{
  float XDiff, YDiff, ZDiff, Dist, Length;
  float XAngle = 0.0f, YAngle = 0.0f;
  float Scale = 1.0f;
  long  i;
  long  SpellNum, MeshNum;
  float SourceX, SourceY, SourceZ;
  float TargetX, TargetY, TargetZ;

  // Process spell effect if no more animations left
  // while storing the current animation number.
  if((SpellPtr->CurrentAnimation = Num) >= 3) {
    if(m_Chars != NULL)
      m_Chars->Spell(SpellPtr->Caster, SpellPtr, m_Spells);

    // Remove any mesh references
    for(i=0;i<3;i++) {
      if(m_Spells[SpellPtr->SpellNum].MeshPos[i] !=           \
                                             POSITION_NONE) {
        MeshNum = m_Spells[SpellPtr->SpellNum].MeshNum[i];

        // Decrease count and remove if needed
        m_Meshes[MeshNum].Count--;
        if(!m_Meshes[MeshNum].Count) {
          m_Meshes[MeshNum].Mesh.Free();
          m_Meshes[MeshNum].Animation.Free();
        }
      }
    }

    // Remove spell from list
    if(SpellPtr->Prev != NULL)
      SpellPtr->Prev->Next = SpellPtr->Next;
    else
      m_SpellParent = SpellPtr->Next;
    if(SpellPtr->Next != NULL)
      SpellPtr->Next->Prev = SpellPtr->Prev;
    SpellPtr->Prev = SpellPtr->Next = NULL;
    delete SpellPtr;

    return TRUE;
  }

  // Setup local data
  SourceX  = SpellPtr->SourceX;
  SourceY  = SpellPtr->SourceY;
  SourceZ  = SpellPtr->SourceZ;
  TargetX  = SpellPtr->TargetX;
  TargetY  = SpellPtr->TargetY;
  TargetZ  = SpellPtr->TargetZ;
  SpellNum = SpellPtr->SpellNum;

  // Go to next animation if no mesh to use
  if(m_Spells[SpellNum].MeshPos[Num] == POSITION_NONE)
    return SetAnimData(SpellPtr,Num+1);

  // Get mesh # to use
  MeshNum = m_Spells[SpellNum].MeshNum[Num];

  // Load mesh and animation if needed
  if(!m_Meshes[MeshNum].Count) {
    m_Meshes[MeshNum].Mesh.Load(m_Graphics,                   \
                   m_Meshes[MeshNum].Filename,                \
                   m_TexturePath);
    m_Meshes[MeshNum].Animation.Load(                         \
                   m_Meshes[MeshNum].Filename,                \
                   &m_Meshes[MeshNum].Mesh);

    // Set animation loop
    m_Meshes[MeshNum].Animation.SetLoop(                      \
             m_Spells[SpellNum].MeshLoop[Num], "Anim");
  }

  // Configure graphics object
  SpellPtr->Object.Create(m_Graphics,&m_Meshes[MeshNum].Mesh);
  m_Meshes[MeshNum].Count++;

  // Setup mesh movements
  switch(m_Spells[SpellNum].MeshPos[Num]) {
    case POSITION_CASTER:
      SpellPtr->XPos = SourceX;
      SpellPtr->YPos = SourceY;
      SpellPtr->ZPos = SourceZ;
      SpellPtr->Time = (long)m_Spells[SpellNum].MeshSpeed[Num];

      if(SpellPtr->Caster != NULL)
        YAngle = SpellPtr->Caster->Direction;
      break;

    case POSITION_TOTARGET:
      // Store position and speed info
      SpellPtr->XPos  = SourceX;
      SpellPtr->YPos  = SourceY;
      SpellPtr->ZPos  = SourceZ;
      SpellPtr->Speed = m_Spells[SpellNum].MeshSpeed[Num];

      // Calculate movement
      XDiff = (float)fabs(TargetX - SourceX);
      YDiff = (float)fabs(TargetY - SourceY);
      ZDiff = (float)fabs(TargetZ - SourceZ);
      Dist  = (float)sqrt(XDiff*XDiff+YDiff*YDiff+ZDiff*ZDiff);

      if((SpellPtr->Distance = Dist) != 0.0f) {
        SpellPtr->XAdd = (TargetX - SourceX) / Dist;
        SpellPtr->YAdd = (TargetY - SourceY) / Dist;
        SpellPtr->ZAdd = (TargetZ - SourceZ) / Dist;

        // Calculate angles
        XAngle = -(float)atan(SpellPtr->YAdd);
        YAngle =  (float)atan2(SpellPtr->XAdd, SpellPtr->ZAdd);
      }
      break;

    case POSITION_TARGET:
      SpellPtr->XPos = TargetX;
      SpellPtr->YPos = TargetY;
      SpellPtr->ZPos = TargetZ;
      SpellPtr->Time = (long)m_Spells[SpellNum].MeshSpeed[Num];

      // Calculate distance from source to target
      XDiff = (float)fabs(TargetX - SourceX);
      ZDiff = (float)fabs(TargetZ - SourceZ);
      Dist  = (float)sqrt(XDiff*XDiff+ZDiff*ZDiff);

      SpellPtr->XAdd = (TargetX - SourceX) / Dist;
      SpellPtr->ZAdd = (TargetZ - SourceZ) / Dist;

      // Calculate angle
      YAngle =  (float)atan2(SpellPtr->XAdd, SpellPtr->ZAdd);
      break;

    case POSITION_TOCASTER:
      // Store position and speed info
      SpellPtr->XPos  = TargetX;
      SpellPtr->YPos  = TargetY;
      SpellPtr->ZPos  = TargetZ;
      SpellPtr->Speed = m_Spells[SpellNum].MeshSpeed[Num];

      // Calculate movement
      XDiff = (float)fabs(SourceX - TargetX);
      YDiff = (float)fabs(SourceY - TargetY);
      ZDiff = (float)fabs(SourceZ - TargetZ);
      Dist  = (float)sqrt(XDiff*XDiff+YDiff*YDiff+ZDiff*ZDiff);

      if((SpellPtr->Distance = Dist) != 0.0f) {
        SpellPtr->XAdd = (SourceX - TargetX) / Dist;
        SpellPtr->YAdd = (SourceY - TargetY) / Dist;
        SpellPtr->ZAdd = (SourceZ - TargetZ) / Dist;

        // Calculate angles
        XAngle = -(float)atan(SpellPtr->YAdd);
        YAngle =  (float)atan2(SpellPtr->XAdd, SpellPtr->ZAdd);
      }
      break;

    case POSITION_SCALE:
      // Store position and speed info
      SpellPtr->XPos  = SourceX;
      SpellPtr->YPos  = SourceY;
      SpellPtr->ZPos  = SourceZ;
      SpellPtr->Time = (long)m_Spells[SpellNum].MeshSpeed[Num];

      // Get distance from source to target and size of mesh
      XDiff = (float)fabs(TargetX - SourceX);
      YDiff = (float)fabs(TargetY - SourceY);
      ZDiff = (float)fabs(TargetZ - SourceZ);
      Dist  = (float)sqrt(XDiff*XDiff+YDiff*YDiff+ZDiff*ZDiff);
      SpellPtr->Object.GetBounds(NULL,NULL,NULL,              \
                                 NULL,NULL,&Length,NULL);

      // Calculate scale
      Scale = Dist / Length;
      
      // Calculate angles
      SpellPtr->XAdd = (TargetX - SourceX) / Dist;
      SpellPtr->YAdd = (TargetY - SourceY) / Dist;
      SpellPtr->ZAdd = (TargetZ - SourceZ) / Dist;
      XAngle = -(float)atan(SpellPtr->YAdd);
      YAngle =  (float)atan2(SpellPtr->XAdd, SpellPtr->ZAdd);

      break;
  }

  // Rotate object to points towards target
  SpellPtr->Object.Rotate(XAngle, YAngle, 0.0f);

  // Scale object
  SpellPtr->Object.Scale(1.0f, 1.0f, Scale);

  // Set the animation
  SpellPtr->Object.SetAnimation(                              \
      &m_Meshes[MeshNum].Animation, "Anim", timeGetTime()/30);

  // Play the sound
  if(m_Spells[SpellNum].MeshSound[Num] != -1)
    SpellSound(m_Spells[SpellNum].MeshSound[Num]);

  return TRUE;
}

BOOL cSpellController::Render(cFrustum *Frustum,              \
                              float ZDistance)
{
  cFrustum    ViewFrustum;  // Local viewing frustum
  float       Radius;       // Bounding radius
  sSpellTracker *SpellPtr;
  DWORD       Time;

  // Error checking
  if(m_Graphics == NULL)
    return FALSE;

  // Return success if no character to draw
  if((SpellPtr = m_SpellParent) == NULL)
    return TRUE;

  // Construct the viewing frustum (if none passed)
  if((m_Frustum = Frustum) == NULL) {
    ViewFrustum.Construct(m_Graphics, ZDistance);
    m_Frustum = &ViewFrustum;
  }

  // Get time to update animations (30fps)
  Time = timeGetTime() / 30;

  // Loop through each spell and draw
  while(SpellPtr != NULL) {
    // Draw spell if in viewing frustum
    SpellPtr->Object.GetBounds(NULL,NULL,NULL,NULL,           \
                              NULL,NULL,&Radius);

    if(m_Frustum->CheckSphere(SpellPtr->XPos,                 \
                              SpellPtr->YPos,                 \
                              SpellPtr->ZPos,                 \
                              Radius) == TRUE) {

      // Position object
      SpellPtr->Object.Move(SpellPtr->XPos,                   \
                            SpellPtr->YPos,                   \
                            SpellPtr->ZPos);

      SpellPtr->Object.UpdateAnimation(Time, TRUE);
      SpellPtr->Object.Render();
    }

    // Go to next spell
    SpellPtr = SpellPtr->Next;
  }

  return TRUE;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -