cocos2d-js开发笔记

一.前言

之前有机会接触了cocos2d-js(cocos2d-x的一个分支)相关的技术,这里就做一个回顾和讲解,会从cocos2d-x的历史架构再到cocos2d-js和2d-x的差异开始,同时也介绍下之前cocos项目的整体结构和使用到的核心知识点,也方便自己后续回顾,目前,cocos官方目前大力推荐的是cocos creator,由于之前在做项目时候cocos creator不是非常成熟,加上js语法简洁和跨平台支持等原因,再到项目中的游戏模块不是很复杂择最后了就选择使用cocos2d-js分支来开发。

如果在现阶段要开发一个cocos 游戏,大力推荐使用cocos creator,这个也是cocos官方大力推荐的,cocos2d-x引擎的更新速度已放慢,cocos2d-js已经不再更新了,creator 已经是未来开发cocos游戏的必选的工具和趋势,cocos creator 和cocos2d-x 是完全不同的两个东西,包括引擎架构和开发流程是完全不一样的,creator这里不再多说,我这边还是要介绍下cocos2d-x相关的技术知识。

二.cocos2d-x 介绍

cocos2d-x是什么

Cocos2d-x 是 MIT 许可证下发布的一款功能强大的开源游戏引擎。

允许开发人员使用 C++、Javascript 及 Lua 三种语言来进行游戏开发。

支持所有常见平台,包括 iOS、Android、Windows、macOS、Linux。

引擎特性

  • 现代化的 C++ API
  • 立足于 C++ 同时支持 JavaScript/Lua 作为开发语言
  • 可以跨平台部署, 支持 iOS、Android、Windows、macOS 和 Linux
  • 可以在 PC 端完成游戏的测试,最终发布到移动端
  • 完善的游戏功能支持,包含精灵、动作、动画、粒子特效、场景转换、事件、文件 IO、数据持久化、骨骼动画、3D

市场占有

Cocos2d-x 用户不仅包括个人开发者和游戏开发爱好者,还包括许多知名大公司如 Zynga、Wooga、Gamevil、Glu、GREE、Konami、TinyCo、HandyGames、IGG 及 Disney Mobile 等。

使用 Cocos2d-x 开发的许多游戏占据苹果应用商店和谷歌应用商店排行榜,同时许多公司如触控、谷歌、微软、ARM,英特尔及黑莓的工程师在 Cocos2d-x 领域也非常活跃。

在中国,每一年的手游榜单大作,Cocos2d-x 从未缺席,市场份额占 50% 以上,游戏品类覆盖从轻度休闲,热火棋牌,到横版,SLG,重度 MMO 等市面全品类。一些以 Cocos2d-x 为基础开发出的游戏如下:

游戏引擎是一种特殊的软件,它提供游戏开发时需要的常见功能;引擎会提供许多组件,使用这些组件能缩短开发时间,让游戏开发变得更简单;专业引擎通常会能比自制引擎表现出更好的性能。游戏引擎通常会包含渲染器,2D/3D 图形元素,碰撞检测,物理引擎,声音,控制器支持,动画等部分。

Cocos2d-x 就是这样的一个游戏引擎,它提供了许多易于使用的组件,有着更好的性能,还同时支持移动端和桌面端。Cocos2d-x 通过封装底层图形接口提供了易用的API,降低了游戏开发的门槛,让使用者可以专注于开发游戏,而不用关注底层的技术细节。更重要的是 Cocos2d-x 是一个完全开源的游戏引擎,这就允许您在游戏开发过程中根据实际需要,定制化引擎的功能,如果您想要一个功能但又不知如何修改,提出这个需求,全世界的开发者可以一起为您完成。

cocos2d-x的几个基本核心概念

导演

Cocos2d-x 使用导演的概念,这个导演和电影制作过程中的导演一样!导演控制电影制作流程,指导团队完成各项任务。在使用 Cocos2d-x 开发游戏的过程中,你可以认为自己是执行制片人,告诉 导演(Director) 该怎么办!一个常见的 Director 任务是控制场景替换和转换。 Director是一个共享的单例对象,可以在代码中的任何地方调用。

如下 Director 就负责场景的转换:

场景(Scene)

在游戏开发过程中,你可能需要一个主菜单,几个关卡和一个结束场景。如何组织所有这些分开的部分?使用 场景(Scene) !当你想到喜欢的电影时,你能观察到它是被分解为不同场景或不同故事线。现在我们对游戏开发应用这个相同的思维过程,你应该很容易就能想出几个场景。

