cocos_cocos creator - CSDN
cocos 订阅
Cocos是由触控科技推出的游戏开发一站式解决方案,包含了从新建立项、游戏制作、到 打包上线的全套流程。开发者可以通过cocos快速生成代码、编辑资源和动画,最终输出适合于多个平台的游戏产品。 [1] 展开全文
Cocos是由触控科技推出的游戏开发一站式解决方案,包含了从新建立项、游戏制作、到 打包上线的全套流程。开发者可以通过cocos快速生成代码、编辑资源和动画,最终输出适合于多个平台的游戏产品。 [1]
信息
软件名称
Cocos
开发商
北京触控爱普科技有限公司 [2]
Cocos基本简介
2015年2月,触控科技正式推出cocos游戏开发一站式解决方案,重新定义无缝的工作流。cocos整合了Cocos 2d-x、Cocos Studio、Cocos Code IDE等框架及工具,为开发者提供了全套的游戏开发解决方案。 [3]  Cocos立足于一个更大的视角,它将cocos家族中的所有开发框架、工具和编辑器整合到了一起。如果说Cocos 2d-x是一款游戏开发引擎,那么cocos就是一个完整的游戏开发解决方案。它不再仅仅着眼于"游戏编码",而是将对开发者的支持延伸到了整个工作流程,将策划、程序、美术这一开发"铁三角"都囊括了进来,为手游开发提供了专业可靠的一站式解决方案。 [4]  Cocos游戏开发一站式解决方案,包含了从新建立项、游戏制作、到打包上线的全套流程。开发者可以通过cocos快速生成代码、编辑资源和动画,最终输出适合于多个平台的游戏产品。 [2]  游戏从创意、开发、测试、上线都有一个完整的流程,触控科技从产品设计角度直接用清晰的脉络把上面提到的这些工具、服务进行了整合,形成最短、最清晰的工作流。这个整合后的产品就是现在的cocos。 [5]  原本cocos引擎家族所有独立产品,如Cocos 2d-x引擎框架,Cocos Studio游戏编辑器、Code IDE代码开发工具等,如今都统一在cocos里。 [6] 
收起全文
精华内容
参与话题
  • Cocos Creator游戏引擎是一个完整的游戏开发解决方案,包含从设计、开发、预览、调试到发布的整个工作流所需的全部功能。目前支持发布游戏到 Web、iOS、Android、各类"小游戏"、PC 客户端等平台,真正实现一次开发,...
  • Cocos Creator微信小游戏开发

    千人学习 2019-10-08 16:52:15
    如今,H5游戏、微信小游戏、抖音小游戏、头条小游戏、快手小游戏、百度小游戏、QQ轻游戏等小程序游戏都特别火,而这些小游戏中80%都是用Cocos Creator开发的,Cocos Creator可以做到一次开发,多平台部署。...
  • CocosCreator游戏开发框架(一):是什么 && 为什么

    万次阅读 热门讨论 2019-07-07 22:37:20
    从微信小游戏出生(2018年初)到现在,已经使用CocosCreator一年多了(之前做手游主要是cocos2d-x+lua),趁着这段时间有空,想着整理出一个基于CocosCreator游戏开发框架。 这个框架主要是将我在开发过程中觉得好用...

    写在前面


    从微信小游戏出生(2018年初)到现在,已经使用CocosCreator一年多了(之前做手游主要是cocos2d-x+lua),趁着这段时间有空,想着整理出一个基于CocosCreator游戏开发框架

    这个框架主要是将我在开发过程中觉得好用的结构和模式、插件,以及在论坛上和博客上参考大神们的教程和想法(有些是直接拿来用),整合在一起的。一方面想提高开发效率,另一方面大家发现问题及时提出及时讨论,慢慢优化和改进。

    框架工程是否跟游戏工程分开

    在开始之前,因为这个问题纠结了好久。框架工程跟游戏工程分离,框架工程作为一个独立代码库,仅仅作为游戏工程的子模块,这样代码库可以统一管理。

    我上个项目就是这样做的,但是你会发现,把框架模块单独拿出来给下一个项目复用,里面有一些耦合了游戏工程的代码。如果要每个成员在紧张的游戏开发过程中保持清醒,去保持框架模块的独立性,肯定是一个蛋疼的过程。

    后来阅读了两篇文章(关于游戏设计模式的)之后,确定了该框架仅仅作为一个“纯净”的基础框架,每开一个新项目就拷贝过去,然后根据游戏的需求自己去调整。

    两篇文章的链接在下面,有兴趣的可以了解下,不扯远了,准备进入正题!

    【游戏设计模式】之一 序言:架构,性能与游戏

    为什么在游戏开发中我不喜欢用MVC系列模式了




    正文


    目录细分和规划

    如下图:

    • animClip:存放动画文件(.anim)
    • font:存放字体文件
    • prefab:存放不需要动态加载的预制体
    • texture:存放用于贴图资源
    • texture/ui_common:存放公用的ui资源图集文件。
    • texture/ui_module:每个功能/模块单独用到的资源打包后的图集文件,比如main场景单独用到的打包一起,然后mian场景勾选自动释放资源,切换场景时就会自动释放没用的资源(前提是没有被其他的地方引用到)。
    • resources:存放一切需要用于动态加载(cc.load.loadRes)的资源

    为什么有些资源放在resources里面,有些放到外面?

    先看官网的解释:

    总结一下:

    1、resources文件夹中的资源可以跟它外部的其他资源,相互引用,所以放哪,问题不大。
    2、只有放在resources文件夹的资源才能用cc.loader.loadRes动态加载。
    3、构建时,resources文件夹中的所有资源连同它们关联依赖的resources文件夹外部的资源,都会被导出,并且项目中无用的资源将会在构建的过程中自动剔除。
    4、resources文件夹的资源,会增大包体和settings.js的大小,JSON的自动合并策略也将受到影响,无法尽可能将零碎的JSON合并起来。




    框架模块介绍


    # 配置表模块

    直接在现有的插件excel-killer的基础上做了小调整。

    • 相关目录(可以根据需求自己改动,相关文件:packages/excel-killer/panel/index.js)

    plugins-excel/excel:存放excel表

    plugins-excel/excel-ouput: 存放执行插件后的js输出文件

    assets/script/data/config: 执行插件后,会自动把js文件从plugins-excel/excel-ouput拷贝到此目录


    • 如何使用
    let cfgman = require('CfgMan');
    console.log(cfgman[1].name);  // 小明
    



    # 数据模块

    • 目录结构

    IDataModel.ts:数据模块基类,主要功能:读取数据表、读写本地缓存数据、网络数据交互


    • 本地缓存数据接口

    LoadStorage():将该模块的本地缓存数据读取到内存

    Query(sKey: string, defaultValue: any = null):访问指定键名的值

    Set(sKey: string, value: string | number):设置指定键名的值

    Save():保存内存数据到缓存文件


    • 网络数据交互接口

    sendProtocolMsg(msg):发送协议到服务端

    registerListeners():注册网络监听事件,需要在getMessageListeners()定义需要监听的协议和方法

    // AccountModel.ts
    getMessageListeners() {
        return {
            // key:消息名,value:执行函数
            ['G2C_Login']: (msg) => { this.G2C_LoginSuccess(msg) },
        }
    }
    



    # UI模块

    • 目录结构

    UIMng:UI管理器,用于打开、关闭UI

    UIBase:UI界面基类,在这里可以定义一些通用方法,供子类调用或者继承

    UIHelp:UI工具类,封装一系列UI相关的功能方法


    • 如何使用(配合自动化插件)

    1、新建一个场景或者prefab

    2、选中,然后到工具栏:扩展 -> ui-creator

    create-node-tree操作:将prefab节点树的结构自动导出到ts文件(目标文件夹:assets/script/data/autoui)

    export default class auto_notice extends cc.Component {
    const { ccclass } = cc._decorator;
    
    @ccclass
    export default class auto_notice extends cc.Component {
    	notice: cc.Node;
    	background: cc.Node;
    	title: cc.Node;
    	content: cc.Node;
    	btnClose: cc.Node;
    
    	public static URL:string = "db://assets/resources/prefab/notice/notice.prefab"
    
        onLoad () {
    		this.notice = this.node
    		this.background = this.notice.getChildByName("background");
    		this.title = this.notice.getChildByName("title");
    		this.content = this.notice.getChildByName("content");
    		this.btnClose = this.notice.getChildByName("btnClose");
    
        }
    }
    
    

    以后,你想要使用ui节点,就不需要各种getChildByName,或者搞个property在编辑器拖,所有的节点都导出在一个ts文件,然后作为一个组件添加到UI文件中,你只需要this.ui[节点名称]即可访问。

    create-ui-template操作:自动生成UI模板TS文件

    UI模板在packages\ui-creator\core\ui-template.txt中定义。

    3、将第2步create-ui-template操作生成的UI脚本文件,在编辑器拖到prefab的根节点作为组件

    4、UI的基本操作都封装在UIHelp中

    UIHelp.ShowUI(UINotice);    // 打开ui
    UIHelp.CloseUI(UINotice);   // 关闭ui
    UIHelp.SetLabel(this.ui.title, '测试公告标题'); // 修改label节点文本
    

    • TODO

    后续补充关闭UI清除相关无用资源


    • 这里说一下对于UI的一些想法和见解

    1、MVC模式。在框架中,每一个功能创建一个model类继承IDataModel,用于处理数据(配置表、本地数据、网络数据)。新建的prefab就是view,挂载在prefab的脚本组件就是controller,在controller实现功能逻辑。

    2、很多人在用CocosCreator开发时,经常会往节点上挂脚本,往按钮上绑定事件(看过好多github上的项目都是这样)。但我个人是很不建议这样做的,正常的团队开发合作中都是分工明确的,比如你在编辑器中用按钮绑定事件,难道美术修改的时候还要关心代码么。而且任意节点都可以挂脚本,这个真的有点“灾难性”,我要找在这个脚本在哪里用到的时候还要去编辑器一个个找么(可能有其他快速查找的方法,我不知道的,请指点一下)。

    3、所以我是比较支持,能用代码实现的尽量用代码实现,脚本文件能挂在根节点(方便找)的尽量挂在根节点。




    # 网络模块

    数据协议用Protobufjs,网络协议用WebSocket

    • Protobufjs(用的是5.x)

    1、安装nodejs、npm

    2、到新建的cocoscreator工程目录,初始化项目:执行npm init -y

    3、安装protobufjs5.x版本:执行npm install --save-dev protobufjs@5

    4、覆盖原protobuf的loadProtoFile方法

    protobuf原来的loadProtoFile方法:

    ProtoBuf.loadProtoFile = function(filename, callback, builder) {
        if (callback && typeof callback === 'object')
            builder = callback,
            callback = null;
        else if (!callback || typeof callback !== 'function')
            callback = null;
        if (callback)
            return ProtoBuf.Util.fetch(typeof filename === 'string' ? filename : filename["root"]+"/"+filename["file"], function(contents) {
                if (contents === null) {
                    callback(Error("Failed to fetch file"));
                    return;
                }
                try {
                    callback(null, ProtoBuf.loadProto(contents, builder, filename));
                } catch (e) {
                    callback(e);
                }
            });
        var contents = ProtoBuf.Util.fetch(typeof filename === 'object' ? filename["root"]+"/"+filename["file"] : filename);
        return contents === null ? null : ProtoBuf.loadProto(contents, builder, filename);
    };
    

    这里用了ProtoBuf.Util.fetch来读文件,所以需要重写loadProtoFile方法,用cc.loader.loadRes代替Util.fetch方法来读取文件:

    let ProtoBuf = require('protobufjs');
    ProtoBuf.Util.IS_NODE = cc.sys.isNative;
    // 此方法是将ProtoBuf.Util.fetch函数替换成cc.loader.loadRes函数,以解决在微信小游戏中不能使用XHR的问题
    ProtoBuf.loadProtoFile = function(filename, callback, builder) {
        if (callback && typeof callback === 'object')
            builder = callback,
            callback = null;
        else if (!callback || typeof callback !== 'function')
            callback = null;
        if (callback)
            return cc.loader.loadRes(typeof filename === 'string' ? filename : filename["root"]+"/"+filename["file"], function(error, contents) {
                if (contents === null) {
                    callback(Error("Failed to fetch file"));
                    return;
                }
                try {
                    callback(error, ProtoBuf.loadProto(contents, builder, filename));
                } catch (e) {
                    callback(e);
                }
            });
        var contents = cc.loader.loadRes(typeof filename === 'object' ? filename["root"]+"/"+filename["file"] : filename); 
        return contents === null ? null : ProtoBuf.loadProto(contents, builder, filename);
    };
    

    • WebSocket

    CocosCreator已经支持WebSocket,而如果是微信小游戏则用微信提供的WebSocket,具体查看:https://developers.weixin.qq.com/minigame/dev/api/network/websocket/wx.connectSocket.html

    工程中两种都实现了,其中浏览器平台已经测试过可行,并且提供了Nodejs服务端工程。


    • 目录结构

    ProtoBuf.ts:对protobufjs的修改和封装

    ProtoLoader.ts:用于加载proto文件

    Message.ts:proto msg的基类,并将msg缓存起来

    ProtoMessage.ts:插件根据proto文件生成的代码

    Socket.ts:WebSocket/WxSocket的具体实现

    SocketDelegate.ts:Socket代理类,根据具体平台创建socket,提供统一回调接口供具体Socket调用

    Network.ts:网络的逻辑实现,跟用户打交道,连接网络、关闭网络、登录流程、断网、重连都可以在这里处理


    • proto-killer插件

    将proto转成TS代码,在开发中会有编辑器智能提示。




    # 日志模块

    • 增加开关配置,每个大功能可以有一个开关,每个开发人员可以有一个开关,按需定义
    export const LOG_TAG = {
        SOCKET: { desc: 'LOG_SOCKET', isOpen: true },
        TEST: { desc: 'LOG_TEST', isOpen: false },
    }
    

    • 使用
    Log.log(LOG_TAG.SOCKET, 'socketprint');
    Log.warn('warn');
    Log.error('error');
    

    log方法第一个参数为开关分类,warn和error没有,因为我认为一般调试打印用log方法就够了,如果你用warn或error,肯定是需要所有人都知道的。




    # 事件模块

    EventMng.ts:事件分发我偷懒了,直接new一个cc.EventTarget来用,目前没有发现其他问题。




    # 其他

    GameController.ts:游戏全局控制类,比较杂的不知道放哪的可以看看能不能放这里

    GameDataCenter.ts:管理游戏各个模块数据

    global.d.ts:用于扩展基础模块

    utils文件夹:用于存放一些工具类





    最后


    这篇文章讲的主要是框架有什么东西,有些地方为何要这么设计,githu工程点这里

    看完有点懵逼?没关系,下篇文章是:CocosCreator游戏开发框架(二):怎么用

    我会在框架的基础上快速开发一个简单的客户端登陆系统,帮助大家快速上手。

    展开全文
  • Cocos2dx入门

    千次阅读 2019-04-18 22:36:19
    一.Cocos2d-x引擎特性 现代化的 C++ API 立足于 C++ 同时支持 JavaScript/Lua 作为开发语言 可以跨平台部署, 支持 iOS、Android、Windows、macOS 和 Linux 可以在 PC 端完成游戏的测试,最终发布到移动端 完善的游戏...

    一.Cocos2d-x引擎特性

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


    二.环境配置

    要求:
    Windows 7+,
    VS 2015+
    python2.7

    JDK
    SDK
    NDK(可选)


    三.cocos命令配置

    1.cocos命令配置

    Cocos2d-x 带有一个命令行工具:cocos 这是一个跨平台的工具,你可以用它创建项目、运行项目、发布项目。命令行工具适用于所有 Cocos2d-x 支持的平台,包括:iOS、Android、Mac、Linux、Windows、Web。不用 IDE,只用命令行,你就能完成所有的工作!

    1.行引擎源码根目录的 setup.py
    python setup.py

    2.测试

    cocos -v
    Python 2.7.10
    cocos2d-x-3.16
    Cocos Console 2.3

    2.cocos命令使用

    • 1.项目创建

    cocos new MyGame -p com.MyCompany.MyGame -l cpp -d ~/MyCompany

    • 2.项目编译(程序从源码到二进制程序,有一个编译环节)

    cocos compile . -p android -m release

    • 3.项目运行

    cocos run . -p android -m release

    • 4.项目发布

    cocos deploy -s c:\MyCompany\MyGame -p android -m release


    四.日志输出

    log("This would be outputted to the console");
    
    string s = "My variable";
    log("string is %s", s);
    
    double dd = 42;
    log("double is %f", dd);
    
    int i = 6;
    log("integer is %d", i);
    
    float f = 2.0f;
    log("float is %f", f);
    

    五.基本功能

    1.Director导演

    Cocos2d-x 使用导演的概念,Director 任务是控制场景替换和转换。
    Director是一个共享的单例对象,可以在代码中的任何地方调用。

    2.Scene场景

    场景(Scene) 是一个容器,容纳游戏中的各个元素,如精灵,标签,节点对象。它负责着游戏的运行逻辑,以帧为单位渲染内容。
    1.场景创建

    class MyScene : public cocos2d::Scene
    {
    public:
    	static cocos2d::Scene* createScene();
    	virtual bool init();
    
    	// 实现crete静态方法
    	CREATE_FUNC(StartScene);
    };
    
    //创建
    auto myScene = MyScene ::create();
    

    2.场景切换

    //加载第一个场景
    Director::getInstance()->runWithScene(myScene);
    
    //切换场景
    Director::getInstance()->replaceScene(myScene);
    
    //叠加场景
    Director::getInstance()->pushScene(myScene);
    
    //释放场景
    Director::getInstance()->popScene(myScene);
    

    场景图
    场景图(Scene Graph)是一种安排场景内对象的数据结构,它把场景内所有的 节点(Node) 都包含在一个 树(tree) 上。
    Cocos2d-x 使用 中序遍历,先遍历左子树,然后根节点,最后是右子树。中序遍历下图的节点,能得到 A, B, C, D, E, F, G, H, I 这样的序列。

    场景图

    3.Layer层

    Layer代表层,一般常做Scene的子容器,可以添加Sprite,相当于精灵的面板容器。

    4.Sprite精灵

    精灵是您在屏幕上移动的对象,它能被控制;

    可以使用一张图像来创建精灵,PNG, JPEG, TIFF, WebP, 这几个格式都可以。当然也可以是图集

    使用图片

    auto mySprite = Sprite::create("mysprite.png");
    

    使用图集

    1.创建图集
    Texture Packer工具创建并导出plist+png图集

    2.加载图集

    auto spritecache = SpriteFrameCache::getInstance();
    spritecache->addSpriteFramesWithFile("sprites.plist");
    

    3.创建精灵

    auto mysprite = Sprite::createWithSpriteFrameName("mysprite.png");
    

    精灵的控制

    1.锚点
    mySprite->setAnchorPoint(0.5, 0.5);
    2.位置
    mySprite->setPosition(Vec2(100, 200));
    3.旋转
    mySprite->setRotation(20.0f);
    4.缩放
    mySprite->setScale(2.0);
    mySprite->setScaleX(2.0);
    mySprite->setScaleY(2.0);
    5.倾斜
    mySprite->setSkewX(20.0f);//水平倾斜
    mySprite->setSkewY(20.0f);//数直倾斜
    6.颜色
    mySprite->setColor(Color3B::WHITE);
    mySprite->setColor(Color3B(255, 255, 255));
    7.透明度
    mySprite->setOpacity(30);
    

    5.Action动作

    动作(Action)通过改变一个 Node 对象的属性,让它表现出某种动作。动作对象能实时的改变 Node 的属性,任何一个对象只要它是 Node 的子类都能被改变。
    1.单一动作

    //从当前位置到目标位置
    auto moveTo = MoveTo::create(2, Vec2(50, 10));
    mySprite1->runAction(moveTo);
    //从目标位置到当前位置
    auto moveBy = MoveBy::create(2, Vec2(20,0));
    mySprite2->runAction(moveBy);
    

    2.动作序列和并列
    还可以创建一个动作 序列(Sequence) 和Swan(并列)

    auto mySprite = Node::create();
    
    auto moveTo1 = MoveTo::create(2, Vec2(50,10));
    auto moveBy1 = MoveBy::create(2, Vec2(100,10));
    auto moveTo2 = MoveTo::create(2, Vec2(150,10));
    
    mySprite->runAction(Sequence::create(moveTo1, moveBy1,moveTo2, nullptr));
    //或者
    mySprite->runAction(Spawn::create(moveTo1, moveBy1, moveTo2, nullptr));
    

    六.UI组件

    UI 代表用户界面,是 User Interface 的缩写,界面组件有标签,按钮,菜单,滑动条等

    1.标签(Label)

    //BMFont
    auto myLabel = Label::createWithBMFont("bitmapRed.fnt", "Your Text");
    //TTF
    auto myLabel = Label::createWithTTF("Your Text", "Marker Felt.ttf", 24);
    //SystemFont
    auto myLabel = Label::createWithSystemFont("My Label Text", "Arial", 16);
    //阴影效果
    myLabel->enableShadow();
    //描边效果
    myLabel->enableOutline(Color4B::WHITE, 1));
    //发光效果
    myLabel->enableGlow(Color4B::YELLOW);
    

    2.菜单(Menu)

    //图片菜单
    auto closeItem = MenuItemImage::create("CloseNormal.png", "CloseSelected.png",
    CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
    
    //文字菜单
    auto startItem = MenuItemText::create("StartGame",
    CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
    
    //menu总菜单
    auto menu = Menu::create(startItem, closeItem, NULL);
    this->addChild(menu, 1);
    
    //Lambda写法
    auto closeItem = MenuItemImage::create("CloseNormal.png", "CloseSelected.png",
    [&](Ref* sender){
        // your code here
    });
    

    3.按钮(Button)

    #include "ui/CocosGUI.h"。
    auto button = Button::create("normal_image.png", "selected_image.png", "disabled_image.png");
    button->setTitleText("Button Text");
    button->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type){
            switch (type)
            {
                    case ui::Widget::TouchEventType::BEGAN:
                            break;
                    case ui::Widget::TouchEventType::ENDED:
                            std::cout << "Button 1 clicked" << std::endl;
                            break;
                    default:
                            break;
            }
    });
    

    4.复选框(CheckBox)(Toggle开关)

    #include "ui/CocosGUI.h"
    
    auto checkbox = CheckBox::create("check_box_normal.png",
                                     "check_box_normal_press.png",
                                     "check_box_active.png",
                                     "check_box_normal_disable.png",
                                     "check_box_active_disable.png");
    
    checkbox->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type){
            switch (type)
            {
                    case ui::Widget::TouchEventType::BEGAN:
                            break;
                    case ui::Widget::TouchEventType::ENDED:
                            std::cout << "checkbox 1 clicked" << std::endl;
                            break;
                    default:
                            break;
            }
    });
    
    this->addChild(checkbox);
    

    5.进度条(LoadingBar)

    #include "ui/CocosGUI.h"
    //创建进度条
    auto loadingBar = LoadingBar::create("LoadingBarFile.png");
    loadingBar->setDirection(LoadingBar::Direction::RIGHT);
    //设置进度
    loadingBar->setPercent(25);
    //add节点
    this->addChild(loadingBar);
    

    6.文本框(TextField)

    #include "ui/CocosGUI.h"
    
    auto textField = TextField::create("","Arial",30);
    textField->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type){
         std::cout << "editing a TextField" << std::endl;
    });
    
    this->addChild(textField);
    

    七.监听事件

    1.五种类型

    EventListenerTouch - 响应触摸事件
    
    EventListenerKeyboard - 响应键盘事件
    
    EventListenerAcceleration - 响应加速度事件
    
    EventListenMouse - 响应鼠标事件
    
    EventListenerCustom - 响应自定义事件
    

    2.事件的吞没(可做遮罩)

    listener1->setSwallowTouches(true);
    listener1->onTouchBegan = [](Touch* touch, Event* event){
        // your code
        return true;
    };
    

    3.触摸事件

    让我们先了解一下什么是触摸事件,当你触摸移动设备的屏幕时,设备感受到被触摸,了解到被触摸的位置,同时取得触摸到的内容,然后你的触摸被回答。 这就是触摸事件。

    //创建触摸
    auto listener1 = EventListenerTouchOneByOne::create();
    // 触摸开始
    listener1->onTouchBegan = [](Touch* touch, Event* event){
        // your code
        Vec2 point = touch->getLocation();//获取点击位置
        return true; // if you are consuming it
    };
    // 触摸滑动
    listener1->onTouchMoved = [](Touch* touch, Event* event){
        // your code
    };
    // 触摸结束
    listener1->onTouchEnded = [=](Touch* touch, Event* event){
        // your code
    };
    // 添加监听(最重要的一步)
    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, this);
    

    4.鼠标事件

    创建鼠标事件监听器:

    //创建事件
    _mouseListener = EventListenerMouse::create();
    //设置不同监听
    _mouseListener->onMouseMove = CC_CALLBACK_1(MouseTest::onMouseMove, this);
    _mouseListener->onMouseUp = CC_CALLBACK_1(MouseTest::onMouseUp, this);
    _mouseListener->onMouseDown = CC_CALLBACK_1(MouseTest::onMouseDown, this);
    
    //绑定监听(最重要一步)
    _eventDispatcher->addEventListenerWithSceneGraphPriority(_mouseListener, this);
    
    //回调函数实现(也可以用匿名函数/Lambda)
    void MouseTest::onMouseDown(Event *event){
    	EventMouse* em = (EventMouse*)event;
    	em->getLocation();//获取鼠标位置
    }
    void MouseTest::onMouseUp(Event *event){}
    void MouseTest::onMouseMove(Event *event){}
    
    

    5.键盘事件

    对于桌面游戏,一般需要通过键盘做一些游戏内的控制,这时你就需要监听键盘事件。

    //创建事件
    auto listener = EventListenerKeyboard::create();
    listener->onKeyPressed = CC_CALLBACK_2(KeyboardTest::onKeyPressed, this);
    listener->onKeyReleased = CC_CALLBACK_2(KeyboardTest::onKeyReleased, this);
    //添加监听
    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
    
    //实现回调函数
    void KeyboardTest::onKeyPressed(EventKeyboard::KeyCode keyCode, Event* event){}
    
    void KeyboardTest::onKeyReleased(EventKeyboard::KeyCode keyCode, Event* event){}
    

    6.Update事件

    如果需要持续的处理某个事件,那么可以开启一个update

    //开启update
    this->scheduleUpdate();
    void Test::update(float delta)
    {}
    

    八.物理引擎

    当你的需求很简单时,就不要使用物理引擎。比如只需要确定两个对象是否有碰撞,结合使用节点对象的 update 函数和 Rect 对象的 containsPoint(),intersectsRect() 方法可能就足够了。例如:

    void update(float dt)
    {
      auto p = touch->getLocation();
      auto rect1 = this->getBoundingBox();
      auto rect2 = this->getBoundingBox();
      if(rect1.containsPoint(p))
      {
          // do something, intersection
      }
      if(rect1.intersectsRect(rect2))
      {
          // do something, intersection
      }
    }
    

    1.刚体碰撞

    如你要开发一个游戏,一个场景有 100 个精灵对象,需要判断它们互相是否有碰撞,如果使用上诉方法那将非常复杂,同时性能消耗还会严重影响 CPU 的使用率和游戏运行的帧率,这游戏根本没法玩。
    这个时候就需要物理引擎了。

    /*创建物理场景*/
    auto scene = Scene::createWithPhysics();
    //显示物理引擎调试界面 --- 有红框
    scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
    //可把自己的类定义为Layer
    auto layer = MyScene::create();
    scene->addChild(layer);
    
    
    /*创建边框测试*/
    //创建一个物理世界, 大小和屏幕的尺寸相同, 使用默认材质, debug框的宽度为3个像素
    auto body = PhysicsBody::createEdgeBox(visibleSize, PHYSICSBODY_MATERIAL_DEFAULT, 3);
    auto edgeShape = Node::create();//创建一个碰撞图形
    edgeShape->setPhysicsBody(body);//将图形和刚刚创建的世界绑定
    edgeShape->setPosition(visibleSize.width / 2, visibleSize.height / 2);//设置图形的位置在屏幕正中间
    this->addChild(edgeShape);
    
    
    /*创建静态刚体精灵*/
    auto sprite = Sprite::create("HelloWorld.png");
    sprite->setPosition(center);
    this->addChild(sprite);
    //添加静态的刚体
    auto physicsBody = PhysicsBody::createBox(sprite->getContentSize(),
    PhysicsMaterial(0.1f, 1.0f, 0.0f));
    physicsBody->setDynamic(false);
    //设置碰撞层
    physicsBody->setCategoryBitmask(8);//种类
    physicsBody->setCollisionBitmask(16);//碰撞
    physicsBody->setContactTestBitmask(16);//接触
    //把刚体赋给精灵
    sprite->addComponent(physicsBody);
    
    
    /*创建动态刚体精灵*/
    auto sprite = Sprite::create("HelloWorld.png");
    sprite->setPosition(center);
    this->addChild(sprite);
    //添加静态的刚体
    auto physicsBody = PhysicsBody::createBox(sprite->getContentSize(),
    PhysicsMaterial(0.1f, 1.0f, 0.0f));
    physicsBody->setGravityEnable(false);
    //设置碰撞层
    physicsBody->setCategoryBitmask(16);//种类
    physicsBody->setCollisionBitmask(8);//碰撞
    physicsBody->setContactTestBitmask(8);//接触
    //把刚体赋给精灵
    sprite->addComponent(physicsBody);
    
    
    /*添加碰撞事件*/
    auto contactListener = EventListenerPhysicsContact::create();
    contactListener->onContactBegin = [](PhysicsContact& contact) {
    	log("OnCollision");
    	//auto nodeA = contact.getShapeA()->getBody()->getNode();
    	//auto nodeB = contact.getShapeB()->getBody()->getNode();
    	return true;
    };
    //绑定监听事件
    _eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);
    

    2.查询

    • 1.点查询
    • 2.射线查询

    九.音乐和音效

    你的游戏肯定会需要音乐和音效!Cocos2d-x 提供了一个 SimpleAudioEngine 类支持游戏内的音乐和音效。它可以被用来增加背景音乐,控制游戏音效。
    SimpleAudioEngine 是一个共享的单例对象,

    #include "SimpleAudioEngine.h"
    using namespace CocosDenshion;
    
    // 播放背景音乐
    auto audio = SimpleAudioEngine::getInstance();
    audio->playBackgroundMusic("mymusic.mp3", loop);
    // 暂停/停止/恢复 背景音乐
    audio->pauseBackgroundMusic();
    audio->stopBackgroundMusic();
    audio->resumeBackgroundMusic();
    
    //播放音效
    audio->playEffect("myEffect.mp3", false, 1.0f, 1.0f, 1.0f);
    // 暂停/停止/恢复 音效
    audio->pauseEffect();audio->stopEffect();audio->resumeEffect();
    // 暂停/停止/恢复 所有音效
    audio->pauseAllEffects();audio->stopAllEffects();audio->resumeAllEffects();
    
    展开全文
  • 通过cocos的学习理解游戏引擎架构,由于cocos封装的并没有Unity那么好,所以很多底层的机制暴露给开发者,虽然对于开发游戏来说不算友好,但是从引擎理解的角度反倒简单不少。

    常用链接

    Cocos2d-x 用户手册

    参考书目

    《Cocos2d-X游戏开发实战精解》
    《我所理解的Cocos2d-x》
    《Effective C++》中文版第三版

    环境搭建

    macOS 10.15.6
    Xcode 11.5
    cocos2d-x 3.17.2
    cmake 3.17.3

    创建工程

    采用cocos2d-x 3.17版本可直接通过cocos console创建,4.0版本需要额外通过cmake生成.xcodeproj文件。

    cocos new 工程名 -p com.cocos2dx.工程名 -l cpp -d 目录名(/Users/xxx)
    

    架构分析

    目录分析

    cocos目录结构
    Classes存放逻辑代码,Resource存放资源文件
    C++文件由.hpp(声明)和.cpp(定义及初始化)组成

    AppDelegate.h

    #ifndef  _APP_DELEGATE_H_  // 宏定义 保证头文件不需要多次编译
    #define  _APP_DELEGATE_H_
    
    #include "cocos2d.h"
    
    class  AppDelegate : private cocos2d::Application
    {
    public:
        AppDelegate(); // 构造
        virtual ~AppDelegate();  // 虚析构
        virtual void initGLContextAttrs();  // 初始化openGL参数
        virtual bool applicationDidFinishLaunching();   // 应用进入
        virtual void applicationDidEnterBackground();   // 应用中途退入后台
        virtual void applicationWillEnterForeground();  // 应用中途来电
        // 虚析构函数能够保证当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用
    	// 虚函数被继承后仍然是虚拟函数,可以省略掉关键字“virtual”
    };
    
    #endif // _APP_DELEGATE_H_
    
    

    AppDelegate.cpp

    #include "AppDelegate.h"
    #include "MainScene.h"
    
    USING_NS_CC;
    // visiableSize 
    static cocos2d::Size designResolutionSize = cocos2d::Size(1386, 640);
    static cocos2d::Size smallResolutionSize = cocos2d::Size(480, 320);
    static cocos2d::Size mediumResolutionSize = cocos2d::Size(1024, 768);
    static cocos2d::Size largeResolutionSize = cocos2d::Size(2048, 1536);
    
    AppDelegate::AppDelegate()
    {
    }
    
    AppDelegate::~AppDelegate() 
    {
    }
    
    void AppDelegate::initGLContextAttrs()
    {
        // set OpenGL context attributes: red, green, blue, alpha, depth, stencil, multisamplesCount
        GLContextAttrs glContextAttrs = {8, 8, 8, 8, 24, 8, 0};
    
        GLView::setGLContextAttrs(glContextAttrs);
    }
    
    bool AppDelegate::applicationDidFinishLaunching() {
        auto director = Director::getInstance();
        auto glview = director->getOpenGLView();
        if(!glview) {
            director->setOpenGLView(glview);
        }
    
        // 显示演示信息
        director->setDisplayStats(true);
    
        // 设置帧率
        director->setAnimationInterval(1.0f / 60);
    
        // designResolutionSize 设计分辨率大小
        glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::FIXED_WIDTH);
        // frameSize 手机分辨率大小
        auto frameSize = glview->getFrameSize();
        
        // 适配策略
    	if (frameSize.height > mediumResolutionSize.height) {
    		director->setContentScaleFactor(MIN(largeResolutionSize.height/designResolutionSize.height, largeResolutionSize.width/designResolutionSize.width));
    	} else if (frameSize.height > smallResolutionSize.height) {
    	director->setContentScaleFactor(MIN(mediumResolutionSize.height/designResolutionSize.height, mediumResolutionSize.width/designResolutionSize.width));
    	} else {
    	director->setContentScaleFactor(MIN(smallResolutionSize.height/designResolutionSize.height, smallResolutionSize.width/designResolutionSize.width));
    	}
    	
        // 创建场景
        auto mainScene = MainScene::createScene();
        // 导演类调度场景
        director->runWithScene(mainScene);
        
        return true;
    }
    
    void AppDelegate::applicationDidEnterBackground() {
        Director::getInstance()->stopAnimation();
    }
    void AppDelegate::applicationWillEnterForeground() {
        Director::getInstance()->startAnimation();
    }
    

    MainScene.hpp

    #ifndef __MAIN_SCENE_H__
    #define __MAIN_SCENE_H__
    
    #include "cocos2d.h"
    // 继承Scene
    class MainScene : public cocos2d::Scene
    {
    public:
        static cocos2d::Scene* createScene(); // 静态,用于获取场景对象
    
        virtual bool init() override; // 初始化场景
    
        CREATE_FUNC(MainScene); // 
    };
    
    #endif // __HELLOWORLD_SCENE_H__
    

    MainScene.cpp

    #include "MainScene.h"
    
    USING_NS_CC; // 等同于 using namespace cocos2d
    Scene* HelloWorld::createScene()
    {
        auto scene = Scene::create(); // 创建一个Scene对象
        auto layer = MainScene::create(); // 创建一个MainScene对象
        scene->addChild(layer); // 将layer加入到场景中
        return scene;
    }
    
    bool mainScene::init()
    {
        if ( !Scene::init() )
        {
            return false;
        }
        // 在这里添加逻辑代码
        return true;
    }
    

    层的生命周期函数

    bool init()                             // 初始化层调用
    void onEnter()                          // 进入层时调用
    void onEnterTransitionDidFinish()       // 进入层且过渡动画结束时调用
    void onEixt()                           // 退出层时调用
    void onEixtTransitionDidStart()         // 退出层且开始过渡动画时调用
    void cleanup()                          // 层对象被清除时调用
    

    场景文件

    // .h文件
    #ifndef __SET_SCENE__
    #define __SET_SCENE__
    
    #include "cocos2d.h"
    
    class SetScene : public cocos2d::Scene
    {
    public:
    	static cocos2d::Scene* createScene();
    	virtual bool init();
    	CREATE_FUNC(SetScene);
    private:
    	int volume = 50;
    };
    #endif 
    --------------------------------------------------------------------------------------
    // .cpp文件
    #include"SetScene.h"
    
    USING_NS_CC;
    
    Scene* SetScene::createScene() { return SetScene::create(); }
    bool SetScene::init()
    {
    	if (!Scene::init())
    	{
    		return false;
    	}
    	auto visibleSize = Director::getInstance()->getVisibleSize();
    	Vec2 origin = Director::getInstance()->getVisibleOrigin();
    }
    

    普通文件

    // .h文件
    #ifndef _PROP_H_
    #define _PROP_H_
    #include "cocos2d.h"
    
    USING_NS_CC;
    
    class Prop : public Entity {
    public:
    	Prop();
    	~Prop();
    	CREATE_FUNC(Prop);
    	virtual bool init();
    };
    #endif;
    --------------------------------------------------------------------------------------
    // .cpp文件
    #include "prop.h"
    
    Prop::Prop() {}
    Prop::~Prop() {}
    bool Prop::init() { return true; }
    void Prop::createProp(float _x, float _y) {
    	this->x = x;
    	this->y = y;
    	}
    }
    --------------------------------------------------------------------------------------
    // 实例化
    Prop* props = Prop::create();
    props->createProp(10, 20);
    

    二段构造

    // 二段构造的宏函数,其中(std::nothrow)当new失败后强制返回指针,而非try-catch异常
    #define CREATE_FUNC(__TYPE__) \
    static __TYPE__* create() \
    { \
        __TYPE__ *pRet = new(std::nothrow) __TYPE__(); \
        if (pRet && pRet->init()) \
        { \
            pRet->autorelease(); \
            return pRet; \
        } \
        else \
        { \
            delete pRet; \
            pRet = nullptr; \
            return nullptr; \
        } \
    }
    

    二段构造并非经典23种设计模式之一,按照cocos2d-x创始人王哲对于为什么要设计成二段构建的看法:

    其实我们设计二段构造时首先考虑其优势而非兼容cocos2d-iphone。初始化时会遇到图片资源不存在等异常,而C++构造函数无返回值,只能用try-catch来处理异常,启用try-catch会使编译后二进制文件大不少,故需要init返回bool值。Symbian, Bada SDK,objc的alloc + init也都是二阶段构造。

    我们暂且接受非兼容cocos2d-iphone这个理由(反正我不信)。按我个人的理解,既然C++现在已经愿意支持try-catch了,说明C++本身已经不在乎这些二进制文件的体量问题了,更不用说对于java、C#等一些语言来说异常已是必备的特性。而且既然C++都决定支持异常,还为了这些老版本的技术提供(std::nothrow)强制返回指针,自然也表明了并不推荐返回指针了。
    所以实际上对于cocos来说,已经不需要采用二段构建来实例化一个类了,只是没有人在愿意调整框架底层,cocos的每个内置类诸如Sprite、Button等都是采用的二段构建。所以对于开发者来说,需要用的地方自然是要用的,自己写的类可用可不用。不过cocos在实现二段构建的同时,已经实现了简化版的垃圾回收机制,可以省去new/delete操作,所以还是能够简化一些操作的。


    常用功能

    UI布局

    Layer的锚点默认为左下角,其他Node的锚点默认为中心
    Layer要设置锚点,必须先:layerTest->setIgnoreAnchorPointForPosition(false);
    锚点不等于原点

    切换场景

    // include "ShopScene.hpp"
    Director::getInstance()->replaceScene(ShopScene::createScene());
    

    通过图集加载图片

    // 使用texture package将美术提供的tps文件转化为plist和pvr.czz文件
    ZipUtils::setPvrEncryptionKey() // plist->czz需要md5秘钥解码
    SpriteFrameCache *sfc = SpriteFrameCache::getInstance(); // 定义SpriteFrameCache
    sfc->addSpriteFrameWithFile("xxx.plist"); // 调用实例方法addSpriteFrameWithFile()
    
    auto mainBg = Sprite::createWithSpritesFrameName("xxx.png"); // 使用图集加载图片
    

    添加Button

    // include "ui/CocosGUI.h"
    auto btn = cocos2d::ui::Button::create();
    btn->loadTextures("xxx_normal.png", "xxx_pressed.png", "", cocos2d::ui::Widget::TextureResType::PLIST);
    btn->setPosition(Vec2(20, 100));
    this->addChild(btn);
    

    添加文本

    auto label = Label::createWithTTF("Hello World", "fonts/Marker Felt.ttf", 24);
    auto label2 = Label::createWithSystemFont("Hello World", "Arial", 24);
    label->setPosition(Vec2(20, 100));
    this->addChild(label);
    

    添加事件

    // 方法一:设置监听器,由_eventDispatcher派发事件。需要注意的是,在添加到多个对象时,需要使用clone()方法。
    auto listener = EventListenerTouchOneByOne::create();
    	listener->setSwallowTouches(true);
    	listener->onTouchBegan = [=](Touch *touch, Event* event) {
    		// 自己实现事件区域检测,默认全屏可触发
    		auto target = static_cast<Sprite*>(event->getCurrentTarget());//获取到你点击的对象具体是哪个精灵
            Point locationInNode = target->convertTouchToNodeSpace(touch);//获取到点击位置在你这个对象的相对位置
            Size size = target->getContentSize();//对象内容大小,在后面用来判断是否点中了某对象的区域
            Rect rect = Rect(0, 0, size.width, size.height);//包含这个对象的矩形区域
            if (rect.containsPoint(locationInNode))//矩形局域检测,点是否在矩形内部
            {
                printf("点到了图片");
                Director::getInstance()->replaceScene(HelloWorld::createScene());
                return true;
            }
            return false;
     };
     _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, btn);
        
    // 方法二:直接通过对象挂载事件监听器
    btn->addTouchEventListener([&](Ref* sender, cocos2d::ui::Widget::TouchEventType type){
            switch (type)
            {
                    default:
                        break;
                    case ui::Widget::TouchEventType::BEGAN:
                        break;
                    case ui::Widget::TouchEventType::ENDED:
                        break;
            }
    });
    // []:默认不捕获任何变量;
    // [=]:默认以值捕获所有变量;
    // [&]:默认以引用捕获所有变量;
    // [x]:仅以值捕获x,其它变量不捕获;
    

    添加菜单

    // 1. 创建标签
    auto volumeHigherLab = Label::createWithTTF("+", "fonts/Marker Felt.ttf", 150);
    auto volumeLowerLab = Label::createWithTTF("-", "fonts/Marker Felt.ttf", 150);
    // 2. 创建菜单项
    auto volumeHigherMenu = MenuItemLabel::create(volumeHigherLab, CC_CALLBACK_1(SetScene::menuCloseCallbackVolumeHigher, this));
    auto volumeLowerMenu = MenuItemLabel::create(volumeLowerLab, CC_CALLBACK_1(SetScene::menuCloseCallbackVolumeLower, this));
    // 3. 创建菜单
    MenuHigherVolume = Menu::create(volumeHigherMenu, NULL);
    MenuLowerVolume = Menu::create(volumeLowerMenu, NULL);
    // 4. 设置位置并添加到场景中
    MenuHigherVolume->setPosition(850, 250);
    MenuLowerVolume->setPosition(960, 260);
    this->addChild(MenuHigherVolume, 1);
    this->addChild(MenuLowerVolume, 1);
    
    

    添加动画

    // 绕y轴旋转180,5s
    auto* rotateBy = RotateBy::create(5.0f, Vec3(0, 180, 0));
    // 定义回调函数
    auto* callFun = CallFunc::create(CC_CALLBACK_0(MainScene::rotateFun, this));
    // 定义动画序列
    auto* sequence = Sequence::create(rotateBy, callFun, NULL);
    sprite->runAction(sequence);
    

    添加定时器

    // 在init()中进行调用
    scheduleUpdate(); // 重写Update(float dt)方法
    schedule(schedule_selector(MainScene::myUpdate), 0.2f);  // 自定义方法
    

    读取XML文件

    // #include <tinyxml2/tinyxml2.h>
    auto doc = new tinyxml2::XMLDocument();
    doc->Parse(FileUtils::getInstance()->getStringFromFile("data.xml").c_str());  // 调用解析函数
    auto root = doc->RootElement(); // 从根节点开始查找
    for (auto e = root->FirstChildElement(); e != NULL; e = e->NextSiblingElement()) {
        for (auto attr = e->FirstAttribute(); attr != NULL; attr = attr->Next()) {
    		printf("%s %s\n", attr->Name(), attr->Value());
        }
    

    读取json文件

    // #include <json/document.h>
    rapidjson::Document d;
    d.Parse<0>(FileUtils::getInstance()->getStringFromFile("data.json").c_str()); // 调用解析函数 <0>默认解析方式
    printf("%s",d[0]["name"].GetString());
    

    读取本地存储

    UserDefault::getInstance()->getIntegerForKey("int"); // 设置key
    UserDefault::getInstance()->setIntegerForKey("int", 999); // 读取key
    printf("saved file path is %s\n", UserDefault::getInstance()->getXMLFilePath().c_str()); // 存储路径
    
    

    网络编程

    弱联网:CURL库
    强联网:socket

    音频控制

    // 声明 .h
    CocosDenshion::SimpleAudioEngine* audio;
    // 定义 .cpp
    audio = CocosDenshion::SimpleAudioEngine::getInstance();
    if (!audio->isBackgroundMusicPlaying())
    	audio->playBackgroundMusic("xxx.mp3", true);
    

    骨骼动画

    // #include "cocostudio/CocoStudio.h"
    // using namespace cocostudio;
    // 引入骨骼动画文件,保证plist和json在同一个目录下
    ArmatureDataManager::getInstance()->addArmatureFileInfo("ani_mainshop.ExportJson");
    auto armature = Armature::create("ani_mainshop");
    armature->getAnimation()->playWithIndex(1); // 按照Animation的index添加动画
    armature->setPosition(Vec2(0, 0));
    mainShopCarBg->addChild(armature, 1);
    

    游戏控制

    CCScheduler* defaultScheduler = CCDirector::sharedDirector()->getScheduler();
    defaultScheduler->setTimeScale(2.0f); // 全局加速
    defaultScheduler->pauseTarget(this); // 暂停游戏
    defaultScheduler->resumeTarget(this); // 恢复游戏
    

    开发经验

    最小化在编写代码前需要了解的信息
    不是解决任何问题都要从头做起
    框架只是让你规范地去开发
    设计模式是学习OOP的最佳模板

    展开全文
  • CocosCreator小游戏排行榜

    万次阅读 2018-07-18 11:43:44
    先贴上几个链接 : https://developers.weixin.qq.com/minigame/dev/tutorial/open-ability/open-data.html?q=  这个是介绍了子域和主域之间的通信 https://www.w3cschool.cn/weixinapp/weixinapp-vibrate.html ...

    先贴上几个链接 :

    https://developers.weixin.qq.com/minigame/dev/tutorial/open-ability/open-data.html?q=     这个是介绍了子域和主域之间的通信

    https://www.w3cschool.cn/weixinapp/weixinapp-vibrate.html   微信小程序的接口  当时查震动就是在这里找到的

    我用的Creator版本是1.9.2。

    制作游戏微信小游戏排行榜,你需要创建两个项目,一个项目作为主域存放你的代码,就是你写的游戏逻辑。另外需要新建一个项目作为子域,这个项目用来和微信之间通信。因为开发者只有在子域中才能访问微信提供的 wx.getFriendCloudStorage() 和 wx.getGroupCloudStorage() 两个 API,才能实现一些排行榜的功能。

    主域构建的时候要在开放域数据代码写上wegame下的一个文件目录,这个文件目录就是子域的代码。

    子域构建勾选小游戏开放数据域。

    由于每次重新构建的时候,都会将之前的东西先删除再构建,所以要首先构建子域项目,构建完成之后再将子域构建的项目复制过来。我这里选择的是将子域构建目录直接放在主域构建目录的wegame文件夹下,所以我会先构建主域,然后构建子域就可以了,不需要手动去复制粘贴。

    打包子域工程的时候,渲染模式选择canvas,选择自动会报错:子域只支持2D渲染模式

    主域和子域都构建完成了之后,建立主域与子域之间的通信,另外说一下,调用微信的接口使用的wx. 是只能在微信开发工具或者预览到手机上才有用的,直接调试或者运行,在creator中wx.是会报错的,建议搞一个枚举,不然调试功能的时候很麻烦,或者从微信平台再转回Android要更改或者注释很多代码。

    微信中的wx.getOpenDataContext()方法可以获得开放数据域的实例,获得的实例调用postMessage,向子域发送数据,子域通过开启wx.onMessage()接受主域传达的消息。

     

                let openDataContext = wx.getOpenDataContext();

    openDataContext.postMessage({

    text: 'writeBubbleNum',

    bubbleToatalNum:cc.sys.localStorage.getItem("wipeBubbleTotalNum"),

    LV:cc.sys.localStorage.getItem("GameLv"),

    });

     

     

     

    wx子域

     

    wx.onMessage(data => {

    console.log(data)

    switch(data.text){

    case "rankList":

    self.label_tips.active = true;

    self.onLoadRankList();

    break;

    case "abilityList":

    self.label_tips.active = true;

    self.onLoadAbilityList();

    break;

    case "writeBubbleNum":

    self.onWriteBubbleNum(data.bubbleToatalNum,data.LV);

    break;

    default:break;

    }

    })

     

    子域中收到主域传递过来的消息,甄别后进入不同的渠道。我上边的代码前两个是进行读操作,后一个是进行写操作。

     

    存储数据wx.setUserCloudStorage(function(){})

     

    wx.setUserCloudStorage({

    KVDataList: [{key: "writeBubbleNum", value: "" + bubbleToatalNum},{key:"LV",value:"" + LV}],

    success:function(res){

    console.log("存储数据成功")

    },

    fail:function(res){

    console.log("存储数据失败")

    },

    complete:function(res){

    console.log("存储数据完成")

    }

    });

    读数据就通过微信提供的接口来实现

     

    wx.getFriendCloudStorage({

    keyList:["LV"], //获取到好友存储的LV值

    success:function(res){

    console.log("读取等级数据成功")

    console.log(res); //微信开发工具中后台可以看到返回的详细数据

                    }

        });

     

    你申请获得的数据会以下边的格式返回,用户写入的数据都会存储到data当中,如果不清楚可以在后台输出,使用console.log()方法,在微信开发工具中可以查看具体的数据。微信头像的返回是一个URL,可以用cocos官网上提供的一个方法,直接将微信返回的url传入就可以显示头像。

     

     

    //加载头像

        createImage(avatarUrl) {

    if (CC_WECHATGAME) {

    try {

    let image = wx.createImage();

    image.onload = () => {

    try {

    let texture = new cc.Texture2D();

    texture.initWithElement(image);

    texture.handleLoadedTexture();

    this.avatarImgSprite.spriteFrame = new cc.SpriteFrame(texture);

    } catch (e) {

    cc.log(e);

    this.avatarImgSprite.node.active = false;

    }

    };

    image.src = avatarUrl;

    }catch (e) {

    cc.log(e);

    this.avatarImgSprite.node.active = false;

    }

    } else {

    cc.loader.load({

    url: avatarUrl, type: 'jpg'

    }, (err, texture) => {

    this.avatarImgSprite.spriteFrame = new cc.SpriteFrame(texture);

    });

    }

    }

     

    这是在子域中的操作,接下来要把子域中的画面渲染到主域上去。微信公众平台提供的方法我试了下,会报错说不能将安全的canvas绘制到不安全的canvas上,一脸懵。搞了半天没解决问题。后边去用了cocos官网的方法,才实现了,可以去看看。

    链接是:http://docs.cocos.com/creator/manual/zh/publish/publish-wechatgame-sub-domain.html

    上边是官网的代码,值得一提的是我没找到sharedCanvas是在哪里定义的,然后它就直接用了,我将这个sharedCanvas保存为全局变量,通过wx.getOpenDataContext()获得,因为微信调试好麻烦的,我也没试直接用这个玩意。但是我保存全局变量是可以的。

    在上边的代码的基础上,我们还要去设置sharedCanvas的宽高,我是设置的设计分辨率的大小。我这里用的self就是this,因为吃过this的亏,所以我在每个方法的第一行都会写上let self = this;

     

             //子域设置尺寸

    let openDataContext = wx.getOpenDataContext()

    self.sharedCanvas = openDataContext.canvas

    self.sharedCanvas.width = 1080;

    self.sharedCanvas.height = 1920;

        当子域绘制在屏幕上的时候,游戏会特别卡,在微信小游戏中帧率掉到了恐怖的6帧。后边查了很久才知道就是这么卡,最好的解决方案是调开排行榜的时候暂停游戏。然后我去看了跳一跳还有一些带排行榜的游戏,我发现跳一跳排行榜是在载入界面的入口,要么就是游戏结束后会自己弹出,根本就不存在游戏运行的时候可以查看排行榜。所以,加载排行榜的时候还是暂停游戏,或者干脆游戏中不给玩家看排行榜。

    有一些问题,微信小程序的帧率问题,我的小游戏在浏览器和微信开发工具上的模拟器上都不卡,但是在微信小游戏中有一点卡顿,我看了一下帧率,在微信中只有30帧左右波动,而在模拟器中却很流畅,60左右波动,打出android包也是不卡。搜索了很久没找到原因。在cocos论坛上看到了也有类似的情况,引擎团队说是要改底层,我没有解决的能力。不过整体不是很影响。

    还有就是在子域中不能修改节点的颜色,会报错。也是引擎级别的bug。后边应该会改进。

    展开全文
  • cocos

    千次阅读 2018-07-03 11:26:47
    帧率(FPS):1秒内死循环能跑多少次 继承于cc.Component,没有它脚本就挂不到节点上去 extends: cc.Component, 1.脚本中取节点的方式 let node=cc.find('Canvas/TNT');...2.this指的是这个脚本而不是节点;...
  • ##01 Cocos 游戏开发薪资待遇如何? 游戏是互联网最熟悉的变现模式,腾讯/网易大部分的收入占比是游戏。 目前为止,手游与微信抖音小游戏是非常火的开发方向,很多游戏公司做国内,海外市场,流水收入都很不错。 微信...
  • cocos引擎老版本下载集合(cocos2d-x-2.2.1 - 3.5),分别有cocos2d-x-3.5、cocos2d-x-3.4、cocos2d-x-3.2、cocos2d-x-2.2.6、cocos2d-x-2.2.2和cocos2d-x-2.2.1。
  • cocos2D转U3D的一些分享

    2019-06-02 22:22:13
    cocos2D转U3D差不多两年时间,最近换到了新公司,给大家做了一个cocos2D转U3D方面的学习经历分享,整理了一些东西,说一下个人的想法。 第一部分:关于前端频繁换引擎的一些想法,其实从做前端开始,就免不了在...
  • 1、cocoscreator实现图片透明区域的穿透,解决了多图片重叠时的问题。 2、预览请移步:https://pan.baidu.com/s/11v096Bbi3PmqbAEL7Uonew#list/path=/我的分享/CSDN/TouchProj 3、版本creator2.0.8,如有疑问请...
  • 目录 关于cocos  cocos creator学习路线建议 ...要开发微信小游戏,需要选择 cocoscocos creator:cocos creator, 不要选择错了哦。 cocos creator的官方文档:cocos开发文档  注意事项:请注意c...
  • 本课程是《从零开始掌握Cocos2d-x 3.0(基于3.0正式版) 》课程配套的项目实战课程。建议对Cocos2d-x 3.0不了解的同学先学习该课程。本课程将利用《从零开始掌握Cocos2d-x 3.0(基于3.0正式版) 》中讲解的知识开发...
  • cocos creator---颜色的设置和更改

    万次阅读 2018-07-04 17:15:40
    var colorCode = cc.color(255,255,255,255); /* cc.color参数分别代表颜色值:red、green、blue、alpha */ 生成的颜色值如下:
  • 说明:cocos2d-x版本为 3.4,cocosStudio版本为2.1.5  cocosStudio 我个人目前的认识,以为就是一个界面编辑器。界面通过美工可以排布好,然后把发布的csb和png资源文件,提供给程序员使用。 1 关于 ...
  • CocosCreator获取某个节点

    万次阅读 2016-07-20 00:00:29
    //getCholdByName 获取某个节点 getComponent 获取节点的某个元素  that._addSpriteFrameToContainer(newNode.getChildByName('pic').getComponent(cc.Sprite), personOb.icon)
  • CocosCreator引擎的技术框架结构

    千次阅读 2018-03-24 23:19:54
    最近总结了下CocosCreator的技术框架结构,如图:
  • Cocos开发VR菜鸟宝典

    万人学习 2020-03-15 19:43:01
    由知名Cocos技术讲师火云红孩儿主讲的Cocos 开发 VR的系统课程,包括硬件选择,Cocos开发VR的框架搭建,陀螺仪处理,手柄处理,打包发布等各项技术。
  • CocosCreator_获取屏幕尺寸

    万次阅读 2018-08-04 00:13:33
    let windowSize=cc.view.getVisibleSize(); cc.log("width="+windowSize.width+",height="+windowSize.height);; windowSize=cc.winSize;//推荐 原因 短 ...+windowSize.heigh...
  • 实现精灵绕圆形轨迹运动的效果,而且精灵自己也要旋转,某一面始终朝着圆心。
1 2 3 4 5 ... 20
收藏数 106,408
精华内容 42,563
关键字:

cocos