2019-01-07 17:17:59 blogsun 阅读数 354
  • Cocos2d-x 3.x项目实战:星空大战(射击类游戏)

    本课程是《从零开始掌握Cocos2d-x 3.0(基于3.0正式版) 》课程配套的项目实战课程。建议对Cocos2d-x 3.0不了解的同学先学习该课程。本课程将利用《从零开始掌握Cocos2d-x 3.0(基于3.0正式版) 》中讲解的知识开发一款射击类游戏:星空大战(与打飞机游戏类似)。从这个项目中可学习到如何利用Cocos2d-x 3.0的相关知识开发一款完整的射击类游戏。

    18362 人正在学习 去看看 李宁

cocos2dx除了curllib和websocket其他的没有封装好用的网络库,尤其是使用socket的时候得自己分装网络层。网络层有哪些东西呢或者说我们要连接服务器收发数据需要怎样的流程?

自己造轮子

关于socket

首先是socket还好是跨平台支持,至于connect receive send就不说了,至于select epoll poll这些是服务端的东西.

创建socket connect之后就是手法数据了当然之前我们得定义好数据专属的协议使用json pb还是直接传byte.收到数据之后我们需要的是解析数据,解析之前得是完整的包吧需要处理粘包问题,解析之后当然是处理了,根据预定义的消息id或者名字分发到逻辑层进行处理.

消息通信格式

通常的消息格式是:长度+消息内容

消息内容:消息id+消息结构体

消息编码

使用pb或者json或者是使用struct

消息接受

开启一个读线程receive消息并且把消息放入消息缓冲区,然后读取消息缓冲区中完整的消息,需要读出长度信息在进行分别处理可能涉及多次receive.完整的消息结构字后放入消息队列,然后通过schedule将消息发送到cocos的逻辑层进行分发处理

消息发送

开启一个发送线程,逻辑层将消息编码后交给发送线程发送线程组装数据,加上长度信息然后发送给socket,这里需要队列,因为发送失败需要再次发送

读线程

receive消息,解析消息。具体的消息结构最好在逻辑层解析

写线程

处理发送操作涉及重发

心跳包

这个主要是看是否离线

现成的轮子

现成的轮子有很多,分门别类的介绍,例如有mqtt,kcp,sprotop,pbc,lpack,struct,bjson等

git@github.com:bytemode/cocos2dx-socket.git

git@github.com:bytemode/skynet_multithread_client_socket.git

git@github.com:bytemode/sproto.git

git@github.com:bytemode/pbc.git

git@github.com:LuaDist/lpack.git

2014-05-19 20:11:46 zlQQhs 阅读数 2640
  • Cocos2d-x 3.x项目实战:星空大战(射击类游戏)

    本课程是《从零开始掌握Cocos2d-x 3.0(基于3.0正式版) 》课程配套的项目实战课程。建议对Cocos2d-x 3.0不了解的同学先学习该课程。本课程将利用《从零开始掌握Cocos2d-x 3.0(基于3.0正式版) 》中讲解的知识开发一款射击类游戏:星空大战(与打飞机游戏类似)。从这个项目中可学习到如何利用Cocos2d-x 3.0的相关知识开发一款完整的射击类游戏。

    18362 人正在学习 去看看 李宁

cocos2dx版本:cocos2dx2.2

示例下载地址:http://pan.baidu.com/s/1jGsT9C6


这里只是简单的说下如何调用非静态函数


c++调用java

#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
    {
        JniMethodInfo methodInfo;
		//判断有没有getObject()这个函数
        bool isHave = JniHelper::getStaticMethodInfo(methodInfo,
            "com/test/platformcall/PlatformCall",//需要调用的Java文件
            "getObject",//调用的方法名
            "()Ljava/lang/Object;");//参数

        jobject activityObj;
        if (isHave)
        {
			//获得一个实例对象,通过实例对象调用非静态函数
            activityObj = methodInfo.env->CallStaticObjectMethod(methodInfo.classID, methodInfo.methodID);
        }

		//判断有没有say()这个函数
        isHave = JniHelper::getMethodInfo(methodInfo,
            "com/test/platformcall/PlatformCall",
            "say", //say()为非静态的函数
            "()V"); 
        if(isHave)
        {
// 			const char *pMessage = "keng die";//需要传递到Java层的字符串
// 			jstring StringArg = methodInfo.env->NewStringUTF(pMessage);
//          jint intA = 10;
//          jint intB = 20;
//          jboolean boolArg = true;
//          methodInfo.env->CallVoidMethod(jobj, methodInfo.methodID);
            methodInfo.env->CallVoidMethod(activityObj, methodInfo.methodID);
//             CCLog("result = %d", result);
        }
        else
        {
            CCLog("jni:the showMessage method is no exits");
        }
    }
