📄 sprite.cpp
字号:
// Sprite.cpp: implementation of the CSprite class.
//
//////////////////////////////////////////////////////////////////////
#include <list>
#include <algorithm>
#include <assert.h>
#include "DSUtil.h"
#include "ddutil.h"
#include "Sprite.h"
using namespace std;
extern CSoundManager* g_pSoundManager;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CSprite::CSprite():m_pfnDead(0),m_pfnKill(0)
{
m_Anim.m_bIsAnimBiDir = true;
::ZeroMemory(&m_CurrState, sizeof(SSTATE));
}
CSprite::~CSprite()
{
Destroy();
}
////////////////////////////////////////////////////////////////////////
// Create the sprite by giving it the Surface containing all the sprite
// images.
// Type is for storing game specific information like, this sprite is an
// enemy or friend or food, etc.
// Set the dimensions of the sprite
/////////////////////////////////////////////////////////////////////////
void CSprite::CreateSprite(CSurface** ppSurface, long nType,long nHeight, long nWidth)
{
m_ppSurface = ppSurface;
m_nType = nType;
m_Anim.m_nHeight = nHeight;
m_Anim.m_nWidth = nWidth;
}
///////////////////////////////////////////////////////////////////////////
// Add a new state for the sprite
// State could be like WALKING_UP or WALKING_DOWN or SHOOTING
// Since sprite will have different animation sequence based on there state
// this function can be used to give all the different things a sprite can do.
// Parameters:
// nState is a user define value used to identify the state
// ptFrame is the x,y for of the first frame in the surface.
// Since the dimentions are fixed we don't need that info here
// nNoOfFrames is the total animations frames this state has
// nDelay is to control the animation speed.
//////////////////////////////////////////////////////////////////////////////
void CSprite::AddState(long nState, POINT ptFrame, long nNoOfFrames, long nDelay, RECT* prcBound, LPTSTR pszSound, bool bLoopSound)
{
SSTATE State;
State.m_nState = nState;
State.m_ptFirstFrame = ptFrame;
State.m_nNoOfFrames = nNoOfFrames;
State.m_nDelay = nDelay;
State.m_bLoopSound = bLoopSound;
State.m_pSound=NULL;
if (prcBound == NULL) {
State.m_rcBounding.top = State.m_rcBounding.left=0;
State.m_rcBounding.bottom=m_Anim.m_nHeight ;
State.m_rcBounding.right= m_Anim.m_nWidth ;
} else {
State.m_rcBounding =*prcBound;
}
if (pszSound) {
// Load the wave file into a DirectSound buffer
g_pSoundManager->Create( &State.m_pSound, pszSound, 0, GUID_NULL );
}
m_StateList.push_back(State);
}
/////////////////////////////////////////////////////////////////////////
// Check if the give rectangle intersects with any part of the sprite
// This is used for collusion detection.
////////////////////////////////////////////////////////////////////////
bool CSprite::IsHit(RECT rcRect)
{
if (m_CurrState.m_nState == ST_DEAD || m_CurrState.m_nState == ST_KILL)
return false;
RECT rcIntersect;
RECT rcSprite= GetBoundingRect(m_ptLocation);
return (::IntersectRect(&rcIntersect, &rcSprite, &rcRect) != 0);
}
////////////////////////////////////////////////////////////////////////
// Move sprite to new location
////////////////////////////////////////////////////////////////////////
void CSprite::MoveTo(POINT ptNewLoc)
{
m_ptLocation = ptNewLoc;
}
////////////////////////////////////////////////////////////////////
// helper function of STL find
///////////////////////////////////////////////////////////////////
bool CSprite::SSTATE::operator==( const long& nState)
{
return m_nState == nState;
}
//////////////////////////////////////////////////////////////////
// Set the state of the sprite
//////////////////////////////////////////////////////////////////
void CSprite::SetState(long nState, bool bForceState)
{
if (m_CurrState.m_nState == nState)
return;
if (m_CurrState.m_nState == ST_KILL && bForceState == false)
return;
if (m_CurrState.m_pSound) {
m_CurrState.m_pSound->Stop();
}
if(nState == ST_KILL && m_pfnKill) {
if (((*m_pfnKill)(this)) == false)
return;
}
list<SSTATE>::iterator iState = find(m_StateList.begin(), m_StateList.end(), nState);
assert(*iState == nState);
m_CurrState = *iState;
m_Anim.m_nCurrFrame = 0;
m_Anim.m_nCurrDelay = m_CurrState.m_nDelay;
m_Anim.m_bIsAnimForward = true;
if (m_CurrState.m_pSound) {
DWORD dwFlags = m_CurrState.m_bLoopSound ? DSBPLAY_LOOPING : 0L;
m_CurrState.m_pSound->Play( 0, dwFlags ) ;
}
}
void CSprite::Update()
{
if (m_CurrState.m_nState == ST_DEAD)
return;
// If m_Movement.m_nPathFindDelay = 0 then path is only updated
// when a collision occurs.
if (m_Movement.m_pfnFindPath && m_Movement.m_nPathFindDelay != 0) {
if (m_Movement.m_nCurrPathFindDelay) {
--m_Movement.m_nCurrPathFindDelay;
} else {
m_Movement.m_nCurrPathFindDelay = m_Movement.m_nPathFindDelay;
(*m_Movement.m_pfnFindPath)(this);
}
}
if (m_CurrState.m_nState == ST_KILL) {
m_Movement.m_dx =0;
m_Movement.m_dy =0;
}
if (m_Movement.m_pfnCollision) {
if (m_Movement.m_nCurrMoveDelay)
--m_Movement.m_nCurrMoveDelay;
else {
m_Movement.m_nCurrMoveDelay = m_Movement.m_nMoveDelay;
POINT pt = m_ptLocation;
pt.x += m_Movement.m_dx;
pt.y += m_Movement.m_dy;
// Check for collision at the new location
// If is has collided call path find function
// for new direction.
if ((*m_Movement.m_pfnCollision)(GetBoundingRect(pt))) {
if (m_Movement.m_pfnFindPath) {
(*m_Movement.m_pfnFindPath)(this);
}
} else {
m_ptLocation = pt;
}
}
}
if (m_Anim.m_nCurrDelay) {
--m_Anim.m_nCurrDelay;
return;
}
m_Anim.m_nCurrDelay = m_CurrState.m_nDelay;
if (m_CurrState.m_nNoOfFrames == 1) {
if (m_CurrState.m_nState == ST_KILL) {
m_CurrState.m_nState = ST_DEAD;
if (m_pfnDead)
(*m_pfnDead)(this);
}
return;
}
if (m_Anim.m_bIsAnimBiDir) {
if (m_Anim.m_bIsAnimForward) {
if ( m_Anim.m_nCurrFrame == m_CurrState.m_nNoOfFrames - 1) {
m_Anim.m_bIsAnimForward = false;
if (m_CurrState.m_nState == ST_KILL) {
m_CurrState.m_nState = ST_DEAD;
if (m_pfnDead) {
(*m_pfnDead)(this);
return;
}
}
--m_Anim.m_nCurrFrame;
}
else
++m_Anim.m_nCurrFrame; // Move to the last frame
} else {
if ( m_Anim.m_nCurrFrame == 0) {
m_Anim.m_bIsAnimForward = true;
++m_Anim.m_nCurrFrame;
}
else
--m_Anim.m_nCurrFrame;
}
} else {
if ( ++m_Anim.m_nCurrFrame == m_CurrState.m_nNoOfFrames) {
m_Anim.m_nCurrFrame = 0;
if (m_CurrState.m_nState == ST_KILL) {
m_CurrState.m_nState = ST_DEAD;
if (m_pfnDead)
(*m_pfnDead)(this);
}
}
}
}
void CSprite::Draw(LPDIRECTDRAWSURFACE7 pdds)
{
if (m_CurrState.m_nState == ST_DEAD)
return;
RECT rcFrame = { m_CurrState.m_ptFirstFrame.x + (m_Anim.m_nCurrFrame * m_Anim.m_nWidth),
m_CurrState.m_ptFirstFrame.y,
m_CurrState.m_ptFirstFrame.x + (m_Anim.m_nCurrFrame * m_Anim.m_nWidth) + m_Anim.m_nWidth,
m_CurrState.m_ptFirstFrame.y + m_Anim.m_nHeight };
if (m_Movement.m_nInvulnerable)
m_Movement.m_nInvulnerable--;
if ((m_Movement.m_nInvulnerable % 2)==0) {
pdds->BltFast(m_ptLocation.x, m_ptLocation.y, (*m_ppSurface)->GetDDrawSurface(), &rcFrame, DDBLTFAST_SRCCOLORKEY);
}
if (m_bDrawBorder) {
CSurface Surface;
rcFrame.left = m_ptLocation.x; rcFrame.top = m_ptLocation.y ;
rcFrame.right= m_ptLocation.x + m_Anim.m_nWidth; rcFrame.bottom =m_ptLocation.y + m_Anim.m_nHeight;
Surface.Create(pdds);
Surface.DrawRect(rcFrame, RGB(0,255,0));
Surface.DrawRect(GetBoundingRect(m_ptLocation), RGB(0,255,0));
}
}
RECT CSprite::GetRect()
{
RECT rcRect = { m_ptLocation.x, m_ptLocation.y, m_ptLocation.x + m_Anim.m_nWidth, m_ptLocation.y + m_Anim.m_nHeight };
return rcRect;
}
void CSprite::MoveTo(long nX, long nY)
{
m_ptLocation.x = nX;
m_ptLocation.y = nY;
}
long& CSprite::GetState()
{
return m_CurrState.m_nState;
}
void CSprite::EnableBorder(bool bDraw)
{
m_bDrawBorder = bDraw;
}
void CSprite::SetAnimBiDir(bool bIsAnimBiDir)
{
m_Anim.m_bIsAnimBiDir = bIsAnimBiDir;
}
RECT CSprite::GetBoundingRect(POINT &ptLoc)
{
RECT rcBound;
rcBound.left = ptLoc.x + m_CurrState.m_rcBounding.left;
rcBound.top = ptLoc.y + m_CurrState.m_rcBounding.top;
rcBound.right = rcBound.left + m_CurrState.m_rcBounding.right;
rcBound.bottom= rcBound.top + m_CurrState.m_rcBounding.bottom ;
return rcBound;
}
const long& CSprite::GetType()
{
return m_nType;
}
void CSprite::Destroy()
{
list<SSTATE>::iterator iState;
for ( iState = m_StateList.begin(); iState != m_StateList.end(); iState++) {
if (iState->m_pSound) {
delete iState->m_pSound;
iState->m_pSound = NULL;
}
}
m_StateList.erase(m_StateList.begin(),m_StateList.end());
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -