【贪吃蛇,C++实现】,由简单游戏开始学习OOP,的编程新手
2015-05-07 16:07
986 查看
{我又来写黑历史了}....
以前学习C语言的时候,老是感觉只能做点数学题什么的(事实程序就是由许多道数学题构成)。
然后最近两个月开始学习C++,接触到OOP,然后感觉视界扩大了(误)特别是最近突然发现好像可以写些小游戏了(大误)。
前天埋头几个小时写了个贪吃蛇,而且成功运行了,但是回头看看代码,虽然使用了类,但还是C语言那套路....类被我当做一个单纯的函数集来使用。于是花了点时间重新构思了下,写下了这篇文章。
第一个类:坐标类
这个类要求
1,有两个变量分别代表X轴和Y轴,这样我们能把光标移动到任意一点。
2,蛇是否会撞到墙壁,就是坐标是否会重叠,所以这个类的对象要能相互比较。
3,构造函数和赋值也是必须的。
头文件:Coordinate.h
#ifndef _COORDINATE_H
#define _COORDINATE_H
class Coordinate
{
public:
Coordinate(int X, int Y)
{
x = X;
y = Y;
}
Coordinate() { }
bool operator == ( const Coordinate &a )
{
return a.x == x&&a.y == y;
}
bool operator !=( const Coordinate &a )
{
return !(a.x == x&&a.y == y);
}
Coordinate &operator=( const Coordinate &a )
{
x = a.x;
y = a.y;
return *this;
}
int x, y;
};
#endif
然后就能用windows的API函数来构建一个函数,这个函数接受一个坐标类的对象,并且把光标移动到该坐标。
头文件:GotoXY.h
#ifndef _GOTOXY_H
#define _GOTOXY_H
#include "Coordinate.h"
#include <Windows.h>
void gotoxy(Coordinate a)
{
COORD local;
local.X = a.x;
local.Y = a.y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), local);
}
#endif
第二个类:蛇类
用一种数据结构来储存坐标类的对象,作为蛇的身体。
这里用了STL模板库的<list>
原因,能迭代访问元素,增加删除头尾元素方便。
类要求:
1,用<list>创建舍得身体
2,要有一个坐标类的对象,存储这条蛇前进到下一个位置的坐标
3,一个在下一个位置增加蛇头的函数(打印字符),一个删除蛇尾的函数(打印空格字符)。
(蛇向前一步,增加蛇头一次,删除蛇尾一次。蛇迟到食物身体变长,只增加蛇头,不删蛇尾)
4,构造函数初始化蛇的身体为坐标(0,0)到(3,0)四格
头文件:Snake.h
#include <iostream>
#include <list>
#include "GotoXY.h"
using namespace std;
class Snake
{
public:
Snake();
void AddHead( );
void SubtractTail( );
Coordinate next;
list <Coordinate> snakebody;
};
Snake::Snake()
{
next = Coordinate(3, 0);
for (int n = 0, m = 0; n < 4; n++)
{
snakebody.push_front(Coordinate(n, m));
}
}
void Snake::AddHead( )
{
gotoxy(next);
cout << "#";
snakebody.push_front(next);
}
void Snake::SubtractTail( )
{
gotoxy(snakebody.back( ));
cout << " ";
snakebody.pop_back( );
}
第三个类:裁判类
功能:
1,用GetAsyncKeyState接受键盘输入信息,改变蛇的方向。
2,根据舍得方向改变蛇下一个位置的坐标。
3,根据下一个位置的坐标,检测下一个位置是否越界或撞上自己的身体,判断是否死亡。
4,能改变分数(吃到食物),并且根据分数多少增加等级(加快速度),然后打印分数和等级。
5,除分数,等级外,还有四个变量,分别为上下左右方向,要符合GetAsyncKeyState的虚拟键码
头文件:Judgement.h
#include <iomanip>
#include "Snake.h"
/*边界*/
const int confineX = 20;
const int confineY = 10;
/*分数和等级坐标*/
const Coordinate _score(confineX + 5, 4);
const Coordinate _level(confineX + 5, 7);
const int Level[6] = { 0, 400, 300, 200, 100, 50 };//每个等级对应前进时间间隔(毫秒)
const int Score[6] = { 0, 10, 30, 60, 100, 150 };//每个等级对应的分数数值
class Judge
{
public:
Judge(int l, int u, int r, int d) :level(1), score(0),
left(l), up(u), right(r), down(d)
{
direction = r;
}
bool Death(Snake &snake);//判断是否死亡
bool ChangeScore( );//改变分数
void ChangeDriection(Snake &snake);//改变蛇的前进方向
void ChangeNext(Snake &snake);//改变蛇下一个位置坐标
int direction;
int level;
int score;
int left, up, right, down;
};
bool Judge::Death(Snake &snake)
{
ChangeNext(snake);
if (snake.next.x >= confineX || snake.next.x < 0)
{
return true;
}
else if (snake.next.y >= confineY || snake.next.y < 0)
{
return true;
}
else
{
for (list<Coordinate>::iterator i = snake.snakebody.begin( );
i != snake.snakebody.cend( ); i++)
{
if (( *i ) == snake.next)
{
return true;
}
}
}
return false;
}
bool Judge::ChangeScore( )
{
score += level;
gotoxy(_score);
cout << setw(5) << score;
if (score >= Score[level])
{
level++;
if (level > 5)
{
return true;
}
gotoxy(_level);
cout << setw(5) << level;
}
return false;
}
void Judge::ChangeDriection(Snake &snake)
{
if (direction == left || direction == right)
{
if (GetAsyncKeyState(up))
{
direction = up;
}
else if (GetAsyncKeyState(down))
{
direction = down;
}
}
else
{
if (GetAsyncKeyState(left))
{
direction = left;
}
else if (GetAsyncKeyState(right))
{
direction = right;
}
}
}
void Judge::ChangeNext(Snake &snake)
{
ChangeDriection(snake);
if (direction == up)
{
snake.next.y--;
}
else if (direction == left)
{
snake.next.x--;
}
else if (direction == down)
{
snake.next.y++;
}
else if (direction == right)
{
snake.next.x++;
}
}
有人说,为什么这么麻烦,非要分开蛇类和裁判类,集合为一个类不就行了吗。
我是这样想的,这样能方便弄出双人游戏,在屏幕上打印两个框,然后弄两条蛇和两个裁判,就能和小伙伴一起玩耍了www。不知是否可行呢.....
最后一个类:控制整个游戏
1,有一个蛇类的对象,和一个裁判类的对象。
2,能制造食物。
3,打印游戏开始前界面。
4,执行游戏流程(游戏开始,循环(判断是否死亡,判断是否吃到食物,蛇前进一步))
头文件:Manage.h
#include "Judgement.h"
#include <ctime>
enum Direction
{
LEFT = 37,
UP = 38,
RIGHT = 39,
DOWN = 40
};
class Manage
{
public:
Manage() :food(confineX / 2, confineY / 2),
B(LEFT,UP,RIGHT,DOWN){ }
void DrawConfine( );
void Begin( );
void MakeFood( );
private:
Snake A;
Judge B;
Coordinate food;
};
void Manage::DrawConfine( )
{
int x, y;
for (y = confineY, x = 0; x <= confineX; x++)
{
gotoxy(Coordinate(x, y));
cout << "-";
}
for (x = confineX, y = 0; y <= confineY; y++)
{
gotoxy(Coordinate(x, y));
cout << "|";
}
for (int n = 0, m = 0; n < 4; n++)
{
gotoxy(Coordinate(n, m));
cout << "#";
}
gotoxy(Coordinate(confineX + 5, 3));
cout << "Score:";
gotoxy(_score);
cout << setw(5) << B.score;
gotoxy(Coordinate(confineX + 5, 6));
cout << "Level:";
gotoxy(_level);
cout << setw(5) << B.level;
gotoxy(Coordinate(confineX / 2, confineY / 2));
cout << "*";
}
void Manage::Begin( )
{
while (!B.Death(A))
{
if (food == A.next)
{
if (B.ChangeScore( ))
{
break;
}
A.AddHead( );
MakeFood( );
}
else
{
A.AddHead( );
A.SubtractTail( );
}
Sleep(Level[B.level]);
}
}
void Manage::MakeFood( )
{
while (1)
{
bool flag = true;
Coordinate f = Coordinate(rand( ) % confineX, rand( ) % confineY);
for (list<Coordinate>::iterator i = A.snakebody.begin( );
i != A.snakebody.cend( ); i++)
{
if (( *i ) == f)
{
flag = false;
break;
}
}
if (flag)
{
food = f;
gotoxy(f);
cout << "*";
break;
}
}
}
然后最后就是源文件了
Snake!!.cpp
#include "Management.h"
int main( )
{
srand(time(NULL));
Manage game;
game.DrawConfine( );
game.Begin( );
}
ctrl+F5,开始游戏吧~~~~
PS:
最后:
其实写这篇文章是为了,能在以后(或许一年,或许几个月)回头看的时候,能感受到自己的进步。
祝大家生活愉快!
以前学习C语言的时候,老是感觉只能做点数学题什么的(事实程序就是由许多道数学题构成)。
然后最近两个月开始学习C++,接触到OOP,然后感觉视界扩大了(误)特别是最近突然发现好像可以写些小游戏了(大误)。
前天埋头几个小时写了个贪吃蛇,而且成功运行了,但是回头看看代码,虽然使用了类,但还是C语言那套路....类被我当做一个单纯的函数集来使用。于是花了点时间重新构思了下,写下了这篇文章。
第一个类:坐标类
这个类要求
1,有两个变量分别代表X轴和Y轴,这样我们能把光标移动到任意一点。
2,蛇是否会撞到墙壁,就是坐标是否会重叠,所以这个类的对象要能相互比较。
3,构造函数和赋值也是必须的。
头文件:Coordinate.h
#ifndef _COORDINATE_H
#define _COORDINATE_H
class Coordinate
{
public:
Coordinate(int X, int Y)
{
x = X;
y = Y;
}
Coordinate() { }
bool operator == ( const Coordinate &a )
{
return a.x == x&&a.y == y;
}
bool operator !=( const Coordinate &a )
{
return !(a.x == x&&a.y == y);
}
Coordinate &operator=( const Coordinate &a )
{
x = a.x;
y = a.y;
return *this;
}
int x, y;
};
#endif
然后就能用windows的API函数来构建一个函数,这个函数接受一个坐标类的对象,并且把光标移动到该坐标。
头文件:GotoXY.h
#ifndef _GOTOXY_H
#define _GOTOXY_H
#include "Coordinate.h"
#include <Windows.h>
void gotoxy(Coordinate a)
{
COORD local;
local.X = a.x;
local.Y = a.y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), local);
}
#endif
第二个类:蛇类
用一种数据结构来储存坐标类的对象,作为蛇的身体。
这里用了STL模板库的<list>
原因,能迭代访问元素,增加删除头尾元素方便。
类要求:
1,用<list>创建舍得身体
2,要有一个坐标类的对象,存储这条蛇前进到下一个位置的坐标
3,一个在下一个位置增加蛇头的函数(打印字符),一个删除蛇尾的函数(打印空格字符)。
(蛇向前一步,增加蛇头一次,删除蛇尾一次。蛇迟到食物身体变长,只增加蛇头,不删蛇尾)
4,构造函数初始化蛇的身体为坐标(0,0)到(3,0)四格
头文件:Snake.h
#include <iostream>
#include <list>
#include "GotoXY.h"
using namespace std;
class Snake
{
public:
Snake();
void AddHead( );
void SubtractTail( );
Coordinate next;
list <Coordinate> snakebody;
};
Snake::Snake()
{
next = Coordinate(3, 0);
for (int n = 0, m = 0; n < 4; n++)
{
snakebody.push_front(Coordinate(n, m));
}
}
void Snake::AddHead( )
{
gotoxy(next);
cout << "#";
snakebody.push_front(next);
}
void Snake::SubtractTail( )
{
gotoxy(snakebody.back( ));
cout << " ";
snakebody.pop_back( );
}
第三个类:裁判类
功能:
1,用GetAsyncKeyState接受键盘输入信息,改变蛇的方向。
2,根据舍得方向改变蛇下一个位置的坐标。
3,根据下一个位置的坐标,检测下一个位置是否越界或撞上自己的身体,判断是否死亡。
4,能改变分数(吃到食物),并且根据分数多少增加等级(加快速度),然后打印分数和等级。
5,除分数,等级外,还有四个变量,分别为上下左右方向,要符合GetAsyncKeyState的虚拟键码
头文件:Judgement.h
#include <iomanip>
#include "Snake.h"
/*边界*/
const int confineX = 20;
const int confineY = 10;
/*分数和等级坐标*/
const Coordinate _score(confineX + 5, 4);
const Coordinate _level(confineX + 5, 7);
const int Level[6] = { 0, 400, 300, 200, 100, 50 };//每个等级对应前进时间间隔(毫秒)
const int Score[6] = { 0, 10, 30, 60, 100, 150 };//每个等级对应的分数数值
class Judge
{
public:
Judge(int l, int u, int r, int d) :level(1), score(0),
left(l), up(u), right(r), down(d)
{
direction = r;
}
bool Death(Snake &snake);//判断是否死亡
bool ChangeScore( );//改变分数
void ChangeDriection(Snake &snake);//改变蛇的前进方向
void ChangeNext(Snake &snake);//改变蛇下一个位置坐标
int direction;
int level;
int score;
int left, up, right, down;
};
bool Judge::Death(Snake &snake)
{
ChangeNext(snake);
if (snake.next.x >= confineX || snake.next.x < 0)
{
return true;
}
else if (snake.next.y >= confineY || snake.next.y < 0)
{
return true;
}
else
{
for (list<Coordinate>::iterator i = snake.snakebody.begin( );
i != snake.snakebody.cend( ); i++)
{
if (( *i ) == snake.next)
{
return true;
}
}
}
return false;
}
bool Judge::ChangeScore( )
{
score += level;
gotoxy(_score);
cout << setw(5) << score;
if (score >= Score[level])
{
level++;
if (level > 5)
{
return true;
}
gotoxy(_level);
cout << setw(5) << level;
}
return false;
}
void Judge::ChangeDriection(Snake &snake)
{
if (direction == left || direction == right)
{
if (GetAsyncKeyState(up))
{
direction = up;
}
else if (GetAsyncKeyState(down))
{
direction = down;
}
}
else
{
if (GetAsyncKeyState(left))
{
direction = left;
}
else if (GetAsyncKeyState(right))
{
direction = right;
}
}
}
void Judge::ChangeNext(Snake &snake)
{
ChangeDriection(snake);
if (direction == up)
{
snake.next.y--;
}
else if (direction == left)
{
snake.next.x--;
}
else if (direction == down)
{
snake.next.y++;
}
else if (direction == right)
{
snake.next.x++;
}
}
有人说,为什么这么麻烦,非要分开蛇类和裁判类,集合为一个类不就行了吗。
我是这样想的,这样能方便弄出双人游戏,在屏幕上打印两个框,然后弄两条蛇和两个裁判,就能和小伙伴一起玩耍了www。不知是否可行呢.....
最后一个类:控制整个游戏
1,有一个蛇类的对象,和一个裁判类的对象。
2,能制造食物。
3,打印游戏开始前界面。
4,执行游戏流程(游戏开始,循环(判断是否死亡,判断是否吃到食物,蛇前进一步))
头文件:Manage.h
#include "Judgement.h"
#include <ctime>
enum Direction
{
LEFT = 37,
UP = 38,
RIGHT = 39,
DOWN = 40
};
class Manage
{
public:
Manage() :food(confineX / 2, confineY / 2),
B(LEFT,UP,RIGHT,DOWN){ }
void DrawConfine( );
void Begin( );
void MakeFood( );
private:
Snake A;
Judge B;
Coordinate food;
};
void Manage::DrawConfine( )
{
int x, y;
for (y = confineY, x = 0; x <= confineX; x++)
{
gotoxy(Coordinate(x, y));
cout << "-";
}
for (x = confineX, y = 0; y <= confineY; y++)
{
gotoxy(Coordinate(x, y));
cout << "|";
}
for (int n = 0, m = 0; n < 4; n++)
{
gotoxy(Coordinate(n, m));
cout << "#";
}
gotoxy(Coordinate(confineX + 5, 3));
cout << "Score:";
gotoxy(_score);
cout << setw(5) << B.score;
gotoxy(Coordinate(confineX + 5, 6));
cout << "Level:";
gotoxy(_level);
cout << setw(5) << B.level;
gotoxy(Coordinate(confineX / 2, confineY / 2));
cout << "*";
}
void Manage::Begin( )
{
while (!B.Death(A))
{
if (food == A.next)
{
if (B.ChangeScore( ))
{
break;
}
A.AddHead( );
MakeFood( );
}
else
{
A.AddHead( );
A.SubtractTail( );
}
Sleep(Level[B.level]);
}
}
void Manage::MakeFood( )
{
while (1)
{
bool flag = true;
Coordinate f = Coordinate(rand( ) % confineX, rand( ) % confineY);
for (list<Coordinate>::iterator i = A.snakebody.begin( );
i != A.snakebody.cend( ); i++)
{
if (( *i ) == f)
{
flag = false;
break;
}
}
if (flag)
{
food = f;
gotoxy(f);
cout << "*";
break;
}
}
}
然后最后就是源文件了
Snake!!.cpp
#include "Management.h"
int main( )
{
srand(time(NULL));
Manage game;
game.DrawConfine( );
game.Begin( );
}
ctrl+F5,开始游戏吧~~~~
PS:
最后:
其实写这篇文章是为了,能在以后(或许一年,或许几个月)回头看的时候,能感受到自己的进步。
祝大家生活愉快!
相关文章推荐
- 回归游戏的世界,简单图形编程学习的开始
- java GUI编程-贪吃蛇游戏简单实现
- java GUI编程-贪吃蛇游戏简单实现
- Java GUI编程之贪吃蛇游戏简单实现方法【附demo源码下载】
- 用C/C++实现较完整贪吃蛇游戏
- 利用unity实现简单的贪吃蛇游戏
- [Java] 【源码】新手初探java网络编程——socket接口实现简单的客户机/服务器程序
- C++类方法实现简单的贪吃蛇游戏
- 雷鸣的游戏人生(六) --- 如何开始学习编程?
- TensorFlow深度学习新手教程:TensorFlow实现简单的卷积网络
- C++简单实现贪吃蛇小游戏(console)
- JavaScript实现一个简单的贪吃蛇游戏
- Windows编程 从消息窗口到基本窗口 游戏循环窗口框架的简单实现
- 【Unity3D游戏开发学习笔记】(七)上帝之眼—第三人称摄像机的简单实现(跟随视角,自由视角)
- 【C++学习】GPU编程的简单学习
- 【C++游戏】2048的实现和简单AI
- VS下用C++实现的简单3D射击游戏(附游戏文件与源工程代码)
- 网络编程学习笔记二(实现一个基于简单TCP的用户注册程序)
- [学习操练]C++智能指针类的简单实现(类模板实现)
- C++简单学习(Part3_lecture 12)(多线程、Web编程)