首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Cocos Creator 只谈实战系列—成语游戏篇

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

作者头像
张晓衡
发布2019-11-24 16:05:24
发布2019-11-24 16:05:24
2K10
代码可运行
举报
运行总次数:0
代码可运行

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 预设,遍历关卡中的成语对象,将带空格属性的字创建为填字对象:

代码语言:javascript
代码运行次数:0
运行
复制
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 上:

代码语言:javascript
代码运行次数:0
运行
复制
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方法具体实现:

代码语言:javascript
代码运行次数:0
运行
复制
//填字逻辑
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 剩下的流程,主要是做自动选中下一个填字格

代码语言:javascript
代码运行次数:0
运行
复制
if (!fillError) {
    //自动跳下一格
    let nextGrid = this.getNextSpaceGrid();
    if (nextGrid)
        Game.instance.level.selectGrid(nextGrid);
    else {
        //当前无可选格,取消选择状态
        Game.instance.level.selectGrid(null);
    }
}
else {
    //停在错词的格子不作处理
}

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

代码语言:javascript
代码运行次数:0
运行
复制
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的泛娱乐/教育/传媒/工具等产品的研究与开发。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-11-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Creator星球游戏开发社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档