超级玛丽制作揭秘27程序框架WinProc

 怎样把所有的功能组织起来,形成一个完整的游戏呢?游戏状态。不同的游戏状态下,对应不同的图片显示、逻辑处理、按键响应。这样就形成了一个结构清晰的框架。各个模块相对独立,也方便扩展。
由于是消息处理机制,所有功能对应到消息处理函数WndProc,程序框架如下:
消息处理函数WndProc
{
 绘图消息WM_PAINT:
  状态1:状态1绘图。
  状态2:状态2绘图。
  ……
 计时消息WM_TIMER:
  状态1:状态1逻辑处理。发WM_PAINT消息,通知绘图。
  状态2:状态2逻辑处理。发WM_PAINT消息,通知绘图。
  ……
 按键消息WM_KEYDOWN  WM_KEYUP:
  状态1:状态1逻辑处理。发WM_PAINT消息,通知绘图。
  状态2:状态2逻辑处理。发WM_PAINT消息,通知绘图。
  ……
}
逻辑处理后是否发WM_PAINT消息,依据具体情况而定。

程序入口:
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
 MyRegisterClass(hInstance); //类注册
 //初始化
 if (!InitInstance (hInstance, nCmdShow))
 {
  return FALSE;
 }
 //消息循环
 while (GetMessage(&msg, NULL, 0, 0))
 {
  if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
  {
   TranslateMessage(&msg);
   DispatchMessage(&msg);
  }
 }
 return msg.wParam;
}
整个消息处理循环,是默认的结构。
说明:InitInstance函数复杂初始化。类注册函数MyRegisterClass中,把菜单栏取消了,即wcex.lpszMenuName=NULL,其它不变。