场景图(Scene Graph)是一种安排场景内对象的数据结构,它把场景内所有的 节点 (Node) 都包含在一个 (tree) 上。(场景图虽然叫做"图",但实际使用一个树结构来表示)。

分解这个场景,看一下它有哪些元素,这些最终会被渲染为一个树。

精灵(Sprite)

所有的游戏都有 精灵(Sprite) 对象,精灵是您在屏幕上移动的对象,它能被控制。你喜欢玩的游戏中主角可能就是一个精灵,我知道你在想是不是每个图形对象都是一个精灵,不是的,为什么? 如果你能控制它,它才是一个精灵,如果无法控制,那就只是一个节点(Node)。

看下面的图片,我们来指出一下,哪个是精灵(Sprite),哪个是节点(Node)。

动作(Action)

创建一个场景,在场景里面增加精灵只是完成一个游戏的第一步,接下来我们要解决的问题就是,怎么让精灵动起来。动作(Action) 就是用来解决这个问题的,它可以让精灵在场景中移动,如从一个点移动到另外一个点。你还可以创建一个动作 序列(Sequence) ,让精灵按照这个序列做连续的动作,在动作过程中你可以改变精灵的位置,旋转角度,缩放比例等等。

序列(Sequence)

能在屏幕上移动精灵,是制作一个游戏所需的一切,是吗?不是的,至少要考虑一下如何执行多个 Action。Cocos2d-x 通过 序列(Sequence) 来支持这种需求。

顾名思义,序列就是多个动作按照特定顺序的一个排列,当然反向执行这个序列也是可以的,Cocos2d-x 能很方便的完成这项工作。

如下是一个通过序列控制精灵移动的例子:

当然远远不止这些,除此之外还有物理引擎的支持(例如碰撞检查重力等)、音视频模块如(音乐音效支持等模块)具体可以查看官方文档

docs.cocos.com/cocos2d-x/m...

Cocos2d引擎家族介绍

cocos2d架构图

Cocos2d-JS是Cocos2d-x中的JavaScript版本,是Cocos2d-HTML5的延伸,官方对基于Web引擎的H5版本和基于Native的C++版本进行了整合,并在API层提供了统一的JavaScript API,使得Cocos开发更加容易

由于之前选用的是cocos2d-js,以下会侧重讲解js相关内容

二.快速开发一个cocos2d-js项目

项目结构

文件目录介绍

  • framework
  • cocos2d-html5 网页端的工程目录
  • cocos2d-x cocos引擎代码目录
  • runtime-src

runtime-src

  • Classes 是navtive 的app入口文件

  • proj.xxx 针对 iOS 安卓 Mac 等平台的工程目录

  • Index.html是网页端的启动文件,如果只是发布客户端可以忽略

  • main.js 是 cocos2d-js的启动入口文件,相当于 iOS 中工程的main文件

  • manifest.webapp 是一些描述信息一般用不到

  • project.json 是配置项目资源的核心文件 主要包括后续js类文件的引用
  • res 所有用到资源的文件目录(图片 音频 字体 动画资源等等)
  • src

也就是js代码的目录 这个文件夹下有一个resource.js 文件 项目中用到的资源文件需要在此文件中引用方可加载

以上为整个工程的文件目录功能介绍

开发工具

因为cocos2d-js 是基于js来开发的,那么关于编辑器就需要用到js相关开发工具,推荐webstrom 或者 vscode ,另外如果需要用到原生相关的功能,譬如iOS 相关的,那么就需要用到xcode,如果是安卓就要用Android studio。

环境搭建&生成工程

github.com/cocos2d/coc...

这里拿3.17.2版本为例,下载完成后目录如下

cocos2d-x.org/filedown/co...

Setup.py为环境配置脚本,由于目前此版本脚本python 要求 2.x 版本 ,我这边就不去演示了,因为我电脑是python 3.x ,有兴趣的可以自己去安装一个2.x 尝试。

官方的目录下有关于js的demo 示例 目录在 js-tests里边,有兴趣的可以逐个研究下官方demo

安装完成环境 通过 cocos new 快速生成工程模板

cocos **new** -**l** js ProjectName

模板如下

模板核心源码介绍

拿iOS 工程举例讲解