#endif

java调用c++

#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
#include <jni.h>
extern
    "C"
{
	//android 调用 c++
    void Java_com_test_platformcall_PlatformCall_pause(JNIEnv*  env, jobject thiz,jint a)
    {
        CCLog("Android call C++ code, the tag is = %d", a);
    }
};
#endif


2019-01-03 17:23:40 blogsun 阅读数 244
  • Cocos2d-x 3.x项目实战:星空大战(射击类游戏)

    本课程是《从零开始掌握Cocos2d-x 3.0(基于3.0正式版) 》课程配套的项目实战课程。建议对Cocos2d-x 3.0不了解的同学先学习该课程。本课程将利用《从零开始掌握Cocos2d-x 3.0(基于3.0正式版) 》中讲解的知识开发一款射击类游戏:星空大战(与打飞机游戏类似)。从这个项目中可学习到如何利用Cocos2d-x 3.0的相关知识开发一款完整的射击类游戏。

    18362 人正在学习 去看看 李宁

2dx的时代UI树便利和渲染是没有分开的,遍历UI树的时候就渲染.3dx版本为了分离了ui树的遍历和渲染,先遍历生成渲染命令发到渲染队列,之后遍历渲染命令队列开始渲染.这样做的好处是渲染命令可以重用,单独的渲染可以做优化例如自动批绘制.本篇首先介绍cocos2D-X 3.x版本的渲染结构,之后会深入opengl es.

mainLoop

void DisplayLinkDirector::mainLoop()
{
	if (_purgeDirectorInNextLoop)
	{
    	//只有一种情况会调用到这里来,就是导演类调用end函数
        _purgeDirectorInNextLoop = false;
        //清除导演类
        purgeDirector();
    }
    else if (! _invalid)
    {
        //绘制
        drawScene();
        //清除内存
        PoolManager::getInstance()->getCurrentPool()->clear();
    }
}

分析的起点是mainLoop函数,这是在主线程里面会调用的循环,其中drawScene函数进行绘制。那么就进一步来看drawScene函数。mainLoop实在opengl的ondrawframe调用过来的即平台每帧渲染会调用.

drawScene

void Director::drawScene()
{
    //计算间隔时间
    calculateDeltaTime();
    //如果间隔时间过小会被忽略
    if(_deltaTime < FLT_EPSILON){ return;}
    //空函数,也许之后会有作用
    if (_openGLView)
    {
        _openGLView->pollInputEvents();
    }

    //非暂停状态
    if (! _paused)
    {
        //scheduler更新 会使actionmanager更新和相关的schedule更新 引擎物理模拟都是在绘制之前做的
        _scheduler->update(_deltaTime);
        _eventDispatcher->dispatchEvent(_eventAfterUpdate);
    }

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    //切换下一场景,必须放在逻辑后绘制前,否则会出bug
    if (_nextScene)
    {
        setNextScene();
    }

    kmGLPushMatrix();
    //创建单位矩阵
    kmMat4 identity;
    kmMat4Identity(&identity);

    //绘制场景
    if (_runningScene)
    {
        //递归的遍历scene中的每个node的visit生成渲染命令放入渲染队列
        _runningScene->visit(_renderer, identity, false);
        _eventDispatcher->dispatchEvent(_eventAfterVisit);
    }

    //绘制观察节点,如果你需要在场景中设立观察节点,请调用摄像机的setNotificationNode函数 
    if (_notificationNode)
    {
        _notificationNode->visit(_renderer, identity, false);//这是一个常驻节点
    }
    //绘制屏幕左下角的状态
    if (_displayStats)
    {
        showStats();
    }
    //渲染
    _renderer->render();
    //渲染后
    _eventDispatcher->dispatchEvent(_eventAfterDraw);

    kmGLPopMatrix();

    _totalFrames++;

    if (_openGLView)
    {
        _openGLView->swapBuffers(); //交换缓冲区
    }
    //计算绘制时间
    if (_displayStats)
    {
        calculateMPF();
    }
}

其中和绘制相关的是visit的调用和render的调用,其中visit函数会调用节点的draw函数,在3.x之前的版本中draw函数就会直接调用绘制代码,3.x版本是在draw函数中生成将绘制命令放入到renderer队列中,然后renderer函数去进行真正的绘制,首先来看sprite的draw函数.

渲染命令