消息处理函数WndProc
代码:
switch (message)
 {
  case WM_PAINT:
   //窗口DC
   hwindow = BeginPaint(hWnd, &ps);
   //初始化空图
   SelectObject(hscreen,hmapnull);
   switch(gamemap.iGameState)
   {
   case GAME_ERR:
    //地图文件加载错误
    gamemap.viewx=0;  //视图坐标
    //显示错误信息
    bmPre.Stretch(2,2,0); //背景图片
    myfont.SelectColor(TC_WHITE,TC_BLACK);//文字颜色
    myfont.SelectFont(0); //字体
    myfont.ShowText(150,290,pPreText[3]); //显示文字
    break;
   case GAME_PRE:
    //菜单显示
    (代码略)
    break;
   case GAME_HELP:
    //菜单项“操作说明”
    (代码略)
    break;

   case GAME_IN_PRE:
    //游戏LIFE,WORLD提示
    gamemap.viewx=0;  //视图坐标
    bmPre.Stretch(2,2,2); //背景图片
    gamemap.ShowInfo(hscreen); //显示LIFE,WORLD
    break;
   case GAME_IN:  //游戏进行中
   case GAME_WIN:   //游戏进行中,过关
   case GAME_FAIL_WAIT: //游戏进行中,失败
   case GAME_PUMP_IN:  //游戏进行中,进入水管
    bmSky.DrawRollStretch(2,2,gamemap.mapinfo.iBackBmp);//背景图片
    gamemap.ShowBkObj(bmMapBkObj);  //地图背景物品
    gamemap.Show(bmMap);    //地图物品
    gamemap.ShowAniObj(bmAniObj);  //动态元素
    gamemap.ShowOther(hscreen);   //金钱数量,攻击提示
    rmain.Draw();  //玩家角色
    break;
   case GAME_OVER:
    //游戏结束
    gamemap.viewx=0;
    bmPre.Stretch(2,2,1);   //输出图片GAME OVER
    break;     
   case GAME_PASS:
    //游戏通关
    gamemap.viewx=0;
    bmPre.Stretch(2,2,3);   //输出图片通关
    break;
   }
   if(gamemap.iScreenScale)
   { //窗口缩放,放大视图区域
    StretchBlt(hwindow,0,0,wwingame,hwingame,hscreen,  gamemap.viewx,0,GAMEW*32,GAMEH*32,SRCCOPY); 
   }
   else
   { //拷贝视图区域    BitBlt(hwindow,0,0,GAMEW*32,GAMEH*32,hscreen,gamemap.viewx,0,SRCCOPY);
   }
   EndPaint(hWnd, &ps); //绘图结束
   break;

  case WM_TIMER:
   switch(gamemap.iGameState)
   {
   case GAME_PRE: //游戏菜单
    c1.DecCount();//计时器减1
    if(0 == c1.iNum%MENU_ARROW_TIME)
    { //每隔10个时间片(即箭头闪烁的时间),刷新屏幕
     InvalidateRect(hWnd,NULL,false);
    }    
    break;
   case GAME_IN_PRE: //游戏LIFE,WORLD提示
    if(c1.DecCount())
    { 
//计时结束,进入游戏。
     gamemap.SetGameState(GAME_IN);
     c1.ReStart(TIME_GAME_IN); //启动计时300秒
    }
    InvalidateRect(hWnd,NULL,false); //刷新屏幕
    break;    
   case GAME_IN:  //游戏进行中
   case GAME_WIN:  //游戏进行中,过关
    c1.DecCount();//计时器计时
    if(0 == c1.iNum%SKY_TIME)
    {
     bmSky.MoveRoll(SKY_SPEED);//云彩移动
    }
    gamemap.ChangeFrame(c1.iNum);//帧控制
    rmain.Move();//人物移动
    gamemap.MoveView();//视图移动
    gamemap.CheckRole();//角色检测
    gamemap.CheckAni(c1.iNum);//逻辑数据检测
    gamemap.IsWin();  //胜负检测
    InvalidateRect(hWnd,NULL,false); //刷新屏幕
    break;
   case GAME_WIN_WAIT: //游戏进行中,过关,停顿2秒
    if(c1.DecCount())
    {
     //计时结束,进入游戏LIFE,WORLD提示
     gamemap.SetGameState(GAME_IN_PRE);     
     InvalidateRect(hWnd,NULL,false); //刷新屏幕
    }
    break;
   case GAME_PUMP_IN:  //游戏进行中,进入水管,停顿2秒
    if(c1.DecCount())
    {
     //计时结束,切换地图
     gamemap.ChangeMap();
     gamemap.SetGameState(GAME_IN); //进入游戏
     c1.ReStart(TIME_GAME_IN);  //启动计时300秒
     rmain.SetAni(ROLE_ANI_UP);  //设置玩家出水管动画
    }
    InvalidateRect(hWnd,NULL,false); //刷新屏幕
    break;
   case GAME_FAIL_WAIT:  //游戏进行中,失败,停顿2秒
    if(c1.DecCount())
    {
     //计时结束,加载地图
     gamemap.Fail_Wait();
    }
    break;
   case GAME_PASS:  //全部通关,停顿2秒
    if(c1.DecCount())
    { 
//计时结束,设置游戏状态:游戏菜单
     gamemap.SetGameState(GAME_PRE);     
    }
    InvalidateRect(hWnd,NULL,false); //刷新屏幕
    break;     
   case GAME_OVER: //游戏结束,停顿3秒
    if(c1.DecCount())
    {
//计时结束,设置游戏状态:游戏菜单
     gamemap.SetGameState(GAME_PRE);     
    }
    InvalidateRect(hWnd,NULL,false); //刷新屏幕
    break;
   }
   break;

  case WM_KEYDOWN: //按键处理
   if(gamemap.KeyProc(wParam)) 
    InvalidateRect(hWnd,NULL,false);
   break;

  case WM_KEYUP: //按键“抬起”处理
   gamemap.KeyUpProc(wParam);      
   break;

  case WM_SIZE: //窗口大小调整,代码略 
   break;   

  case WM_DESTROY:  //窗口销毁,释放DC, 代码略
   break;

消息处理函数完成。

终于,所有模块全部完成,游戏制作完成。整个工程差不多3000行代码。第一个制作超级玛丽的程序员,是否用了这么多代码,肯定没有。当时,应该是汇编。3000行C++代码,还达不到汇编程序下的地图规模、图片特效、游戏流畅度。可见,程序的乐趣无穷。至于,下一个游戏是什么样子,且听下回分解。

附:
超级玛丽第一版源码链接:http://download.csdn.net/source/497676
超级玛丽增强版源码链接:http://download.csdn.net/source/584350

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值