Skip to the content.

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 的值永远在我的计算当中,因为每次刷新这两个值都应该会重新计算的吧。若是按照刷新次数去计算这两个值,只会更大吧。