最近比较忙,有一段时间没写东西了,今天算是忙里偷闲,分享点东西。
在美区有个游戏叫bloodbrothers,玩了玩,感觉还不错,其中有一个页面,可以选择人物的奴仆,页面布局是中间是主人,四周是奴仆,以一个椭圆形围着主人转圈,仆人的数目可以增减,觉得这个页面挺有意思,我就试着实现了一个。
blood brothers的效果:
玩家滑动屏幕,两个骷髅兵会围着中间的老大按照椭圆轨迹转圈。
我实现的效果:
中间的老大我没做,滑动屏幕,四周的机器人图片会以椭圆轨迹旋转,个人感觉效果尚可,如果美工跟得上
我觉得效果不会比人家的差-_-!
废话不多说了,上代码
cwMainLayer.h
#ifndef _cwMainLayer_h_
#define _cwMainLayer_h_
#include "cocos2d.h"
using namespace cocos2d;
#include <string>
#include <vector>
using namespace std;
class cwShowSprite : public CCSprite
{
public:
cwShowSprite() : m_fAngle(0) {}
~cwShowSprite() {}
public:
staticcwShowSprite* create(const char *pszFileName);
private:
//当前角度
CC_SYNTHESIZE(float, m_fAngle, Angle);
};
class cwMainLayer : public CCLayer
{
public:
cwMainLayer() : m_pArrShow(NULL), m_fAngleStep(0),m_fScaleStart(1.0f), m_fScaleEnd(0.6f) {}
~cwMainLayer();
//增加显示图片
voidaddShow(const char* pcName);
//排列图片
voidarrange();
private:
//计算图片角度
voidarrangeAngle();
//计算图片位置
voidarrangePosition();
//计算图片zorder
voidarrangeZOrder();
//计算图片缩放值
voidarrangeScale();
//根据y坐标排序(由小到大)
vector<cwShowSprite*>orderByY();
//计算那个图片被点击
cwShowSprite* clickSprite(CCPoint& pt);
//将图片移动指定角度
voidmoveShow(float angle);
public:
CREATE_FUNC(cwMainLayer);
boolinit();
virtual voidonEnter();
virtual voidonExit();
virtual boolccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
virtual voidccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);
virtual voidccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);
private:
//存储图片数组
CCArray*m_pArrShow;
//圆环中点
CC_SYNTHESIZE_PASS_BY_REF(CCPoint, m_nCenter, Center);
//椭圆长短轴
CC_SYNTHESIZE(float, m_fLongA, LongA);
CC_SYNTHESIZE(float, m_fShortB, ShortB);
//缩放范围
CC_SYNTHESIZE(float, m_fScaleStart, ScaleStart);
CC_SYNTHESIZE(float, m_fScaleEnd, ScaleEnd);
//图片的起始zorder
CC_SYNTHESIZE(int, m_iZStart, ZStart);
//图片在圆环上排列的角度步长
floatm_fAngleStep;
//图片Y值区间,也就是椭圆短轴y坐标区域
floatm_fYMin;
floatm_fYMax;
//fortouch
CCPointm_nTouchBegin;
CCPointm_nTouchMoving;
//background
CCSprite*m_pBackGround;
};
#endif
cwMainLayer.cpp
#include "cwMainLayer.h"
#include <list>
#include <vector>
#include <algorithm>
using namespace std;
cwShowSprite* cwShowSprite::create(const char *pszFileName)
{
cwShowSprite* pSprite = new cwShowSprite();
if(pSprite&&pSprite->initWithFile(pszFileName)) {
pSprite->autorelease();
returnpSprite;
}
CC_SAFE_DELETE(pSprite);
returnNULL;
}
cwMainLayer::~cwMainLayer()
{
CC_SAFE_RELEASE_NULL(m_pArrShow);
}
bool cwMainLayer::init()
{
if(!CCLayer::init()) return false;
CCSizewinSize =CCDirector::sharedDirector()->getWinSize();
m_pBackGround = CCSprite::create("bk.png");
m_pBackGround->setPosition(ccp(winSize.width*0.5,winSize.height*0.5));
this->addChild(m_pBackGround, -1);
m_pArrShow =CCArray::create();
m_pArrShow->retain();
this->setAnchorPoint(ccp(0, 0));
setCenter(ccp(winSize.width*0.5, winSize.height*0.7));
setLongA(winSize.width*0.3);
setShortB(getLongA()*0.25);
m_iZStart =1;
m_fYMin =m_nCenter.y - m_fShortB;
m_fYMax =m_nCenter.y + m_fShortB;
returntrue;
}
void cwMainLayer::addShow(const char* pcName)
{
cwShowSprite* pSprite = cwShowSprite::create(pcName);
if(!pSprite)return;
m_pArrShow->addObject(pSprite);
m_fAngleStep= 360.0f / float(m_pArrShow->count());
this->addChild(pSprite);
}
void cwMainLayer::arrange()
{
arrangeAngle();
arrangePosition();
arrangeScale();
arrangeZOrder();
}
void cwMainLayer::arrangeAngle()
{
if(m_pArrShow->count() == 0) return;
float fStart=((cwShowSprite*)(m_pArrShow->objectAtIndex(0)))->getAngle();
int index =0;
CCObject*pObj;
CCARRAY_FOREACH(m_pArrShow, pObj) {
cwShowSprite* pSprite = (cwShowSprite*)pObj;
pSprite->setAngle(fStart -index*m_fAngleStep);
index++;
}
}
void cwMainLayer::arrangePosition()
{
CCObject*pObj;
CCARRAY_FOREACH(m_pArrShow, pObj) {
cwShowSprite* pSprite = (cwShowSprite*)pObj;
float fAngle= fmod(pSprite->getAngle(), 360.0f);
float x =cosf(fAngle/180.0*3.14159)*m_fLongA + m_nCenter.x;
float y =sinf(fAngle/180.0*3.14159)*m_fShortB*0.5f + m_nCenter.y;
pSprite->setPosition(ccp(x, y));
}
}
void cwMainLayer::arrangeZOrder()
{
int iZMax =m_iZStart + m_pArrShow->count();
vector<cwShowSprite*> v =orderByY();
vector<cwShowSprite*>::iterator it =v.begin();
for(;it!=v.end(); ++it) {
(*it)->removeFromParentAndClean
up(false);
this->addChild((*it), iZMax--);
}
}
void cwMainLayer::arrangeScale()
{
CCObject*pObj;
CCARRAY_FOREACH(m_pArrShow, pObj) {
cwShowSprite* pSprite = (cwShowSprite*)pObj;
float fy =pSprite->getPositionY() - m_fYMin;
if(fy< 0) fy = 0;
float fScale= fy / (m_fShortB*2);
pSprite->setScale(1.0 -(m_fScaleStart-m_fScaleEnd)*fScale);
}
}
void cwMainLayer::moveShow(float angle)
{
CCObject*pObj;
CCARRAY_FOREACH(m_pArrShow, pObj) {
cwShowSprite* pSprite = (cwShowSprite*)pObj;
pSprite->setAngle(pSprite->getAngle()+angle);
}
}
void cwMainLayer::onEnter()
{
CCLayer::onEnter();
CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this,-200, false);
}
void cwMainLayer::onExit()
{
CCLayer::onExit();
CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this);
}
bool comp(const cwShowSprite* p1, const cwShowSprite* p2)
{
return((CCNode*)(p1))->getPositionY() <((CCNode*)(p2))->getPositionY();
}
vector<cwShowSprite*>cwMainLayer::orderByY()
{
vector<cwShowSprite*> v;
CCObject*pObj;
CCARRAY_FOREACH(m_pArrShow, pObj) {
cwShowSprite* pSprite = (cwShowSprite*)pObj;
v.push_back(pSprite);
}
sort(v.begin(), v.end(), comp);
returnv;
}
cwShowSprite* cwMainLayer::clickSprite(CCPoint&pt)
{
vector<cwShowSprite*> v =orderByY();
vector<cwShowSprite*>::iterator it =v.begin();
for(;it!=v.end(); ++it) {
if((*it)->boundingBox().containsPoint(pt)) return(*it);
}
returnNULL;
}
bool cwMainLayer::ccTouchBegan(CCTouch *pTouch, CCEvent*pEvent)
{
m_nTouchBegin =this->convertTouchToNodeSpace(pTouch);
m_nTouchMoving = m_nTouchBegin;
returntrue;
}
void cwMainLayer::ccTouchMoved(CCTouch *pTouch, CCEvent*pEvent)
{
CCPoint pt =this->convertTouchToNodeSpace(pTouch);
float fStep= 1.0;
if(pt.x< m_nTouchMoving.x)
fStep =-fStep;
moveShow(fStep);
arrange();
m_nTouchMoving = pt;
}
void cwMainLayer::ccTouchEnded(CCTouch *pTouch, CCEvent*pEvent)
{
CCPoint pt =this->convertTouchToNodeSpace(pTouch);
float fDist= cocos2d::ccpDistance(pt, m_nTouchBegin);
if(fDist> 5.0) return;
cwShowSprite* pSprite = clickSprite(pt);
if(!pSprite)return;
CCLog("click%d", pSprite->m_uID);
}
///
代码量不大,300行左右。
其中cwMainLayer::init()中的“bk.png”是我随手做的背景图片。
原理就是椭圆上每个对象保存与向量(1,0)的夹角,有了这个夹角,就可以根据椭圆公式计算其x,y坐标;
根据y坐标来计算其所在层的zorder,计算zorder的目的是使前面的图片可以盖住后面的图片;还可以根据其y值计算其缩放值,计算缩放值目的是达到近似近大远小的效果。
关键的就是那么几个函数:
void cwMainLayer::arrangeAngle()
这个函数计算每个对象在椭圆上与向量(1,0)。
void cwMainLayer::arrangePosition()
使用椭圆公式,根据对象的夹角计算其位置,关于椭圆方面的数学知识可以参考
http://hi.baidu.com/ejoqsqmrmvakuxr/item/389ed4d5d48b03d9241f402b
的文章。
void cwMainLayer::arrangeZOrder()
计算图片zorder,首先对所有图片根据其y坐标由小到大进行排序,然后重新设置其zorder,y值越小
的zorder值越大,熟悉3D的朋友应该对这算法比较熟悉吧,原理类似于z-buffer,不过细节上比z-buffer
简单。
void cwMainLayer::arrangeScale()
计算对象的缩放值,图片y值越大,scale值越小,这样就得到近大远小的效果。
使用起来也不麻烦
在HelloWorld::init()中添加如下代码:
cwMainLayer* pMLayer = cwMainLayer::create();
pMLayer->addShow("show3.png");
pMLayer->addShow("show4.png");
pMLayer->addShow("show3.png");
pMLayer->addShow("show4.png");
pMLayer->addShow("show3.png");
pMLayer->addShow("show4.png");
pMLayer->addShow("show3.png");
pMLayer->addShow("show4.png");
pMLayer->addShow("show3.png");
pMLayer->addShow("show4.png");
pMLayer->addShow("show3.png");
pMLayer->addShow("show4.png");
pMLayer->arrange();
pMLayer->setPosition(ccp(0,0));
this->addChild(pMLayer, 10);
“show3.png”与“show4.png”就是那两个机器人图片。
忙活了两个多小时,边听歌边写代码,感觉还不错。
不过现在该去睡觉了,最近偏头痛犯了,得早休息!
在美区有个游戏叫bloodbrothers,玩了玩,感觉还不错,其中有一个页面,可以选择人物的奴仆,页面布局是中间是主人,四周是奴仆,以一个椭圆形围着主人转圈,仆人的数目可以增减,觉得这个页面挺有意思,我就试着实现了一个。
blood brothers的效果:
玩家滑动屏幕,两个骷髅兵会围着中间的老大按照椭圆轨迹转圈。
我实现的效果:
![实现了个类似blood <wbr>brothers中的转轴特效 实现了个类似blood <wbr>brothers中的转轴特效](https://i-blog.csdnimg.cn/blog_migrate/a4c26d1e5885305701be709a3d33442f.gif)
中间的老大我没做,滑动屏幕,四周的机器人图片会以椭圆轨迹旋转,个人感觉效果尚可,如果美工跟得上
我觉得效果不会比人家的差-_-!
废话不多说了,上代码
cwMainLayer.h
#ifndef _cwMainLayer_h_
#define _cwMainLayer_h_
#include "cocos2d.h"
using namespace cocos2d;
#include <string>
#include <vector>
using namespace std;
class cwShowSprite : public CCSprite
{
public:
public:
private:
};
class cwMainLayer : public CCLayer
{
public:
private:
public:
private:
};
#endif
cwMainLayer.cpp
#include "cwMainLayer.h"
#include <list>
#include <vector>
#include <algorithm>
using namespace std;
cwShowSprite* cwShowSprite::create(const char *pszFileName)
{
}
cwMainLayer::~cwMainLayer()
{
}
bool cwMainLayer::init()
{
}
void cwMainLayer::addShow(const char* pcName)
{
}
void cwMainLayer::arrange()
{
}
void cwMainLayer::arrangeAngle()
{
}
void cwMainLayer::arrangePosition()
{
}
void cwMainLayer::arrangeZOrder()
{
}
void cwMainLayer::arrangeScale()
{
}
void cwMainLayer::moveShow(float angle)
{
}
void cwMainLayer::onEnter()
{
}
void cwMainLayer::onExit()
{
}
bool comp(const cwShowSprite* p1, const cwShowSprite* p2)
{
}
vector<cwShowSprite*>cwMainLayer::orderByY()
{
}
cwShowSprite* cwMainLayer::clickSprite(CCPoint&pt)
{
}
bool cwMainLayer::ccTouchBegan(CCTouch *pTouch, CCEvent*pEvent)
{
}
void cwMainLayer::ccTouchMoved(CCTouch *pTouch, CCEvent*pEvent)
{
}
void cwMainLayer::ccTouchEnded(CCTouch *pTouch, CCEvent*pEvent)
{
}
///
代码量不大,300行左右。
其中cwMainLayer::init()中的“bk.png”是我随手做的背景图片。
原理就是椭圆上每个对象保存与向量(1,0)的夹角,有了这个夹角,就可以根据椭圆公式计算其x,y坐标;
根据y坐标来计算其所在层的zorder,计算zorder的目的是使前面的图片可以盖住后面的图片;还可以根据其y值计算其缩放值,计算缩放值目的是达到近似近大远小的效果。
关键的就是那么几个函数:
void cwMainLayer::arrangeAngle()
这个函数计算每个对象在椭圆上与向量(1,0)。
void cwMainLayer::arrangePosition()
使用椭圆公式,根据对象的夹角计算其位置,关于椭圆方面的数学知识可以参考
http://hi.baidu.com/ejoqsqmrmvakuxr/item/389ed4d5d48b03d9241f402b
的文章。
void cwMainLayer::arrangeZOrder()
计算图片zorder,首先对所有图片根据其y坐标由小到大进行排序,然后重新设置其zorder,y值越小
的zorder值越大,熟悉3D的朋友应该对这算法比较熟悉吧,原理类似于z-buffer,不过细节上比z-buffer
简单。
void cwMainLayer::arrangeScale()
计算对象的缩放值,图片y值越大,scale值越小,这样就得到近大远小的效果。
使用起来也不麻烦
在HelloWorld::init()中添加如下代码:
“show3.png”与“show4.png”就是那两个机器人图片。
忙活了两个多小时,边听歌边写代码,感觉还不错。
不过现在该去睡觉了,最近偏头痛犯了,得早休息!