📄 game.cpp
字号:
/*********************************************
程序设计:罗穆峰 2008-11-20
http://lmf.biaotian.com
E-mail: lmf@biaotian.com
QQ: 16324942 [模范英雄]
*********************************************/
#include "Game.h"
#include "SoundMan.h"
#include "地图数据.h"
#include "Brick.h"
#include "Ground.h"
#include "Stone.h"
#include "PipeBody.h"
#include "PipeTop.h"
#include "Question.h"
#include "FungusDemon.h"
#include "TortoiseDemon.h"
#include "FlyTortoiseDemon.h"
#include "ClipDemon.h"
#include "BeetleDemon.h"
#include "Coin.h"
#include <queue>
int g_FlushAction=0;//问号和金币当前的闪烁状态。所有问号的金币的闪烁状态是一致的。取值为0~2。
static int s_FlushTimeCount=0;//并非每个时钟周期闪烁一次,而是要等到该变量记录到一定值后再改变一次闪烁状态。
static int s_FlushDir;//当前的闪烁方向。1:由亮变暗 2:由暗变亮
CGame::CGame()
{
m_Mario=NULL;
}
const std::set<CObject*> * CGame::GetAllObject()
{
/*
返回所有角色和物体的列表。返回NULL表示游戏尚未开始。
*/
if(!m_Mario)return NULL;//游戏尚未开始
return &m_Object;
}
void CGame::Start()
{
/*
开始游戏。
*/
if(m_Mario)return;//游戏已经开始,则不再响应该事件
//清除所有角色和物体
std::set<CObject*>::iterator it;
for(it=m_Object.begin();it!=m_Object.end();++it)
{
delete *it;
}
m_Object.clear();
//创建主角玛莉
m_Mario=new CMario(this,0,0,1);
m_Object.insert(m_Mario);
//从第0关开始
m_CurLevel=0;
m_MapData=MapData+1;
LoadMapData();
}
void CGame::InsertObject(int X,int Y,int Type)
{
/*
插入一个新角色或物体。
参数:
[i]X,Y 要插入到哪个位置。
[i]Type 要插入的物体类型。取值为:
1 砖块。
2 石头。
3 水管体。
4 水管顶。
5 问号(内藏一枚金币)。
6 问号(内藏蘑菇)。
7 问号(内藏十枚金币)。
8 砖块(内藏蘑菇)。
9 砖块(内藏五星)。
10 砖块(内藏十枚金币)。
11 蘑菇妖怪。
12 乌龟妖怪。
13 飞乌龟妖怪。
14 夹子妖怪。
15 地板。
16 金币。
17 甲虫妖怪。
*/
switch(Type)
{
case 1:
m_Object.insert(new CBrick(this,X,Y,0));
break;
case 2:
m_Object.insert(new CStone(this,X,Y));
break;
case 3:
m_Object.insert(new CPipeBody(this,X,Y));
break;
case 4:
m_Object.insert(new CPipeTop(this,X,Y));
break;
case 5:
m_Object.insert(new CQuestion(this,X,Y,3));
break;
case 6:
m_Object.insert(new CQuestion(this,X,Y,1));
break;
case 7:
m_Object.insert(new CQuestion(this,X,Y,2));
break;
case 8:
m_Object.insert(new CBrick(this,X,Y,1));
break;
case 9:
m_Object.insert(new CBrick(this,X,Y,3));
break;
case 10:
m_Object.insert(new CBrick(this,X,Y,2));
break;
case 11:
m_Object.insert(new CFungusDemon(this,X,Y));
break;
case 12:
m_Object.insert(new CTortoiseDemon(this,X,Y));
break;
case 13:
m_Object.insert(new CFlyTortoiseDemon(this,X,Y));
break;
case 14:
m_Object.insert(new CClipDemon(this,X,Y));
break;
case 15:
m_Object.insert(new CGround(this,X,Y));
break;
case 16:
m_Object.insert(new CCoin(this,X,Y));
break;
case 17:
m_Object.insert(new CBeetleDemon(this,X,Y));
break;
}
}
void CGame::Clock(void)
{
/*
执行一次时序信号动作。
*/
//改变问号和金币当前的闪烁状态
s_FlushTimeCount++;
switch(g_FlushAction)
{
case 0:
if(s_FlushTimeCount>=10)
{//最亮的状态显示10个时钟周期
g_FlushAction=1;
s_FlushDir=1;
s_FlushTimeCount=0;
}
break;
case 1:
if(s_FlushTimeCount>=2)
{//稍暗的状态显示2个时钟周期
g_FlushAction+=s_FlushDir;
s_FlushTimeCount=0;
}
break;
default://case 2:
if(s_FlushTimeCount>=3)
{//最暗的状态显示3个时钟周期
g_FlushAction=1;
s_FlushDir=-1;
s_FlushTimeCount=0;
}
}
std::set<CObject*>::iterator it,it2;
//使所有的角色和物体动作一次
for(it=m_Object.begin();it!=m_Object.end();)
{
if(3==(*it)->LiveState||(*it)->XPos>288+32||(*it)->XPos+(*it)->Width<-32||(*it)->YPos>256)
{//对象已死亡,则删除
//左边线超出右边界32像素以上,左边线超出左边界32像素以上,上边线超出下边界,则认为对象超出地图范围之外,要删除该对象
if(*it==m_Mario)
{//删除的是玛莉
if(1==m_Mario->LiveState)
{//删除的是活玛莉,则要停止背景音乐,播放玛莉死亡时的音乐
m_SoundMan->PlayBackMusic(0);
m_SoundMan->PlaySound(CSoundMan::DEATH);
}
m_Mario=NULL;
}
it2=it;
++it;
delete *it2;
m_Object.erase(it2);
}
else
{
(*it)->Clock();
++it;
}
}
if(!m_Mario)return;//玛莉已被删除
int Offset=m_Mario->XPos-((288-m_Mario->Width)>>1);
if(Offset>0)
{//玛莉超过了地图中线,则要将地图移动,使玛莉到达地图中央
MoveMap(Offset);
}
if(m_Mario->XPos==288-m_Mario->Width)
{//玛莉到达了地图右边线,则进入下一关
//清除除玛莉外的所有角色和物体
for(it=m_Object.begin();it!=m_Object.end();)
{
it2=it;
it++;
if(*it2==m_Mario)continue;//玛莉不能删除
delete *it2;
m_Object.erase(it2);
}
m_CurLevel++;
if(MapData[0]==m_CurLevel)
{//已经玩过了最后一关,则游戏结束
m_SoundMan->PlayBackMusic(0);
//删除玛莉
m_Object.clear();
delete m_Mario;
m_Mario=NULL;
}
else
{
m_MapData+=3+m_MapData[2]*16;
LoadMapData();
}
}
}
void CGame::Move(int Dir, bool Acc)
{
/*
使主角开始或停止移动。
参数:
[i]Dir 移动方向。取值为:
1 向上
2 向下
3 向左
4 向右
0 停止
[i]Acc 是否加速移动。
*/
if(!m_Mario)return;//游戏尚未开始
m_Mario->Move(Dir,Acc);
}
void CGame::Jump(void)
{
/*
使主角跳跃一次。
*/
if(!m_Mario)return;//游戏尚未开始
m_Mario->Jump();
}
void CGame::Fire(void)
{
/*
使主角发射一次子弹。
*/
if(!m_Mario)return;//游戏尚未开始
m_Mario->Fire();
}
struct BLOCKINFO
{//移动路径内的阻挡物信息
CObject * Blocker;//阻挡本对象运动的物体
int x,y;//受该物体阻挡后能运动到的位置
int BlockMode;//阻挡方式,取值与本函数的返回值一致。当MayBe为true时,忽略该成员
int BumpMode;//与该物体的碰撞方式,取值取CObject::Bump函数的中Mode参数一致。当MayBe为true时,忽略该成员
bool MayBe;//如果阻挡物刚好在运动区域的边界上,则可能阻挡,也可能不阻挡
};
struct BLOCKINFOCompare
{//BLOCKINFO的比较器,若b距离被阻挡物较近,则返回true。
//以X坐标较近为准,若X值相同则以Y较近为准,若Y值也相同,则以一定阻挡的物体为准
//不可能出现X较近而Y值较远的情况
bool operator() (const BLOCKINFO & a,const BLOCKINFO & b)
{
if(XLarge)
{
if(b.x>a.x)return true;
if(b.x<a.x)return false;
}
else
{
if(b.x<a.x)return true;
if(b.x>a.x)return false;
}
if(YLarge)
{
if(b.y>a.y)return true;
if(b.y<a.y)return false;
}
else
{
if(b.y<a.y)return true;
if(b.y>a.y)return false;
}
if(!b.MayBe&&a.MayBe)return true;
return false;
}
bool XLarge;//若为true,则X值越大则越近,否则X值小越近
bool YLarge;//若为true,则Y值越大则越近,否则Y值小越近
};
int CGame::Move(CObject * Obj,int Horz,int Vert)
{
/*
移动某个角色或物体。
参数:
[i]Obje 要移动的对象。
[i]Horz 要移动的水平距离(像素),向右为正,向左为负。
[i]Vert 要移动的竖直距离(像素),向下为正,向上为负。
返回值:
返回一个位段值。以下各值可用位或合并。
0 成功。
1 水平方向遇到阻挡。
2 竖直方向遇到阻挡。
*/
int retval=0;
//如果没有阻挡,应该移动到的位置
int OrDestX=Obj->XPos+Horz;
int OrDestY=Obj->YPos+Vert;
BLOCKINFOCompare Compare;
BLOCKINFO bi;
if(Vert>0)
{//向下移动,则Y值越小越近
Compare.YLarge=false;
}
else
{//向上移动,则Y值越大越近
Compare.YLarge=true;
}
if(Horz>0)
{//向右移动,则X值越小越近
Compare.XLarge=false;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -