手把手教你企业级游戏项目开发,2048小游戏(附源码+设计文稿)
文/IT可达鸭
图/IT可达鸭、网络
相信很多人在学习编程或者在工作中,不可避免地会阅读其他的人的代码。一份优秀的源码,除了代码逻辑清晰,还配有相应的注释。
学会阅读源码,是一个优秀程序员必备的技能。当然,源码的阅读与理解是有难度,特别是对于优化后的源码,为了执行效率,必定会使得代码更加难以阅读。
所以源码配备设计文档,有助理解源码。至少,我还是初学者的时候,特别渴望有这样一份文档。所以,我写了这份文档,时刻提醒自己。
首先声明,2048游戏的源码并不是我首创。我是参考了几份比较好的源码,针对一些晦涩的代码做了算法示意图,同时也改进部分代码的逻辑。
例如:改进随机在棋盘中生成2或者4的逻辑、部分显示在不同机型的适配(windows、mac)、针对一些常见的报错信息做了相应的解决方案等等。
《2048》是一款比较流行的数字游戏,最早于2014年3月20日发行。原版2048首先在GitHub上发布,原作者是Gabriele Cirulli,后被移植到各个平台。这款游戏是基于《1024》和《小3传奇》的玩法开发而成的新型数字游戏。
这款游戏的玩法很简单,每次可以选择上下左右滑动,每滑动一次,所有的数字方块都会往滑动的方向靠拢,系统也会在空白的地方乱数出现一个数字方块,相同数字的方块在靠拢、相撞时会相加。不断的叠加最终拼凑出2048这个数字就算成功。
python版本: 3.6.0
编辑器: pycharm
项目所需要的环境安装包:
curses: 命令行界面,输入字符回显与隐藏
itertools: 二维数组迭代工具
random: 生成随机数、在指定列表中随机获取一个元素
windows:在命令行中运行,python 2048_game.py,(pycharm的命令行tab下运行也可以,文章最后有介绍);
mac: 直接在pycharm下运行即可。
1 移动逻辑
用户进行一次左移操作,首先矩阵中的所有数字逐行向左非零的位置移动,其次是向左合并,最后再进行逐行向左非零的位置移动。这三个步骤结合起来,为用户的一个左移操作。
矩阵数字移动图如上图,相关代码如下图。
有了左移操作,相应就有右移操作、上移操作、下移操作。为了简化代码,这里使用了矩阵变化操作配合左移操作来实现四个方向的操作。
那么矩阵的转置和反转的操作是怎样的?接下来介绍矩阵的运算。
2 矩阵运算
如上图,先看红色的箭头,指示矩阵转置、矩阵反转后的数字位置变化。
再看蓝色箭头,在原矩阵进行左移操作,就相当于矩阵转置后进行上移操作。同样的,左移操作配合矩阵反转、配合矩阵反转+转置,会形成相应的右移操作、下移操作。
其矩阵的转置操作、反转操作代码如下图示例。
有了这些操作之后,我们应该怎么设计这些操作,使得代码简洁而且便于理解?
这里使用了设计模式中的策略模式。
3 设计模式–策略模式
什么是策略模式?
简单的说,就是在有多种算法相似的情况下(四个方位的移动操作),使用 if…else… 所带来的复杂和难以维护。所以使用同一个接口,在代码运行时去调用不同的方法或对象。
策略模式的优点:1. 算法可以自由切换; 2. 避免使用多重判断条件; 3. 扩展性良好。
策略模式的缺点:1. 策略方法或策略类会增多;2. 所有策略类都需要对外暴露。
使用场景: 1. 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为; 2. 一个系统需要动态地在几种算法中选择一种; 3. 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
下面以一个四则运算来演示策略模式的运用:
4 curses 模块的使用
curses 模块的主要用法,命令行界面,输入字符回显与隐藏。
这里梳理了使用的方式: 1. curses.initsr() 启用curses模块; 2. while 循环体不断渲染界面;3. stdscr.clear() 每次循环前清屏;4. 清屏后, stdsrc.addstr() 设置回显字符串; 5. stdscr.getch() 等待用户输入,这里是一个断点,只要用户没有进行输入操作,就会一直停留在这里。
程序分为四个模块, 配置信息模块、主逻辑模块、判断模块、算法模块。
配置信息模块: 棋盘大小(4X4)、键盘控制的定义(上下左右的按键)、胜利条件;
主逻辑模块: 初始化、棋盘重置、随机在棋盘位置生成数字、画一个棋盘、移动策略接口、获取用户操作、游戏主逻辑;
判断模块:判断是否赢了、判断是否结束、判断是否可以移动;
算法模块:四个方向移动算法、数字合并算法、矩阵转置、矩阵反转;
具体细分如下思维导图:
提前编写代码框架是一个良好的习惯,这样在开发的时候就比较容易把控项目整体进度。
开发过程中,如果被某个细节难住,可以使用标签 #todo 来标记它。先去写其他简单模块,等有时间再回过头来解决这个难点。
节选一个判断模块代码框架(cube 表示矩阵的浅拷贝):
大体框架如下图(与源码分开,单独一个代码文件,主要用来查看):
以下分四个模块,主要根据难易程度进行排序,先从简单模块的代码入手。
- 分模块编写-配置信息
- 分模块编写-判断模块
判断是否赢,是否游戏结束:
判断是否可以向左移动
判断是否可以向右、向上、向下移动:利用矩阵操作(转置与反转)配合左移判断。
判断用户的选择是否可以移动(这里也用到了策略模式)
- 分模块编写-算法部分
移动的基础操作(左移)
四个方向移动:根据上面的矩阵操作示意图可以知道,左移的基本操作,配合矩阵操作,就能衍生出其他三个方向的移动操作。
数字合并(向左合并)
矩阵转置
矩阵反转
- 分模块编写-主逻辑部分
初始化:
棋盘重置:
随机在棋盘生成数字:
画一个棋盘:
移动策略:根据用户的选择,在程序运行时自动选择相应的移动算法。
获取用户操作:
主逻辑:
- windows 环境下可能出现的问题:
- 报错 ModuleNotFoundError: No module named \’_curses\’
解决方案:
下载一个:curses-2.2.1+utf8-cp36-cp36m-win_amd64.whl 文件
使用pip 进行安装: pip install curses-2.2.1+utf8-cp36-cp36m-win_amd64.whl
(其中cp36 表示对应python版本为3.6, amd64 对应的是64位系统)
- 报错 Redirection is not supported.
解决方案:如图所示
- 显示的内容不对
解决方案:
进入Terminal 控制台,使用命令启动运行代码: python 2048_game.py
4. 报错 _curses.error: addwstr() returned ERR
解决方案:
把terminal 这个框放大就行,原因是因为 curses 需要合适的界面大小进行渲染游戏界面,界面太小会导致渲染失败。
- Mac 环境下可能出现的问题:
我在Mac环境下,直接就可以运行了,好像还没遇到问题。
- 游戏演示
终于看到运行结果了
至此,2048的游戏就设计完成了。当然里面有很多东西可以优化,例如排行榜、文件存储、双人对战、分值计算加入时间因素、接入H5页面等等。我记得产品经理曾说过这么一句话:先保证80%的功能可以用,再去考虑优化问题。
网上有很多2048的小游戏,但唯独,自己写出来的游戏,才是最香的。
如果有疑问想获取源码,可以关注后,在后台私信我,回复:python2048。 我把源码发你。持续关注\”IT可达鸭\”,每天除了分享有趣Python源码,还会介绍NLP算法。最后,感谢大家的阅读,祝大家工作生活愉快!
个人网站集成js小游戏《圈小猫》教程及源码
今天在某网站浏览帖子的时候,发现帖子被删除了,然后弹出了404页面,页面上集成了一个小游戏,小游戏长什么样子呢?看下面这个图!
查看小游戏源码,发现这个小游戏完全是由JavaScript编写的,因此,我们可以将这个小游戏轻松集成到我们的个人网站中,或者个人博客中,甚至你可以发布到你的QQ空间等地方!那么怎么做呢?
查看网页源代码,我们可以发现,这个小游戏最主要的两个js文件库来源于
这两个文件。那么我们直接在网站上面查看资源,找到这两个库文件,然后保存到本地
当然,你也可以直接引用网站中的https地址资源,无需保存这两个文件。
我们找到了js文件(或者js路径),那么怎么用呢?
假如我们的个人博客是使用的wordpress搭建好的,那么我们就可以直接在博客后台里面发布这个小游戏了。
进入博客后台,点击文章发布,在正文内容中输入以下代码
代码解释:
如图中所示,我们引用了上面第一步当中的两个js文件,如果你将这两个JS文件放到你自己的服务器上,那么更改图中的src地址即可,你没有服务器的话,你就直接使用代码中的地址即可
这一行代码中的参数说明,分别是
w-11-横向格子数;
h-11-竖向格子数;
r-20圆的半径像素;他们分别对应的是游戏界面中的蓝色背景点数量以及整体画布的大小!
根据自己页面大小自主调整上面的三个值,可以达到最佳效果,手机上展示的效果图如下
看完后是不是非常简单,自己动手试一试吧!
手把手教你实现一个高性能的抽抽乐H5小游戏(含源码)
那我们就来学点有意思的,用几十行代码来实现一个高性能的抽奖小游戏.也基于此,来巩固我们的javascript基础,以及前端一些基本算法的应用.
- 防抖函数的应用
- 用css实现九宫格布局
- 生成n维环形坐标的算法
- 如何实现环形随机轨道运动函数
- 实现加速度动画
- 性能分析与优化
由于目前已有很多方案可以实现九宫格抽奖动画,比如使用动态active实现边框动画,用随机算法和定时器设置在何处停止等等. 为了进一步提高性能,本文介绍的方法,将使用坐标法,将操作dom的成本降低,完全由js实现滑块的路径的计算,滑块元素采用绝对定位,让其脱离文档流,避免其他元素的重绘等等,最后点击按钮我们会使用防抖函数来避免频繁执行函数,造成不必要的性能损失.
为了让大家更加熟悉dom结构,这里我就不用js动态生成了.如下html结构:
九宫格布局我们使用flex来实现,核心代码如下:
由上可知容器box采用flex布局,要想让flex子元素换行,我们这里要设置flex-wrap: wrap;此时九宫格布局就实现了. 滑块采用绝对定位,至于具体如何去沿着环形轨道运动,请继续看下文介绍.
由上图我们可以知道,一个九宫格的4条边,可以用以上8个坐标收尾连接起来,那么我们可以基于这个规律.来生成环形坐标集合.代码如下:
如果是单位坐标,那么cell为1,cell设计的目的就位为了和现实的元素相结合,我们可以手动设置单元格的宽度来实现不同大小的n维环形坐标集.
由抽奖动画分析可知,我们滑块运动的轨迹,其实就是环形坐标集合,所以我们只要让滑块的顶点(默认左上角)沿着环形坐标集合一步步变化就好了.
这样就能实现我们的滑块按照九宫格边框运动的动画了,当然以上函数只是基本的动画, 还没有实现在随机位置停止, 以及滑块的加速度运动,这块需要一定的技巧和js基础知识比如闭包.
加速度运动其实很简单,比如每转过一圈将setTimeout的延迟时间改变即可.代码如下:
随机停止这块主要是用了Math.random这个API, 我们在最后一圈的时候, 根据随机返回的数值来决定何时停止,这里我们在函数内部实现随机数值,完整代码如下:
防抖函数实现:
那么我们点击时,代码应该长这样:
在文章发布之后,有热心的小伙伴们提出了几个建议,综合如下:
- 抽奖动画结束后提供回调来通知页面以便处理其他逻辑
- 处理多次点击时,虽然加了防抖,但是用户在动画没结束时点击了开始按钮,又会执行动画导致动画越来越快,发生混乱.
综合以上问题,我在之前基础上做了进一步扩展,来解决以上提到的问题.
- 添加动画结束时回调:
- 处理多次点击时,虽然加了防抖,但是用户在动画没结束时点击了开始按钮,又会执行动画导致动画越来越快,发生混乱.
谢谢各位认真的建议,继续优化吧.
该实现方式的好处是支持n维环形坐标的抽奖,基于坐标法的应用还有很多,尤其是游戏和图形领域,在实现过程中一定要考虑性能和可扩展性,这样我们就可以在不同场景使用同一套方法论,岂不乐哉?本文完整源码我会放在github上,欢迎交流学习~
github地址:https://github.com/MrXujiang?tab=repositories
欢迎在公众号《趣谈前端》加入我们一起学习讨论,共同探索前端的边界。
本文作者及来源:Renderbus瑞云渲染农场https://www.renderbus.com
文章为作者独立观点不代本网立场,未经允许不得转载。