2048游戏之——C++与控制台

本文详细介绍了使用C++在控制台实现2048游戏的框架设计,包括Map、Event、GameController类的设计,以及游戏核心算法的实现,如随机生成、矩阵操作和游戏状态管理。通过枚举定义游戏状态,并在main函数中实现游戏循环状态机。文章还探讨了随机生成的两种方法,讨论了不同方法的优缺点。
摘要由CSDN通过智能技术生成

概要

我是Kpurek,首次在CSDN写blog,请多指教。

本文讲解我如何根据既定规则,设计2048游戏的框架结构,包括类设计、游戏流程设计、算法设计。因为游戏比较简单,设计起来思路容易理清,用控制台实现的话效果也不会很差(能玩)
最初版的效果:(还没有优化随机生成方法)
控制台效果

本项目开源,GitHub地址

需求

1、显示4*4数字矩阵,左对齐
2、键盘输入,检测方向键,上下左右对应2048界面的上向左右滑动。
3、能够控制帧率,并尽量使界面流畅、舒适
4、游戏结束时暂停游戏

因此根据这些简单的需求,我构思出了以下的游戏框架:

1、核心部分:
存储游戏的信息,包括方块的值等信息;
实现游戏的核心算法,包括移动、合并方块以及判断游戏状态。
用于将矩阵对象渲染到屏幕上;
能够接受消息,例如键盘输入信息;
发送消息,例如游戏结束;

2、控制部分:
控制游戏流程,包括接收消息、处理消息等功能。

3、消息部分:
用于核心组件和控制组件的通信;
检测键盘事件;
处理游戏状态信息;
这个部分主要起到解耦作用,方便更改游戏的输入方式、状态信息。

4、还需要一个游戏循环状态机
我将它放在了main函数中。

因此,根据以上的框架,我设计出以下几个类:

设计

一、Map类

class Map
{
   
public:

	构造
	Map();
	
	//析构,用于RAII的自动回收
	~Map();
	
	随机生成方块
	void RandomCreate();

	//渲染矩阵
	void Draw()const;

	//检测、更新事件
	void Update(Event& ev);

	//返回矩阵大小
	size_t size()const;

private:

	//向上操作
	void Move_UP()//向下
	void Move_DOWN()//向左
	void Move_LEFT()//向右
	void Move_RIGHT()//是否游戏结束
	bool isOver()private:

	//Map的矩阵
	int** Mapper;

	//每次随机生成的方块数量不能超过2:
	const int AdditionNumber = 2;

	//矩阵大小
	size_t m_size;
};

二、Event类

class Event //  
{
   
public:

	//  由键盘事件获取消息
	void CheckKeyEvent();

	//原本应该有的push和get方法(公有),游戏对象能够发送消息
	//但本游戏几乎不需要,因此省略
	/*
	void pushEvent();
	vector<STATE> getEvent()const;
	*/

	
public:
    
    使用vector容器搭建的数组,作为消息队列:
	vector<STATE>state;
};

三、GameController类

class GameController
{
   
public:

	//构造
	GameController();
	
public:

	//清空画面
	void clear();
	
	//渲染
	void draw(Map const& map);

	//控制
	void display();

	//设置帧率
	void SetFPS(int const& fps);

	//获取事件
	void PullEvent(Event const& ev);
	
	//窗口是否为打开状态
	bool isOpen()const;
	
private:

	//退出游戏
	void exit();

	//游戏结束
	void GameOver();

private:

	//是否打开
	bool isOpening;

	//是否结束
	bool isGameOver;

	//是否操作了矩阵
	bool isMoved;

	//每一帧的开始事件
	time_t StartTime;

	//帧率
	int FPS;

	//帧间间隔
	time_t FrameTime;
};

各个类的成员、方法,都已经做了详细的注释;
可能有一点容易混淆:
Map类和GameController类都有一个名为draw的方法,一个是Draw一个是draw。要注意,这两个方法不止是名字有区别:Map的Draw是被GameController内部调用的,不会在我们的游戏循环内被直接调用。
也就是这样一个过程:
游戏循环(状态机)—调用—>GameController.draw()—调用—>Map.Draw()
那么说到状态,我使用了一个非常简单但使用的方法来定义游戏的状态——枚举。
枚举定义在了以下的总头文件中:

四、total.h

#pragma once
#include<iostream>
#include<conio.h>
#include<ctime>
#include<cassert>
#include<vector>

using namespace std;

各种宏
//ESC的ASCII
#define ESC_ASC 27
//方向键的前字符ASCII
#define DIRECTION_ASC 224
//方向键后字符ASCII
#define UP_ASC 72
#define DOWN_ASC 80
#define LEFT_ASC 75
#define RIGHT_ASC 77

//游戏公共事件的枚举类
enum class STATE
{
   
	//游戏结束事件
	GAME_OVER 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值