C++練習例項————貪吃蛇(OO思想)
阿新 • • 發佈:2018-12-12
這是一款在vs上直接控制檯輸出的貪吃蛇遊戲,沒有使用任何圖形庫。遊戲具有多個介面,狀態轉換如下:
下面直接上程式碼:
Position類,用來記錄遊戲中的座標位置:
#include<iostream> using namespace std; #ifndef POSITION_H #define POSITION_H class Position { public: Position(int x = 0, int y = 0) : m_x(x), m_y(y) {}; ~Position() {}; Position& operator=(const Position &p) { m_x = p.m_x; m_y = p.m_y; return *this; } bool operator==(const Position &p)const { if (m_x == p.m_x&&m_y == p.m_y) return true; else return false; } void Set(const int x, const int y) { m_x = x; m_y = y; } void SetX(const int x) { m_x = x; } void SetY(const int y) { m_y = y; } int GetX() const { return m_x; } int GetY()const { return m_y; } private: int m_x; int m_y; }; #endif
GameObject類,遊戲中所有物件都要繼承的基類,其中HANDLE為控制代碼:
#include "Position.h" #include <Windows.h> #ifndef GAMEOBJECT_H #define GAMEOBJECT_H class GameObject { protected: Position m_firstpos; public: GameObject() {} virtual ~GameObject() {} virtual void Display(HANDLE) = 0; virtual void Clear(HANDLE) = 0; }; #endif // GAMEOBJECT_H
Field類,用於遊戲邊框的輸出和處理:
#include "GameObject.h" #ifndef FIELD_H #define FIELD_H class Field:GameObject { public: Field(int x,int y){m_firstpos.Set(x, y);} ~Field() {} void Display(HANDLE handle); void Clear(HANDLE){} Position GetFirstPos()const { return m_firstpos; } static int GetWidth(); static int GetHeight(); }; #endif
#include "Field.h"
void Field::Display(HANDLE handle)
{
{
COORD coord;
coord.X = m_firstpos.GetX();
coord.Y = m_firstpos.GetY();
for (int r = 0; r < Field::GetHeight()+1; ++r)
{
coord.X = m_firstpos.GetX();
SetConsoleCursorPosition(handle, coord);
cout << "#";
coord.X = Field::GetWidth() + m_firstpos.GetX();
SetConsoleCursorPosition(handle, coord);
cout << "#";
coord.Y++;
}
coord.X = m_firstpos.GetX();
coord.Y = m_firstpos.GetY();
for (int r = 0; r < Field::GetWidth()+1; ++r)
{
coord.Y = m_firstpos.GetY();
SetConsoleCursorPosition(handle, coord);
cout << "#";
coord.Y = Field::GetHeight() + m_firstpos.GetY();
SetConsoleCursorPosition(handle, coord);
cout << "#";
coord.X++;
}
}
}
int Field::GetWidth()
{
static const int width = 75;
return width;
}
int Field::GetHeight()
{
static const int height =20;
return height;
}
Food類,遊戲中食物的顯示和管理:
#include "GameObject.h"
#include "Field.h"
#ifndef FOOD_H
#define FOOD_H
class Food:GameObject
{
private:
char m_symbol;
public:
Food(int x,int y) : m_symbol('$')
{
m_firstpos.Set(x,y);
}
void Setpos(int x, int y){m_firstpos.Set(x, y);}
void Reposition(int leftupx,int leftupy)
{
m_firstpos.Set(
(rand() % (Field::GetWidth()-leftupx-2)+leftupx+1),
(rand() %( Field::GetHeight()-leftupy-2)+leftupy+1));
}
Position GetPos() const { return m_firstpos; }
void Display(HANDLE handle)
{
COORD coord;
coord.X = m_firstpos.GetX();
coord.Y = m_firstpos.GetY();
SetConsoleCursorPosition(handle, coord);
cout << m_symbol;
}
void Clear(HANDLE handle)
{
COORD coord;
coord.X = m_firstpos.GetX();
coord.Y = m_firstpos.GetY();
SetConsoleCursorPosition(handle, coord);
cout << " ";
}
};
#endif
Snake類,用於蛇體的顯示和玩法規則的表現:
#include <conio.h>
#include <vector>
#include "GameObject.h"
#include "Food.h"
#ifndef SNAKE_H
#define SNAKE_H
class Snake :GameObject
{
private:
enum { UP, DOWN, LEFT, RIGHT } m_dir;
vector<Position> m_snakepos;
Position * m_headpos;
char m_symbol, m_headsymbol;
int m_speed;
bool m_canturn;
public:
Snake(int x, int y) :
m_symbol('X'), m_headsymbol('@'), m_snakepos(),
m_speed(1), m_dir(RIGHT),
m_headpos(nullptr), m_canturn(true)
{
m_snakepos.push_back(Position(x, y));
m_snakepos.push_back(Position(x - 1, y));
m_snakepos.push_back(Position(x - 2, y));
m_headpos = &m_snakepos[0];
}
~Snake()
{
if(!m_headpos)
delete m_headpos;
}
void GetInput();
Position Move();
bool CheckFood(const Food & food)
{
if (food.GetPos() == *m_headpos)
{
m_snakepos.push_back(m_snakepos[m_snakepos.size() - 1]);
return true;
}
return false;
}
bool CheckFoodInBody(Position food)
{
for each (Position var in m_snakepos)
{
if (var == food)return true;
}
return false;
}
bool CheckHeadInBody()
{
int num(0);
for each (Position var in m_snakepos)
{
if (var == *m_headpos)num++;
if (num == 2)return true;
}
return false;
}
bool CheckHeadInWall(int leftupx, int leftupy)
{
if (m_headpos->GetX()==Field::GetWidth()+leftupx||
m_headpos->GetX()== leftupx||
m_headpos->GetY() == Field::GetHeight() + leftupy||
m_headpos->GetY() == leftupy )
return true;
else return false;
}
void Display(HANDLE handle);
void Clear(HANDLE){}
};
#endif
#include "Snake.h"
void Snake::GetInput()
{
if (_kbhit())//得到鍵盤相應
{
int key = _getch();
if (key == 72 && m_dir != DOWN)
m_dir = UP;
if (key == 80 && m_dir != UP)
m_dir = DOWN;
if (key == 75 && m_dir != RIGHT)
m_dir = LEFT;
if (key == 77 && m_dir != LEFT)
m_dir = RIGHT;
}
}
Position Snake::Move()
{
Position next = { 0, 0 };
switch (m_dir) {
case UP:
next = Position(m_headpos->GetX(), m_headpos->GetY() - 1);
break;
case DOWN:
next = Position(m_headpos->GetX(), m_headpos->GetY() + 1);
break;
case LEFT:
next = Position(m_headpos->GetX() - 1, m_headpos->GetY());
break;
case RIGHT:
next = Position(m_headpos->GetX() + 1, m_headpos->GetY());
}
m_snakepos.insert(m_snakepos.begin(), next);
Position temp = m_snakepos[m_snakepos.size() - 1];
m_snakepos.pop_back();
m_headpos = &m_snakepos[0];
return temp;
}
void Snake::Display(HANDLE handle)
{
Position temppos = Move();
COORD coord;
coord.X = temppos.GetX(); coord.Y = temppos.GetY();
SetConsoleCursorPosition(handle, coord);
cout << " ";//消除最後一個節點
for (int i = 0; i < m_snakepos.size(); i++)
{
coord.X = m_snakepos[i].GetX();
coord.Y = m_snakepos[i].GetY();
SetConsoleCursorPosition(handle, coord);
cout << m_symbol;
}
coord.X = m_snakepos[0].GetX();
coord.Y = m_snakepos[0].GetY();
SetConsoleCursorPosition(handle, coord);
std::cout << m_headsymbol;//輸出頭節點
}
DataManager類,用於管理遊戲資料並記錄遊戲最高分(檔案操作),採用單例模式:
#include<iostream>
#include<fstream>
#include <string>
using namespace std;
#ifndef DATAMANAGER_H
#define DATAMANAGER_H
class Datamanager
{
private:
int m_curscore;
int m_highscore;
bool m_isend;
public:
Datamanager(int curscore):
m_curscore(curscore),m_isend(false)
{}
~Datamanager(){ }
static Datamanager*Instance();//單例模式
void AddCurScore() {m_curscore++;}
int GetCurScore(){ return m_curscore; }
bool IsEnd() { return m_isend; }
void SetEnd(bool end) { m_isend = end; }
int GetHighScore(){return m_highscore;}
string GetHighFromFile();
void StoreHighScore(string);
void ReStart()
{
m_curscore = 0;
m_highscore = 0;
m_isend = false;
}
};
#endif
#include "DataManager.h"
string Datamanager::GetHighFromFile()
{
ifstream fin("data.txt");
string name;
if (!fin)
{
ofstream fout("data.txt");//若沒有該檔案,建立一個
//return NULL;
}
do {
fin >> name;
fin >> m_highscore;
if (fin.fail())//如果檔案為空
{
//cout << "Data error!" << endl;
return "*the file is empty";
}
} while (!fin.eof());
fin.close();
return name;
}
void Datamanager::StoreHighScore(string name)
{
ofstream fout("data.txt");
if (!fout)
{
cerr << " file error!" << endl;
return;
}
fout << name << endl;
fout << m_curscore;
fout.close();
}
Datamanager* Datamanager::Instance()
{
static Datamanager instance(0);
return &instance;
}
最後是main函式,主要用於遊戲更個介面的切換:
#include <iostream>
#include <time.h>
#include "Snake.h"
#include "DataManager.h"
#include <string>
#define MYDATA Datamanager::Instance()
using namespace std;
static HANDLE handle; //控制檯控制代碼
static CONSOLE_SCREEN_BUFFER_INFO info; //控制檯資訊結構
enum OutPutState
{
MENU,
PLAYING,
END,
INSCRUCTION
};
int main() {
//field.clear();
handle = GetStdHandle(STD_OUTPUT_HANDLE);
//獲取相關資訊(主要是緩衝區大小)
GetConsoleScreenBufferInfo(handle, &info);
CONSOLE_CURSOR_INFO cursor; //游標結構
cursor.dwSize = 10;
cursor.bVisible = 0; //0為隱藏游標
SetConsoleCursorInfo(handle, &cursor);//設定隱藏游標函式
srand((unsigned)time(0));
OutPutState m_state = MENU;
while (1)
{
if (m_state == MENU)
{
cout << endl; cout << endl; cout << endl;
cout << " |WELECOME TO SNAKE| " << endl;
cout << " *****************************************************" << endl;
cout << " * *" << endl;
cout << " * press (1) to start *" << endl;
cout << " * press (2) for inscruction *" << endl;
cout << " * press (3) to quit *" << endl;
cout << " * *" << endl;
cout << " *****************************************************" << endl;
int c(0);
cin >> c;
if (c == 1)m_state = PLAYING;
if (c == 2)m_state = INSCRUCTION;
if (c == 3)exit(0);
system("cls");
}
if (m_state == PLAYING)
{
Food food(35, 15);
Snake snake(20, 10);
Field field(10, 5);
MYDATA->ReStart();
while (1)
{
snake.GetInput();
if (snake.CheckFood(food))
{
MYDATA->AddCurScore();
food.Clear(handle);
do
{
food.Reposition(field.GetFirstPos().GetX(), field.GetFirstPos().GetY());
} while (snake.CheckFoodInBody(food.GetPos()));//如果刷新出的新食物在蛇的身體上,重新重新整理
}
if (snake.CheckHeadInBody() ||
snake.CheckHeadInWall(field.GetFirstPos().GetX(), field.GetFirstPos().GetY()))
MYDATA->SetEnd(true);
if (MYDATA->IsEnd())
{
m_state = END;
break;
};
snake.Display(handle);
field.Display(handle);
food.Display(handle);
Sleep(250);
}
system("cls");
}
if (m_state == END)
{
string highname = MYDATA->GetHighFromFile();
if (highname=="*the file is empty"|| MYDATA->GetCurScore() > MYDATA->GetHighScore())
{
cout << endl; cout << endl; cout << endl;
cout << " GAME OVER " << endl;
cout << " *****************************************************" << endl;
cout << " * *" << endl;
cout << " * You broke the record !!! *" << endl;
cout << " * your score: " << MYDATA->GetCurScore()
<< " *" << endl;
cout << " * *" << endl;
cout << " * *" << endl;
cout << " *****************************************************" << endl;
cout << " please write your name:";
string name(" ");
cin >> name;
MYDATA->StoreHighScore(name);
cout << " *****************************************************" << endl;
cout << " * press (r) to play again *" << endl;
cout << " * press (e) to menu *" << endl;
cout << " *****************************************************" << endl;
}
else
{
cout << endl; cout << endl; cout << endl;
cout << " GAME OVER " << endl;
cout << " *****************************************************" << endl;
cout << " * *" << endl;
cout << " The record holder is :" << highname << " "
<< MYDATA->GetHighScore() << endl;
cout << " * your score: " << MYDATA->GetCurScore()
<< " *" << endl;
cout << " * press (r) to play again *" << endl;
cout << " * press (e) to menu *" << endl;
cout << " *****************************************************" << endl;
}
char c(' ');
cin >> c;
if (c == 'r')m_state = PLAYING;
if (c == 'e')m_state = MENU;
system("cls");
}
if (m_state == INSCRUCTION)
{
cout << endl; cout << endl; cout << endl;
cout << " ******************************INSTRUCTION****************************" << endl;
cout << " * 1.Use keyboard to control the direction of the snake *" << endl;
cout << " * 2.Eat Fruit to make your snake longer *" << endl;
cout << " * 3.Avoid hitting the boarder or yourself *" << endl;
cout << " * 4.One fruit will give you 1 point as score *" << endl;
cout << " * | press 's' to start | *" << endl;
cout << " *********************************************************************" << endl;
char c(' ');
cin >> c;
if (c == 's')m_state = PLAYING;
system("cls");
}
}
return 0;
}
遊戲畫面截圖:
蟹蟹觀看:)