void Sprite::draw(Renderer *renderer, const kmMat4 &transform, bool transformUpdated)
{
    //检查是否超出边界,自动裁剪
    _insideBounds = transformUpdated ? renderer->checkVisibility(transform, _contentSize) : _insideBounds;

    if(_insideBounds)
    {
        //初始化
        _quadCommand.init(_globalZOrder, _texture->getName(), _shaderProgram, _blendFunc, &_quad, 1, transform);
        renderer->addCommand(&_quadCommand);

        //物理引擎相关绘制边界
if CC_SPRITE_DEBUG_DRAW
        _customDebugDrawCommand.init(_globalZOrder);
        //自定义函数
        _customDebugDrawCommand.func = CC_CALLBACK_0(Sprite::drawDebugData, this);
        renderer->addCommand(&_customDebugDrawCommand);
endif
    }
}

这里面用了两种不同的绘制命令quadCommand初始化后就可以加入到绘制命令中,customDebugDrawCommand传入了一个回调函数,具体的命令种类会在后面介绍。其中自定义的customDebugDrawCommand命令在初始化的时候只传入了全局z轴坐标,因为它的绘制函数全部都在传入的回调函数里面,_quadCommand则需要传入全局z轴坐标,贴图名称,shader,混合,坐标点集合,坐标点集个数,变换

Render

void Renderer::render()
{
    _isRendering = true;
    if (_glViewAssigned)
    {
        //清除
        _drawnBatches = _drawnVertices = 0;
     
        //排序
        for (auto &renderqueue : _renderGroups)
        {
            renderqueue.sort();
        }
        //绘制
        visitRenderQueue(_renderGroups[0]);
        flush();
    }
    clean();
    _isRendering = false;

}

Render类中的render函数进行真正的绘制,首先排序,再进行绘制,从列表中的第一个组开始绘制。在visitRenderQueue函数中可以看到五种不同类型的绘制命令类型,分别对应五个类,这五个类都继承自RenderCommand。

绘制命令
  1. QUAD_COMMAND:

    QuadCommand类绘制精灵等。所有绘制图片的命令都会调用到这里,处理这个类型命令的代码就是绘制贴图的openGL代码,

  2. CUSTOM_COMMAND:

    自定义绘制,自己定义绘制函数,在调用绘制时只需调用已经传进来的回调函数就可以,裁剪节点,绘制图形节点都采用这个绘制,把绘制函数定义在自己的类里。这种类型的绘制命令不会在处理命令的时候调用任何一句openGL代码,而是调用你写好并设置给func的绘制函数,并自己实现一个自定义的绘制。

  3. BATCH_COMMAND:

    批处理绘制,批处理精灵和粒子,其实它类似于自定义绘制,也不会再render函数中出现任何一句openGL函数,它调用一个固定的函数。

  4. GROUP_COMMAND:

    绘制组,一个节点包括两个以上绘制命令的时候,把这个绘制命令存储到另外一个renderGroups中的元素中,并把这个元素的指针作为一个节点存储到renderGroups[0]中。

render流程
void Renderer::addCommand(RenderCommand* command)
{
    //获得栈顶的索引
    int renderQueue =_commandGroupStack.top();
    //调用真正的addCommand
    addCommand(command, renderQueue);
}

void Renderer::addCommand(RenderCommand* command, int renderQueue)
{
    //将命令加入到数组中
    _renderGroups[renderQueue].push_back(command);
}

addCommand它是获得需要把命令加入到renderGroups位置中的索引,这个索引是从commandGroupStack获得的,commandGroupStack是个栈,当我们创建一个GROUP_COMMAND时,需要调用pushGroup函数,它是把当前这个命令在_renderGroups的索引位置压到栈顶,当addCommand时,调用top,获得这个位置

groupCommand.init(globalZOrder);
renderer->addCommand(&_groupCommand);
renderer->pushGroup(_groupCommand.getRenderQueueID());

GROUP_COMMAND一般用于绘制的节点有一个以上的绘制命 令,把这些命令组织在一起,无需排定它们之间的顺序,他们作为一个整体被调用,所以一定要记住,栈是push,pop对应的,关于这个节点的所有的绘制命令被添加完成后,请调用pop,将这个值从栈顶弹出,否则后面的命令也会被添加到这里。

为什么调用的起始只需调用为什么只是0,其他的呢?

visitRenderQueue(_renderGroups[0]);

它们会在处理GROUP_COMMAND被调用

else if(RenderCommand::Type::GROUP_COMMAND == commandType) {
    flush();
    int renderQueueID = ((GroupCommand*) command)->getRenderQueueID();
    visitRenderQueue(_renderGroups[renderQueueID]);
}

