才开始了解cocos2dx几天,只是觉得学习还是得边用边学,所以才想实现点什么,下面提到的有什么问题请指出,谢谢
我想实现简单的画板功能,就看了官方cpp_test的Node:Draw测试代码,遗憾的是我先看到的是DrawPrimitives,所以就研究了一下,简单的实现了我的功能,当我写的差不多的时候才发现DrawPrimitives应该尽量不再使用,而使用DrawNode来实现。
代码都写的差不多了,而且测试效果感觉还特别好,还是在这里留存一下吧:
#pragma once #include "cocos2d.h" struct Segment { cocos2d::Point p1; cocos2d::Point p2; }; class BoardLayer : public cocos2d::LayerColor { public: BoardLayer(); virtual ~BoardLayer(); CREATE_FUNC(BoardLayer); virtual bool init(); virtual bool onTouchBegan(cocos2d::Touch *touch,cocos2d::Event *unused_event); virtual void onTouchMoved(cocos2d::Touch *touch,cocos2d::Event *unused_event); virtual void onTouchEnded(cocos2d::Touch *touch,cocos2d::Event *unused_event); virtual void onTouchCancelled(cocos2d::Touch *touch,cocos2d::Event *unused_event); virtual void draw(cocos2d::Renderer *renderer,const cocos2d::Mat4 &transform,uint32_t flags); private: Segment _bufferSegment; cocos2d::Point _originPoint; cocos2d::Point _prevIoUsPoint; std::vector<Segment> _drawSegment; std::vector<cocos2d::Point> _drawPoint; cocos2d::DrawNode* _drawNode; cocos2d::Color4F _drawColor; float _drawSize; };
#include "BoardLayer.h" USING_NS_CC; BoardLayer::BoardLayer() { } BoardLayer::~BoardLayer() { } bool BoardLayer::init() { Size visibleSize = Director::getInstance()->getVisibleSize(); if (!LayerColor::initWithColor(Color4B(255,255,255),visibleSize.width,visibleSize.height)) return false; this->setTouchMode(Touch::DispatchMode::ONE_BY_ONE); this->setTouchEnabled(true); _drawNode = DrawNode::create(); this->addChild(_drawNode); _drawColor = Color4F(1,1); _drawSize = 2; return true; } bool BoardLayer::onTouchBegan(cocos2d::Touch *touch,cocos2d::Event *unused_event) { Point location = touch->getLocation(); _originPoint = _prevIoUsPoint = location; return true; } void BoardLayer::onTouchMoved(cocos2d::Touch *touch,cocos2d::Event *unused_event) { Point location = touch->getLocation(); // 新点与原点X和Y存在相同 if (_originPoint.x == location.x || _originPoint.y == location.y) { _prevIoUsPoint = location; // 缓冲线段 _bufferSegment.p1 = _originPoint; _bufferSegment.p2 = _prevIoUsPoint; } else { Segment segment; segment.p1 = _originPoint; segment.p2 = _prevIoUsPoint; _drawSegment.push_back(segment); // 存在新点与记忆点X和Y均不同 if (_prevIoUsPoint.x != location.x || _prevIoUsPoint.y != location.y) { Segment segment; segment.p1 = location; segment.p2 = _prevIoUsPoint; _drawSegment.push_back(segment); // 重置原点及记忆点 _originPoint = _prevIoUsPoint = location; } else { _originPoint = _prevIoUsPoint; _prevIoUsPoint = location; } } } void BoardLayer::onTouchEnded(cocos2d::Touch *touch,cocos2d::Event *unused_event) { // 处理点击 Point location = touch->getLocation(); if (_originPoint == location && _prevIoUsPoint == location) return _drawPoint.push_back(location); // 处理MOVE到该点 this->onTouchMoved(touch,unused_event); // 此时若存在有效缓冲线段 if (!_bufferSegment.p1.isZero() || !_bufferSegment.p2.isZero()) { Segment segment; segment.p1 = _bufferSegment.p1; segment.p2 = _bufferSegment.p2; _drawSegment.push_back(segment); // 重置有效缓冲线段 _bufferSegment.p1.setZero(); _bufferSegment.p2.setZero(); } } void BoardLayer::onTouchCancelled(cocos2d::Touch *touch,cocos2d::Event *unused_event) { } void BoardLayer::draw(cocos2d::Renderer *renderer,uint32_t flags) { glLineWidth(2); DrawPrimitives::setPointSize(2); DrawPrimitives::setDrawColor4B(255,255); // 画缓冲线段 if (!_bufferSegment.p1.isZero() || !_bufferSegment.p2.isZero()) { DrawPrimitives::drawLine(_bufferSegment.p1,_bufferSegment.p2); CHECK_GL_ERROR_DEBUG(); } // 画所有线段 for (auto segment : _drawSegment) { DrawPrimitives::drawLine(segment.p1,segment.p2); CHECK_GL_ERROR_DEBUG(); } // 画所有点 for (auto point : _drawPoint) { DrawPrimitives::drawPoint(point); CHECK_GL_ERROR_DEBUG(); } }
之后代码统一换成DrawNode实现,代码竟然精简了如此之多,基本没有什么逻辑:
#pragma once #include "cocos2d.h" class BoardLayer : public cocos2d::LayerColor { public: BoardLayer(); virtual ~BoardLayer(); CREATE_FUNC(BoardLayer); virtual bool init(); virtual bool onTouchBegan(cocos2d::Touch *touch,cocos2d::Event *unused_event); private: cocos2d::Point _originPoint; cocos2d::DrawNode* _drawNode; cocos2d::Color4F _drawColor; float _drawSize; };
#include "BoardLayer.h" USING_NS_CC; BoardLayer::BoardLayer() { } BoardLayer::~BoardLayer() { } bool BoardLayer::init() { Size visibleSize = Director::getInstance()->getVisibleSize(); if (!LayerColor::initWithColor(Color4B(255,cocos2d::Event *unused_event) { _originPoint = touch->getLocation(); return true; } void BoardLayer::onTouchMoved(cocos2d::Touch *touch,cocos2d::Event *unused_event) { Point location = touch->getLocation(); _drawNode->drawSegment(_originPoint,location,_drawSize / 2,_drawColor); _originPoint = location; } void BoardLayer::onTouchEnded(cocos2d::Touch *touch,cocos2d::Event *unused_event) { if (_originPoint == touch->getLocation()) _drawNode->drawPoint(_originPoint,_drawSize,_drawColor); }
这里作一下对比,这里需要提到两个指标,GL Verts 和 GL Calls,概念的含义也是我朋友给我说的,前者是绘图的顶点数量,后者是opengl的调用次数,朋友还特意给我说了这两个值都是越小越好。
当我使用DrawPrimitives实现画板的时候,我每画一个点,GL Verts 值加1,GL Calls 值加1,我每画一条线,GL Verts 值加2(两个顶点),GL Calls 值加1。
当我使用DrawNode实现的时候,我每画一个点,GL Verts 值加1,我每画一条线,GL Verts 这个值是一直累加的(每次累加18),GL Calls 值始终为1。
可能这里也就从一定层面上说明DrawNode早晚会取代DrawPrimitives的原因,DrawPrimitives迟早会被淘汰。
但是这里也有一个疑问是,当使用DrawNode的为什么GL Verts累加的时候每次累加18呢,按我上面给出的参数我怎么想都想不到18啊?
这里也再多说明一个问题,当使用DrawPrimitives的时候,我是在draw实现绘画功能的,但是draw函数我后来发现是被循环调用的,应该是和刷新频率有关,就像MFC程序一样界面每隔一段时间刷新一次,当然这个时间很短,也也就导致了我看到的GL Verts 和 GL Calls 的值永远在我的计算当中,因为每次刷新这两个值都应该会重新计算的吧。若是按照刷新次数去计算这两个值,只会更大吧。