❤️学姐教我做游戏,一做便是十四载❤️
Posted 英雄哪里出来
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了❤️学姐教我做游戏,一做便是十四载❤️相关的知识,希望对你有一定的参考价值。
文章目录
一、前言
该文将通过对话的形式,介绍一个童年的回忆 —— 推箱子 游戏。
这个故事发生在 ❤️学姐教我十道题搞定C语言❤️ 后的三个月,我开始和大部分大学生一样沉迷游戏,这时候学姐为了助我脱坑,竟然要求教我做游戏,也就是因为这么一教,让我入了游戏坑,一做就是十四年!那是我逝去的青春!
在此也劝诫现在在校打算出来找工作的大学生,千万要选一个你认为能够坚持一辈子做下去的行业,不然中途想转行真的很难!除非你能够接受重新学习和平薪或者降薪切换!
二、预备知识
1、游戏介绍
- 然而,实际最后我们是用控制台实现的,也就是这样……
2、基础 c/c++ 语法
- 本文涉及的代码语法均为 C/C++,包含但不限于:
1)一些基本的输入输出、循环迭代、递归语法;
2)一些 STL 队列 queue 的接口;
3)一些控制台的显示接口;
- 这里澄清一点,学姐那时候也是半吊子,她一直以为 C 和 C++ 是一个语言,我在这里澄清下,C++ 完美继承了 C语言的语法,但是这的确是两个思想完全不同的语言! 当然,那时候我的哪知道这么多……
3、数学基础排列组合
- 主要是涉及到状态的计算,需要用到组合数;只需要了解
n
n
n 个元素中取
m
m
m 个元素的方案数为:
C n m = n ! m ! ( n − m ) ! C_n^m = \\frac {n!}{m!(n-m)!} Cnm=m!(n−m)!n!
4、深度、广度优先搜索
- 深度、广度优先搜索作为最主要的图论遍历算法,有着广泛的应用呢;
- 游戏中的寻路算法就是基于广搜的 A*;
- 可以大致浏览一下以下文章,有一个初步了解:❤️深度优先搜索❤️ 和 ❤️广度优先搜索❤️。
5、哈希表
- 哈希表主要用于广搜的时候进行状态标记,避免搜索重复状态,将原本 多维 的状态压缩到 一维 后进行哈希;
- 我之前也有介绍过哈希表,具体可以参见这篇文章:❤️哈希表底层详解❤️。
三、算法分析
1、数据表示
- 通过 ASCII 符号来表示不同的游戏块:
□(空心方块)代表空地
■(实心方块)代表障碍物
●(实心圆)代表箱子
◎(同心圆)代表目标位置
♂(男性符号)代表推箱子的人
- 将 游戏关卡 表示成 ASCII 如图三-1-1所示:
- 当然,在实际编码中,每个格子是用 C/C++ 中的枚举来表示的,代码如下:
enum BlockType {
BT_EMPTY = 0, // 空地
BT_WALL = 1, // 障碍物、墙
BT_BOX = 2, // 箱子
BT_TARGET = 3, // 目标位置
BT_MAN = 4, // 推箱子的人
BT_MAX
};
// 这些都是宽字符,占用2个字节,加上字符串末尾 '\\0',总共3个字节
const char BlockSign[BT_MAX][3] = { "□", "■", "●", "◎", "♂" };
- 这里的数字代表了游戏中实际每个方块的含义,就是上面学姐提到的数据,而显示层进行渲染的时候其实也是通过不同的数据来显示成不同的画面,可以是 ASCII 字符,也可以是图片,甚至还可以是 3D 的。如图三-1-2所示:
图三-1-2 - 为了将输入数据转换成我们可以处理的数据,需要提供转换接口如下,对于给定的输入遍历寻找对应匹配的枚举:
BlockType convertCharToBlockType(char chigh, char clow) {
BlockType tp = BlockType::BT_EMPTY;
for (int i = BlockType::BT_EMPTY; i < BlockType::BT_MAX; ++i) {
if (BlockSign[i][0] == chigh && BlockSign[i][1] == clow) {
tp = (BlockType)i;
break;
}
}
return tp;
}
2、算法设计
1)算法方向确定
- 首先,一定是用搜索算法;
- 其次,尽量肯定是要求最少步数把所有箱子推到目标位置,也就是求最短路问题,那么就是一个很明显的 广度优先搜索 问题(当然,也可以用 迭代加深 逐步扩大解空间来求解,今天就只介绍广搜吧)。
2)状态表示
- 算法确定后,就需要确定如何进行状态表示了;
- 算法的焦点一定在这个 “小人” 身上,但是光用 “小人” 的位置来表示状态肯定是不够的;如图三-2-1所示,两个地图关卡的小人的位置是相同的,但是不能作为同一种情况来考虑,因为箱子的位置不同,所以最终状态表示也不同。
- 于是,我们发现,状态和所有能够动的对象(人、箱子)有关系,那么可以把所有人和箱子的位置联合起来作为状态表示的依据,即: ( m a n P o s , b o x P o s 1 , b o x P o s 2 , . . . , b o x P o s 2 ) (manPos, boxPos_1,boxPos_2, ..., boxPos_2) (manPos,boxPos1,boxPos2,...,boxPos2)
3)状态降维
-
假设一个 R × C R \\times C R×C 的地图上,我们令 “小人” 的位置为 ( m x , m y ) (m_x,m_y) (mx,my), n n n 个箱子的位置分别为 ( b 1 x , b 1 y ) , ( b 2 x , b 2 y ) , . . . , ( b n x , b n y ) (b1_x,b1_y),(b2_x,b2_y),..., (bn_x,bn_y) (b1x,b1y),(b2x,b2y),...,(bnx,bny) ,并且所有 x x x 坐标都是在 [ 0 , R ) [0, R) [0,R) 范围内,所有 y y y 坐标都是在 [ 0 , C ) [0, C) [0,C) 范围内;
-
为了简化问题, 我们将位置再进行一次转换,把二维转换成一维,即:
( m x , m y ) = m p o s = m x × C + m y ( b 1 x , b 1 y ) = b 1 p o s = b 1 x × C + b 1 y . . . ( b n x , b n y ) = b n p o s = b n x × C + b n y (m_x,m_y) = m_{pos} = m_x \\times C + m_y \\\\ (b1_x,b1_y) = b1_{pos} = b1_x \\times C + b1_y \\\\ ...\\\\ (bn_x,bn_y) = bn_{pos} = bn_x \\times C + bn_y (mx,my)=mpos=mx×C+my(b1x,b1y)=b1pos=b1x×C+b1y...(bnx,bny)=bnpos=bnx×C+bny -
将这 n + 1 n+1 n+1 个对象的位置看成是 K K K 进制的每一位,就可以编码成一个数字 x x x 了(其中 K = R × C K = R \\times C K=R×C );
x = m p o s × K 0 + b 1 p o s × K 1 + b 2 p o s × K 2 + . . . + b n p o s × K n x = m_{pos} \\times K^0 + b1_{pos} \\times K^1 + b2_{pos} \\times K^2 + ... + bn_{pos} \\times K^n x=mpos×K0+b1pos×K1+b2pos×K2+...+bn以上是关于❤️学姐教我做游戏,一做便是十四载❤️的主要内容,如果未能解决你的问题,请参考以下文章
❤️学姐说她用 8 行代码写了 8 个算法(上)❤️(推荐收藏)