2014-07-02 11:58:11 zlQQhs 阅读数 3017
  • Cocos2d-x 3.x项目实战:星空大战(射击类游戏)

    本课程是《从零开始掌握Cocos2d-x 3.0(基于3.0正式版) 》课程配套的项目实战课程。建议对Cocos2d-x 3.0不了解的同学先学习该课程。本课程将利用《从零开始掌握Cocos2d-x 3.0(基于3.0正式版) 》中讲解的知识开发一款射击类游戏:星空大战(与打飞机游戏类似)。从这个项目中可学习到如何利用Cocos2d-x 3.0的相关知识开发一款完整的射击类游戏。

    18362 人正在学习 去看看 李宁

使用cocos2dx3.1.1和VS2012


新建了一个名为test的工程,放在D:\cocos2dx\cocos2d-x-3.1.1\projects下

编译通过,没问题


用cocostudio的场景编辑器做了个场景,

在HelloWorldScene.h中加入

#include "cocostudio/Cocostudio.h"
using namespace cocostudio;

无法包含cocostudio/Cocostudio.h

右键test工程-->属性-->C/C++-->>附加包含目录,将

D:\cocos2dx\cocos2d-x-3.1.1\projects\test\cocos2d\cocos\editor-support

D:\cocos2dx\cocos2d-x-3.1.1\projects\test\cocos2d\cocos

D:\cocos2dx\cocos2d-x-3.1.1\projects\test\cocos2d

包含进来,一路点确定,正常包含,编译,出现以下错误



右键解决方案-->>添加-->>现有项,将以下三个vcxproj添加进来并逐个右键-->>生成

D:\cocos2dx\cocos2d-x-3.1.1\projects\test\cocos2d\extensions\proj.win32\libExtensions.vcxproj

D:\cocos2dx\cocos2d-x-3.1.1\projects\test\cocos2d\cocos\editor-support\cocostudio\proj.win32\libCocosStudio.vcxproj

D:\cocos2dx\cocos2d-x-3.1.1\projects\test\cocos2d\cocos\ui\proj.win32\libGUI.vcxproj


编译,还不是行,右键test工程-->>属性-->>链接器-->>输入-->>附加依赖项,将以下三个lib附加进来

libCocosStudio.lib
libExtensions.lib
libGUI.lib


一路点确定,编译,可以正常运行了,如果遇到其他的问题,可以试着把对应的lib附加进来

2019-01-07 18:48:07 blogsun 阅读数 76
  • Cocos2d-x 3.x项目实战:星空大战(射击类游戏)

    本课程是《从零开始掌握Cocos2d-x 3.0(基于3.0正式版) 》课程配套的项目实战课程。建议对Cocos2d-x 3.0不了解的同学先学习该课程。本课程将利用《从零开始掌握Cocos2d-x 3.0(基于3.0正式版) 》中讲解的知识开发一款射击类游戏:星空大战(与打飞机游戏类似)。从这个项目中可学习到如何利用Cocos2d-x 3.0的相关知识开发一款完整的射击类游戏。

    18362 人正在学习 去看看 李宁

基本机制

事件机制类似观察者模式。

EventListener 事件监听者,封装事件处理代码,包含事件会回调。

事件包含时间信息。

EventDispatcher 事件分发者,管理分发事件。

事件添加机制

EventDispatcher中以 listenerId->EventListenerVector的方式保存了事件监听者。

事件有两种添加方式一种是关联节点,一种是固定优先级的。

添加时根据是添加的方式放入不同的vector。

std::unordered_map<EventListener::ListenerID, EventListenerVector*> _listenerMap;

EventListenerVector包含。

std::vector<EventListener*>* _fixedListeners;

std::vector<EventListener*>* _sceneGraphListeners;

void EventDispatcher::addEventListenerWithSceneGraph(EventListener* listener, Node* node)

void EventDispatcher::addEventListenerWithFixedPriority(EventListener* listener, int priority)

事件移除

固定优先级的需要removeEventListener()

关联节点的节点消失会自行移除。

事件分发

根据id取出事件监听者,

排序事件监听者按照绘制顺序相反顺序或者是事件的优先级排序

sortEventListeners(listenerID);

取出事件监听者id关联的事件监听者列表 将事件分发给每个事件监听者。

分发顺序:

分别取出节点关联的和固定优先级的时间接听者给予分发

分发顺序是按照优先级<0 ==0(关联节点) >0 的分发顺去

cocos2dx 系列教程

阅读数 662

没有更多推荐了,返回首页