• 无意中看到steam平台。知道这个平台上有很多游戏,第一次接触这个平台是在Dota2出来时,想在mac os系统上玩游戏的时候。今天看到这个平台上也有独立开发者开发的游戏发布。听说也有开发者赚了不少钱的。在网上找了...
    无意中看到steam平台。知道这个平台上有很多游戏,第一次接触这个平台是在Dota2出来时,想在mac os系统上玩游戏的时候。今天看到这个平台上也有独立开发者开发的游戏发布。听说也有开发者赚了不少钱的。在网上找了一下开发工具。发现下文特地拿来分享。想必这几个工具一定要比写C++代码的cocos2d-x好用很多。
    这些年,一直在从事cocos2d-x引擎的游戏开发。除了U3d和UE4之外,很少接触到其他的游戏开发工具。今天也算收获不小。虽然工具是winodws下使用的,但好像开发出来的游戏支持很多开发平台。这样也算是弥补了自已在游戏开发界的眼界。
    文章中提到的三个2D游戏开发工具:
    文章的评论中还提到几个3D游戏开发工具:
    其实还有很多游戏引擎,参考下边的链接。
    本人凭着对游戏开发的热爱,尝试学习了Steam平台的3款2D游戏开发软件的基础教程,这三款软件分别是:GameMaker: StudioClickteam Fusion 2.5Construct 2。因为没有系统学习过编程,也不是专业游戏开发人员,下面对这三款软件的对比,仅限于通过学习三款软件的基础教程后对他们的了解进行讲述,内容不一定正确和全面,仅给大家作为参考。

    一、总评
    1. 这三款软件都是买断制的,而不像一些大型游戏引擎,需要按时间支付版权费用。
    2. 三款软件都是以2D游戏开发为主,支持非编程试开发,以及多平台导出。即是说,不要求专业的编程知识即可进行游戏开发,制作的项目可以导出为多种平台文件,降低跨平台开发成本。
    3. 区别于RPG Maker这类专项游戏开发软件,软件提供的都是最基本的游戏功能设置,虽然理论上说是可以开发任何类型的游戏,但个人感觉开发动作类游戏要相对简单一些,但开发策略或RPG类型的游戏,需要构建一些基础功能,开发难度会更大一些。简单来说就是自由度有了,但一切都需要从头来过。

    二、软件的版本和价格对比

    GameMaker:Studio 官方网站:http://yoyogames.com/
    官方提供以下4个版本:
    免费版本(下载地址)在使用资源上有一些限制,详细内容参考这里
    Standard版本售价$49.99,和免费版本相比只是去掉了资源使用限制,因为不支持其它扩展,主要用于教学和培训,因此不建议购买。
    Professional版本售价$99.99,包括所有功能,但要做其它平台输出就需要单独购买相应的扩展,例如你如果想开发苹果手机上的游戏,那么就需要购买iOS Export。
    Master Collection版本售价$799.99,一次性买断所有的扩展和以后推出的新扩展,一次性投入,终身受益。
    各个版本功能对比见 http://yoyogames.com/studio

    需要注意的是官方没有直接提供各个版本的升级方案,即是说如果你有Standard版若想升级为Professional版的话,只能重新购买。但如果想升级也并非完全不可能,例如官方在新年的促销活动中允许玩家以补差额的方式进行升级。
    关于Master Collection的价格还有一个小故事,讲述的是在2013年8月,YoyoGame为了庆祝推出GMS1.2版本和Yoyo编译器,特别将Master Collection版本的售价从$499.99提升到$799.99,另外还在官网搞活动可以支付差额获得Master Collection的非Steam版本。(详情点这里
    最近在官方的技术博客中发布了一些关于1.3开发中的新特性文章,有兴趣的可以去看看。

    Clickteam Fusion 2.5 官方网站:http://www.clickteam.com/
    官方提供以下3个版本:
    免费版本(暂无下载)缺少一些功能。
    标准版本售价$99.99,有一些商业用途上的限制,Steam平台上的也是这个版本。
    Developer版本售价$399.99,免去一切限制。
    各个版本功能对比见 http://www.clickteam.com/compare-versions

    多平台输出作为额外的模组需要单独购买,以后官方还会推出内购商店用来购买官方或是第三方开发的一些功能模块。
    Fusion 2 的版本原来是叫Multimedia Fusion 2(现已被Clickteam Fusion 2.5取代),另外官方还有一个软件叫The Games Factory 2,官方在玩文字游戏么?
    Fusion 2 曾经出现在Humble商店每周特惠活动的第32周内,可以在官网支付40刀升级为Fusion 2.5,并可激活Steam版本。
    关于Fusion 2.5对于Fusion 2进行的提升以及优惠信息,请参考这里http://www.clickteam.com/clickteam-fusion-2-5-released.html

    Construct 2 官方网站:https://www.scirra.com/
    官方提供以下3个版本:
    免费版本(下载地址)在使用资源上有一些限制。
    Personal版本售价79英镑(Steam售价$118.99,无功能限制,限定个人使用。
    Business版本售价259英镑(Steam售价$398.99),无限制,如果你的作品给你带来的收入超过5000美金,就要买它了。

    在Steam的商店页面下面的差评中,有人评论Steam上的版本不够稳定,建议使用官方版本。
    可能因为是基于Html5技术开发,所以Construct 2直接支持多平台输出,而不需要额外购买导出插件。
    展开全文
  • 最近完整的学习了learnopengl(http://www.learnopengl.com/),觉得非常有启发,从而又想起了这个长草许久的专题,正好趁这段时间,从本篇起完成这个专题,需要说明的是,从本系列的第五篇起将使用cocos2d-x3.10...

    最近完整的学习了learnopenglhttp://www.learnopengl.com/),觉得非常有启发,从而又想起了这个长草许久的专题,正好趁这段时间,从本篇起完成这个专题,需要说明的是,从本系列的第五篇起将使用cocos2d-x3.10版本对应的代码,最早的三篇采用的是相对比较老的代码,但是我重新阅读后发现对理解有没有什么影响,所以暂时我不会升级之前的代码,但是为了保持和最新代码的一致性,从本篇起我们会采用最新的代码。

           cocos2d-x的底层调用的是openGL ESapi,因此所有的绘制命令追根到底都是调用openGLES,本系列的教程会“刨根问底”的从cocos2d-x的功能讲解到底层代码的调用,从而达到“从cocos2d-x学习openGL”的目的。

    几乎所有openGL教程都会从渲染过程调用着色器的渲染顺序讲起,由于我们这个系列是从cocos2d-x学习openGL,所以,我们的顺序略有不同,我们会从cocos2d-x的应用层讲起,然后讲到调用openGL的代码,将这个过程讲清楚后,我们会在下一节从openGL的层面介绍渲染顺序。

    下面的代码会被添加到我们的场景的上,从而我们的屏幕会显示一条直线:

    auto drawNode = DrawNode::create();
        drawNode->drawLine(Vec2(100, 100), Vec2(200 ,200), Color4F::BLUE);
        this->addChild(drawNode);
            细节我想应该不用详细解释了,我们创建了一个DrawNode节点,然后让他绘制了一个从(100,100)到(200,200)的蓝色直线,显示的结果如图所示:

                    

    那么这个直线到底是如何绘制出来的呢?首先,我们先复习一下VAO和VBO的概念,VBO即顶点缓冲对象,他可以发送顶点数据到GPU上,VAO是顶点数组对象,可以绑定VBO,这样就不用每次都重新配置VBO了,任何对VBO数据层面的修改都可以直接映射,类似数据的指针和组织形式,但是并不是所有设备都支持VAO,所以,我们cocos2d-x通过一个函数来判断当前设备的openGL是否支持VAO:

    Configuration::getInstance()->supportsShareableVAO()

             这个函数返回布尔型的返回值,如果是true说明设备支持VAO,我们首先看DrawNode类的init函数,我们从相对简单的VBO部分说起

    //生成VBO
        glGenBuffers(1, &_vbo);
        //绑定VBO
        glBindBuffer(GL_ARRAY_BUFFER, _vbo);
        //传入数据
        glBufferData(GL_ARRAY_BUFFER, sizeof(V2F_C4B_T2F)* _bufferCapacity, _buffer, GL_STREAM_DRAW);
        //直线部分
        glGenBuffers(1, &_vboGLLine);
        glBindBuffer(GL_ARRAY_BUFFER, _vboGLLine);
        glBufferData(GL_ARRAY_BUFFER, sizeof(V2F_C4B_T2F)*_bufferCapacityGLLine, _bufferGLLine, GL_STREAM_DRAW);
        //点部分
        glGenBuffers(1, &_vboGLPoint);
        glBindBuffer(GL_ARRAY_BUFFER, _vboGLPoint);
        glBufferData(GL_ARRAY_BUFFER, sizeof(V2F_C4B_T2F)*_bufferCapacityGLPoint, _bufferGLPoint, GL_STREAM_DRAW);
        //解绑
        glBindBuffer(GL_ARRAY_BUFFER, 0);

            glGenBuffers返回n(第一个参数)个当前未使用的缓存对象名称,并保存到第二个参数的地址中。这里返回的名称只用于分配其他缓存对象,它们在绑定之后只会记录一个可用的状态。

           然后是调用glBindBuffer绑定缓冲,glBindBuffer完成三项工作,1)如果是第一次绑定,且它是一个非零的无符号整型,那么将创建一个与该名称相应得新缓存对象。2)如果绑定到一个已经创建的缓存对象,那么它将成为当前被激活的缓存对象。3)如果绑定的buffer值为0,那么openGL将不再对当前target应用任何缓存对象。要记住,openGL是个状态机,所有的设置都是设置当前的状态,如果进行下一次设置,那么当前的状态将会继续保留,就像一个工作台,我们把需要处理的零件放在工作台上才能处理,为了防止零件被做额外的处理,在处理完成后我们要把工作台清理干净,这里“glBindBuffer(GL_ARRAY_BUFFER, _vbo);”就是把零件放在加工台上,而“glBindBuffer(GL_ARRAY_BUFFER, 0);”就是将零件台清理干净。

           最后就是调用glBufferData装入数据,它主要有两个任务:分配顶点数据所需的存储空间,然后将数据从应用程序的数组中拷贝到openGL服务端的内存中。这个函数有五个参数,它们的意义如下:

            第一个参数:顶点属性数据类型,顶点数据是GL_ARRAY_BUFFER,索引数据是GL_ELEMENT_ARRAY_BUFFER,纹理缓冲数据GL_TEXTURE
            第二个参数:数据大小
            第三个参数:要么是个客户端内存指针,以便初始化缓存对象,要么是NULL。如果传入的指针非空,那么数据将从客户端拷贝到服务器端,如果传入的指针为空,那么将保留未初始化数据。
            第四个参数:分配数据的读取和写入方式,包括GL_STATIC_DRAW(几乎不会改变),GL_DYNAMIC_DRAW(数据易变),GL_STEAM_DRAW(每次都会被改变)等
            需要说明的是,这里把数据分为vbo,线vbo和点vbo,因为这里绘制的基本图形不是由线组成的,就是用点组成的(是的,画圆的时候要设置segments,其实就是设置直线的片段数)。
            下面是VAO,VAO也分为vao,线vao和点vao,这里节约空间,只介绍vao一个:

    //VAO的处理
        glGenVertexArrays(1, &_vao);
        GL::bindVAO(_vao);
        //设置VBO数据
        glGenBuffers(1, &_vbo);
        glBindBuffer(GL_ARRAY_BUFFER, _vbo);
        glBufferData(GL_ARRAY_BUFFER, sizeof(V2F_C4B_T2F)* _bufferCapacity, _buffer, GL_STREAM_DRAW);
        //绑定VAO
        //顶点
        glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_POSITION);
        glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(V2F_C4B_T2F), (GLvoid *)offsetof(V2F_C4B_T2F, vertices));
        //颜色
        glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_COLOR);
        glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(V2F_C4B_T2F), (GLvoid *)offsetof(V2F_C4B_T2F, colors));
        //贴图
        glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_TEX_COORD);
        glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORD, 2, GL_FLOAT, GL_FALSE, sizeof(V2F_C4B_T2F), (GLvoid *)offsetof(V2F_C4B_T2F, texCoords));
        //解绑
        GL::bindVAO(0);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
             整个过程和VBO类似,首先调用glGenVertexArrays生成一个VAO,然后调用GL::bindVAO(_vao);绑定VAO,最后调用GL::bindVAO(0);解绑

             中间是VAO和VBO的数据连接的过程

             




            如图就是VBO和VAO的关系,VAO索引到VBO数据上,像个指针,索引着VBO上的数据。

            接下来调用glEnableVertexAttribArray和glVertexAttribPointer连接顶点属性,glEnableVertexAttribArray设置是否启用与index(参数)相关联的顶点数据,默认是关闭的。glVertexAttribPointer是一个非常灵活的命令,我们手动指定我们的数据中的那部分对应相应的着色器上的那部分,参数的意义如下
            第一个参数:着色器位置索引,在GLProgram中我们定义了一个枚举,索引了所有的属性,这个参数和glEnableVertexAttribArray一致
            第二个参数:每个顶点的元素数目,第三个参数:数据类型
            第四个参数:是否对参数进行标准化,标准化即把参数转换成(-1,1)的范围,注意这项如果设为TRUE会进行额外的转化计算,会造成额外的开销,这时需要注意的

            第五个参数:步长,两段相同数据之间的距离,第六个参数:偏移量,为什么要设计偏移量呢,因为数据未必是连续的,有可能是位置和颜色混在一起,就如同cocos2d-x中的一样,我们来看V2F_C4B_T2F结构体的定义:

    struct V2F_C4B_T2F
    {
        /// vertices (2F)
        Vec2       vertices;
        /// colors (4B)
        Color4B        colors;
        /// tex coords (2F)
        Tex2F          texCoords;
    };
            也就是首先是二维位置,然后是颜色和贴图,所以,偏移量就是我们需要的数据的起始位置,注意,我们2d图形只有x,y坐标,所以就是Vec2,DrawNode3D就是三维的。

           为什么在init中采用VAO的代码量反倒多了呢,因为VAO一劳永逸的把数据的组织方式都设置好了,后面不再修改,VBO则要在绘制的每一帧都设置一遍这些内容,代码如下:

    if (_dirty)
        {
            glBindBuffer(GL_ARRAY_BUFFER, _vbo);
            glBufferData(GL_ARRAY_BUFFER, sizeof(V2F_C4B_T2F)*_bufferCapacity, _buffer, GL_STREAM_DRAW);
            
            _dirty = false;
        }
        if (Configuration::getInstance()->supportsShareableVAO())
        {
            GL::bindVAO(_vao);
        }
        else
        {
            GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_POS_COLOR_TEX);
    
            glBindBuffer(GL_ARRAY_BUFFER, _vbo);
            // vertex
            glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(V2F_C4B_T2F), (GLvoid *)offsetof(V2F_C4B_T2F, vertices));
            // color
            glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(V2F_C4B_T2F), (GLvoid *)offsetof(V2F_C4B_T2F, colors));
            // texcood
            glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORD, 2, GL_FLOAT, GL_FALSE, sizeof(V2F_C4B_T2F), (GLvoid *)offsetof(V2F_C4B_T2F, texCoords));
        }
    
        glDrawArrays(GL_LINES, 0, _bufferCount);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        
        if (Configuration::getInstance()->supportsShareableVAO())
        {
            GL::bindVAO(0);
        }

           这里只有一个新函数,就是glDrawArrays,它使用当前绑定的顶点数组元素(VAO)来建立一系列几何图元,第一个参数是绘制图形,第二个参数是起始位置,第三个参数是元素个数
           以上就是OpenGL的VAO和VBO的使用,以及绘制流程,下一篇将介绍着色器

           

           能力不足,水平有限,如有错误,多谢指出。


           





             

       








    展开全文
  • steam文档1111

    2020-05-22 23:31:15
    UABE(Unity Assets Bundle Extractor)是一个编辑AssetBundle的工具,可以将AssetBundle中的资源提取出来,也可以把编辑后的资源信息存入AssetBundle
  • cocos2d-x中的触屏事件分为多点触屏和单点触屏,而多点触屏用到的地方并不是很多,所以先主要记录一下单点触屏的用法和基本原理。 一般经常用到的触屏的情况有两种:一种是Layer统一接收触屏消息,然后由程序...

    cocos2d-x中的触屏事件分为多点触屏和单点触屏,而多点触屏用到的地方并不是很多,所以先主要记录一下单点触屏的用法和基本原理。


    一般经常用到的触屏的情况有两种:一种是Layer统一接收触屏消息,然后由程序根据需要分发给不同位置的精灵;另一种情况是自定义一个可以接收触屏消息的Sprite,比如类似于Button功能的Sprite,这就需要在定义Sprite的时候就要定义好触屏所触发的操作!


    下面就两种情况分别记录一下基本用法:

    1.Layer接收触屏消息

    用法很简单,只需要覆写父类的4个方法(可以根据需要,但是ccTouchBegan()是必须要覆写的,并且其返回值对触屏事件的传递有影响,后面会总结),并在init()方法中将其添加到CCTouchDispacher中,代码如下

    class TouchableLayer: public CCLayer 
    {
    public:
        
        virtual bool init();
        
        LAYER_NODE_FUNC(TouchableLayer);
        
        virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
    
        virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);
        virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);
        virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent);
    };
    在Layer的init()中添加如下代码,这个Layer就可以接收到触屏消息了

    CCTouchDispatcher::sharedDispatcher()->addTargetedDelegate(this, 0, true);

    如果想通过这种方式判断具体触摸的Sprite或者区域等信息,就需要自己写判断和分发消息的代码了!

    2.自定义可以接收触屏消息的Sprite

    这种稍微复杂一些,但是还是比较好理解的,首先要先继承CCSprite或者其父类,以满足精灵形状,位置等信息的要求,另外还需要继承触屏事件委托CCTargetedTouchDelegate,CCTargetedTouchDelegate中定义了接收触屏信息的回调虚函数,而这些虚函数,正是我们需要覆写的部分,代码如下

    class TouchableSprite: public CCSprite, public CCTargetedTouchDelegate
    {
        
    public:
        TouchableSprite();
        virtual ~TouchableSprite();
        
        static TouchableSprite *touchSpriteWithFile(const char *file);
        
        bool initWithFile(const char *file);
        
        virtual void onEnter();
        virtual void onExit();
        
        CCRect rect();
        bool containsTouchLocation(CCTouch *touch);
        
        virtual bool ccTouchBegan(CCTouch *touch, CCEvent *event);
        virtual void ccTouchMoved(CCTouch *touch, CCEvent *event);
        virtual void ccTouchEnded(CCTouch *touch, CCEvent *event);
    
    };
    
    重点在于判断自定义Sprite是否被点击,这时就需要得到精灵所在的矩形了,这时又有两种判断方式

    (1)得到触屏所在位置,然后根据精灵所在位置的矩形区域和触屏的点判断是否包含,如果包含,则说明触摸到了Sprite。这里写了一个得到精灵当前所在矩形的方法

    CCRect TouchableSprite::rect()
    {
        CCSize size = getContentSize();
        CCPoint pos = getPosition();
    
        return CCRectMake(pos.x - size.width / 2, pos.y - size.height / 2, size.width, size.height);
    }
    然后在每次点击的时候都需要将当前触屏位置转换为GL坐标的位置,然后和Sprite所在矩形做包含判断

    bool TouchableSprite::containsTouchLocation(cocos2d::CCTouch *touch)
    {
        CCPoint touchPoint = touch->locationInView(touch->view());
        touchPoint = CCDirector::sharedDirector()->convertToGL(touchPoint);
        
        return CCRect::CCRectContainsPoint(rect(), touchPoint);
    }

    (2)其实cocos2d为我们提供了一种相对简单的方法,但是原理类似,调用CCNode中定义的convertTouchToNodeSpaceAR()方法,将触屏点转化为相对于结点的相对坐标

    (ps:由于默认anchor点是中点,所以每一个Sprite上的相对坐标系是从(-width / 2, -height / 2)为左上角点坐标),所以上面的两个方法需要修改一下

    CCRect TouchableSprite::rect()
    {
        CCSize size = getTexture()->getContentSize();
    
        return CCRectMake(-size.width / 2, -size.height / 2, size.width, size.height);
    }
    bool TouchableSprite::containsTouchLocation(cocos2d::CCTouch *touch)
    {
        return CCRect::CCRectContainsPoint(rect(), convertTouchToNodeSpaceAR(touch));
    }

    3.触屏传递顺序

    另外需要主要的是

    virtual bool ccTouchBegan(CCTouch *touch, CCEvent *event);
    方法,其返回值是对此触屏消息有影响的,简单来说,如果返回false,表示不处理ccTouchMoved(),ccTouchEnded(),ccTouchCanceld()方法,而交由后续接收触屏消息的对象处理;如果返回true,表示会处理ccTouchMoved(),ccTouchEnded(),ccTouchCanceld()方法,并且消耗掉此触屏消息。

    总结如下:

    1.CCLayer 只有一层的情况:

    virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
    a.返回false,则ccTouchMoved(),ccTouchEnded()不会再接收到消息
    b.返回true,则ccTouchMoved(),ccTouchEnded()可以接收到消息

    2.CCLayer 有多层的情况:
    virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
    a.返回false,则本层的ccTouchMoved(),ccTouchEnded()不会再接收到消息,但是本层之下的其它层会接收到消息
    b.返回true,则本层的ccTouchMoved(),ccTouchEnded()可以接收到消息,但是本层之下的其它层不能再接收到消息

    3.有自定义接收触摸消息的精灵的情况:
    virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
    a.返回false,则此精灵的ccTouchMoved(),ccTouchEnded()不会再接收到消息,而此精灵所在的层会接收到触摸消息(如果精灵所在层没有设置接收触摸消息,则向下传递
    b.返回true,则此精灵的ccTouchMoved(),ccTouchEnded()会继续接收消息,并消耗此消息(即不再向所在层和其他层传递)

    测试代码






    展开全文
  • cocos2d-x 接入 GameCenter排行榜与成就 [mac - XCode 8.3 - cocos2d-x lua]

    前言


    要求接入GameCenter的排行榜和成就。

    GameCenter 是苹果推出的一个社交平台,
    它主要提供了以下几个功能:

    • 排行榜
    • 成就
    • 挑战

    而且,苹果同时提供了GameKit框架来让GameCenter更易集成。

    可能是因为GameCenter的热度过去了吧,相关的东西都比较早期。
    整理总结了一下,希望对他人有所帮助。

    我的环境:

    mac - XCode 8.3 - cocos2d-x lua






    公共的处理


    1. 配置 iTunes Connect 排行榜与成就的位置。

    登录iTunes Connect, 找到要处理的APP。
    选择 功能->GameCenter
    可以看到三个大项:
    - 移动群组
    - 排行榜
    - 成就


    2. 添加GameKit框架

    打开项目工程,将 Capabilities 的 GameCenter 打开。
    这样,XCode就会将GameKit框架加到我们的工程中。


    3. 登录GameCenter

    登录GameCenter: 【这个步骤在我们加载完游戏时进行即可】

        -(void) authenticateLocalPlayer {
            // 获取本地用户
            GKLocalPlayer* localPlayer = [GKLocalPlayer localPlayer];
    
            // 认证登录
            localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error) {
                [self setLastError:error];
    
                if (localPlayer.authenticated) {                        // 本地用户已经登录
                    _gameCenterFeaturesEnabled = YES;                   // 此变量是判断是否已经登录上GameCenter
                } else if(viewController) {                             // 没有用户,弹出登录界面
                    [self presentViewController:viewController];        
                } else {                                                // 没有用户,并且没有登录界面
                    _gameCenterFeaturesEnabled = NO;
                }
            };
        }
    


    4. 关于lua调用object-c

    因为我的环境是 cocos2d-x lua,所以,用通过lua来调用object-c。
    cocos2d-x其实已经有相关的调用结构 —— LuaObjcBridge, 可以直接用 callStaticMethod来调用:

        LuaObjcBridge.callStaticMethod(methodName className,args)
    


    5. GameKit辅助处理类

    GameKitHelper.h:

        #import <GameKit/GameKit.h>
        #import "cocos2d.h"
    
        // 方便lua调用
        #include "CCLuaEngine.h"
        #include "CCLuaBridge.h"
    
        @interface GameKitHelper : NSObject
        // 处理错误
        @property (nonatomic, readonly) NSError* lastError;
    
        // 初始化
        + (id) sharedGameKitHelper;
    
        // Player authentication, info
        -(void) authenticateLocalPlayer;
        @end
    

    GameKitHelper.mm

        #import "GameKitHelper.h"
    
        @interface GameKitHelper ()
                <GKGameCenterControllerDelegate> {
            BOOL _gameCenterFeaturesEnabled;
        }
        @end
    
        @implementation GameKitHelper
    
        #pragma mark Singleton stuff
    
        +(id) sharedGameKitHelper {
            static GameKitHelper *sharedGameKitHelper;
            static dispatch_once_t onceToken;
            dispatch_once(&onceToken, ^{
                sharedGameKitHelper =
                        [[GameKitHelper alloc] init];
            });
            return sharedGameKitHelper;
        }
    
        #pragma mark Player Authentication
    
        -(void) authenticateLocalPlayer {
            GKLocalPlayer* localPlayer = [GKLocalPlayer localPlayer];
    
            localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error) {
                [self setLastError:error];
                if (localPlayer.authenticated) {
                    _gameCenterFeaturesEnabled = YES;
                } else if(viewController) {
                    [self presentViewController:viewController];
                } else {
                    _gameCenterFeaturesEnabled = NO;
                }
            };
        }
    
        #pragma mark Property setters
    
        -(void) setLastError:(NSError*)error {
            _lastError = [error copy];
            if (_lastError) {
                NSLog(@"GameCenter -- setLastError -- ERROR: %@", [[_lastError userInfo] 
                  description]);
            }
        }
    
        #pragma mark UIViewController stuff
    
        -(UIViewController*) getRootViewController {
            return [UIApplication 
              sharedApplication].keyWindow.rootViewController;
        }
    
        -(void)presentViewController:(UIViewController*)vc {
            UIViewController* rootVC = [self getRootViewController];
            [rootVC presentViewController:vc animated:YES 
              completion:nil];
        }
    
        @end
    


    6. 登录GameCenter时机

    由你决定,可以放在 AppDelegate 中 applicationDidFinishLaunching时。






    关于排行榜


    配置 iTunes Connect

    在iTunes Connect 找到 排行榜。

    简单说一下流程吧:
    配置排行榜的结构,然后我们在游戏中将数据上传到这个结构,最后显示到GameCenter中。

    排行榜分为 单个排行榜 与 组合排行榜。(顾名思义,区别就不需要解释了吧?)
    里面需要配置的相应属性,可参考本文末尾的关于。

    要注意两点:

    1. 排行榜ID,因为只有它是在创建后无法更改的。(而且,要记住这个ID,因为后面程序要用到)
    2. 排行榜只要发布了(经过审批发布),就无法删除了。

    接下来就看属性去配置它吧。




    XCode工程配置

    模拟这个流程:登录GameCenter -> 提交排行榜数据 ( -> 如果需要,弹出GameCenter排行榜)

    提交排行榜数据:

        -(void) submitScore:(int64_t)score category:(NSString*)category {       // 这里两个参数 score是数据, category是ID,就是我们创建排行榜以后,不可更改的那个ID。
            // 检查是否在登录状态
            if (!_gameCenterFeaturesEnabled)    {
                NSLog(@"GameCenter -- submitScore -- Player not authenticated");
                return;
            }
    
            // 创建一个分数对象
            GKScore* gkScore = [[GKScore alloc] initWithCategory:category];
    
            // 设置分数对象的值
            gkScore.value = score;
    
            // 向GameCenter提交数据
            [gkScore reportScoreWithCompletionHandler: ^(NSError* error)    {
                [self setLastError:error];
            }];
        }
    




    实践使用

    在公用部分,已经添加了GameCenter的登录验证相关的东西了。

    • 将排行榜数据提交的函数

    GameKitHelper.h

        -(void) submitScore:(int64_t)score category:(NSString*)category;
    

    GameKitHelper.mm

        -(void) submitScore:(int64_t)score category:(NSString*)category {
    
            if (!_gameCenterFeaturesEnabled)    {
                NSLog(@"GameCenter -- submitScore -- Player not authenticated");
                return;
            }
    
            GKScore* gkScore = [[GKScore alloc] initWithCategory:category];
    
            gkScore.value = score;
    
            [gkScore reportScoreWithCompletionHandler: ^(NSError* error)    {
                [self setLastError:error];
            }];
        }
    
    • 给lua调用的函数

    GameKitHelper.h

        +(void) getScore:(NSDictionary *)dict;
    

    GameKitHelper.mm

        +(void) getScore:(NSDictionary *)dict {
            NSString* rID = [dict objectForKey:@"id"];
            int score = [[dict objectForKey:@"score"] intValue];
    
            [[GameKitHelper sharedGameKitHelper] submitScore:(int64_t)score category:rID];
        }
    
    • lua调用

      LuaObjcBridge.callStaticMethod("GameKitHelper", "getScore", {id = 排行榜的ID, score = 分数值})
      






    关于成就


    配置 iTunes Connect

    还是老位置,之前看的排行榜,这次点成就。
    还是老样子,成就的ID,创建后不可修改,成就发布后不可删除。
    但是,成就还要多一点,就是每个游戏总共有2000点成就分(为什么是2000?你问老乔去。。),你可以给每个成就分配一些成就分。
    成就还有是否隐藏的选项,但是它的隐藏并不是看不到这个成就了,而是有一个成就名称为隐藏的成就显示在列表中。
    还有,它的进度是一个顺时针扇形来表示,就是你的图标刚开始是被遮掩的,随着进度的增加,会逐渐显现出图标,方向是顺时针扇形。

    其他相关参数,可参考本文末尾的关于。




    XCode工程配置

    流程与排行榜的一样,但是这次提交的不是分数了,而是成就完成的百分比。

        // 提交成就数据
        -(void) submitAchievment:(NSString *)identifier percent:(double) percentComplete {          // identifier 成就ID, percentComplete: 成就完成百分比
            // 判断登录认证
            if (!_gameCenterFeaturesEnabled)    {
                NSLog(@"GameCenter -- submitAchievment -- Player not authenticated");
                return;
            }
    
            // 创建成就结构,注入成就ID
            GKAchievement *achievement = [[GKAchievement alloc] initWithIdentifier:identifier];  
    
            // 设置成就百分比
            [achievement setPercentComplete:percentComplete];  
    
            // 提交成就数据
            [achievement reportAchievementWithCompletionHandler:^(NSError *error) {  
                if(error != nil){  
                    NSLog(@"GameCenter -- submitAchievment --  error:%@", [error localizedDescription]);  
                }else{  
                    NSLog(@"GameCenter -- submitAchievment --  提交成就成功");  
                }  
            }];  
        } 
    




    实践使用

    同排行榜一样。

    • 将成就数据提交的函数

    GameKitHelper.h

        - (void)submitAchievment:(NSString *)identifier percent:(double)percentComplete;
    

    GameKitHelper.mm

        -(void) submitAchievment:(NSString *)identifier percent:(double) percentComplete {
            if (!_gameCenterFeaturesEnabled)    {
                NSLog(@"GameCenter -- submitAchievment -- Player not authenticated");
                return;
            }
    
            GKAchievement *achievement = [[GKAchievement alloc] initWithIdentifier:identifier];  
    
            [achievement setPercentComplete:percentComplete];  
    
            [achievement reportAchievementWithCompletionHandler:^(NSError *error) {  
                if(error != nil){  
                    NSLog(@"GameCenter -- submitAchievment --  error:%@", [error localizedDescription]);  
                }else{  
                    NSLog(@"GameCenter -- submitAchievment --  提交成就成功");  
                }  
            }];  
        } 
    
    • 给lua调用的函数

    GameKitHelper.h

        +(void) getAchievement:(NSDictionary *)dict;
    

    GameKitHelper.mm

        +(void) getAchievement:(NSDictionary *)dict {
            NSString* aID = [dict objectForKey:@"id"];
            double percent = [[dict objectForKey:@"percent"] doubleValue];
    
            [[GameKitHelper sharedGameKitHelper] submitAchievment:(NSString *)aID percent:percent];
        }
    
    • lua调用

      LuaObjcBridge.callStaticMethod("GameKitHelper", "getAchievement", {id = 成就ID, percent = 成就百分比})
      






    最后

    GameCenter还是挺好的一个东西。
    它还有一个好友挑战功能,但这个主要适合之前 Flappy Bird,别踩白块 那些游戏来弄。
    或许,这也是这个平台没落了的原因吧。






    关于






    参考

    展开全文
  • 场景在cocos2d-x引擎中对应CCScene类。CCScene是游戏的表现舞台,所有布景、人物角色、菜单等都存放在场景里,作为一个整体,一起渲染,一起销毁,一起被切换。CCScene类继承自CCNode类(CCNode继承自CCObject),它...
    场景在cocos2d-x引擎中对应CCScene类。CCScene是游戏的表现舞台,所有布景、人物角色、菜单等都存放在场景里,作为一个整体,一起渲染,一起销毁,一起被切换。

    CCScene类继承自CCNode类(CCNode继承自CCObject),它本身的方法有用的仅一个,即:
    static CCScene *create(void);   /** 创建一个CCScene对象*/

    因为在cocos2d-x引擎中,CCScene主要承担的是一个容器的功能。游戏开发时把需要渲染的多个对象放到CCScene中统一管理。

    在实际应用中,需要使用到CCScene的基类CCNode的许多方法,因此将CCNode类的主要方法解释如下:
        virtual bool isVisible();    /** 是否可见*/
        virtual void setVisible(bool visible);      /** 设置是否可见*/
        bool isRunning();       /** 节点是否允许*/
        bool isIgnoreAnchorPointForPosition();    // 如果为真,则节点锚点坐标为(0,0)
        void ignoreAnchorPointForPosition(bool isIgnoreAnchorPointForPosition);     /** 设置是否忽略锚点坐标*/
        static CCNode * create(void);       /** 创建一个CCNode对象,有自动释放对象功能*/
        virtual void onEnter();      /** 节点进入舞台(stage)时的回调函数*/ 
        virtual void onEnterTransitionDidFinish();  /** 节点计入舞台后的回调函数*/ 
        virtual void onExit();    /** 节点离开舞台后的回调函数*/
        virtual void onExitTransitionDidStart();    /** 节点离开舞台时的回调函数*/
        virtual void registerScriptHandler(int nHandler);     /** 注册onEnter、onExit的脚本处理函数,onEnter运行后脚本处理函数自动取消注册*/
        virtual void unregisterScriptHandler(void);      /** 取消注册脚本处理函数*/
        virtual void addChild(CCNode * child);     /** 增加子节点,z坐标为0。如果子节点附加到一个运行中的节点,那么onEnter和onEnterTransitionDidFinish函数将立即被调用*/
        virtual void addChild(CCNode * child, int zOrder);    /** 增加子节点,z坐标为zOrder。如附加到一个运行中节点,同上*/
        virtual void addChild(CCNode * child, int zOrder, int tag);   /** 增加子节点,z坐标为zOrder,tag为标志。如附加到运行中节点,同上。*/
        void removeFromParentAndCleanup(bool cleanup);    /** 从父节点中删除自己,若参数cleanup为真,同时删除所有动作和回调函数。若本节点无父节点,则不执行操作*/
        virtual void removeChild(CCNode* child, bool cleanup);     /** 删除子节点。根据参数cleanup删除运行中的动作*/
        void removeChildByTag(int tag, bool cleanup);    /** 通过tag值删除子节点,根据参数cleanup删除动作*/
        virtual void removeAllChildrenWithCleanup(bool cleanup);    /** 删除所有子节点,根据参数cleanup删除动作*/
        CCNode * getChildByTag(int tag);     /** */根据tag值获取子节点,返回值是CCNode型
        virtual void reorderChild(CCNode * child, int zOrder);    /** 根据参数zOrder对子节点重排序,子节点必须已经被附加至本节点*/
        virtual void sortAllChildren();    /** 在被绘制前对子节点进行排序,而不是在每次增减子节点时排序。除非子节点在同一帧内附加后被删除,不然不要手动调用此方法*/
        virtual void cleanup(void);     /** 停止所有运行的动作和定时器*/
        virtual void draw(void);      /** 可重载此函数来绘制节点*/
        virtual void visit(void);     /** 递归访问子节点并绘制它们*/
        CCAction* runAction(CCAction* action);     /** 运行指定的动作*/
        void stopAllActions(void);     /** 从运行动作列表中删除所有动作,即停止所有动作*/
        void stopAction(CCAction* action);     /** 停止指定的动作*/
        void stopActionByTag(int tag);     /** 停止参数tag指定的动作*/
        CCAction* getActionByTag(int tag);    /** 获取参数tag指定的动作*/
        unsigned int numberOfRunningActions(void);     /** 运行动作的数目,为运行中的动作数加上定时器计划将运行的动作数。组合动作如序列动作将被当成一个动作计算。*/
        bool isScheduled(SEL_SCHEDULE selector);     /** 检测参数selector指定的选择器是否被计划定时*/
        void scheduleUpdate(void);     /** 定时调度update方法,其序列号为0。定时后,每帧将调用一次update方法。序列号越小的定时器越先调度。每个节点只能定时一个update方法。*/
        void scheduleUpdateWithPriority(int priority);    /** 定时调度update选择器,自定义优先级。每帧将调用一次update选择器。优先级越小越先调度。每个节点只能定时一个update选择器。*/
        void unscheduleUpdate(void);     /** 取消定时update*/
        void schedule(SEL_SCHEDULE selector);     /** 定时一个选择器,每帧调用一次*/
        void schedule(SEL_SCHEDULE selector, float interval);    /** 定时一个自定义选择器,参数interval为时间间隔,单位为秒。若interval为0,则每帧调用一次(此时推荐使用scheduleUpdate方法)。若选择器已被定时,则仅更新时间间隔,而不重复定时。*/
        void schedule(SEL_SCHEDULE selector, float interval, unsigned int repeat, float delay);  /** 重复执行动作repeat+1次,不断重复则设置repeat为kCCRepeatForever。参数delay指定动作执行前延迟的时间*/ 
        void scheduleOnce(SEL_SCHEDULE selector, float delay);     /** 定时一个仅运行一次的选择器*/
        void unschedule(SEL_SCHEDULE selector);    /** 取消定时一个选择器*/
        void unscheduleAllSelectors(void);    /** 取消所有定时器,包括update选择器。动作不受影响*/
        void resumeSchedulerAndActions(void);    /** 恢复所有定时器和动作,被onEnter内部调用*/
        void pauseSchedulerAndActions(void);    /** 暂停所有定时器和动作,被onExit内部调用*/
    展开全文
  • 2019独角兽企业重金招聘Python工程师标准>>> ...
  • 独立开发者在对接STEAM SDK之前首先得先登上青睐之光,也就是我们俗称的“绿光” 一般要先对接G胖家的SDK,然后提交版本,最后等待审核。。。 我本身是unity 开发,对C++也是糊里糊涂..所以这里主要围绕unity说下...
  • cocos2d backup

    2013-12-19 23:27:28
    https://github.com/cocos2d/cocos2d-iphone-extensions Learning Cocos2D Resources and Source Code SpriteFun 演示(添加sprits) http://www.supersuraccoon-cocos2d.com/zh/2011/06/05/spritefun-demo/ ...
  • cocos2d-iphone FAQ

    2011-07-16 11:13:26
    目录许可证给cocos2d做贡献开发人员疑难解答 许可证 我能在闭源的iPhone应用程序中使用cocos2d吗?是的,可以。cocos2d-iPhone使用MIT许可。如果你有任何疑问,请仔细阅读该协议。 如果有人购买了我的游戏,我...
  • 《Quick-Cocos2d-x v3.3小白书系列教程》 《Quick-Cocos2d-x初学者游戏教程》 转载于:https://www.cnblogs.com/luorende/p/6343345.html
  • 2019-03-01T03:48:37.912Z - normal: Load ~/.CocosCreator/settings.json 2019-03-01T03:48:37.916Z - normal: checking language setting... 2019-03-01T03:48:37.916Z - normal: Language: zh ...
  • 使用jni java反射机制 和callfunc jni:java c++相互调用。 反射机制:主要使用Class Filed Constructor来动态的获取类的方法属性构造器进一步调用对象的方法属性以及构造对象。 callfunc:函数调用。...
  • 前言过年这几天写了几篇Angular2的开发笔记,算是有点“不务正业”,这次为大家带来我正在参与开发的一...这个项目目前仅依赖于cocos2d,实际上他就是使用cocos2d来作为引擎的。需要说明的是,这个系列记述的是软件的开
  • 使用一个简单的游戏开发示例,由浅入深,介绍了如何用Laya引擎开发微信小游戏。    img    作者:马晓东,腾讯前端高级工程师。... 在支持微信小游戏的游戏引擎中,Cocos,Egret,Laya都对小游...
  • 从今往后的项目,由于需要图形化界面,所以建立在cocos2d 3.4引擎基础之上。 说到运动,不得不复习一下平面向量的有关知识(忘完了,尴尬 ^_^;) 这里我就不多做讲解了,向量方面需要用到点乘,内积,外积,矩阵...
  • List of game engines that use lua: 2D Agen (Lua; Windows) Blitwizard (Lua; Windows, Linux, Mac) ...Cocos2d-x (C++/Lua/JS; Windows, Linux, Mac; iOS/Android/BlackBerry) Corona (Lua; Windows, Mac; iO
  • 摘要:今天Unity、Unreal、Cocos2d-x等游戏引擎大行其道,但编程基础成了很多开发者最大的门槛。其实,移动游戏的开发,并没有想象的那么困难。今天为大家推荐几款比较主流的免编程类移动游戏开发工具和引擎。 ...
  • 从Xbox、Windows,到iOS、安卓,再到浏览器平台,每天都有数以亿计的用户在这些设备上运行由游戏开发者设计和开发的游戏。多年以来,我们很荣幸的看到,Visual Studio一直是游戏行业最流行的开发工具,其深受大型...
1 2 3 4 5 ... 11
收藏数 209
精华内容 83
热门标签