对于想了解[Cocos2d-x]在Cocos2d-x3.x版本中如何通过WebSocket连接服务器进行数据传输的读者,本文将提供新的信息,并且为您提供关于cocos2d--WebSocket分析、c
对于想了解[Cocos2d-x]在Cocos2d-x 3.x版本中如何通过WebSocket连接服务器进行数据传输的读者,本文将提供新的信息,并且为您提供关于cocos2d--WebSocket分析、cocos2d-iphone – 在Cocos2d中替换场景时不会触发dealloc、cocos2d-iphone – 如何在cocos2d中显示CCNode的边框?、cocos2d-iphone – 如何在cocos2d中测试精灵碰撞?的有价值信息。
本文目录一览:- [Cocos2d-x]在Cocos2d-x 3.x版本中如何通过WebSocket连接服务器进行数据传输
- cocos2d--WebSocket分析
- cocos2d-iphone – 在Cocos2d中替换场景时不会触发dealloc
- cocos2d-iphone – 如何在cocos2d中显示CCNode的边框?
- cocos2d-iphone – 如何在cocos2d中测试精灵碰撞?
[Cocos2d-x]在Cocos2d-x 3.x版本中如何通过WebSocket连接服务器进行数据传输
首先新建一个空的文件夹,通过npm安装nodejs-websocket
:
npm install nodejs-websocket
新建app.js
文件:
var ws = require("nodejs-websocket"); ws.createServer(function(conn){ conn.on("text",function (str) { console.log("get the message: "+str); conn.sendText("the server got the message"); }) conn.on("close",function (code,reason) { console.log("connection closed"); }); conn.on("error",68)">"an error !"); }); }).listen(8001);
通过node app.js
启动,这样服务器就搭建好了。
Cocos2d-x
- 首先在头文件中include头文件:
#include "network/WebSocket.h"
- 实现WebSocket的委托:
class HelloWorld : public cocos2d::Layer,public cocos2d::network::WebSocket::Delegate
- 四个委托中定义的函数接口以及一个用来连接的socketClient对象:
// for virtual function in websocket delegate virtual void onopen(cocos2d::network::WebSocket* ws); virtual void onMessage(cocos2d::network::WebSocket* ws,const cocos2d::network::WebSocket::Data& data); virtual void onClose(cocos2d::network::WebSocket* ws); virtual void onError(cocos2d::network::WebSocket* ws,const cocos2d::network::WebSocket::ErrorCode& error); // the websocket io client cocos2d::network::WebSocket* _wsiClient;
- 初始化client:
_wsiClient = new cocos2d::network::WebSocket(); _wsiClient->init(*this,"ws://localhost:8001");
- 在cpp文件中实现这些函数:
// 开始socket连接 void HelloWorld::onopen(cocos2d::network::WebSocket* ws) { cclOG("Onopen"); } // 接收到了消息 void HelloWorld::onMessage(cocos2d::network::WebSocket* ws,const cocos2d::network::WebSocket::Data& data) { std::string textStr = data.bytes; textStr.c_str(); cclOG(textStr.c_str()); } // 连接关闭 void HelloWorld::onClose(cocos2d::network::WebSocket* ws) { if (ws == _wsiClient) { _wsiClient = NULL; } CC_SAFE_DELETE(ws); cclOG("onClose"); } // 遇到错误 void HelloWorld::onError(cocos2d::network::WebSocket* ws,const cocos2d::network::WebSocket::ErrorCode& error) { if (ws == _wsiClient) { char buf[100] = {0}; sprintf(buf,68)">"an error was fired,code: %d",error); } cclOG("Error was fired,error code: %d",error); }
还有一个使用SocketIO的方案,尚未尝试,明天测试一下:
// Require HTTP module (to start server) and Socket.IO var http = require('http'),io = require('socket.io'); // Start the server at port 8080 var server = http.createServer(function(req,res){ // Send HTML headers and message res.writeHead(200,{ 'Content-Type': 'text/html' }); res.end('<h1>Hello Socket lover!</h1>'); }); server.listen(8080); // Create a Socket.IO instance,passing it our server var socket = io.listen(server); // Add a connect listener socket.on('connection',function(client){ // Create periodical which ends a message to the client every 5 seconds var interval = setInterval(function() { client.send('This is a message from the server! ' + new Date().getTime()); },5000); // Success! Now listen to messages to be received client.on('message',function(event){ console.log('Received message from client!',event); }); client.on('disconnect',function(){ clearInterval(interval); console.log('Server has disconnected'); }); });
cocos2d--WebSocket分析
WebSocket初始化之后,就可以send了,创建一个新的线程并且循环udpate,线程函数循环onSubThreadLoop,update发送消息给Delegate
线程函数循环onSubThreadLoop 判断是否要destory或者触发拿发送的数据
int WebSocket::onSubThreadLoop() { if (_readyState == State::CLOSED || _readyState == State::CLOSING) { libwebsocket_context_destroy(_wsContext); // return 1 to exit the loop. return 1; } if (_wsContext && _readyState != State::CLOSED && _readyState != State::CLOSING) { libwebsocket_service(_wsContext,0);//触发LWS_CALLBACK_CLIENT_WRITEABLE,去拿发送到server的数据 } // Sleep 50 ms std::this_thread::sleep_for(std::chrono::milliseconds(50)); // return 0 to continue the loop. return 0; } //WebSocket收到消息 int WebSocket::onSocketCallback(struct libwebsocket_context *ctx,struct libwebsocket *wsi,int reason,void *user,void *in,ssize_t len) { //cclOG("socket callback for %d reason",reason); CCASSERT(_wsContext == nullptr || ctx == _wsContext,"Invalid context."); CCASSERT(_wsInstance == nullptr || wsi == nullptr || wsi == _wsInstance,"Invaild websocket instance."); switch (reason) { case LWS_CALLBACK_DEL_POLL_FD: case LWS_CALLBACK_PROTOCOL_DESTROY: case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: { WsMessage* msg = nullptr; if (reason == LWS_CALLBACK_CLIENT_CONNECTION_ERROR || (reason == LWS_CALLBACK_PROTOCOL_DESTROY && _readyState == State::CONNECTING) || (reason == LWS_CALLBACK_DEL_POLL_FD && _readyState == State::CONNECTING) ) { msg = new (std::nothrow) WsMessage(); msg->what = WS_MSG_TO_UITHREAD_ERROR; _readyState = State::CLOSING; //先设置为CLOSING,下一次循环的时候,会destory,才会变成CLOSE } else if (reason == LWS_CALLBACK_PROTOCOL_DESTROY && _readyState == State::CLOSING) { msg = new (std::nothrow) WsMessage(); msg->what = WS_MSG_TO_UITHREAD_CLOSE; } if (msg) { _wsHelper->sendMessagetoUIThread(msg); } } break; case LWS_CALLBACK_CLIENT_ESTABLISHED: { WsMessage* msg = new (std::nothrow) WsMessage(); msg->what = WS_MSG_TO_UITHREAD_OPEN; _readyState = State::OPEN; /* * start the ball rolling,* LWS_CALLBACK_CLIENT_WRITEABLE will come next service */ //每次libwebsocket_service(loop调用)之后,会触发LWS_CALLBACK_CLIENT_WRITEABLE libwebsocket_callback_on_writable(ctx,wsi); _wsHelper->sendMessagetoUIThread(msg); } break; case LWS_CALLBACK_CLIENT_WRITEABLE: { std::lock_guard<std::mutex> lk(_wsHelper->_subThreadWsMessageQueueMutex); std::list<WsMessage*>::iterator iter = _wsHelper->_subThreadWsMessageQueue->begin(); int bytesWrite = 0; for (; iter != _wsHelper->_subThreadWsMessageQueue->end();) { WsMessage* subThreadMsg = *iter; if ( WS_MSG_TO_SUBTRHEAD_SENDING_STRING == subThreadMsg->what || WS_MSG_TO_SUBTRHEAD_SENDING_BINARY == subThreadMsg->what) { Data* data = (Data*)subThreadMsg->obj; const size_t c_bufferSize = WS_WRITE_BUFFER_SIZE; size_t remaining = data->len - data->issued; // 有可能一次发不完,分多次 size_t n = std::min(remaining,c_bufferSize ); //fixme: the log is not thread safe // cclOG("[websocket:send] total: %d,sent: %d,remaining: %d,buffer size: %d",static_cast<int>(data->len),static_cast<int>(data->issued),static_cast<int>(remaining),static_cast<int>(n)); //数据前后加PADDING unsigned char* buf = new unsigned char[LWS_SEND_BUFFER_PRE_PADDING + n + LWS_SEND_BUFFER_POST_PADDING]; memcpy((char*)&buf[LWS_SEND_BUFFER_PRE_PADDING],data->bytes + data->issued,n); int writeProtocol; if (data->issued == 0) { //第一次发送指定writeProtocol为LWS_WRITE_TEXT或者LWS_WRITE_BINARY if (WS_MSG_TO_SUBTRHEAD_SENDING_STRING == subThreadMsg->what) { writeProtocol = LWS_WRITE_TEXT; } else { writeProtocol = LWS_WRITE_BINARY; } // If we have more than 1 fragment if (data->len > c_bufferSize) writeProtocol |= LWS_WRITE_NO_FIN; //说明这还不是最后部分数据 } else { // we are in the middle of fragments writeProtocol = LWS_WRITE_CONTINUATION; //不是第一个发送的部分。 // and if not in the last fragment if (remaining != n) writeProtocol |= LWS_WRITE_NO_FIN; //说明这还不是最后部分数据 } //发送数据,设置writeProtocol类型,具体解析交给WebSocket去做吧。 bytesWrite = libwebsocket_write(wsi,&buf[LWS_SEND_BUFFER_PRE_PADDING],n,(libwebsocket_write_protocol)writeProtocol); //fixme: the log is not thread safe // cclOG("[websocket:send] bytesWrite => %d",bytesWrite); // Buffer overrun? if (bytesWrite < 0) { break; } // Do we have another fragments to send? else if (remaining != n) //没有全部发送,还有一些,记录以及发送的数据issued,下次跳过issued这么多数据 { data->issued += n; break; } // Safely done! else //说明本次的data全部发送完成,移除之 { CC_SAFE_DELETE_ARRAY(data->bytes); CC_SAFE_DELETE(data); CC_SAFE_DELETE_ARRAY(buf); _wsHelper->_subThreadWsMessageQueue->erase(iter++); CC_SAFE_DELETE(subThreadMsg); } } } /* get notified as soon as we can write again */ libwebsocket_callback_on_writable(ctx,wsi); } break; case LWS_CALLBACK_CLOSED: { //fixme: the log is not thread safe // cclOG("%s","connection closing.."); _wsHelper->quitSubThread(); if (_readyState != State::CLOSED) { WsMessage* msg = new (std::nothrow) WsMessage(); _readyState = State::CLOSED; msg->what = WS_MSG_TO_UITHREAD_CLOSE; _wsHelper->sendMessagetoUIThread(msg); } } break; case LWS_CALLBACK_CLIENT_RECEIVE: //有新的数据来了 { if (in && len > 0) { // Accumulate the data (increasing the buffer as we go) if (_currentDataLen == 0) { _currentData = new char[len]; memcpy (_currentData,in,len); _currentDataLen = len; } else {//分配更多的内存,并且保存之前的数据 char *new_data = new char [_currentDataLen + len]; memcpy (new_data,_currentData,_currentDataLen); memcpy (new_data + _currentDataLen,len); CC_SAFE_DELETE_ARRAY(_currentData); _currentData = new_data; _currentDataLen = _currentDataLen + len; } _pendingFrameDataLen = libwebsockets_remaining_packet_payload (wsi);//说明还有滞留的数据,下次才能收到 if (_pendingFrameDataLen > 0) { //cclOG("%ld bytes of pending data to receive,consider increasing the libwebsocket rx_buffer_size value.",_pendingFrameDataLen); } // If no more data pending,send it to the client thread if (_pendingFrameDataLen == 0)//为0,说明没有更多的数据 { WsMessage* msg = new (std::nothrow) WsMessage(); msg->what = WS_MSG_TO_UITHREAD_MESSAGE; char* bytes = nullptr; Data* data = new (std::nothrow) Data(); if (lws_frame_is_binary(wsi)) { bytes = new char[_currentDataLen]; data->isBinary = true; } else { bytes = new char[_currentDataLen+1]; bytes[_currentDataLen] = '\0'; data->isBinary = false; } memcpy(bytes,_currentDataLen); data->bytes = bytes; data->len = _currentDataLen; msg->obj = (void*)data; CC_SAFE_DELETE_ARRAY(_currentData); _currentData = nullptr; _currentDataLen = 0; _wsHelper->sendMessagetoUIThread(msg); } } } break; default: break; } return 0; } }
cocos2d-iphone – 在Cocos2d中替换场景时不会触发dealloc
[[CCDirector sharedDirector] replaceScene:[CCFadeTransition transitionWithDuration:2.0f scene:[HelloWorld scene]]];
按下按钮时会触发上面的代码.
我已经在dealloc方法中放置了一个永远不会触发的NSLog.
更新1:
我最后通过在更换场景之前手动释放内存来解决问题.
解决方法
在我的情况下,我被添加为目标委托自我,这意味着增加了对自我的引用计数.
[[CCTouchdispatcher shareddispatcher] addTargetedDelegate:self priority:2] swallowstouches:NO];
我通过删除所有委托来解决这个问题(你也可以指定特定的委托):
[[CCTouchdispatcher shareddispatcher] removeAllDelegates];
cocos2d-iphone – 如何在cocos2d中显示CCNode的边框?
[super draw]; ccDrawColor4F(0,1,1); ccDrawCircle(self.anchorPointInPoints,20,8,YES);
这很好.为了额外的信用,我添加了以下内容来显示它的边框:
CGRect bb = self.boundingBox; CGPoint vertices[4] = { [self convertToNodeSpace:ccp(bb.origin.x,bb.origin.y)],[self convertToNodeSpace:ccp(bb.origin.x + bb.size.width,bb.origin.y + bb.size.height)],[self convertToNodeSpace:ccp(bb.origin.x,}; ccDrawpoly(vertices,4,YES);
这也很好,直到我重申一个精灵:
CGPoint oldPosition = [sprite convertToWorldspace:sprite.position]; [sprite removeFromParentAndCleanup:NO]; [parentSprite addChild:sprite]; sprite.position = [sprite convertToNodeSpace:oldPosition];
小精灵现在处于正确的位置,其定位点应该在哪里,但是边框将在错误的地方.我究竟做错了什么?
当您将节点重新分配给具有不同来源的父节点,同时保持该节点的相同“世界”位置时,其边界框的起始点将更改.
你的错误是,你对待你的小精灵的边框,好像它的坐标在世界空间.
第二,你不需要做转换x空间的舞蹈来画一个精灵的边框.在项目的cocos2d文件夹中打开ccConfig.h文件并进行更改
#define CC_SPRITE_DEBUG_DRAW 0
行到
#define CC_SPRITE_DEBUG_DRAW 1
第三,sprite.position点的坐标是相对于它的父,而不是精灵.当您调用[node convertToWorldspace:aPoint]时,它会将aPoint视为节点的本地空间.如果要获取节点位置的世界坐标,则应在节点的父节点上调用convertToWorldspace:[node.parent convertToWorldspace:node.position].
cocos2d-iphone – 如何在cocos2d中测试精灵碰撞?
解决方法
在这里看到我的答案:
Collision Detection in Cocos2d game?
今天的关于[Cocos2d-x]在Cocos2d-x 3.x版本中如何通过WebSocket连接服务器进行数据传输的分享已经结束,谢谢您的关注,如果想了解更多关于cocos2d--WebSocket分析、cocos2d-iphone – 在Cocos2d中替换场景时不会触发dealloc、cocos2d-iphone – 如何在cocos2d中显示CCNode的边框?、cocos2d-iphone – 如何在cocos2d中测试精灵碰撞?的相关知识,请在本站进行查询。
本文标签: