Cocos Creator 只谈实战系列—成语游戏篇

H5线体验链接:

  • H5关卡编辑:http://game.ixuexie.com/idiomEditor
  • H5成语游戏:http://game.ixuexie.com/idiomGame

1

数据对象

上一篇主要分享了 成语游戏的关卡编辑器实现,经过了关卡编辑器的开发,我们大致理清了成语游戏关键的数据结构和对象关系:

  1. 词条基本数据:对应 IdiomData.js,描述成语词库里的一条原始数据,被成语对象引用;
  2. 成语对象:对应 Idiom.js,我们还发现,描述关卡中编辑好的每一条成语,同时会记录成语所占用的格子;
  3. 格子对象:对应 Grid.js,描述编辑区每个格子的状态与行为,如格子被使用,可从格子引用到成语对象;
  4. 关卡对象:对应 Level.js,关卡对象组织了格子和成语对象,并且负责对刷成语和换成语/删成语/去字/保存加载等。

在编辑器开发过程中,我们已经实现了上面4个核心对象,而这些源码文件都可以直接复用到游戏项目,因为它们的数据结构和算法是完全一致的,只是游戏项目中,对象的表现需要做更精细化的处理。

接下来,我们主要分享游戏部分的实现重点。

2

成语界面布局

成语区域是 9X9 的格子布局,我们制作了一个格子Prefab, 一次性创建81个实例将背景区域铺满。这样的好处是我们不需要在每次关卡加载时去创建新实例和销毁,只需要根据每个关卡的数据去复用格子对象,

控制和刷新每个格子的状态即可, 如果我们将显示控制条件关闭,看下面这张图就清楚了:

格子Prefab:

下方填字区域也同样复用Grid 预设,遍历关卡中的成语对象,将带空格属性的字创建为填字对象:

for (let j = 0; j < idiom.grids.length; j++) {
    //创建下方可选格子
    if (idiom.grids[j].isSpaceGrid && this.isInBottomSelGrids(idiom.grids[j].gridId) === false) {
        let selGrid = cc.instantiate(this.bottomGridPrefab);
        let gridComponent = selGrid.getComponent("Grid");
        //格子设置为填字模式
        gridComponent.setSelectMode(true);
        gridComponent.setChar(idiom.grids[j].char);
        gridComponent.gridId = idiom.grids[j].gridId;
        this.bottomSelGrids.push(selGrid);
    }
}

//填字格子需打乱顺序再addChild
this.bottomSelGrids.sort(() => {
    return Math.random() > 0.5 ? -1 : 1;
});

3

填词算法

填词逻辑触发放在 Grid 的 touchEvent 上:

registTouchEvent: function() {
    this.node.on(cc.Node.EventType.TOUCH_START, (event) => {
        if (this.node.scale !== 1 || Grid.disappearGrid !== null)
            return;
        if (this.isSelectMode) {
            Audio.instance.playFillChar();
            Game.instance.level.fillGrid(this);
        }
    }
}

fillGrid方法具体实现:

//填字逻辑
fillGrid: function (grid) {
    //设置charLabel显示
    this.charLabel.node.active = true;
    this.setCharLabel(grid.char);
    //设置其它显示属性...
    //填字格子消失动画
    grid.bottomGridDisappear();

    //检查格子引用的成语
    let fillError = false;
    for (let i = 0; i < this.idioms.length; i++) {
        if (this.idioms[i].checkIdiomFillResult()) {
            //填词成功动画播放
            this.idioms[i].onFillRight();
        }
        else {
            //填词有错误
            if (this.idioms[i].getFilledCharNum() === 4) {
                //填错动画播放
                this.idioms[i].onFillError();
                fillError = true;
            }
        }
    }
}

onFillRight() 和 onFillError() 中主要实现 填词正确和错误的动画播放。

动画对象添加在单个格子上,成语对象持有所占用格的引用,在正确和错误情况下都做全部格子的整体动画播放,看下图:

填词正确

填词错误

fillGrid 剩下的流程,主要是做自动选中下一个填字格

if (!fillError) {
    //自动跳下一格
    let nextGrid = this.getNextSpaceGrid();
    if (nextGrid)
        Game.instance.level.selectGrid(nextGrid);
    else {
        //当前无可选格,取消选择状态
        Game.instance.level.selectGrid(null);
    }
}
else {
    //停在错词的格子不作处理
}

同时还需要,过关条件的判断

let levelPass = true;
for (let i = 0; i < Game.instance.level.idioms.length; i++) {
    if (!Game.instance.level.idioms[i].filled) {
        //如果还有成语未完成则break
        levelPass = false;
        break;
    }
}
if (levelPass) {
    //过关,显示结算界面...
}

4

小结

成语游戏主体的实现差不多就是以上内容,编辑器部分的代码复用省了不少代码工作。

这里也顺便分享一个心得,休闲小游戏开发周期较短,一般我们会将编辑器投入占比作为是否单独开发编辑器的判断依据。如果编辑器开发不超过项目整体周期30%,通常都单独开发编辑器,如果大于这个占比,则需要考虑项目类型和编辑器在以后被复用的可能性,满足这一条件的话,也能摊薄编辑器所投入的开发成本。

成语项目则比较特殊,由于关卡数量太多,立项时直接先制作了编辑器,其实益智类游戏很多都是这样的情况。

作者简介:肖尧

从事游戏前端/后端/3D引擎开发多年 前盛大锦天项目主程,前成都网龙研发负责人,高级架构师 现任休闲游戏公司H5技术总监,未来将持续专注于基于H5的泛娱乐/教育/传媒/工具等产品的研究与开发。

本文分享自微信公众号 - Creator星球游戏开发社区(creator-star)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-11-18

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏全栈修仙之路

Node.js 小打小闹之图片合成

前阵子公司的产品经理找我谈个需求,希望能为每个用户生成专属的资讯分享图片及让开通专栏的用户能够生成专属的文章分享图片。这两天刚好有空,就抽空预研了 “生成专属的...

18220
来自专栏全栈修仙之路

RxJS Subject

观察者模式,它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使得它们能够自动更新自己。

11520
来自专栏全栈修仙之路

Webpack loader 之 url-loader

url-loader 功能类似于 file-loader,但是在文件大小(单位 byte)低于指定的限制时,可以返回一个 DataURL。

9230
来自专栏全栈修仙之路

深入学习 Node.js Module

Node.js 遵循 CommonJS规范,该规范的核心思想是允许模块通过 require 方法来同步加载所要依赖的其他模块,然后通过 exports 或 mo...

6630
来自专栏全栈修仙之路

Sequelize 系列教程之一对多模型关系

Sequelize 是一个基于 Promise 的 Node.js ORM,目前支持 Postgres、MySQL、SQLite 和 Microsoft SQL...

8830
来自专栏全栈修仙之路

Nest系列教程之入门篇

Nest 用于构建高效且可扩展的服务器端应用程序的渐进式 Node.js 框架,深受 Angular 的启发。

8920
来自专栏彤哥读源码

面试 LockSupport.park()会释放锁资源吗?

大家知道,我最近在招人,今天遇到个同学,他的源码看过一些,然后我就开始了AQS连环问。

8830
来自专栏全栈修仙之路

Angular 工具篇之文档管理

本文我们将介绍 Compodoc 这款工具,它用于为 Angular 应用程序生成静态文档。Compodoc 能够帮助 Angular开发人员为他们的应用程序生...

8510
来自专栏全栈修仙之路

Ionic 开发之 Ionic Storage 详解

Ionic Storage 是一款基于 localForage 用于 Ionic 应用程序的简单 “键-值” 存储模块,支持 SQLite 开箱即用。该工具可以...

6110
来自专栏全栈修仙之路

Webpack loader 之 file-loader

默认情况下,生成的文件的文件名就是文件内容的 MD5 哈希值并会保留所引用资源的原始扩展名。

8140

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励