1. 程式人生 > >cocos2dx 畫素碰撞

cocos2dx 畫素碰撞

FDPixelSprite.h

#pragma once

#include "cocos2d.h"

using namespace cocos2d;


class FDPixelSprite : public Sprite
{
public:
	FDPixelSprite();
	~FDPixelSprite();

	static FDPixelSprite* create(const std::string& filename);

	void setAlphaThreshold(float threshold);

	inline void setClickCallback(const std::function<void(FDPixelSprite*, float, float)>& call);
	
protected:
	
	void initImageData(const std::string& filename);

	virtual bool onTouchBegan(Touch *touch, Event *unusedEvent);

	virtual void onTouchEnded(Touch *touch, Event *unusedEvent);

protected:

	unsigned char m_threshold;

	Image* m_image;
	EventListenerTouchOneByOne* m_touchListener;

	std::function<void(FDPixelSprite*, float, float)> m_clickCallback;
};

void FDPixelSprite::setClickCallback(const std::function<void(FDPixelSprite*, float, float)>& call)
{
	m_clickCallback = call;
}

FDPixelSprite.cpp

#include "FDPixelSprite.h"


FDPixelSprite* FDPixelSprite::create(const std::string& filename)
{
	FDPixelSprite *sprite = new (std::nothrow) FDPixelSprite();
	if (sprite && sprite->initWithFile(filename))
	{
		sprite->initImageData(filename);
		sprite->autorelease();
		return sprite;
	}
	CC_SAFE_DELETE(sprite);
	return nullptr;
}

FDPixelSprite::FDPixelSprite()
	: m_image(NULL)
	, m_touchListener(NULL)
	, m_threshold(100)
	, m_clickCallback(nullptr)
{}

FDPixelSprite::~FDPixelSprite()
{
	CC_SAFE_DELETE(m_image);
	if (m_touchListener)
	{
		_eventDispatcher->removeEventListener(m_touchListener);
	}
}

void FDPixelSprite::setAlphaThreshold(float threshold)
{
	threshold = MAX(threshold, 0.0f);
	threshold = MIN(threshold, 1.0f);
	m_threshold = 255 * threshold;
}

void FDPixelSprite::initImageData(const std::string& filename)
{
	CC_SAFE_DELETE(m_image);

	m_image = new Image();
	m_image->initWithImageFile(filename);

	if (m_touchListener)
	{
		_eventDispatcher->removeEventListener(m_touchListener);
	}
	m_touchListener = EventListenerTouchOneByOne::create();
	m_touchListener->setSwallowTouches(true);
	m_touchListener->onTouchBegan = CC_CALLBACK_2(FDPixelSprite::onTouchBegan, this);
	m_touchListener->onTouchEnded = CC_CALLBACK_2(FDPixelSprite::onTouchEnded, this);
	_eventDispatcher->addEventListenerWithSceneGraphPriority(m_touchListener, this);
}

bool FDPixelSprite::onTouchBegan(Touch *touch, Event *unusedEvent)
{
	if (!isVisible())
		return false;

	Rect rect;
	rect.size = getContentSize();
	bool ret = isScreenPointInRect(touch->getLocation(), Camera::getVisitingCamera(), getWorldToNodeTransform(), rect, NULL);
	return ret;
}

void FDPixelSprite::onTouchEnded(Touch *touch, Event *unusedEvent)
{
	if (m_clickCallback == nullptr)
	{
		return;
	}

	Rect rect;
	rect.size = getContentSize();
	Vec3 p;
	bool ret = isScreenPointInRect(touch->getLocation(), Camera::getVisitingCamera(), getWorldToNodeTransform(), rect, &p);

	if (ret)
	{
		int width = m_image->getWidth();
		int height = m_image->getHeight();
		int _x = p.x;
		int _y = p.y;
		if (_x > 0 && _x <= width && _y > 0 && _y <= height)
		{
			_y = height - _y;
			int index = _y * width + _x;
			index = index * 4;
			unsigned char* colorData = m_image->getData() + index;

			//CCLOG("r:%d g:%d b:%d a:%d", colorData[0], colorData[1], colorData[2], colorData[3]);
			//alpha
			if (colorData[3] > m_threshold)
			{
				m_clickCallback(this, p.x, p.y);
			}
		}
	}
}