可以看到 和 iOS 新建工程类似,区别在于cocos 项目是在启动生命周期做了cocos引擎的初始化并且加载了一个GLView来渲染

scss 复制代码
cocos2d::Application *app = cocos2d::Application::getInstance();

    // Initialize the GLView attributes

    app->initGLContextAttrs();

    cocos2d::GLViewImpl::convertAttrs();

    // Override point for customization after application launch.

    // Add the view controller's view to the window and display.

    window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];

    // Use RootViewController to manage CCEAGLView

    _viewController = [[RootViewController alloc]init];

    _viewController.wantsFullScreenLayout = YES;

    // Set RootViewController to window

    if ( [[UIDevice currentDevice].systemVersion floatValue] < 6.0)

    {
        // warning: addSubView doesn't work on iOS6

        [window addSubview: _viewController.view];
    }

    else

    {
        // use this method on ios6

        [window setRootViewController:_viewController];
    }

    [window makeKeyAndVisible];
    [[UIApplication sharedApplication] setStatusBarHidden:true];

    // IMPORTANT: Setting the GLView should be done after creating the RootViewController

    cocos2d::GLView *glview = cocos2d::GLViewImpl::createWithEAGLView((__bridge void *)_viewController.view);

    cocos2d::Director::getInstance()->setOpenGLView(glview);

    //run the cocos2d-x game scene

    app->run();

    return YES;

}

此外initGLContextAttrs是cocos 的初始化核心方法,也就是启动js相关模块的初始化方法,核心方法都在AppDelegate.cpp类里边

同时可以看到applicationDidFinishLaunching 中的 ScriptingCore::getInstance()->runScript("main.js"); 即为启动js模块的入口类

App前后台切换暂停 重启游戏都是通过原生调用cocos引擎来完成的

这里main.js 运行起来后 就开始了游戏的初始化流程了,我这里拿我之前做的项目来展示

javascript 复制代码
//load resources

    cc.LoaderScene.preload(g_resources, function () {

        cc.director.runScene(new SXTHomePageScene());

    }, this);

即为第一个页面场景的类,在场景加载之前可以自定义的处理一些事情,如预加载资源,做屏幕适配等初始化等,后边我会详细讲下我之前项目的整体结构和大概功能点。

实战项目功能介绍

我这边会结合我之前做的项目 介绍下 cocos2d-js相关的开发 以及 cocos和 na交互能技术,包括cocos2d-js 功能代码结构等,以及 cocos 核心概念动画等。

我这边拿部分功能举例

cocos2d-js项目结构

我这边不详细介绍游戏实现,主要说下项目模块的功能梳理和框架

游戏模块

游戏网络请求

主要通过Api 实现游戏业务网络请求处理

统一通过Network 类实现网络请求处理

Cocos2d-js 网络请求用的是 cc.loader.getXMLHttpRequest() ,此类主要是封装post 和get方法和业务明确的一些状态码以及加密解密数据的逻辑

代码如下

  1. 请求参数处理
  1. 设置参数相关编码和预处理等
  1. 真正的请求逻辑
  1. 错误超时的处理

游戏部分功能模块

游戏模块使用 layer scene 和script 来分层

Layer 主要做ui的布局和交互逻辑

Scene 来做场景的切换和游戏逻辑处理 每个场景都会用一个layer来处理核心逻辑

Script 就是对一些自定义精灵 的封装

场景的切换统一封装了route

游戏列表页面

列表页面使用的是ccui.ScrollView 实现的

游戏写字模块

1.轮廓绘制

首先使用了一个开源的笔画数据,这个数据是每个文字的每一笔画的点,核心绘制笔画轮廓的部分代码

