本文乃Siliphen原创,转载请注明出处

目录

游戏介绍

概述

游戏整体流程

游戏框架设计

主要流程控制类

本文项目的代码组织结构

构建游戏世界

数字方块

地图

 触摸手势识别

防触摸抖动

判断用户输入的方向

地图

任意大小的地图

初始化地图大小

地图绘制

合并和移动

合并和移动的逻辑

丝滑的合并和移动动画

本文的完整实现源码工程


游戏介绍

《2048》是一款曾经风靡全球的数字益智游戏。

目前(2023.08.14)在 App Store 的情况如下图:

关于这个游戏的更多情况可看看百度百科:百度百科-验证

概述

本文讲解用 Cocos Creator 实现经典《2048》的核心流程和算法。

Cocos Creator 版本:Cocos Creator 3.8.0

本文实现的游戏效果如下:

 

可以随意调整地图大小。可随意调整方块移动速度。

上图分别演示了 4 x 4 ,7 x 10 地图大小的效果。

可在这个地址运行体验下本文实现的版本:Cocos Creator | 2048

文本末尾给出完整实现的源码工程。

游戏整体流程

游戏执行一轮玩家操作的流程:等待玩家输入操作 -> 用户滑动屏幕 -> 移动数字方块 -> 合并方块 -> 空白地方随机出现一个数字方块 -> 等待玩家输入操作

以上流程是游戏玩家操作一次,游戏执行一轮的分解动作循环。

游戏通关条件:合成数字方块2048。

游戏失败条件:当整个棋盘都填满数字方块,且没有可以合并的方块。

游戏框架设计

主要流程控制类

从调用先后顺序开始依次如下:

类名

作用

UiTouch

处理用户触摸输入

Merge

处理移动、合并的逻辑和动画。

FlowRound.fillEntity()

在地图空白处随机生成一个数字方块。

FlowRound.judge()

判断输赢。

本文项目的代码组织结构

构建游戏世界

《2048》的游戏世界只有2个实体:数字方块、棋盘地图。

棋盘是数字方块的容器。后面的移动和合并算法,都是作用在棋盘上计算的。

数字方块

// 实体
export class Entity {// 实体所代表的数值public val : number ;// 表现public presentation = new EntityPresentation() ;}// 实体表现
export class EntityPresentation {public root : Node ;}

地图

地图数据本质是个二维数组。定义如下:

export class Map {// 单件public static ins : Map = null ;// 地图单元格public grid = new Array< Array< MapCell > >() ;// 格子宽高public size = new Size() ; // 表现public presentation = new MapPresentation() ;}// 地图表现
export class MapPresentation {// 根节点public root : Node ;}// 地图单元格
export class MapCell {// 单元格上的实体public entity : Entity = null ;// 单元格所在的局部空间的坐标public pos : Vec3 = null ;}

我们规定地图单元格(0,0)的位置在地图显示的左下角。x , y 的增长分别向右边和上边延伸。如下图:

