cocos2d::DrawPrimitives和DrawNode分别实现画板功能
2015-05-17 20:15:55
才开始了解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, 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, 0, 0, 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, const cocos2d::Mat4 &transform, uint32_t flags)
{
glLineWidth(2);
DrawPrimitives::setPointSize(2);
DrawPrimitives::setDrawColor4B(255, 0, 0, 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);
virtual void onTouchMoved(cocos2d::Touch *touch, cocos2d::Event *unused_event);
virtual void onTouchEnded(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, 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, 0, 0, 1);
_drawSize = 2;
return true;
}
bool BoardLayer::onTouchBegan(cocos2d::Touch *touch, 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 的值永远在我的计算当中,因为每次刷新这两个值都应该会重新计算的吧。若是按照刷新次数去计算这两个值,只会更大吧。