ini 复制代码
//绘制轮廓

    makePath: function (strokeStr) {

        let strokeCommands = strokeStr.split(" ");

        let offset = GC.h - this._Offset_y * this.getStrokeYRatio();

        let lastPos = cc.p;

        let outlineColor = cc.color(221, 113, 60);

        let counter = 0;

        while (counter < strokeCommands.length) {

            let commend = strokeCommands[counter];

            if (commend == "M") {

                let x = this.scalePointX(strokeCommands[counter + 1]);

                let y = this.scalePointY(strokeCommands[counter + 2]);
                
                this._m_drawNode.drawDot(cc.p(x, offset - y), 0, outlineColor);

                lastPos = cc.p(x, offset - y);

                counter += 3;

            }

            if (commend == "Q") {

                let x1 = this.scalePointX(strokeCommands[counter + 1]);

                let y1 = this.scalePointY(strokeCommands[counter + 2]);

                let x2 = this.scalePointX(strokeCommands[counter + 3]);

                let y2 = this.scalePointY(strokeCommands[counter + 4]);

                this._m_drawNode.drawQuadBezier(lastPos, cc.p(x1, offset - y1), cc.p(x2, offset - y2), 50, 1, outlineColor);

                lastPos = cc.p(x2, offset - y2);

                counter += 5;

            }

            if (commend == "C") {

                let control1x = this.scalePointX(strokeCommands[counter + 1]);

                let control1y = this.scalePointY(strokeCommands[counter + 2]);

                let control2x = this.scalePointX(strokeCommands[counter + 3]);

                let control2y = this.scalePointY(strokeCommands[counter + 4]);

                let destinationX = this.scalePointX(strokeCommands[counter + 5]);

                let destinationY = this.scalePointY(strokeCommands[counter + 6]);

                this._m_drawNode.drawCubicBezier(lastPos, cc.p(control1x, offset - control1y), cc.p(control2x, offset - control2y), cc.p(destinationX, offset - destinationY), 50, 1, outlineColor);

                lastPos = cc.p(destinationX, offset - destinationY);

                counter += 7;

            }

            if (commend == "L") {

                let x = this.scalePointX(strokeCommands[counter + 1]);

                let y = this.scalePointY(strokeCommands[counter + 2]);

                this._m_drawNode.drawSegment(lastPos, cc.p(x, offset - y), 1, outlineColor);

                lastPos = cc.p(x, offset - y);

                counter += 3;

            }

            if (commend == "Z") {

                break;

            }

        }

    },

2.画笔处理

通过自定义一个精灵元素,实现拖拽逻辑进行笔画绘制

ini 复制代码
onTouchBegan : function (touch, event) {

        this. _enableTouch = true;

        var target = event.getCurrentTarget();

        if (false == target._enableMoved){

            return;

        }

        if (!target.isTouchInRect(touch)){

            return false

        }

        target._callback();

        return true;

    },

    onTouchMoved : function (touch, event) {

        var pos = touch.getLocation();

        var target = event.getCurrentTarget();

        var delta = touch.getDelta();

        var point = target.parent.convertToNodeSpace(cc.p(target.x,target.y));
        target.setPosition(cc.p(target.x+delta.x,target.y+delta.y));

        target._callback();

    },

在layer层通过移动的坐标点和 之前绘制出来目标点的位置进行碰撞检测cc.rectContainsPoint,如果绘制出的目标点最后一个被吃掉视为完成写字。

游戏场景模块

主要有打地鼠,推箱子,朗诵,连线等10几种小游戏。

1.游戏音频播放

短音频

scss 复制代码
//播放

this.audioId =audio.playEffect(res);

 audio.setEffectsVolume(1);

//停止

 cc.audioEngine.stopEffect(audioID)

长音频

用的ccui.VideoPlayer()

有些场景cocos的播放器不太好用,就通过原生封装了一个播放器,通过jsb调用实现,这里iOS 是单独用的iOS avplayer播放器,安卓用的cocos系统的,其实系统底层也是用的原生播放器。

原生模块

主要做语音评测 ,分享能力,登录能力 支付能力 以及一些竖屏用户学习数据展示列表页面等等。

原生游戏交互模块

1.核心调用是通过jsb.reflection实现的

2.这里也处理了一下多方法调用原生,并且需要原生返回处理的逻辑

譬如获取用户信息是异步的,会把js方法对象传递到native,最终端上处理完成回调到callbackmannager,通过传递生成的时间戳作对比找到回调

3.端上其实就是一个类方法实现

三.官方学习资料

docs.cocos.com/cocos2d-x/m...

docs.cocos.com/cocos2d-x/m...

总结

以上为我在项目实战中的一些记录,有兴趣可以自己去尝试学习,希望也能对大家有一定的帮助,同时也是自己对过去的一个简要总结。

相关推荐
成长ing121388 个月前
Cocos 游戏入门 飞翔的小鸟
cocos creator·cocos2d-x
iOS阿玮9 个月前
iOS-Swift项目嵌入Cocos2d-x游戏开发(二)
cocos2d-x
iOS阿玮9 个月前
iOS-Swift项目嵌入Cocos2d-x游戏开发(一)
cocos2d-x