//Game.h
#pragma once //游戏类 #include "glfDC.h" #include "panel.h" #include "worm.h" class Game { //游戏的基本元素 private: Panel m_GamePanel; Worm m_Worm; Obstacle m_Obstacle; private: glfDC* m_pDC; //游戏的状态 private: bool m_bPanelGridOn; bool m_bGameOver; //游戏的初始化数据 private: int m_nRow; //面板中网格行、列 int m_nCol; float m_fWidth; //面板的宽度 float m_fHeight; //面板的高度 public: Game(void); ~Game(void); public: void ShowPanelGrid(bool bGridOn); //控制面板网格显示 void ShowUserScore(); //显示用户得分 void ShowGameLevel(); //显示游戏级别 Obstacle CreateObstacle(); //用户操作 public: void GameKeyboard(unsigned char key, int x, int y); public: //初始化游戏 bool InitGame(float fWidth, float fHeight, int nRow, int nCol); //开始游戏 bool StartGame(); //进行游戏 bool RunGame(); //暂停游戏 bool PauseGame(); //复位游戏 bool ResetGame(); //结束游戏 bool EndGame(); };
//game.cpp
#include "stdafx.h" #include "Game.h" #include <time.h> #include <iostream> Game::Game(void) { m_pDC = new glfDC(); m_bGameOver = false; } Game::~Game(void) { } void Game::ShowPanelGrid(bool bGridOn) { m_bPanelGridOn = bGridOn; } void Game::ShowUserScore() { } void Game::ShowGameLevel() { } bool Game::InitGame(float fWidth, float fHeight, int nRow, int nCol) { m_fWidth = fWidth; m_fHeight = fHeight; m_nRow = nRow; m_nCol = nCol; //初始化面板 m_GamePanel.SetArea(fWidth, fHeight); m_GamePanel.SetGrid(nRow, nCol); return true; } bool Game::StartGame() { //开始游戏 绘制障碍物和蛇 nPoint ptInit; ptInit.x = m_nRow / 2; ptInit.y = m_nCol / 2; m_Worm.InitWorm(ptInit, DOWN); //随即产生障碍物 m_Obstacle = CreateObstacle(); return true; } bool Game::RunGame() { //运行游戏 绘制面板 障碍物 蛇 m_GamePanel.ShowGrid(m_bPanelGridOn); m_pDC->SetColor(1.0f, 0.0f, 0.0f); //设定面板颜色为红色 m_GamePanel.DrawPanel(m_pDC); //-----------蛇的控制 时序问题 蛇的移动、绘制 if (!m_bGameOver) { if (m_Worm.MeetFood(m_Obstacle)) //判断蛇是否遇到食物 { m_Obstacle = CreateObstacle(); //遇到食物则要产生另一个食物 } m_Worm.WormMove(); //蛇移动一步 } if (m_bGameOver = m_Worm.IsGameOver(&m_GamePanel)) { cout << "Game Over/n"; } m_pDC->SetColor(1.0f, 1.0f, 0.0f); //设定蛇的颜色 m_Worm.DrawWorm(&m_GamePanel, m_pDC); //--------------以上为蛇的控制代码 //取得障碍物的坐标 nPoint ptObstacle; ptObstacle.x = m_Obstacle.col; ptObstacle.y = m_Obstacle.row; //在面板上绘制障碍物 m_pDC->SetColor(0.5f, 0.5f, 0.5f); //设定障碍物颜色 m_GamePanel.FillGrid(ptObstacle, 1, UP, m_pDC); return m_bGameOver; } bool Game::PauseGame() { return true; } bool Game::EndGame() { return true; } void Game::GameKeyboard(unsigned char key, int x, int y) { Direction dir; switch (key) { case 'w': case 'W': dir = UP; break; case 's': case 'S': dir = DOWN; break; case 'a': case 'A': dir = LEFT; break; case 'd': case 'D': dir = RIGHT; break; case '1': this->StartGame(); std::cout << "Start Game/n"; break; } m_Worm.WormTurn(dir); } Obstacle Game::CreateObstacle() { Obstacle obs; srand(time(NULL)); obs.col = rand() % m_nCol; obs.row = rand() % m_nRow; return obs; }
//glfDC.h
#pragma once #include "stdafx.h" //封装OpenGL的API的设备上下文类 //值为浮点数的坐标结构 struct fPoint { float x; float y; }; //值为整形的坐标结构 struct nPoint { int x; int y; }; //设备上下文 class glfDC { public: glfDC(void); ~glfDC(void); public: void SetColor(GLfloat r, GLfloat g, GLfloat b); //设定绘图颜色 public: void Rectangle(GLfloat left, GLfloat top, GLfloat right, GLfloat bottom); //绘制矩形区域 void Line(GLfloat startX, GLfloat startY, GLfloat endX, GLfloat endY); //绘制直线 void Line(fPoint ptStart, fPoint ptEnd); //绘制直线 private: GLfloat red, green, blue; //绘图颜色 };
//glfDC.cpp
#include "glfDC.h" glfDC::glfDC(void) { red = 0.0f; green = 0.0f; blue = 0.0f; } glfDC::~glfDC(void) { } /************************************************************************/ /* 函数名称:Rectangle */ /* 参数名称: */ /* left 矩形左边界 */ /* top 矩形上边界 */ /* right 矩形右边界 */ /* bottom 矩形下边界 */ /* 作者:梁飞 */ /************************************************************************/ void glfDC::Rectangle(GLfloat left, GLfloat top, GLfloat right, GLfloat bottom) { glColor3f(red, green, blue); glBegin(GL_QUADS); glVertex2f(left, top); glVertex2f(left, bottom); glVertex2f(left, bottom); glVertex2f(right, bottom); glVertex2f(right, bottom); glVertex2f(right, top); glVertex2f(right, top); glVertex2f(left, top); glEnd(); } /************************************************************************/ /* 函数名称:Line */ /* 参数参数: */ /* startX 起点坐标X值 */ /* startY 起点坐标Y值 */ /* endX 终点坐标X值 */ /* endY 终点坐标Y值 */ /* 作者:梁飞 */ /************************************************************************/ void glfDC::Line(GLfloat startX, GLfloat startY, GLfloat endX, GLfloat endY) { glColor3f(red, green, blue); glBegin(GL_LINES); glVertex2f(startX, startY); glVertex2f(endX, endY); glEnd(); } /************************************************************************/ /* 函数名称:Line /* 函数参数: /* ptStart 起点坐标值 /* ptEnd 终点坐标值 /* 作者:梁飞 /************************************************************************/ void glfDC::Line(fPoint ptStart, fPoint ptEnd) { this->Line(ptStart.x, ptStart.y, ptEnd.x, ptEnd.y); } void glfDC::SetColor(GLfloat r, GLfloat g, GLfloat b) { this->red = r; this->green = g; this->blue = b; }
//panel.h
#pragma once #include "glfDC.h" struct Obstacle { int row; int col; }; class Panel { public: Panel(); ~Panel(); //根据游戏长宽值来初始化面板 Panel(float width, float height); //设定面板区域 大小为width×height bool SetArea(float width, float height); //根据行、列来初始化网格 float SetGrid(int row, int col); //绘制面板 bool DrawPanel(glfDC* pDC); //显示面板网格 void ShowGrid(bool flag); //根据网格的逻辑坐标转换成设备坐标 fPoint LPtoDP(int x, int y); fPoint LPtoDP(nPoint lp); //物理坐标转换成逻辑坐标 nPoint DPtoLP(float x, float y); //判断物体是否在面板边界 bool OnPanelEdge(float pt_x, float pt_y, int pt_dir); void FillGrid(nPoint pt, int nLen, Direction dir, glfDC* pDC); public: float m_fWidth; //控制面板宽度值 float m_fHeight; //控制面板高度值 fPoint m_ptPanel[4]; //面板四个角的坐标值 int m_nRow; //网格列数 int m_nCol; //网格行数 float m_fGridGap; //网格间隔值 bool m_bGridOn; //网格显示标志 };
//panel.cpp
#include "Panel.h" #include "stdafx.h" #include <iostream> using namespace std; Panel::Panel() { } Panel::Panel(float width, float height) { m_fWidth = width; m_fHeight = height; } float Panel::SetGrid(int row, int col) { m_nRow = row; m_nCol = col; m_fGridGap = (m_fWidth / m_nCol) < (m_fHeight / m_nRow) ? (m_fWidth / m_nCol) : (m_fHeight / m_nRow); m_ptPanel[0].x = -m_fGridGap * m_nCol / 2; m_ptPanel[0].y = -m_fGridGap * m_nRow / 2; m_ptPanel[1].x = m_ptPanel[0].x + m_nCol * m_fGridGap; m_ptPanel[1].y = m_ptPanel[0].y; m_ptPanel[2].x = m_ptPanel[1].x; m_ptPanel[2].y = m_ptPanel[1].y + m_nRow * m_fGridGap; m_ptPanel[3].x = m_ptPanel[2].x - m_nCol * m_fGridGap; m_ptPanel[3].y = m_ptPanel[2].y; return m_fGridGap; } bool Panel::DrawPanel(glfDC* pDC) { for (int i = 0; i < 4; i++) { pDC->Line(m_ptPanel[i], m_ptPanel[(i + 1) % 4]); } if (m_bGridOn) { for (int i = 1; i < m_nRow; i++) { pDC->Line(m_ptPanel[0].x, m_ptPanel[0].y + i * m_fGridGap, m_ptPanel[1].x, m_ptPanel[1].y + i *m_fGridGap); } for (int j = 1; j < m_nCol; j++) { pDC->Line(m_ptPanel[0].x + j * m_fGridGap, m_ptPanel[0].y, m_ptPanel[3].x + j * m_fGridGap, m_ptPanel[3].y); } } return true; } void Panel::ShowGrid(bool flag) { m_bGridOn = flag; } bool Panel::SetArea(float width, float height) { m_fWidth = width; m_fHeight = height; return true; } /************************************************************************/ /* 函数名称:LPtoDP */ /* 函数功能:将逻辑坐标转换成设备坐标 */ /* 参数说明: */ /* x 逻辑坐标的x值 */ /* y 逻辑坐标的y值 */ /************************************************************************/ fPoint Panel::LPtoDP(int x, int y) { fPoint pt; pt.x = m_ptPanel[0].x + x * m_fGridGap; pt.y = m_ptPanel[0].y + y * m_fGridGap; return pt; } fPoint Panel::LPtoDP(nPoint lp) { return this->LPtoDP(lp.x, lp.y); } void Panel::FillGrid(nPoint pt, int nLen, Direction dir, glfDC* pDC) { fPoint fpt[4]; //绘制区域的四个点坐标 switch (dir) { case LEFT: { fpt[0] = this->LPtoDP(pt); fpt[1].x = fpt[0].x + nLen * m_fGridGap; fpt[1].y = fpt[0].y; fpt[2].x = fpt[1].x; fpt[2].y = fpt[1].y + m_fGridGap; fpt[3].x = fpt[2].x - nLen * m_fGridGap; fpt[3].y = fpt[2].y; break; } case RIGHT: { fpt[0] = this->LPtoDP(pt.x - nLen + 1, pt.y); fpt[1].x = fpt[0].x + nLen * m_fGridGap; fpt[1].y = fpt[0].y; fpt[2].x = fpt[1].x; fpt[2].y = fpt[1].y + m_fGridGap; fpt[3].x = fpt[2].x - nLen * m_fGridGap; fpt[3].y = fpt[2].y; break; } case UP: { fpt[0] = this->LPtoDP(pt.x, pt.y - nLen + 1); fpt[1].x = fpt[0].x + m_fGridGap; fpt[1].y = fpt[0].y; fpt[2].x = fpt[1].x; fpt[2].y = fpt[1].y + nLen * m_fGridGap; fpt[3].x = fpt[2].x - m_fGridGap; fpt[3].y = fpt[2].y; break; } case DOWN: { fpt[0] = this->LPtoDP(pt.x, pt.y); fpt[1].x = fpt[0].x + m_fGridGap; fpt[1].y = fpt[0].y; fpt[2].x = fpt[1].x; fpt[2].y = fpt[1].y + nLen * m_fGridGap; fpt[3].x = fpt[2].x - m_fGridGap; fpt[3].y = fpt[2].y; break; } } //填充方格 // pDC->SetColor(0.0f, 0.0f, 1.0f); pDC->Rectangle(fpt[3].x, fpt[3].y, fpt[1].x, fpt[1].y); } Panel::~Panel() { }
//worm.h
#ifndef HEADER_WORM #define HEADER_WORM #include "panel.h" #include "glfDC.h" #include <vector> using namespace std; class WormLink; class Worm { private: nPoint m_ptHead; //头坐标 Direction m_dirHead; vector<WormLink*> m_vLink; //节 bool m_bMeetFood; enum WormStatus{EATEFOOD, GAMEOVER, NORMAL}; //蛇的三个状态 吃到食物、游戏结束、正常 public: Worm(); public: void InitWorm(nPoint ptHead, Direction dir); void WormTurn(Direction dir); void WormMove(); nPoint GetHeadPoint(); //获取蛇头坐标 bool BumpSelf(); //判断蛇是否撞到自己 void DrawWorm(Panel* pGamePanel, glfDC* pDC); bool IsGameOver(Panel* pGamePanel); bool MeetFood(Obstacle& obs); }; #endif
//worm.cpp
#include "WormLink.h" #include "Worm.h" #include <iostream> Worm::Worm() { m_bMeetFood = false; } void Worm::InitWorm(nPoint ptHead, Direction dir) { //创建一个蛇节作为蛇的头部所在节 m_dirHead = dir; m_ptHead = ptHead; WormLink* pLink = new WormLink(ptHead, 3, dir); m_vLink.push_back(pLink); } nPoint Worm::GetHeadPoint() { return m_ptHead; } bool Worm::IsGameOver(Panel* pGamePanel) { bool bCollidePanel = (m_ptHead.x > pGamePanel->m_nCol - 1 || m_ptHead.x < 0 || m_ptHead.y < 0 || m_ptHead.y > pGamePanel->m_nRow - 1); return bCollidePanel || this->BumpSelf(); } bool Worm::MeetFood(Obstacle& obs) { cout << "Food:(" << obs.col << " " << obs.row << ")" << endl; cout << "SnakeHead(" << m_ptHead.x <<" " << m_ptHead.y << ")" << endl; //if (m_ptHead.x == obs.col && m_ptHead.y == obs.row) //{ // m_bMeetFood = true; //} // //return m_bMeetFood; switch (this->m_dirHead) { case UP: if (obs.row - 1 == m_ptHead.y && obs.col == m_ptHead.x) { m_bMeetFood = true; } break; case DOWN: if (obs.row + 1 == m_ptHead.y && obs.col == m_ptHead.x) { m_bMeetFood = true; } break; case LEFT: if (obs.row == m_ptHead.y && obs.col + 1 == m_ptHead.x) { cout << obs.row << " " << obs.col + 1 << endl; cout << m_ptHead.y << " " << m_ptHead.x << endl; m_bMeetFood = true; } break; case RIGHT: if (obs.row == m_ptHead.y && obs.col - 1 == m_ptHead.x) { m_bMeetFood = true; } break; } if (m_bMeetFood) cout << "Food" << endl; return m_bMeetFood ; } bool Worm::BumpSelf() { for (vector<WormLink*>::iterator it = m_vLink.begin(); it != m_vLink.end(); it++) { if ((*it)->Bump(m_ptHead, this->m_dirHead)) { return true; } } return false; } void Worm::WormMove() { WormLink* pHead = m_vLink[m_vLink.size() - 1]; //获取头所在节 pHead->InLength(); //头节长度加一 this->m_ptHead = pHead->m_ptLinkHead; if (m_bMeetFood) //遇到食物则蛇的尾部长度不发生变化 { m_bMeetFood = false; return; } WormLink* pTail = m_vLink[0]; if (pTail->Delength() == 0) //尾节长度减一 { delete pTail; m_vLink.erase(m_vLink.begin()); } } void Worm::DrawWorm(Panel* pGamePanel, glfDC* pDC) { for (vector<WormLink*>::iterator it = m_vLink.begin(); it != m_vLink.end(); it++) { (*it)->DrawWormLink(pGamePanel, pDC); } } void Worm::WormTurn(Direction dir) { if (this->m_dirHead == UP || this->m_dirHead == DOWN) { if (dir == LEFT || RIGHT) { WormLink* p = new WormLink(m_ptHead, 0, dir); m_vLink.push_back(p); this->m_dirHead = dir; } } else if (this->m_dirHead == LEFT || this->m_dirHead == RIGHT) { if (dir == UP || dir == DOWN) { WormLink* p = new WormLink(m_ptHead, 0, dir); m_vLink.push_back(p); this->m_dirHead = dir; } } }
//wormlink.h
#pragma once #include "panel.h" class WormLink { public: WormLink(nPoint ptLinkHead, int nLen, Direction dir); public: void DrawWormLink(Panel* pGamePanel, glfDC* pDC); //绘制蛇节 int InLength(); //蛇节减少长度 int Delength(); //蛇节增加长度 bool Bump(nPoint ptWormHead, Direction dir); //判断蛇头是否与本节相撞 public: nPoint m_ptLinkHead; //蛇节首部坐标 int m_nLen; //蛇节长度 Direction m_Dir; //蛇节移动方向 };
//wormlink.cpp
#include "WormLink.h" WormLink::WormLink(nPoint ptLinkHead, int nLen, Direction dir) { m_ptLinkHead = ptLinkHead; m_nLen = nLen; m_Dir = dir; } int WormLink::Delength() { m_nLen--; return m_nLen; } int WormLink::InLength() { m_nLen++; switch (m_Dir) { case LEFT: m_ptLinkHead.x--; break; case RIGHT: m_ptLinkHead.x++; break; case UP: m_ptLinkHead.y++; break; case DOWN: m_ptLinkHead.y--; break; } return m_nLen; } void WormLink::DrawWormLink(Panel* pGamePanel, glfDC* pDC) { pGamePanel->FillGrid(m_ptLinkHead, m_nLen, m_Dir, pDC); } bool WormLink::Bump(nPoint ptWormHead, Direction dir) { nPoint ptTail; if (this->m_Dir == UP) { ptTail.x = m_ptLinkHead.x; ptTail.y = m_ptLinkHead.y - m_nLen; if (dir == UP || dir == DOWN) { return false; } else if (dir == RIGHT || dir == LEFT) { return (ptWormHead.x == ptTail.x && ptWormHead.y <= m_ptLinkHead.y && ptWormHead.y >= ptTail.y); } } else if (this->m_Dir == DOWN) { ptTail.x = m_ptLinkHead.x; ptTail.y = m_ptLinkHead.y + m_nLen; if (dir == UP || dir == DOWN) { return false; } else if (dir == RIGHT || LEFT) { return (ptWormHead.x == ptTail.x && ptWormHead.y >= m_ptLinkHead.y && ptWormHead.y <= ptTail.y); } } else if (this->m_Dir == LEFT) { ptTail.x = m_ptLinkHead.x - m_nLen; ptTail.y = m_ptLinkHead.y; if (dir == LEFT || dir == RIGHT) { return false; } else if (dir == UP || dir == DOWN) { return (ptWormHead.x >= ptTail.x && ptWormHead.x <= m_ptLinkHead.x && ptWormHead.y == ptTail.y); } } else if (this->m_Dir == RIGHT) { ptTail.x = m_ptLinkHead.x + m_nLen; ptTail.y = m_ptLinkHead.y; if (dir == LEFT || dir == RIGHT) { return false; } else if (dir == UP || dir == DOWN) { return (ptWormHead.x >= m_ptLinkHead.x && ptWormHead.x <= ptTail.x && ptWormHead.y == ptTail.y); } } return true; }
//wormgame.cpp
// WormGame.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "Game.h" #include <iostream> using namespace std; //游戏主体 Game g_Game; void InitScense() { g_Game.InitGame(2.0f, 2.0f, 10, 10); g_Game.ShowPanelGrid(true); g_Game.StartGame(); } void myTimer(int value) { glutPostRedisplay(); glutTimerFunc(300, myTimer, 0); } void myReshape(int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(-0.5, 0.5, -0.5, 0.5); if(w <= h) glOrtho(-2.25, 2.25, -2.25 * h / w, 2.25 * h / w,-10.0, 10.0); else glOrtho(-2.25 * w / h, 2.25 * w / h,-2.25, 2.25, -10.0, 10.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void myDisplay(void) { glClear(GL_COLOR_BUFFER_BIT); if (!g_Game.RunGame()) //游戏结束取消定时器 { glutTimerFunc(300, NULL, 0); } glFlush(); glutSwapBuffers(); } void myKeyboard(unsigned char key, int x, int y) { g_Game.GameKeyboard(key, x, y); // glutPostRedisplay(); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(600, 600); glutInitWindowPosition(100, 100); glutCreateWindow("Worm"); glPixelStorei (GL_UNPACK_ALIGNMENT, 1); glutDisplayFunc(myDisplay); glutReshapeFunc(myReshape); glutKeyboardFunc(myKeyboard); glutTimerFunc(300, myTimer, 0); InitScense(); //初始化游戏场景 glutMainLoop(); return 0; }
源码下载