貪喫蛇案例_c++

wall.h
#pragma once

#ifndef _WALL_HEAD
#define _WALL_HEAD

#include <iostream>
using namespace std;

class Wall
{
public:
	enum {
		ROW = 26 , 
		COL = 26
	};
	
	// 初始化牆壁
	void initWall();
	// 畫出強牆壁
	void drawWall();
	// 根據索引設置二維數組裏的內容
	void setWall(int x, int y, char c);
	// 根據索引獲取當前位置的符號
	char getWall(int x, int y);

private:
	char gameArray[ROW][COL];


};



#endif // !WALL


wall.cpp
#include "wall.h"

void Wall::initWall()
{
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			// 放牆壁
			if (i == 0 || j == 0 || i == ROW - 1 || j == COL - 1)
			{
				gameArray[i][j] = '*';
			}
			else
			{
				gameArray[i][j] = ' ';
			}
		}
	}
}

void Wall::drawWall()
{
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			cout << gameArray[i][j] << " ";
		}
		if (i == 5)
		{
			cout << "create by xiaomeng";
		}
		if (i == 6)
		{
			cout << "a:left";
		}
		if (i == 6)
		{
			cout << "a:left";
		}
		if (i == 7)
		{
			cout << "d:right";
		}
		if (i == 8)
		{
			cout << "w:ip";
		}
		if (i == 9)
		{
			cout << "s:down";
		}
		cout << endl;
		// cout << endl;
	}
}

void Wall::setWall(int x, int y, char c)
{
	gameArray[x][y] = c;
}

char Wall::getWall(int x, int y)
{
	return gameArray[x][y];
}

snake.h
#pragma once
#include <iostream>
#include "wall.h"
#include "food.h"
#include <Windows.h>
using namespace std;

class Snake
{
public:
	Snake(Wall & tmpWall, Food &food);

	enum {
		UP = 'w',
		DOWN = 's',
		LEFT = 'a',
		RIGHT = 'd'
	};

	// 節點
	struct Point
	{
		// 數據域
		int x;
		int y;
		// 指針域
		Point * next;
	};
	void initSnake();
	// 銷燬節點
	void destoryPonit();
	// 添加節點
	void addPonit(int x, int y);

	// 刪除節點  --刪除最後一個節點
	void delPoint();

	// 移動蛇的操作  -- 返回值代表移動是否成功
	bool move(char key);

	// 設定難度
	// 獲取刷屏時間
	int getSleepTime();
	// 獲取蛇的身段
	int countList();

	// 獲取分數
	int getScore();

	Point * pHead;	// 頭節點
	Wall &wall;
	Food &food;
	bool isRool;  // 是否碰到尾巴  -- 循環的標識
};

snake.cpp
#include "snake.h"


void gotoxy1(HANDLE hOut1, int x, int y)
{
	COORD pos;
	pos.X = x;	// 橫座標
	pos.Y = y;	// 縱座標
	SetConsoleCursorPosition(hOut1, pos);
}
HANDLE hOut1 = GetStdHandle(STD_OUTPUT_HANDLE);	// 定義顯示器句柄變量


Snake::Snake(Wall & tmpWall, Food &tmpFood):wall(tmpWall),food(tmpFood)  // 初始化 Snake 類裏面的wall
{
	pHead = NULL;
	isRool = false;
}

// 初始化蛇
void Snake::initSnake()
{
	destoryPonit();
	addPonit(5, 3);
	addPonit(5, 4);
	addPonit(5, 5);
}
// 銷燬所有節點
void Snake::destoryPonit()
{
	Point * pCur = pHead;
	while (pHead != NULL)
	{
		pCur = pHead->next;
		delete pHead;
		pHead = pCur;
	}
}

void Snake::addPonit(int x, int y)
{
	// 創建新節點
	Point * newPoint = new Point;
	newPoint->x = x;
	newPoint->y = y;
	newPoint->next = NULL;

	// 如果原來頭不爲空  改爲身子
	if (pHead != NULL)
	{
		wall.setWall(pHead->x, pHead->y, '=');
		gotoxy1(hOut1, pHead->y * 2, pHead->x);
		cout << "=";
	}
	newPoint->next = pHead;
	pHead = newPoint;	// 更新頭部
	wall.setWall(pHead->x, pHead->y, '@');
	gotoxy1(hOut1, pHead->y * 2, pHead->x);
	cout << "@";
}

// 刪除節點 - 刪除最後一個節點
void Snake::delPoint()
{
	// 兩個節點以上  纔去做刪除節點操作
	if (pHead == NULL || pHead->next == NULL)
	{
		return;
	}
	Point * pPre = pHead;
	Point * pCur = pHead->next;
	
	while (pCur->next != NULL)
	{
		pPre = pPre->next;
		pCur = pCur->next;
	}
	// 刪除尾節點
	wall.setWall(pCur->x, pCur->y, ' ');
	gotoxy1(hOut1, pCur->y * 2, pCur->x);
	cout << ' ';
	delete pCur;
	pCur = NULL;
	pPre->next = NULL;


}

