MFC 小游戏之贪吃蛇

来源:互联网 发布:网络发票验旧系统 编辑:程序博客网 时间:2024/04/29 19:44

弄了控制台的贪吃蛇等游戏后,学了一些MFC,即马上去弄MFC的贪吃蛇。写的时候由于学的MFC视频和实际操作还是有很大区别的,很多东西还是要自己去查MSDN或百度才知道的,在这里次MFC贪吃蛇中学到了很多知识!做出来后发现界面有闪烁的显现,后有前辈说可以采取双缓冲去避免闪烁,即百度查了不少这方面的资料,自己编写后还是闪烁,后问前辈是否写错,前辈说未写错,我就继续找度娘,找了很久没弄出来,最后就去csdn论坛去发了个帖子。呵,果然给力,一下解决了问题。即只要添加一个消息函数OnEraseBkgnd(CDC* pDC) 在加上之前的双缓冲即可避免不闪烁了!很是高兴啊!


代码下载网址: http://download.csdn.net/detail/hai8902882/3823052 


关于双缓冲 和 OnEraseBkgnd(CDC* pDC) 的资料请看我博客的文章。

 

我是用VC6建立一个.exe 的文本空间,即再在view类中添加文件,我将这部分的代码贴出

大家可以交流下,如有不好之处,请见谅!


