玩家控制的小人,和各种小怪基本一致。没什么神秘的。主要有三个功能要实现:动作控制,键盘响应,动画播放。
为了方便图片显示,玩家角色类MYROLE直接派生自图片类:
成员函数功能列表:
class MYROLE:public MYBITMAP
{
public:
//构造函数,析构函数
MYROLE();
~MYROLE();
//初始化部分
//功能 初始化玩家信息
//入参 玩家运动范围的左边界 右边界()
void InitRole(int xleft, int xright);
//功能 设置玩家运动范围
//入参 玩家运动范围的左边界 右边界()
void SetLimit(int xleft, int xright);
//图片显示部分
//功能 显示玩家角色图片(当前坐标 当前帧)
//入参 无
void Draw();
//功能 显示玩家角色图片
//入参 指定的横坐标 纵坐标 帧
void Draw(int x,int y,int iframe);
//功能 刷新帧,该函数没有使用, 帧刷新的功能在其它地方完成
//入参 无
void ChangeFrame();
//功能 设置玩家状态. 该函数没有使用
//入参 玩家状态
void SetState(int i);
//动作部分
//功能 玩家角色移动
//入参 无
void Move();
//功能 玩家角色跳跃. 该函数没有使用
//入参
void Jump();
//功能 移动到指定地点
//入参 指定地点横坐标 纵坐标
void MoveTo(int x,int y);
//功能 从当前位置移动一个增量
//入参 横坐标增量 纵坐标增量
void MoveOffset(int x,int y);
//功能 向指定地点移动一段距离(移动增量是固定的)
//入参 指定地点横坐标 纵坐标
void MoveStepTo(int x,int y);
//动画部分
//功能 播放动画
//入参 无
void PlayAni();
//功能 设置动画方式
//入参 动画方式
void SetAni(int istyle);
//功能 判断是否正在播放动画, 如果正在播放动画,返回1.否则,返回0
//入参 无
int IsInAni();
//数据部分
//玩家状态, 该变量没有使用
int iState;
//图片数据
//玩家当前帧
int iFrame;
//动作控制数据
//玩家活动范围: 左边界 右边界(只有横坐标)
int minx;
int maxx;
//运动速度
int movex;//正值,向右移动
int movey;//正值,向下移动
//跳跃
int jumpheight;//跳跃高度
int jumpx;//跳跃时, 横向速度(正值,向右移动)
//玩家运动方向
int idirec;
//动画数据
int iAniBegin;//动画是否开始播放
int iparam1;//动画参数
int iAniStyle;//动画方式
};
各个功能的实现:
键盘响应。
玩家通过按键,控制人物移动。
消息处理函数函数:WndProc
代码:
case WM_KEYDOWN:
if(gamemap.KeyProc(wParam))
InvalidateRect(hWnd,NULL,false);
break;
case WM_KEYUP:
gamemap.KeyUpProc(wParam);
break;
按键消息包括“按下”“抬起”两种方式:
KEYDOWN处理函数:int GAMEMAP::KeyProc(int iKey)
代码:不同游戏状态下,按键功能不同。
switch(iGameState)
{
case GAME_PRE://选择游戏菜单
switch(iKey)
{
case 0xd://按下回车键
switch(iMenu)
{
case 0: //菜单项0“开始游戏”
c1.ReStart(TIME_GAME_IN_PRE); //计时两秒
iGameState=GAME_IN_PRE;//进入游戏LIFE/WORLD提示状态
break;
case 1: //菜单项1“操作说明”
SetGameState(GAME_HELP); //进入游戏状态“操作说明”,显示帮助信息
break;
}
break;
case VK_UP: //按方向键“上”,切换菜单项
iMenu=(iMenu+1)%2;
break;
case VK_DOWN: //按方向键“下”,切换菜单项
iMenu=(iMenu+1)%2;
break;
}
return 1;
case GAME_HELP: //游戏菜单项“操作说明”打开
switch(iKey)
{
case 0xd: //按回车键,返回游戏菜单
SetGameState(GAME_PRE); //设置游戏状态:选择菜单
break;
}
return 1;
case GAME_IN: //游戏进行中
//如果人物正在播放动画,拒绝键盘响应
if(rmain.IsInAni())
{
break;
}
//根据方向键, X, Z, 触发移动,跳跃,攻击等功能
switch(iKey)
{
case VK_RIGHT:
case VK_LEFT:
case VK_DOWN:
case KEY_X: //跳
case KEY_Z: //FIRE
//秘籍?
case 0x7a://按键F11, 直接切换攻击方式
iAttack=(iAttack+1)%ATTACK_MAX_TYPE;
break;
case 0x7b://按键F12 直接通关(游戏进行中才可以,即游戏状态GAME_IN)
rmain.xpos = MAX_PAGE*GAMEW*32;
break;
}
break;
}
return 0;
}
可见,按键响应只需要处理三个状态:
菜单选择GAME_PRE
操作说明菜单打开GAME_HELP
游戏进行中GAME_IN
说明:前两个状态属于菜单控制,函数返回1,表示立即刷新屏幕。对于状态GAME_IN,返回0。游戏过程中,屏幕刷新由其它地方控制。
按键“抬起”的处理:
函数:void GAMEMAP::KeyUpProc(int iKey)
代码:按键抬起,只需要清除一些变量。
switch(iKey)
{
//松开方向键“左右”,清除横向移动速度
case VK_RIGHT:
rmain.movex=0;
break;
case VK_LEFT:
rmain.movex=0;
break;
case KEY_X: //松开跳跃键,无处理
break;
case KEY_Z: //松开攻击键,清除变量iBeginFire,表示停止攻击
iBeginFire=0;
break;
case KEY_W: //按W,调整窗口为默认大小
MoveWindow(hWndMain,
(wwin-GAMEW*32)/2,
(hwin-GAMEH*32)/2,
GAMEW*32,
GAMEH*32+32,
true);
break;
}
这就是游戏的所有按键处理。
显示问题:
函数:void MYROLE::Draw()
代码:
//判断是否播放动画,即iAniBegin为1
if(iAniBegin)
{
//显示动画帧
PlayAni();
}
else
{
//显示当前图片
SelectObject(hdcsrc,hBm);
BitBlt(hdcdest,xpos,ypos,
width,height/2,
hdcsrc,iFrame*width,height/2,SRCAND);
BitBlt(hdcdest,xpos,ypos,
width,height/2,
hdcsrc,iFrame*width,0,SRCPAINT);
}
玩家角色是怎样行走和跳跃的呢?动画播放怎样实现?且听下回分解。
附:
超级玛丽第一版源码链接:http://download.youkuaiyun.com/source/497676
超级玛丽增强版源码链接:http://download.youkuaiyun.com/source/584350