最近公司要在一个项目里接入一个拼玩法,下面我简单做了一个demo
###1. 碎片的实现
这里派生一个Piece类来实现
####Piece.h
#ifndef Piece_hpp
#define Piece_hpp
#include <stdio.h>
#include "cocos2d.h"
#define DELTA 50
typedef enum
{
GROUP_NULL = 0,
GROUP_1 = 1,
GROUP_2 = 2,
GROUP_3 = 3,
}Type;
using namespace cocos2d;
class Piece : public Sprite
{
public:
public:
Piece();
~Piece();
static Piece* create(const std::string &filename);
virtual bool init(const std::string &filename);
public:
/*点击到碎片*/
void setActived(bool bActive);
bool getActived();
/*碎片是否和其他组合*/
void setIsInGroup(bool bGroup);
bool getIsInGroup();
/*设置目标位置*/
void setTargetPoistion(Vec2 targetPosition);
Vec2 getTargetPosition();
/*一定误差范围内移动到正确位置*/
void moveToTargetPosition();
/*碎片是否已经移动到正确的位置*/
void setIsMovedSuccessed(bool success);
bool getIsMovedSuccessed();
/*本次触摸事件完成*/
void setIsEnded(bool end);
bool getIsEnded();
/*加入的组合*/
void setType(Type type);
Type getType();
private:
bool m_bActived;
bool m_bSuccessed;
bool m_bGroup;
bool m_bEnded;
Vec2 m_targetPosition;
Type m_nType;
};
#endif /* Piece_hpp */
####Piece.cpp
//
// Piece.cpp
// Puzzle-mobile
#include "Piece.hpp"
Piece::Piece() : m_targetPosition(Vec2(0,0)),m_bGroup(false),m_bSuccessed(false),m_bEnded(false)
{
}
Piece::~Piece()
{
m_targetPosition = Vec2(0,0);
}
Piece *Piece::create(const std::string &filename)
{
Piece *piece = new Piece();
if (piece && piece->init(filename))
{
piece->autorelease();
}
else
{
delete piece;
return nullptr;
}
return piece;
}
bool Piece::init(const std::string &filename)
{
if (!Sprite::init())
{
return false;
}
this->initWithFile(filename);
return true;
}
void Piece::setIsEnded(bool end)
{
this->m_bEnded = end;
}
bool Piece::getIsEnded()
{
return this->m_bEnded;
}
void Piece::setTargetPoistion(cocos2d::Vec2 targetPosition)
{
m_targetPosition = targetPosition;
}
Vec2 Piece::getTargetPosition()
{
return this->m_targetPosition;
}
void Piece::setActived(bool bActive)
{
this->m_bActived = bActive;
}
bool Piece::getActived()
{
return this->m_bActived;
}
void Piece::setIsInGroup(bool bGroup)
{
this->m_bGroup = bGroup;
}
bool Piece::getIsInGroup()
{
return this->m_bGroup;
}
void Piece::setIsMovedSuccessed(bool success)
{
m_bSuccessed = success;
}
bool Piece::getIsMovedSuccessed()
{
return m_bSuccessed;
}
void Piece::moveToTargetPosition()
{
this->runAction(MoveTo::create(0.2f, m_targetPosition));
this->setIsMovedSuccessed(true);
}
void Piece::setType(Type type)
{
this->m_nType = type;
}
Type Piece::getType()
{
return this->m_nType;
}
####PuzzleScene.h
//
// PuzzleScene.hpp
// Puzzle-mobile
#ifndef PuzzleScene_hpp
#define PuzzleScene_hpp
#include <stdio.h>
#include "cocos2d.h"
#include "Piece.hpp"
USING_NS_CC;
using namespace std;
class PuzzleScene : public Layer
{
public:
PuzzleScene();
~PuzzleScene();
static Scene *scene();
bool init();
virtual void setTouchListener();
virtual bool onTouchBegan(Touch *touch,Event *unused_event);
virtual void onTouchMoved(Touch *touch,Event *unused_event);
virtual void onTouchEnded(Touch *touch,Event *unused_event);
CREATE_FUNC(PuzzleScene);
public:
void checkPiecePosition(Vec2 pt);
bool checkPiecePositionRelativePiece(int i, int j);//没有组合时碎片的相对位置
bool checkPiecePositionRelativeGroup(int i, int j);//检测碎片相对于组合的位置
bool checkGroupPositionRelativePiece(int i, vector<Piece *> vec);//检测组合相对位置
void checkFinalPosition();
private:
map<Type,vector<Piece *>> m_mapPiece;
vector<Piece *> m_vecPiece;
vector<Vec2> m_positionVec;
Sprite *m_background;
};
#endif /* PuzzleScene_hpp */
####PuzzleScene.cpp
//
// PuzzleScene.cpp
// Puzzle-mobile
#include "PuzzleScene.hpp"
PuzzleScene::PuzzleScene()
{
}
PuzzleScene::~PuzzleScene()
{
}
Scene *PuzzleScene::scene()
{
Scene *scene = Scene::create();
PuzzleScene *pLayer = PuzzleScene::create();
scene->addChild(pLayer);
return scene;
}
bool PuzzleScene::init()
{
if (!Layer::init())
{
return false;
}
LayerColor *layer = LayerColor::create(Color4B(255,255,255,255));
this->addChild(layer,0);
this->m_background = Sprite::create("puzzle/background.png");
this->m_background->setPosition(Vec2(this->getContentSize().width/2,this->getContentSize().height/2));
this->addChild(m_background,1);
Vec2 positionPieceTopLeft = Vec2(m_background->getPositionX()- m_background->getContentSize().width/4,
m_background->getPositionY()+ m_background->getContentSize().height/4);
Vec2 positionPieceTopRight = Vec2(m_background->getPositionX()+ m_background->getContentSize().width/4,
m_background->getPositionY()+ m_background->getContentSize().height/4);
Vec2 positionPieceBottomLeft = Vec2(m_background->getPositionX()- m_background->getContentSize().width/4,
m_background->getPositionY()- m_background->getContentSize().height/4);
Vec2 positionPieceBottomRight = Vec2(m_background->getPositionX()+ m_background->getContentSize().width/4,
m_background->getPositionY()- m_background->getContentSize().height/4);
m_positionVec.push_back(positionPieceTopLeft);
m_positionVec.push_back(positionPieceTopRight);
m_positionVec.push_back(positionPieceBottomLeft);
m_positionVec.push_back(positionPieceBottomRight);
for (int i = 0; i < 4; i++)
{
Piece *piece = Piece::create("puzzle/piece_0" + to_string(i) + ".png");
piece->setTargetPoistion(m_positionVec[i]);
piece->setPosition(Vec2(piece->getContentSize().width,this->getContentSize().height - piece->getContentSize().height * i - 50));
this->m_vecPiece.push_back(piece);
this->addChild(piece,2);
}
setTouchListener();
return true;
}
void PuzzleScene::setTouchListener()
{
EventListenerTouchOneByOne *listener = EventListenerTouchOneByOne::create();
listener->onTouchBegan = CC_CALLBACK_2(PuzzleScene::onTouchBegan, this);
listener->onTouchMoved = CC_CALLBACK_2(PuzzleScene::onTouchMoved, this);
listener->onTouchEnded = CC_CALLBACK_2(PuzzleScene::onTouchEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
}
bool PuzzleScene::onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *unused_event)
{
for (int i = 0; i < m_vecPiece.size(); i++)
{
if (m_vecPiece.at(i)->getBoundingBox().containsPoint(touch->getLocation()) && !m_vecPiece.at(i)->getIsMovedSuccessed())
{
m_vecPiece.at(i)->setActived(true);
}
}
return true;
}
void PuzzleScene::onTouchMoved(cocos2d::Touch *touch, cocos2d::Event *unused_event)
{
Vec2 delta = touch->getDelta();
for (int i = 0; i < m_vecPiece.size(); i++)
{
if (m_vecPiece.at(i)->getActived() && !m_vecPiece.at(i)->getIsMovedSuccessed())
{
if (!m_vecPiece.at(i)->getIsInGroup())
{
m_vecPiece.at(i)->setPosition(m_vecPiece.at(i)->getPosition() + delta);
return;
}
else
{
map<Type, vector<Piece *>>::iterator itor = m_mapPiece.find(m_vecPiece.at(i)->getType());
if (itor != m_mapPiece.end())
{
vector<Piece *> vec = itor->second;
for (int j = 0; j < vec.size(); j++)
{
vec.at(j)->setPosition(vec.at(j)->getPosition() + delta);
}
}
}
}
}
}
void PuzzleScene::onTouchEnded(cocos2d::Touch *touch, cocos2d::Event *unused_event)
{
checkPiecePosition(touch->getLocation());
checkFinalPosition();
for (int i = 0; i < m_vecPiece.size(); i++)
{
m_vecPiece.at(i)->setIsEnded(false);
m_vecPiece.at(i)->setActived(false);
}
}
void PuzzleScene::checkPiecePosition(cocos2d::Vec2 pt)
{
for (int i = 0; i < m_vecPiece.size(); i++)
{
if (m_vecPiece.at(i)->getActived() && !m_vecPiece.at(i)->getIsMovedSuccessed())
{
//位置发生变化的碎片没有和其他碎片组合时
if (!m_vecPiece.at(i)->getIsInGroup())
{
bool bBreak = false;
for (int j = 0; j < m_vecPiece.size(); j++)
{
if (i != j)
{
if (!m_vecPiece.at(j)->getIsInGroup() && !m_vecPiece.at(j)->getIsMovedSuccessed())
{
bBreak = checkPiecePositionRelativePiece(i, j);
}
else if(m_vecPiece.at(j)->getIsInGroup() && !m_vecPiece.at(j)->getIsMovedSuccessed())
{
bBreak = checkPiecePositionRelativeGroup(i, j);
}
if (bBreak)
{
break;
}
}
}
}
else
{
//位置发生变化的碎片与其他碎片组合
map<Type,vector<Piece *>>::iterator itor = m_mapPiece.find(m_vecPiece.at(i)->getType());
if (itor != m_mapPiece.end())
{
vector<Piece *> vec = itor->second;
if (checkGroupPositionRelativePiece(i, vec))
{
break;
}
}
}
}
}
}
bool PuzzleScene::checkPiecePositionRelativePiece(int i, int j)
{
bool bBreak = false;
if (!m_vecPiece.at(i)->getIsMovedSuccessed() && !m_vecPiece.at(j)->getIsMovedSuccessed())
{
Vec2 loc_i = m_vecPiece.at(i)->getPosition();
Vec2 loc_j = m_vecPiece.at(j)->getPosition();
int dis = loc_i.distance(loc_j);
int lim = m_vecPiece.at(i)->getTargetPosition().distance(m_vecPiece.at(j)->getTargetPosition());
if (dis < lim)
{
if (m_vecPiece.at(i)->getTargetPosition().x == m_vecPiece.at(j)->getTargetPosition().x)
{
if (m_vecPiece.at(i)->getTargetPosition().y > m_vecPiece.at(j)->getTargetPosition().y)
{
m_vecPiece.at(j)->runAction(MoveTo::create(0.2f, Vec2(loc_i.x,loc_i.y - lim)));
}
else
{
m_vecPiece.at(j)->runAction(MoveTo::create(0.2f, Vec2(loc_i.x,loc_i.y + lim)));
}
long count = m_mapPiece.size();
m_vecPiece.at(i)->setIsInGroup(true);
m_vecPiece.at(i)->setType((Type)(count + 1));
m_vecPiece.at(j)->setIsInGroup(true);
m_vecPiece.at(j)->setType((Type)(count + 1));
vector<Piece *> vec;
vec.push_back(m_vecPiece.at(i));
vec.push_back(m_vecPiece.at(j));
m_mapPiece.insert(map<Type, vector<Piece *>>::value_type(m_vecPiece.at(i)->getType(),vec));
bBreak = true;
}
else if (m_vecPiece.at(i)->getTargetPosition().y == m_vecPiece.at(j)->getTargetPosition().y)
{
if (m_vecPiece.at(i)->getTargetPosition().x > m_vecPiece.at(j)->getTargetPosition().x)
{
m_vecPiece.at(j)->runAction(MoveTo::create(0.2f, Vec2(loc_i.x - lim,loc_i.y)));
}
else
{
m_vecPiece.at(j)->runAction(MoveTo::create(0.2f, Vec2(loc_i.x + lim,loc_i.y)));
}
long count = m_mapPiece.size();
m_vecPiece.at(i)->setIsInGroup(true);
m_vecPiece.at(i)->setType((Type)(count + 1));
m_vecPiece.at(j)->setIsInGroup(true);
m_vecPiece.at(j)->setType((Type)(count + 1));
vector<Piece *> vec;
vec.push_back(m_vecPiece.at(i));
vec.push_back(m_vecPiece.at(j));
m_mapPiece.insert(map<Type, vector<Piece *>>::value_type(m_vecPiece.at(i)->getType(),vec));
bBreak = true;
}
}
}
return bBreak;
}
bool PuzzleScene::checkPiecePositionRelativeGroup(int i, int j)
{
bool bBreak = false;
int dis = m_vecPiece.at(i)->getPosition().distance(m_vecPiece.at(j)->getPosition());
int lim = m_vecPiece.at(i)->getTargetPosition().distance(m_vecPiece.at(j)->getTargetPosition());
if (dis < lim)
{
Vec2 delta = Vec2(0,0);
Vec2 loc_i = m_vecPiece.at(i)->getPosition();
Vec2 loc_j = m_vecPiece.at(j)->getPosition();
if (m_vecPiece.at(i)->getTargetPosition().x == m_vecPiece.at(j)->getTargetPosition().x)
{
if (m_vecPiece.at(i)->getTargetPosition().y > m_vecPiece.at(j)->getTargetPosition().y)
{
delta = Vec2(loc_i.x,loc_i.y - lim) - loc_j;
}
else
{
delta = Vec2(loc_i.x,loc_i.y + lim) - loc_j;
}
map<Type, vector<Piece *>>::iterator itor = m_mapPiece.find(m_vecPiece.at(j)->getType());
vector<Piece *> vec;
if (itor != m_mapPiece.end())
{
vec = itor->second;
for (int k = 0; k < vec.size(); k++)
{
Vec2 loc = vec.at(k)->getPosition();
vec.at(k)->runAction(MoveTo::create(0.2f, Vec2(loc.x + delta.x,loc.y + delta.y)));
}
m_vecPiece.at(i)->setIsInGroup(true);
m_vecPiece.at(i)->setType(m_vecPiece.at(j)->getType());
vec.push_back(m_vecPiece.at(i));
m_mapPiece.erase(m_vecPiece.at(j)->getType());
m_mapPiece.insert(map<Type, vector<Piece *>>::value_type(m_vecPiece.at(i)->getType(),vec));
}
bBreak = true;
}
else if (m_vecPiece.at(i)->getTargetPosition().y == m_vecPiece.at(j)->getTargetPosition().y)
{
if (m_vecPiece.at(i)->getTargetPosition().x > m_vecPiece.at(j)->getTargetPosition().x)
{
delta = Vec2(loc_i.x - lim,loc_i.y) - loc_j;
}
else
{
delta = Vec2(loc_i.x + lim,loc_i.y) - loc_j;
}
map<Type, vector<Piece *>>::iterator itor = m_mapPiece.find(m_vecPiece.at(j)->getType());
vector<Piece *> vec;
if (itor != m_mapPiece.end())
{
vec = itor->second;
for (int k = 0; k < vec.size(); k++)
{
Vec2 loc = vec.at(k)->getPosition();
vec.at(k)->runAction(MoveTo::create(0.2f, loc + delta));
}
m_vecPiece.at(i)->setIsInGroup(true);
m_vecPiece.at(i)->setType(m_vecPiece.at(j)->getType());
vec.push_back(m_vecPiece.at(i));
m_mapPiece.erase(m_vecPiece.at(j)->getType());
m_mapPiece.insert(map<Type, vector<Piece *>>::value_type(m_vecPiece.at(i)->getType(),vec));
}
bBreak = true;
}
}
return bBreak;
}
bool PuzzleScene::checkGroupPositionRelativePiece(int i, vector<Piece *> vec)
{
bool bBreak = false;
Type nType = m_vecPiece.at(i)->getType();
for (int k = 0; k < m_vecPiece.size();k++)
{
Piece *piece = m_vecPiece.at(k);
if (nType != piece->getType() && !piece->getIsMovedSuccessed())
{
if (!piece->getIsInGroup())
{
for (int m = 0; m < vec.size(); m++)
{
Piece *pie = vec.at(m);
int dis = piece->getPosition().distance(pie->getPosition());
int lim = piece->getTargetPosition().distance(pie->getTargetPosition());
if (dis < lim)
{
bBreak = true;
if (pie->getTargetPosition().x == piece->getTargetPosition().x)
{
if (pie->getTargetPosition().y < piece->getTargetPosition().y)
{
piece->runAction(MoveTo::create(0.2f, Vec2(pie->getPosition().x,pie->getPosition().y + lim)));
piece->setType(pie->getType());
piece->setIsInGroup(true);
vec.push_back(piece);
m_mapPiece.erase(pie->getType());
m_mapPiece.insert(map<Type,vector<Piece *>>::value_type(pie->getType(),vec));
return bBreak;
}
else
{
piece->runAction(MoveTo::create(0.2f, Vec2(pie->getPosition().x,pie->getPosition().y - lim)));
piece->setType(pie->getType());
piece->setIsInGroup(true);
vec.push_back(piece);
m_mapPiece.erase(pie->getType());
m_mapPiece.insert(map<Type,vector<Piece *>>::value_type(pie->getType(),vec));
return bBreak;
}
}
if (pie->getTargetPosition().y == piece->getTargetPosition().y)
{
if (pie->getTargetPosition().x < piece->getTargetPosition().x)
{
piece->runAction(MoveTo::create(0.2f, Vec2(pie->getPosition().x + lim,pie->getPosition().y)));
piece->setType(pie->getType());
piece->setIsInGroup(true);
vec.push_back(piece);
m_mapPiece.erase(pie->getType());
m_mapPiece.insert(map<Type,vector<Piece *>>::value_type(pie->getType(),vec));
return bBreak;
}
else
{
piece->runAction(MoveTo::create(0.2f, Vec2(pie->getPosition().x - lim,pie->getPosition().y)));
piece->setType(pie->getType());
piece->setIsInGroup(true);
vec.push_back(piece);
m_mapPiece.erase(pie->getType());
m_mapPiece.insert(map<Type,vector<Piece *>>::value_type(pie->getType(),vec));
return bBreak;
}
}
}
}
}
else
{
map<Type, vector<Piece *>>::iterator itor = m_mapPiece.find(piece->getType());
vector<Piece *> vec2;
if (itor != m_mapPiece.end())
{
vec2 = itor->second;
}
for (int k = 0; k < vec.size(); k++)
{
for (int m = 0; m < vec2.size(); m++)
{
Piece *vecPie = vec.at(k);
Piece *vec2Pie = vec2.at(m);
int dis = vecPie->getPosition().distance(vec2Pie->getPosition());
int lim = vecPie->getTargetPosition().distance(vec2Pie->getTargetPosition());
if (dis < lim)
{
Vec2 delta;
bBreak = true;
if (vecPie->getTargetPosition().x == vec2Pie->getTargetPosition().x)
{
if (vecPie->getTargetPosition().y < vec2Pie->getTargetPosition().y)
{
delta = Vec2(vecPie->getPosition().x,vecPie->getPosition().y + lim) - vec2Pie->getPosition();
for (int n = 0; n < vec2.size(); n++)
{
vec2.at(n)->runAction(MoveTo::create(0.2f,vec2.at(n)->getPosition() + delta));
vec2.at(n)->setType(vecPie->getType());
vec.push_back(vec2.at(n));
}
m_mapPiece.erase(vecPie->getType());
m_mapPiece.insert(map<Type,vector<Piece *>>::value_type(vecPie->getType(),vec));
return bBreak;
}
else
{
delta = Vec2(vecPie->getPosition().x,vecPie->getPosition().y - lim) - vec2Pie->getPosition();
for (int n = 0; n < vec2.size(); n++)
{
vec2.at(n)->runAction(MoveTo::create(0.2f,vec2.at(n)->getPosition() + delta));
vec2.at(n)->setType(vecPie->getType());
vec.push_back(vec2.at(n));
}
m_mapPiece.erase(vecPie->getType());
m_mapPiece.insert(map<Type,vector<Piece *>>::value_type(vecPie->getType(),vec));
return bBreak;
}
}
if (vecPie->getTargetPosition().y == vec2Pie->getTargetPosition().y)
{
if (vecPie->getTargetPosition().x < vec2Pie->getTargetPosition().x)
{
delta = Vec2(vecPie->getPosition().x + lim,vecPie->getPosition().y) - vec2Pie->getPosition();
for (int n = 0; n < vec2.size(); n++)
{
vec2.at(n)->runAction(MoveTo::create(0.2f,vec2.at(n)->getPosition() + delta));
vec2.at(n)->setType(vecPie->getType());
vec.push_back(vec2.at(n));
}
m_mapPiece.erase(vecPie->getType());
m_mapPiece.insert(map<Type,vector<Piece *>>::value_type(vecPie->getType(),vec));
return bBreak;
}
else
{
delta = Vec2(vecPie->getPosition().x - lim,vecPie->getPosition().y) - vec2Pie->getPosition();
for (int n = 0; n < vec2.size(); n++)
{
vec2.at(n)->runAction(MoveTo::create(0.2f,vec2.at(n)->getPosition() + delta));
vec2.at(n)->setType(vecPie->getType());
vec.push_back(vec2.at(n));
}
m_mapPiece.erase(vecPie->getType());
m_mapPiece.insert(map<Type,vector<Piece *>>::value_type(vecPie->getType(),vec));
return bBreak;
}
}
}
}
}
}
}
}
return bBreak;
}
void PuzzleScene::checkFinalPosition()
{
for (int i = 0; i < m_vecPiece.size(); i++)
{
if (m_vecPiece.at(i)->getPosition().distance(m_vecPiece.at(i)->getTargetPosition()) < DELTA)
{
m_vecPiece.at(i)->moveToTargetPosition();
}
}
}