bool Snake::move(char key)
{
	int x = pHead->x;
	int y = pHead->y;

	switch (key)
	{
	case UP:
		x--;
		break;
	case DOWN:
		x++;
		break;
	case LEFT:
		y--;
		break;
	case RIGHT:
		y++;
		break;
	default:
		break;
	}

	// 判斷 如果下一步碰到的是尾巴  不應該死亡
	Point * pCur = pHead->next;
	Point * pPre = pHead;
	while (pCur->next != NULL)
	{
		pPre = pPre->next;
		pCur = pCur->next;
	}
	if (pCur->x == x && pCur->y == y)
	{
		// 碰到尾巴的循環
		isRool = true;
	}
	else
	{
		// 判斷用戶到達位置是否成功
		if (wall.getWall(x, y) == '*' || wall.getWall(x, y) == '=')
		{
			addPonit(x, y);
			system("cls");
			wall.drawWall();
			cout << "得分 : " << getScore() << "分" << endl;
			cout << "GAME OVER !!!" << endl;
			return false;
		}
	}



	
	// 移動成功分兩種
	// 喫到食物   未喫到食物
	if (wall.getWall(x, y) == '#')
	{
		addPonit(x, y);
		// 重新設置食物
		food.setFood();
	}
	else
	{
		addPonit(x, y);
		delPoint();
		if (isRool == true)
		{
			// 重新繪製頭節點
			wall.setWall(x, y, '@');
			gotoxy1(hOut1, y * 2, x);
			cout << "@";
		}
	}
	return true;
}

int Snake::getSleepTime()
{
	int sleepTime = 0;
	int size = countList();
	if (size < 5)
	{
		sleepTime = 300;
	}
	else if (size >= 5 <= 9)
	{
		sleepTime = 200;
	}
	else
	{
		sleepTime = 100;
	}
	return sleepTime;
}

int Snake::countList()
{
	int size = 0;
	Point * curPoint = pHead;
	while (curPoint != NULL)
	{
		size++;
		curPoint = curPoint->next;
	}
	return size;
}

int Snake::getScore()
{
	int size = countList();
	int score = (size - 3) * 100;
	return score;
}



food.h
#pragma once
#include <iostream>
#include "wall.h"
#include <Windows.h>
using namespace std;

class Food
{
public:
	Food(Wall &tmpWall);
	// 設置食物
	void setFood();
	int foodX;
	int foodY;

	Wall & wall;

};
food.cpp
#include "food.h"


void gotoxy2(HANDLE hOut2, int x, int y)
{
	COORD pos;
	pos.X = x;	// 橫座標
	pos.Y = y;	// 縱座標
	SetConsoleCursorPosition(hOut2, pos);
}
HANDLE hOut2 = GetStdHandle(STD_OUTPUT_HANDLE);	// 定義顯示器句柄變量


Food::Food(Wall &tmpWall) :wall(tmpWall)
{

}

void Food::setFood()
{
	while (true)
	{
		// 隨機生成食物的
		foodX = rand() % (Wall::ROW - 2) + 1;
		foodY = rand() % (Wall::COL - 2) + 1;
		// 如果隨機的位置是蛇頭或者是蛇身  就重新生成隨機數
		if (wall.getWall(foodX, foodY) == ' ')
		{
			wall.setWall(foodX, foodY, '#');
			gotoxy2(hOut2, foodY * 2, foodX);
			cout << "#";
			break;
		}
	}
}

game.cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;

#include "wall.h"
#include "snake.h"
#include "food.h"
#include "ctime"
#include "conio.h"
#include <Windows.h>


void gotoxy(HANDLE hOut, int x, int y)
{
	COORD pos;
	pos.X = x;	// 橫座標
	pos.Y = y;	// 縱座標
	SetConsoleCursorPosition(hOut, pos);
}
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);	// 定義顯示器句柄變量

int main()
{

	// 添加隨機種子
	srand((unsigned int)time(NULL));

	// 是否死亡的標識
	bool isDead = false;

	char preKey = NULL;

	Wall wall;
	wall.initWall();
	wall.drawWall();  // initWall()  之後就需要 drawWall()
	

	// 測試
	/*wall.setWall(5, 4, '=');
	wall.setWall(5, 5, '=');
	wall.setWall(5, 6, '@');*/

	Food food(wall);
	food.setFood();

	Snake snake(wall, food);
	snake.initSnake();
	
	gotoxy(hOut, 0, Wall::ROW);
	cout << "得分 : " << snake.getScore() << "分" << endl;

	gotoxy(hOut, 10, 5);


	// 接收用戶輸入
	while (!isDead)
	{
		char key = _getch();

		// 判斷如果是第一次 按了左鍵  纔不能激活遊戲
		// 判斷上一次的移動方向
		if (preKey == NULL && key == snake.LEFT)
		{
			continue;
		}

		do
		{
			if (key == snake.UP || key == snake.DOWN || key == snake.LEFT || key == snake.RIGHT)
			{
				// 判斷本次的按鍵是否與上次衝突
				if (
					(key == snake.LEFT && preKey == snake.RIGHT) || (key == snake.RIGHT && preKey == snake.LEFT) ||
					(key == snake.UP && preKey == snake.DOWN) || (key == snake.DOWN && preKey == snake.UP)
					)
				{
					key = preKey;
				}
				else
				{
					preKey = key;  // 不是衝突按鍵  就直接更新按鍵
				}
				if (snake.move(key) == true)
				{
					// 移動成功
					// system("cls");
					// wall.drawWall();
					gotoxy(hOut, 0, Wall::ROW);
					cout << "得分 : " << snake.getScore() << "分" << endl;
					Sleep(snake.getSleepTime());
				}
				else
				{
					isDead = true;
					break;
				}
			}
			else
			{
				key = preKey;  // 強制將鎖霧按鍵變爲上一次移動的方向
			}
		} while (!_kbhit());  // _kbhit() 在沒有鍵盤輸入的時候  返回爲 0
	}
	

	system("pause");
	return EXIT_SUCCESS;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章