 触摸手势识别

防触摸抖动

在触摸按下时记录按下的坐标,在触摸结束时用结束时的坐标减去按下时的坐标,得到一个向量。

判断这个向量的长度,大于某个数值后,就认为是有效的输入。

如果只是个很小的滑动,可能是抖动造成的,为了防止玩家误操作,可以丢弃这种输入。

判断用户输入的方向

用上一步减法得到的向量就可以判断用户操作的方向。

主要是用到 Math.atan2 这个系统函数。atan2 判断一个向量与 x 轴正方向的夹角,单位是弧度。

注意:atan2 的参数是 ( y , x ) , 不是( x , y ),y 是第一个参数。

不习惯使用弧度的话,可以转换成角度。

判断角度代码如下:

// 手势识别
export class GestureRecognition {// 返回:上左下右 1234 从上开始顺时针。0 无效方向public static exe( v : Vec2 ) : number {let rad = Math.atan2( v.y , v.x ) ;let degree = rad * ( 180 / Math.PI ) ;if( 45 < degree && degree < 135 ){return 1 ;} else if( -45 < degree && degree < 45  ){return 2 ;} else if( -135 < degree && degree < -45 ){return 3 ;}else if( 135 < degree && degree < 180 || -180 < degree && degree < -135 ){return 4 ;}// console.log( "度数:" + degree ) ;return 0 ;}}

地图

任意大小的地图

本文的实现,可设置任意地图大小。

如下图:

上图展示了这些尺寸的地图大小效果:3 x 3 , 5 x 5 , 6 x 4 , 7 x 10

不同地图尺寸对应不同的地图根结点缩放值。

要实现可指定任意大小的地图的前提是,动态绘制地图。

先初始化地图二维数组结构的大小,然后,地图绘制类再处理地图的绘制。

初始化地图大小

// 地图数据初始化
export class MapInit {public static exe( map : Map ) {map.presentation.root = find( "Canvas/Map" ) ;// 地图宽高let mapWidth = 3 ; let mapHeight = 3 ; map.size = new Size( mapWidth , mapHeight ) ;for( let y = 0 ; y < mapHeight ; ++y ) {let row = new Array< MapCell >( ) ;map.grid.push(row) ;for( let x = 0 ; x < mapWidth ; ++x ){let cell = new MapCell() ; row.push( cell ) ;} // end for} // end for}}

地图绘制

本文实现的中心对其的地图布局,地图的几何中心点与其父节点的原点重叠。

算法是,先算出整个地图的大小,然后宽高分别除以2,先算出 ( 0 , 0 ) 起始逻辑坐标单元格的位置。

先算出左下角的起始单元格的位置,后续可以统一处理其他单元格位置。仅仅是通过不断累加间隔就行。

地图绘制 具体实现查看源码工程的类 MapDraw

设置地图大小位置:MapInit.exe 函数

合并和移动

这个是2048的核心玩法实现,也是最难的部分。

合并和移动的逻辑

可以先算方块逻辑上的合并,后算方块逻辑上的移动。

也可以合并和移动合并在一起计算。

上下左右的合并和移动要分别处理。

这里列举用户向左( <- )滑动的处理算法,其他3个方向的以此类推。为了说明原理和简单起见以下为描述性伪代码。

// 一行行遍历地图。从左到右(->)
for( let y = 0 ; y < map.size.height ; ++y ) {for( let x = 0 ; x < map.size.width ; ++x ) {let cell = map.grid[ y ][ x ] ;// 如果单元格上没有实体,略过。因为我们只处理实体。不处理空格。if( cell.entity == null ) continue ;let cell2 = 向右(->)查找一个最近的实体所在的单元格。if( cell2 != null && cell2 和 cell 的实体数字相同 ){   // 这表示找到一个可以合并的实体2个实体合并,合并和的实体放在 cell 单元格的位置上。}以 cell 单元格为起点向左(<-)查找一个连续的空位的最右边的那个空位这个空位便是 cell 上的方块实体要移动到的位置。} // end for
} // end for

算法图示:

丝滑的合并和移动动画

如果只是按照上一步说的先在逻辑上计算合并和移动的结果,然后直接更新画面显示,会显得很生硬。

大部分的瞬间更新结果都会让画面显得生硬。好的做法是,有个滑动和合并的移动缓动动画。

加入动画后,流程就变成了:

所有的方块都会先移动到一边,然后进行合并,如果合并后留出了空位,需要再移动。保证移动后,中间不留空位。

这个流程需要对以上的逻辑处理进行改造。

具体实现查看源码工程的类 Merge

本文的完整实现源码工程

源码工程下载地址:Cocos Store

作者创作不易,您的支持让我创造出更多更好的作品。​:)

【 Cocos Creator 项目实战】系列文章链接:

【 Cocos Creator 项目实战】益智游戏《2048》

​​​​​​【Cocos Creator 项目实战 】消灭星星加强版

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/42453.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/42453.shtml
英文地址,请注明出处:http://en.pswp.cn/news/42453.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构----结构--线性结构--栈,队列

数据结构----结构–线性结构–栈&#xff0c;队列 一.栈&#xff1a;Stack 1.栈的特点&#xff1a; ​ 先进后出&#xff1a;FILO&#xff08;对一组数据有倒叙要求时可以用栈&#xff09; 2.栈的实现 顺序存储&#xff1a;数组实现&#xff1a; ​ 缺点&#xff1a;空间…

无涯教程-Perl - sysread函数

描述 该函数等效于C /操作系统函数read(),因为它绕过了诸如print,read和seek之类的函数所采用的缓冲系统,它仅应与相应的syswrite和sysseek函数一起使用。 它从FILEHANDLE中读取LENGTH个字节,并将输出放入SCALAR中。如果指定了OFFSET,则将数据从OFFSET字节写入SCALAR,从而有效…

IC流程中 DFT 学习笔记(2)

引言 DFT是ASIC芯片设计流程中不可或缺的环节。其主要目的是在芯片前端设计验证完成后插入一些诸如寄存器链等可供测试的逻辑&#xff0c;算是IC后端设计的范畴&#xff0c;属于结构测试而非功能测试。主要是在ASIC芯片流片完成后&#xff0c;通过这些已插入的逻辑&#xff0c…

手机照片误删怎么办,电脑照片误删怎么办怎么才能找回,EasyRecovery来帮您

手机照片误删怎么办&#xff0c;电脑照片误删怎么办怎么才能找回&#xff0c;EasyRecovery 2023来帮您&#xff01;&#xff01;&#xff01; EasyRecovery 2023是一款操作安全、价格便宜、用户自主操作的 数据恢复 方案&#xff0c;它支持从各种各样的 存储介质 恢复删除 或者…

Vue3.X 创建简单项目

一、环境安装与检查 首先&#xff0c;我们要确保我们安装了构建vue框架的环境&#xff0c;不会安装的请自行百度&#xff0c;有很多安装教程。检查环境 node -v # 如果没有安装nodejs请安装&#xff0c;安装教程自行百度 vue -V# 没有安装&#xff0c;请执行npm install -g v…

Cesium for unity 1.5.0使用注意事项

Cesium for Unity Quickstart – Cesium 1.Unity版本仅支持Unity2021.3.2f1以后版 2.仅支持 3D (URP)和3D (HDRP)渲染管线 3.如果Package Manager中不出现My Registries选项&#xff0c;请在 Edit > Project Settings...>Package Manager中重命名或删除重新添加Packag…

深入浅出PHP封装根据商品ID获取淘宝商品详情数据方法

要通过淘宝的API获取商品详情&#xff0c;您可以使用淘宝开放平台提供的接口来实现。以下是一种使用PHP编程语言实现的示例&#xff0c;展示如何通过淘宝开放平台API获取商品详情&#xff1a; 首先&#xff0c;确保您已注册成为淘宝开放平台的开发者&#xff0c;并创建一个应用…

【微服务实战】01-工程结构概览

文章目录 工程结构概览:定义应用分层及依赖关系1.应用分层2.定义Entity3.仓储层3.1 工作单元&#xff1a;事务管理3.2 仓储层 4.领域事件5.APIController最佳实践 工程结构概览:定义应用分层及依赖关系 1.应用分层 领域模型层基础设施层 ⇒ 仓储应用层 ⇒ Api、后台任务Job共…

TCP服务器实现—多进程版,多线程版,线程池版

目录 前言 1.存在的问题 2.多进程版 3.多线程版 4.线程池版 总结 前言 在上一篇文章中使用TCP协议实现了一个简单的服务器&#xff0c;可以用来服务端和客户端通信&#xff0c;但是之前的服务器存在一个问题&#xff0c;就是当有多个客户端连接服务器的时候&#xff0c;服…

002-Spring boot 自动配置相关分析

目录 自动配置 EnableAutoConfiguration开启自动配置读取配置提前过滤自动配置配置包 AutoConfigurationPackage 自动配置 EnableAutoConfiguration 开启自动配置 在Spring 启动类上的 SpringBootApplication 中有 EnableAutoConfiguration 读取配置 Import(AutoConfigurat…

后端返回图片,前端接收并显示的解决方案

后端图片数据返回 后端通过二进制流的形式&#xff0c;写入response中 controller层 /*** 获取签到二维码*/GetMapping("/sign-up-pict")public void signUpPict(Long id, Long semId, HttpServletResponse response) throws NoSuchAlgorithmException {signUpServ…

musl libc ldso 动态加载研究笔记:01

前言 musl 是一个轻量级的标准C库&#xff0c;建立在系统调用之上&#xff0c;可以认为是【用户态】的C 库&#xff0c;与 glibc 或者 uClibc 属于同一类。 基于 musl 的 gcc 工具链包括交叉编译工具链&#xff0c;可以用于编译 Linux 或者其他的操作系统&#xff0c;如当前 L…

深入解析 MyBatis 中的 <foreach> 标签:优雅处理批量操作与动态 SQL

在当今的Java应用程序开发中&#xff0c;数据库操作是一个不可或缺的部分。MyBatis作为一款颇受欢迎的持久层框架&#xff0c;为我们提供了一种优雅而高效的方式来管理数据库操作。在MyBatis的众多特性中&#xff0c;<foreach>标签无疑是一个强大的工具&#xff0c;它使得…

构建可远程访问的企业内部论坛

文章目录 前言1.cpolar、PHPStudy2.Discuz3.打开PHPStudy&#xff0c;安装网页论坛所需软件4.进行网页运行环境的构建5.运行Discuz网页程序6.使用cpolar建立穿透内网的数据隧道&#xff0c;发布到公网7.对云端保留的空白数据隧道进行配置8.Discuz论坛搭建完毕 前言 企业在发展…

Python中import模块导入的实现原理

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 Python中import模块导入的实现原理 什么是模块import搜索路径import导入模块的原理图书推荐 专栏&…

京东门详一码多端探索与实践 | 京东云技术团队

本文主要讲述京东门详业务在支撑过程中遇到的困境&#xff0c;面对问题我们在效率提升、质量保障等方向的探索和实践&#xff0c;在此将实践过程中问题解决的思路和方案与大家一起分享&#xff0c;也希望能给大家带来一些新的启发 一、背景 1.1、京东门详介绍 1.1.1、京东门…

VB+SQL上机考试系统设计与实现

摘 要 随着计算机技术的迅猛发展,学校教学和管理的信息化发展也有长足的进步,这就要求各个环节都均衡发展,从软硬件双方面把学校建设成一流的信息管理、教育教学的平台。本文设计开发的考试管理系统也是其中重要的一个方面。该系统本着减轻教师工作负担、提高工作效率、优…

六、分组背包

六、分组背包 题记算法题目代码 题记 一个旅行者有一个最多能装V公斤的背包和有N件物品&#xff0c;它们的重量分别是W[1]&#xff0c;W[2]&#xff0c;…,W[n]&#xff0c;它们的价值分别为C[1],C[2],…,C[n]。这些物品被划分为若干组&#xff0c;每组中的物品互相冲突&#…

【es6】函数参数设置默认值

1、es6之前的函数参数默认值写法 1.1、使用短路或||的写法 当y为空时&#xff0c;y判断为false &#xff0c;走||右边的&#xff0c;所以y world;当y不为空时&#xff0c;y判断为true&#xff0c;不需要再运行||右边的&#xff0c;所以 y y function log(x, y) {y y || W…

数据的深海潜行:数据湖、数据仓库与数据湖库之间的微妙关系

导言&#xff1a;数据的重要性与存储挑战 在这个信息爆炸的时代&#xff0c;数据已经成为企业的核心资产&#xff0c;而如何高效、安全、便捷地存储这些数据&#xff0c;更是每个组织面临的重大挑战。 数据作为组织的核心资产 数据在过去的几十年里从一个辅助工具演变成企业的…