// mfc_snackeView.cpp : implementation of the CMfc_snackeView class//#include "stdafx.h"#include "mfc_snacke.h"#include "mfc_snackeDoc.h"#include "mfc_snackeView.h"#include <cstdlib>#include <ctime>#include <cmath>#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif/////////////////////////////////////////////////////////////////////////////// CMfc_snackeViewIMPLEMENT_DYNCREATE(CMfc_snackeView, CView)BEGIN_MESSAGE_MAP(CMfc_snackeView, CView) //{{AFX_MSG_MAP(CMfc_snackeView) ON_WM_TIMER() ON_WM_KEYDOWN() ON_COMMAND(IDS_EASY, OnEasy) ON_COMMAND(IDS_MEDIUM, OnMedium) ON_COMMAND(IDS_HARD, OnHard) ON_WM_ERASEBKGND() //}}AFX_MSG_MAP // Standard printing commands ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)END_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////// CMfc_snackeView construction/destructionCMfc_snackeView::CMfc_snackeView(){ // TODO: add construction code here m_Count = m_UseTime = 0; m_start = 0;   //记录玩家开始第几次玩 m_speed = 500;  //初始化速度为0.5s H = 35;   //地图的high 和 length,实际x = (40,580), y = (40, 380) L = 55;   //这样主要是为了rand的方便 srand(time(0));  //随机种子 CMfc_snackeView::Initial_Game();  //初始化游戏的界面}CMfc_snackeView::~CMfc_snackeView(){}BOOL CMfc_snackeView::PreCreateWindow(CREATESTRUCT& cs){ // TODO: Modify the Window class or styles here by modifying //  the CREATESTRUCT cs  return CView::PreCreateWindow(cs);}/////////////////////////////////////////////////////////////////////////////// CMfc_snackeView drawingvoid CMfc_snackeView::OnDraw(CDC* pDC)   //画界面{ CMfc_snackeDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); //////////////////////////////////////////////////////////////////////////    CDC MemDC;   //首先定义一个显示设备对象 CBitmap MemBitmap;   //定义一个位图对象    //随后建立与屏幕显示兼容的内存显示设备 MemDC.CreateCompatibleDC(pDC); //这时还不能绘图,因为没有地方画 //下面建立一个于屏幕显示兼容的位图,至于位图的大小嘛 //可以用窗口的大小 CRect rect; GetClientRect(&rect);    MemBitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height()); //将位图选入到内存显示设备中 //只要有选入了位图的内存显示设备才有地方地方绘图,画到指定的位图上 CBitmap *pOldBit = MemDC.SelectObject(&MemBitmap); //先用背景色将位图清除干净,这里我用的是白色作为背景 //你也可以用自己应该用的颜色 MemDC.FillSolidRect(0, 0, rect.Width(), rect.Height(), RGB(255, 255, 255)); //绘图//////////////////////////////////////////////////////////////////////////  //draw border of game MemDC.Rectangle(CRect(39, 39, 601, 401)); //Records cstring show CString s; s.Format("当前用时: %d", m_UseTime/(1000/m_speed)); MemDC.TextOut(620, 60, s); s.Format("当前得分: %d", m_Count); MemDC.TextOut(620, 100, s); s.Format("版权所有: [菜菜]咸鱼"); MemDC.TextOut(620, 140, s); s.Format("时间: 2011-10-22"); MemDC.TextOut(620, 180, s); //draw snake //draw head of snake CPoint h; h = m_body.GetAt(0); MemDC.SelectStockObject(DKGRAY_BRUSH); switch(m_NowDir)    {    case 4: MemDC.Pie(CRect(h.x, h.y, h.x+20, h.y+20), CPoint(h.x+5, h.y), CPoint(h.x+15, h.y));         MemDC.SelectStockObject(WHITE_BRUSH );  //蛇的眼睛      MemDC.Ellipse(h.x+13, h.y+5, h.x+18, h.y+10);      break;  case 3: MemDC.Pie(CRect(h.x, h.y, h.x+20, h.y+20), CPoint(h.x+20, h.y+5), CPoint(h.x+20, h.y+15));      MemDC.SelectStockObject(WHITE_BRUSH );      MemDC.Ellipse(h.x+10, h.y+2, h.x+15, h.y+7);      break;    case 2: MemDC.Pie(CRect(h.x, h.y, h.x+20, h.y+20), CPoint(h.x+15, h.y+20), CPoint(h.x+5, h.y+20));      MemDC.SelectStockObject(WHITE_BRUSH );      MemDC.Ellipse(h.x+13, h.y+10, h.x+18, h.y+15);      break;  case 1: MemDC.Pie(CRect(h.x, h.y, h.x+20, h.y+20), CPoint(h.x, h.y+15), CPoint(h.x, h.y+5));      MemDC.SelectStockObject(WHITE_BRUSH );      MemDC.Ellipse(h.x+5, h.y+2, h.x+10, h.y+7);      break; }    //draw body of snake CPoint b; MemDC.SelectStockObject(GRAY_BRUSH); for(int i = 1; i <= m_body.GetUpperBound(); i++) {  b = m_body.GetAt(i);  MemDC.Rectangle(CRect(b.x, b.y, b.x+20, b.y+20)); } //draw a food CBrush br; br.CreateSolidBrush(RGB(0, 255, 0)); MemDC.SelectObject(br); MemDC.FillRect(CRect(m_food.x, m_food.y, m_food.x+20, m_food.y+20), &br);    MemDC.Rectangle(CRect(m_food.x, m_food.y, m_food.x+20, m_food.y+20));  //将内存中图拷贝到屏幕上进行显示 pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &MemDC, 0, 0, SRCCOPY); //绘图完成后的清理 MemBitmap.DeleteObject(); MemDC.DeleteDC();}/////////////////////////////////////////////////////////////////////////////// CMfc_snackeView printingBOOL CMfc_snackeView::OnPreparePrinting(CPrintInfo* pInfo){ // default preparation return DoPreparePrinting(pInfo);}void CMfc_snackeView::OnBeginPrinting(CDC* , CPrintInfo* ){ // TODO: add extra initialization before printing}void CMfc_snackeView::OnEndPrinting(CDC* , CPrintInfo* ){ // TODO: add cleanup after printing}/////////////////////////////////////////////////////////////////////////////// CMfc_snackeView diagnostics#ifdef _DEBUGvoid CMfc_snackeView::AssertValid() const{ CView::AssertValid();}void CMfc_snackeView::Dump(CDumpContext& dc) const{ CView::Dump(dc);}CMfc_snackeDoc* CMfc_snackeView::GetDocument() // non-debug version is inline{ ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMfc_snackeDoc))); return (CMfc_snackeDoc*)m_pDocument;}#endif //_DEBUG/////////////////////////////////////////////////////////////////////////////// CMfc_snackeView message handlersvoid CMfc_snackeView::Initial_Game()   //游戏地图的初始化{ m_body.RemoveAll();  //initial direciton m_NowDir = m_PreDir = 3;  //inital head of snake CPoint head; head.x = 100;  head.y = 100; m_body.Add(head); //create rand food CMfc_snackeView::Create_food();}void CMfc_snackeView::Create_food(){ CPoint t;    int x, y, prove;    while(1) {  x = rand()%L + 4;        y = rand()%H + 4;  if(x%2 == 0 && y%2 == 0)  //其实坐标是x=(40,580), y=(40,380)  {                         //每一个图标如蛇头的high和length是占20, 20   prove = 0;      x *= 10;  y *= 10;            //食物不能是蛇的地方   for(int i = 0; i <= m_body.GetUpperBound(); i++)   {    t = m_body.GetAt(i);    if(t.x == x && t.y == y)    {     prove = 1;           break;    }   }      if(!prove)    break;  } } m_food = CPoint(x, y);}void CMfc_snackeView::GameStart()  //开始游戏哦{   //玩家时间和得分数的初始化 m_Count = m_UseTime = 0; m_start++; if(m_start > 1)   CMfc_snackeView::Initial_Game();  //每隔m_speed时间发送WM_TIMER消息    Timer = SetTimer(1, m_speed, NULL);}void CMfc_snackeView::OnTimer(UINT nIDEvent) //WM_TIMER消息{ // TODO: Add your message handler code here and/or call default m_UseTime++;  //时间记录    //蛇移动 CMfc_snackeView::Move(); CView::OnTimer(nIDEvent);}void CMfc_snackeView::Move() //蛇移动函数{    if(m_PreDir == m_NowDir || abs(m_PreDir-m_NowDir) == 2)  m_NowDir = m_PreDir; else  m_PreDir = m_NowDir; CPoint head; head = m_body.GetAt(0);  //4个方向 switch(m_NowDir) { case 4: head.y -= 20;      break;  case 3: head.x += 20;      break;  case 2: head.y += 20;      break;    case 1: head.x -= 20;      break; }   int over = 0;    CPoint t;    //蛇头是否吃到自己 for(int i = 0; i <= m_body.GetUpperBound(); i++) {  t = m_body.GetAt(i);  if(head.x == t.x && head.y == t.y)  {   over = 1;   break;  } }  if(!Check(head) || over) { //结束Timer,并弹出一个结束的对话框  KillTimer(Timer);  MessageBox("Game is over! You are fail!"); } else {   m_body.InsertAt(0, head);        //蛇头吃到食物  if(head.x == m_food.x && head.y == m_food.y)  {   m_Count++;   Create_food();  }  else   m_body.RemoveAt(m_body.GetUpperBound()); }     //使整个窗口客户区无效,意味着需要重绘,即调用OnDraw函数 //InvalidateRect(CRect(39, 39, 839, 489));    Invalidate();}//键盘按键判断void CMfc_snackeView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags){ // TODO: Add your message handler code here and/or call default    if(m_start) {   switch(nChar)  {     case 38:  //up   m_NowDir = 4;      break;  case 39:  //right      m_NowDir = 3;      break;     case 40:  //down      m_NowDir = 2;      break;     case 37:  //left      m_NowDir = 1;      break;  default:   m_NowDir = m_PreDir;   break;  } } CView::OnKeyDown(nChar, nRepCnt, nFlags);}//判断是否出界int CMfc_snackeView::Check(CPoint head){ if(head.x < 40 || head.x > 580 || head.y < 40 || head.y > 380)     return 0; else        return 1;}void CMfc_snackeView::OnEasy(){ // TODO: Add your command handler code here m_speed = 500;    CMfc_snackeView::GameStart();}void CMfc_snackeView::OnMedium(){ // TODO: Add your command handler code here m_speed = 200;    CMfc_snackeView::GameStart();}void CMfc_snackeView::OnHard(){ // TODO: Add your command handler code here m_speed = 50;    CMfc_snackeView::GameStart();}BOOL CMfc_snackeView::OnEraseBkgnd(CDC* pDC){ // TODO: Add your message handler code here and/or call default //即擦除背景由本函数处理,不需要OnPain()来擦除背景 return true; }


原创粉丝点击