C++实战小项目贪吃蛇网游化框架搭建2

上篇记录了main函数、game类和food类的设计,本片继续记录Snake类的设计。

四、Snake类的设计

同样从Game类中对Snake类的需求出发,Snake类用一个deque保存一系列点,每次循环需要根据其方向完成点的更新、方向更新、食物是否与蛇身重合等等一些列功能:

#pragma once
#include <deque>
#include "Point.h"
#include <conio.h>

class Snake
{
public:
	Snake(initializer_list<Point> li = { {20,20},{20,21},{20,22} }, char c = 'd') :body(li), direction(c) { bodysize = body.size(); };
	void paintbody(HANDLE);
	bool hititself()
	{
		Point head = body.front();
		for (auto k = --body.end(); k != (body.begin() + 2); k--)
			if (head == *k)
				return true;
		return false;
	}
	bool overlap(const Point &p)//判断刷新的食物是否与蛇身重合
	{
		for (auto k = --body.end(); k != (body.begin() ); k--)
			if (p == *k)
				return true;
		return false;
	}

	bool senddata(int &sock);

	bool recvdata(int &sock);

	void painthead(HANDLE hand)
	{
		body.front().paint(hand);
	}

	void tailclear(HANDLE hand)
	{
		body.back().clear(hand);
		body.pop_back();
	}

	const Point& Head()
	{
		return body.front();
	}

	bool changedirection(char &k);

	void update();

	void reset();

	bool press(char &k)
	{
		return k == direction;
	}
private:
	deque<Point> body;
	char direction;
	size_t bodysize;
};

inline
bool Snake::changedirection(char &k)
{
	if (k == 'A' || k == 'S' || k == 'W' || k == 'D')
		k = tolower(k);
	if (k == 'a' || k == 's' || k == 'w' || k == 'd') {
		if ((k + direction) == 234 || (k + direction) == 197 || k == direction)
			return false;
		direction = k;
		return true;
	}
	return false;
}

inline
void Snake::update()
{
	switch (direction) {
	case 'w':
		body.emplace_front(body.front().xx(), body.front().yy() - 1);
		break;
	case 's':
		body.emplace_front(body.front().xx(), body.front().yy() + 1);
		break;
	case 'a':
		body.emplace_front(body.front().xx() - 2, body.front().yy());
		break;
	case 'd':
		body.emplace_front(body.front().xx() + 2, body.front().yy());
		break;
	}
}

蛇身绘制方面,因为整个程序中food的绘制颜色及符号与蛇身一致,因此在吃上食物后不需进行任何操作,而未吃上食物则只需在头部多绘制一个点并抹掉尾部的点即可。因为需要在Game中判定是否撞墙,因此定义一个返回头部数据的接口;reset完成数据的重置。
###五、Point类的设计
  point类基本上就是一个pair加上了几个接口,需要能够完成point的绘制及清除、数据的返回即可:

#pragma once
#include <Windows.h>
#include <iostream>

using namespace std;

class Point
{
public:
	Point(int a=0,int b=0):x(a),y(b){}
	void paint(HANDLE hand)
	{
		SetOutputposition(x, y, hand);
		cout << "■";
	}
	void clear(HANDLE hand)
	{
		SetOutputposition(x, y, hand);
		cout << "  ";
	}
	int& xx() {
		return x;
	}
	const int& xx() const
	{
		return x;
	}
	int& yy() {
		return y;
	}
	const int &yy() const
	{
		return y;
	}
	bool operator==(const Point& point) const
	{
		if (x == point.x&&y == point.y)
			return true;
		else
			return false;
	}
private:
	int x;
	int y;
};

###六、公用数据和函数

static HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE);

static bool chekans(const int &sock)
{
	char buff[4];
	int n;
	while ((n = recv(sock, buff, 4, 0)) < 0)//可将此处单独顶一个为一个Recv函数代替原函数
	{
		if (errno == EINTR)
			continue;
		else
			return false;
	}
	buff[n] = 0;
	return (strcmp("LWB", buff) ? false : true);
}

static void SetOutputposition(int x, int y, HANDLE hand)
{
	COORD position;
	position.X = x;
	position.Y = y;
	SetConsoleCursorPosition(hand, position);
}

static int n;

chekanks用于check服务器在成功接受数据后返回的消息,SetOutputposition则用于设置光标位置,这个函数在程序中使用很多,主要是对SetConsoleCursorPosition进行了封装。n则用于一些函数的返回值检测。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值