📄 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结构,记录对应状态的数据信息
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; //CSound 对象
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) //碰撞检测:检测精灵是否碰上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);//有交集返回true
}
////////////////////////////////////////////////////////////////////////
// Move sprite to new location
////////////////////////////////////////////////////////////////////////
void CSprite::MoveTo(POINT ptNewLoc)//移动精灵到点坐标
{
m_ptLocation = ptNewLoc; //m_ptLocation 精灵左上角坐标
}
////////////////////////////////////////////////////////////////////
// helper function of STL find
///////////////////////////////////////////////////////////////////
bool CSprite::SSTATE::operator==( const long& nState) //SSTATE结构操作符“==”的定义
{
return m_nState == nState; //如果相等返回true,否则false
}
//////////////////////////////////////////////////////////////////
// Set the state of the sprite
//////////////////////////////////////////////////////////////////
void CSprite::SetState(long nState, bool bForceState) //设置精灵状态为nState,比如原来是静止的变成向左走
{
if (m_CurrState.m_nState == nState)//已经是该State
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) //如果是门,过关,返回true为其它物品
return;
}
//查找 nState
list<SSTATE>::iterator iState = find(m_StateList.begin(), m_StateList.end(), nState);//使用到操作符等于的定义
//迭代器 (iterators)。它是指针的概括
assert(*iState == nState); // iState->m_nState==nState
m_CurrState = *iState; // m_CurrState 被设置为 状态为nState的结构
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.
//--- 计算路径
// 注:m_Movement.m_pfnFindPath 是一个函数指针,如果精灵需要计算路径,必须使它指向一个具体可用的路径计算函数
// 如果 m_Movement.m_pfnFindPath==NULL 不需要计算路径
// m_nPathFindDelay,是两次计算路径之间的延时,计算完一次路径之后将沿着该路径走一段时间,直到改变路径
if (m_Movement.m_pfnFindPath && m_Movement.m_nPathFindDelay != 0) {
if (m_Movement.m_nCurrPathFindDelay) {
--m_Movement.m_nCurrPathFindDelay;
} else { // m_Movement.m_nCurrPathFindDelay==0 时间到,执行计算路径,并重新设定延时
m_Movement.m_nCurrPathFindDelay = m_Movement.m_nPathFindDelay;
(*m_Movement.m_pfnFindPath)(this); //计算路径函数
}
}
if (m_CurrState.m_nState == ST_KILL) { //如果被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; //延时基数减少1
else { //m_Movement.m_nCurrMoveDelay==0
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); //this 指代当前Sprite
}
} else { //如果没碰撞上迷宫壁
m_ptLocation = pt;
}
}
}
// 帧延时:
if (m_Anim.m_nCurrDelay) { // 延时时间不够 返回
--m_Anim.m_nCurrDelay;
return;
}
// if (m_Anim.m_nCurrDelay==0) :延时时间到
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; //置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 };
// 不死延时计数减1
if (m_Movement.m_nInvulnerable)
m_Movement.m_nInvulnerable--;
if ((m_Movement.m_nInvulnerable % 2)==0) {//不死闪烁,同时等于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 ;
//rcBound.right = ptLoc.x + m_CurrState.m_rcBounding.right;
//rcBound.bottom= ptLoc.y + 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 + -