我是靠谱客的博主 谨慎外套,最近开发中收集的这篇文章主要介绍【C++】2048游戏系列---功能模块第三稿【添加新数】一、判断一下是否要添加二、添加新数逻辑三、整合到上篇的代码中四、运行效果展示结语:,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

2048游戏系列---功能模块第三稿【添加新数】

(更新中……)
参考博客:https://blog.csdn.net/qq_39151563/article/details/104283217
由于放在一篇会导致篇幅太长,所以分成了几个部分。
(可能有个10篇吧=.=)

前几篇:
2048游戏系列—总览篇
2048游戏系列—功能模块第一稿【矩阵操作】
2048游戏系列—功能模块第二稿【键盘输入】
本篇介绍如何根据条件生成新的数字

一、判断一下是否要添加

  1. 在我们添加新数之前,要判断一下是否要添加,例如下列矩阵 grid 向上滑动时,移动前后并没有变化,因此也不需要添加新数:

    int grid[4][4] = {
    {0,1,2,3},
    {0,0,0,0},
    {0,0,0,0},
    {0,0,0,0}
    };
    
  2. 如何判断移动是否有效,这提供两种思路:
    2.1将 grid 移动前后的每个元素进行比较:如果每个元素都一样,则可以判断移动无效,反之,只要有一个元素不同,则移动有效。(此逻辑在主函数中实现

    2.2.在移动过程中判断:如果移动了数字,则移动有效,反之,移动无效。(此逻辑在 Move() 函数中实现

二、添加新数逻辑

在知道移动有效后,添加新数的逻辑如图:添加新数流程图

2.1 找到一个空位

  1. 如果 EmptyBlock = 0,已经没有空位了
  2. 利用 EGE 的 random 函数
random(n);//返回一个 0 ~ n-1 的整数

假设 grid 如下:

int grid[4][4] = {
{0,1,2,3},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0}
};

EmptyBlock应为 16-3=13,所以我们有13个位置可选择,random(EmptyBlock)+1正好随机返回 1~13 中的一个整数

2.2 代码

(小知识点:多维数组在计算机存储中是映射成一维的)

//添加新数
//有很多调试注释可以删掉
void addnum(int n)
{
while(n--)//添加n个
{
EmptyBlock = CalculateEmpty();
//cout << "addnum Test" << endl;
if(EmptyBlock<=0)
{
//cout << "addnum EmptyBlock = " << EmptyBlock << endl;
//cout << "addnum Test1" << endl;
return;
}
int cnt = random(EmptyBlock)+1;//随机得到一个空格数以内的数
//cout << "找到第" << cnt << "个空位" << endl;
//cout << "cnt = " << cnt << endl;
int *p = &grid[0][0]-1;//记录矩阵首地址前一个 ,因为后面的 p 在找到时还会 ++
//cout << "n = "<< n <<endl;
for(int i=0; i<4&&cnt; i++)
for(int j=0; j<4&&cnt; j++)
{
if(grid[i][j]==0 && cnt)//如果有空格并且cnt有效
{
//cout << "cnt = " << cnt << endl;
cnt--;//找到一个划一个
}
p++;//p 指向下一个再进行判断
}
//循环结束时 p 指向我们之前随机指定的空格
*p = (random(10)==0)?2:1;// 0.1 的概率为2,0.9 的概率为1
//cout << "插入成功" << endl;
//*p = (random(10)==0)+1;//这样写也可以
EmptyBlock--;
}
}

测试代码:添加新数测试代码

测试结果(成功在随机位置添加了2个数):添加新数测试结果

三、整合到上篇的代码中

3.1 程序的小改动

  1. 矩阵置0

    int grid[4][4] = {0};//矩阵置0
    
  2. ShowInfo()打印信息函数

    //显示信息-将一些要打印的信息集中
    void ShowInfo()
    {
    cout << "dir = " << dir << endl;
    cout<< "EmptyBlock = " << CalculateEmpty() << endl;
    PrintGrid();
    }
    
  3. 判断移动是否有效(用的第一种思路)


bool flag = false;
//移动标志位
int tempGrid[4][4];
//暂存数组
int i,j;
for(i=0;i<4;i++)
for(j=0;j<4;j++)
tempGrid[i][j] = grid[i][j];
//
cout << "tempGrid[4][4] = " << endl;
//
for(i=0; i<4; i++)
//
{
//
for(j=0; j<4; j++)
//
cout << tempGrid[i][j] << " ";
//
cout << endl;
//
}
//
cout << endl;
Move(dir);//移动
//比较
for(i=0; i<4; i++)
for(j=0; j<4; j++)
if(grid[i][j]!=tempGrid[i][j])
{
flag = true;
break;
}
if(flag)
{
addnum(1);
cout << "有效移动" << endl;
}
//else	cout << "无效移动" << endl;
ShowInfo();
dir = -1;//将 dir 置为无效,否则控制台会一直刷新

3.2 所有代码!

#include <iostream>
#include "graphics.h"
using namespace std;
//测试矩阵
int grid[4][4] = {0
//
{1,2,3,4},
//
{4,5,6,7},
//
{7,8,9,10},
//
{1,1,1,0}
};
int EmptyBlock = 4 ;	//空格数
int dir = -1;
// 0-左,1-上,2-右,3-下
//打印函数
void PrintGrid()
{
for(int i=0; i<4; i++)
{
for(int j=0; j<4; j++)
cout << grid[i][j] << " ";
cout << endl;
}
cout << endl;
}
//计算空格函数
int CalculateEmpty()
{
int cnt = 0;
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
if(grid[i][j]==0)
cnt++;
return cnt;
}
//显示信息
void ShowInfo()
{
cout << "dir = " << dir << endl;
cout<< "EmptyBlock = " << CalculateEmpty() << endl;
cout << "grid[4][4] = " << endl;
PrintGrid();
}
//移动函数
static int x0[4] = {0, 0, 3, 0};
static int y0[4] = {0, 0, 0, 3};
static int firstOffset[4][2]
= {{1,0},{0,1},{-1,0},{0,-1}};
static int secondOffset[4][2] = {{0,1},{1,0},{0,1} ,{1,0}};
void Move(int dir)
{
//bool moved = false;
if(dir==-1)	return;
int tx, ty;
int t1x, t1y;
int t2x, t2y;
for(int i=0; i<4; i++)
{
tx = x0[dir] + i*secondOffset[dir][0];
ty = y0[dir] + i*secondOffset[dir][1];
//cout << "(" << tx << ", " << ty << ")" << endl;
t1x = tx;
t1y = ty;
t2x = tx + firstOffset[dir][0];
t2y = ty + firstOffset[dir][1];
for( ;t2x>=0&&t2x<=3&&t2y>=0&&t2y<=3; t2x+=firstOffset[dir][0],t2y+=firstOffset[dir][1])
{
if(grid[t2y][t2x]!=0)
{
if(grid[t1y][t1x]==0)
{
grid[t1y][t1x] = grid[t2y][t2x];
grid[t2y][t2x] = 0;
// moved = true;
}
else if(grid[t1y][t1x]==grid[t2y][t2x])
{
grid[t1y][t1x]++;
grid[t2y][t2x] = 0;
t1x += firstOffset[dir][0];
t1y += firstOffset[dir][1];
// moved = true;
}
else if(t1x+firstOffset[dir][0]!=t2x||t1y+firstOffset[dir][1]!=t2y)
{
grid[t1y+firstOffset[dir][1]][t1x+firstOffset[dir][0]] = grid[t2y][t2x];
grid[t2y][t2x] = 0;
t1x += firstOffset[dir][0];
t1y += firstOffset[dir][1];
//cout << "Move Test" << endl;
// moved = true;
}
else
{
t1x += firstOffset[dir][0];
t1y += firstOffset[dir][1];
}
}
}
}
//return moved;
}
//添加新数
void addnum(int n)
{
while(n--)//添加n个
{
EmptyBlock = CalculateEmpty();
if(EmptyBlock<=0)
{
//cout << "addnum EmptyBlock = " << EmptyBlock << endl;
//cout << "addnum Test1" << endl;
return;
}
int cnt = random(EmptyBlock)+1;//随机得到一个空格数以内的数
//cout << "找到第" << cnt << "个空位" << endl;
//cout << "cnt = " << cnt << endl;
int *p = &grid[0][0]-1;//记录矩阵首地址前一个 ,因为后面的 p 在找到时还会 ++
//cout << "n = "<< n <<endl;
for(int i=0; i<4&&cnt; i++)
for(int j=0; j<4&&cnt; j++)
{
if(grid[i][j]==0 && cnt)//如果有空格并且cnt有效
{
//cout << "cnt = " << cnt << endl;
cnt--;//找到一个划一个
}
p++;//p 指向下一个再进行判断
}
//循环结束时 p 指向我们之前随机指定的空格
*p = (random(10)==0)?2:1;// 0.1 的概率为2,0.9 的概率为1
//cout << "插入成功" << endl;
//*p = (random(10)==0)+1;//这样写也可以
EmptyBlock--;
}
}
int main()
{
initgraph(200, 200);
addnum(2); //在随机2个位置添加新数
ShowInfo();
for ( ; is_run(); delay_fps(60) )
{
cleardevice();
// todo: 逻辑更新(数据更新)
//按键检测
while(kbmsg())
{
key_msg keyMsg = getkey();
if(keyMsg.msg == key_msg_down)
{
switch(keyMsg.key)
{
case 'A':case key_left
: dir = 0; break;//左
case 'W':case key_up
: dir = 1; break;//上
case 'D':case key_right : dir = 2; break;//右
case 'S':case key_down	: dir = 3; break;//下
}
}
}
// todo: 图形更新
if(dir!=-1)
{
system("cls");
switch(dir)
{
case
0: cout << "按下了 A/左 键" << endl; break;//左
case
1: cout << "按下了 W/上 键" << endl; break;//上
case
2: cout << "按下了 D/右 键" << endl; break;//右
case
3: cout << "按下了 S/下 键" << endl; break;//下
}
bool flag = false;
//移动标志位
int tempGrid[4][4];
//暂存数组
int i,j;
for(i=0;i<4;i++)
for(j=0;j<4;j++)
tempGrid[i][j] = grid[i][j];
{
//cout << "tempGrid[4][4] = " << endl;
//
for(i=0; i<4; i++)
//
{
//
for(j=0; j<4; j++)
//
cout << tempGrid[i][j] << " ";
//
cout << endl;
//
}
//
cout << endl;
}
Move(dir);
//比较
for(i=0; i<4; i++)
for(j=0; j<4; j++)
if(grid[i][j]!=tempGrid[i][j])
{
flag = true;
break;
}
//if(flag) cout << "是否移动:" <<	flag << endl;
if(flag)
{
cout << "有效移动" << endl;
addnum(1);
}
else	cout << "无效移动" << endl;
ShowInfo();
dir = -1;//将 dir 置为无效,否则控制台会一直刷新
}
}
getch();
closegraph();
return 0;
}

四、运行效果展示048-具体功能实现三稿-添加新数


结语:

到这里这个游戏的“内核”部分就差不多结束了,看上去像是一个2048了,但是它太丑了……=。=
下面小结一下功能实现部分:

  1. 移动逻辑
  2. 键盘输入控制
  3. 添加新数字

接下来的稿子是写优化部分(暂定以下几点):

  1. 将数字用图形替代
  2. 加入计分
  3. 类封装

冲鸭

最后

以上就是谨慎外套为你收集整理的【C++】2048游戏系列---功能模块第三稿【添加新数】一、判断一下是否要添加二、添加新数逻辑三、整合到上篇的代码中四、运行效果展示结语:的全部内容,希望文章能够帮你解决【C++】2048游戏系列---功能模块第三稿【添加新数】一、判断一下是否要添加二、添加新数逻辑三、整合到上篇的代码中四、运行效果展示结语:所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(49)

评论列表共有 0 条评论

立即
投稿
返回
顶部