Cocos2d-x 之 八方向小摇杆

Cocos2d-x 之 八方向小摇杆,第1张

概述***************************************转载请注明出处:http://blog.csdn.net/lttree******************************************* 前文: 之前做   >>>CatchingJoy <<<   的时候,用到了摇杆, 网上有四方向的, 我用到的是八个方向,看了下它的思路,改动了一些,就成了8方向拉

***************************************转载请注明出处:http://blog.csdn.net/lttree*******************************************



前文:

之前做 >>>CatchingJoy <<< 的时候,用到了摇杆,

网上有四方向的,

我用到的是八个方向,看了下它的思路,改动了一些,就成了8方向拉~

嘿嘿~ let it go~


****************************************************************转载请注明出处:********************************************************************


正文:

1.先准备好图片:

需要移动的小方块:


摇杆背景 和 摇杆中心:




********************************************************************


2.原理

首先,放摇杆的需要是一个层,放着摇杆背景 和 中心(显然中心要在背景上层),

然后我们再把这个层放在场景中。

这个层需要接受触摸(单点),并屏蔽下层触摸(一般来说)。


然后,摇杆 如何瓜分?


(Windows画图绘制,很渣,凑合看吧= =。)

每个方向 都占45° 45*8 = 360


其次,TouchBegan,接受到触摸点,判断是否在 摇杆中心 那个范围,用contiansPoint实现。

然后,TouchMoved,看往哪个方向移动,移动的距离,如果拉扯的距离大于半径,摇杆中心是不能出摇杆背景的,如果拉扯距离小于等于半径,中心该在哪就在哪。

最后,TouchEnd,要让摇杆中心从当前位置移动回初始位置。


所以,比较麻烦的地方仅仅在于 TouchMoved部分,要判断距离,判断摇杆中心该放在哪里等...


****************************************************************转载请注明出处:********************************************************************


3.实现

> 准备工作

(1) 先做个 enum(枚举),把8个方向用英语比1,2,3...8好很多:

//用于标识摇杆方向typedef enum{    rocker_stay = 0,rocker_right,rocker_up,rocker_left,rocker_down,rocker_leftUp,rocker_rightUp,rocker_leftDown,rocker_rightDown,}rockerDirecton;

可以看到,除了8个方向,还有一个stay(原地不动)

(2) 这里,设置摇杆位置,可以自定义也可以固定,我用的自定义(好处不多说),

所以原来那种 create,init就不用了,用其他的替代:

// JoyRocker.hstatic JoyRocker* create(Vec2 pos);bool initRocker(Vec2 pos);// JoyRocker.cppJoyRocker* JoyRocker::create(Vec2 pos){	JoyRocker* layer = JoyRocker::create();    if ( layer )    {        layer->initRocker(pos);        return layer;    }    CC_SAFE_DELETE(layer);    return NULL;}bool JoyRocker::initRocker(Vec2 pos){	// 摇杆背景 图片	Sprite* spRockerBG = Sprite::create("spi_joystickBG.png");	spRockerBG->setPosition(pos);	spRockerBG->setTag(1);        this->addChild(spRockerBG,0); 	// 摇杆中心 图片	Sprite* spRockerCenter = Sprite::create("spi_joystickCenter.png");	spRockerCenter->setPosition(pos);	spRockerCenter->setTag(2);        this->addChild(spRockerCenter,1); 	// 设置 摇杆中心 位置	rockerCenterPos = pos;	// 获取 摇杆背景 半径        rockerBGR = spRockerBG->getContentSize().width*0.5;        // 设置 摇杆 初始方向	rocketDirection = 0;	// 事件监听部分	listener = EventListenerTouchOneByOne::create();	// 吞掉这个触摸	listener->setSwallowTouches(true);	listener->onTouchBegan = CC_CALLBACK_2(JoyRocker::TouchBegan,this);	listener->onTouchMoved = CC_CALLBACK_2(JoyRocker::TouchMoved,this);	listener->onTouchEnded = CC_CALLBACK_2(JoyRocker::TouchEnded,this);	// 注册事件监听机制	eventDispatcher = Director::getInstance()->getEventDispatcher();	return true;}


> 然后就是 Touch 三兄弟,这里我用的传统的方式,没有用lamda表达式= =。

TouchBegan:

bool JoyRocker::TouchBegan(Touch* touch,Event* event){    Sprite* sp = (Sprite*)this->getChildByTag(2);            //得到触屏点坐标      Vec2 point = touch->getLocation();            //判断是否点击到sp这个精灵:boundingBox()精灵大小之内的所有坐标      if(sp->boundingBox().containsPoint(point))      {          // 可以移动了        isCanMove = true;      }    return true;}


TouchMoved:

void JoyRocker::TouchMoved(Touch* touch,Event* event){    // 如果不能移动,直接返回    if(!isCanMove)      {          return;      }            Sprite* sp = (Sprite*)getChildByTag(2);      Vec2 point = touch->getLocation();            //得到摇杆与触屏点所形成的角度    float angle = getRad(rockerCenterPos,point);    //判断两个圆的圆心距是否大于摇杆背景的半径    if (sqrt(pow((rockerCenterPos.x - point.x),2) + pow((rockerCenterPos.y - point.y),2)) >= rockerBGR)    {        //保证内部小圆运动的长度限制	sp->setPosition(ccpAdd(getAnglePosition(rockerBGR,angle),Vec2(rockerCenterPos.x,rockerCenterPos.y)));    }    else    {        //当没有超过,让摇杆跟随用户触屏点移动即可        sp->setPosition(point);    }    	//判断方向	// 右方	if( angle>=-PI/8 && angle<PI/8 )	{		rocketDirection = rocker_right;		isLeft = false;	}	// 右上方	else if( angle>=PI/8 && angle<3*PI/8 )	{		rocketDirection = rocker_rightUp;		isLeft = false;	}	// 上方	else if( angle>=3*PI/8 && angle<5*PI/8 )	{		rocketDirection = rocker_up;	}	// 左上方	else if( angle>=5*PI/8 && angle<7*PI/8 )	{		rocketDirection = rocker_leftUp;		isLeft = true;	}	// 左方	else if( (angle>=7*PI/8&&angle<=PI) || (angle>=-PI&&angle<-7*PI/8) )	{		rocketDirection = rocker_left;		isLeft = true;	}	// 左下方	else if( angle>=-7*PI/8 && angle<-5*PI/8 )	{		rocketDirection = rocker_leftDown;		isLeft = true;	}	// 下方	else if( angle>=-5*PI/8 && angle<-3*PI/8 )	{		rocketDirection = rocker_down;	}	// 右下方	else if( angle>=-3*PI/8 && angle<-PI/8 )	{		rocketDirection = rocker_rightDown;		isLeft = false;	}	}


要解释的有三点:

① 两个工具函数

· 用户 触摸 一个点后,这个点与 摇杆中心 相连,这条线段与水平方向 所构成的角度,

就是——函数 getRad(返回的是 弧度值)

float JoyRocker::getRad(Vec2 pos1,Vec2 pos2){	float px1 = pos1.x;    float py1 = pos1.y;    float px2 = pos2.x;    float py2 = pos2.y;     //得到两点x的距离    float x = px2 - px1;    //得到两点y的距离    float y = py1 - py2;    //算出斜边长度    float xie = sqrt(pow(x,2) + pow(y,2));    //得到这个角度的余弦值(通过三角函数中的点里:角度余弦值=斜边/斜边)    float cosAngle = x / xie;    //通过反余弦定理获取到期角度的弧度    float rad = acos(cosAngle);    //注意:当触屏的位置Y坐标<摇杆的Y坐标,我们要去反值-0~-180    if (py2 < py1)    {        rad = -rad;    }    return rad;}

用简单的高数知识推一推,在纸上画一画,就出来了,这里不解释了就(画图太麻烦啊)...o(╯□╰)o...

如果实在不懂,回复我,我再更新上去

· 第二个工具函数

根据 与水平方向形成的角度的弧度值,返回对应点的位置,就是第一个工具函数的 反

// 根据角度,返回点坐标Vec2 JoyRocker::getAnglePosition(float r,float angle){    return Vec2(r*cos(angle),r*sin(angle));}

三角形的那一串,应该不用解释了= =。。。


② 关于 判断圆心距那块的 函数 cppAdd

其实,并不神秘的东西,跳转到定义就发现:

ccpAdd(const Vec2& v1,const Vec2& v2){    return v1 + v2;}

就是这么简单,当然那一系列还有:

加减乘除,取反,取中点等等等等,

具体的看 头文件--> CCDeprecated.h

③ 关于 isLeft

每次判断完方向,都会对 isLeft赋值,

这个的作用是 标记 正面朝向,

假设,我们做的图是人物走动的,肯定只是做一个方向的(当然,也可以做两个方向,但。。)

然后,什么时候用向右走,什么时候用向左走,(如果向没做图的那个方向,我们可以用 setFlipedX(true),让Sprite 180° 大翻转)

这时候,isLeft 就用到了~



> TouchEnd

void JoyRocker::TouchEnded(Touch* touch,Event* event){    if(!isCanMove)      {  	return;      }            // 获取 摇杆背景 与 摇杆中心    Sprite* rocker = (Sprite*)getChildByTag(2);      Sprite* rockerBG = (Sprite*)getChildByTag(1);            // 让 摇杆中心 停止之前所有动作,然后开始 执行归位    rocker->stopAllActions();      rocker->runAction(MoveTo::create(0.08,rockerBG->getPosition()));           // 设置 方向为 stay,并且 在下次触摸开始前 不可移动    rocketDirection=rocker_stay;    isCanMove = false;  }

摇杆已经OK啦


>现在 把小方块加进来,动起来

//  场景的 init 函数    // 获取 屏幕大小    visibleSize = Director::getInstance()->getVisibleSize();    // 添加绿色小方块    bg = Sprite::create("green.png");    bg->setPosition(visibleSize.width/2,visibleSize.height/2);    this->addChild(bg);    // 添加 摇杆    jr = JoyRocker::create(Vec2(visibleSize.width-100,100));    this->addChild(jr);    // 时时更新函数    this->scheduleUpdate();

这里,我们调用 scheduleUpdate,就是让程序 每一帧 都自动调用 void update(float ft) 函数,

然后,我们重写下 update 函数:

void DemoScene::update(float ft){    //判断是否按下摇杆及其类型   switch( jr->getDirection() )    {    case 1:	bg->setPosition(Vec2(bg->getPosition().x+2,bg->getPosition().y));		//向右走        break;    case 2:	bg->setPosition(Vec2(bg->getPosition().x,bg->getPosition().y+2));		//向上走	break;    case 3:	bg->setPosition(Vec2(bg->getPosition().x-2,bg->getPosition().y));		//向左走	break;    case 4:	bg->setPosition(Vec2(bg->getPosition().x,bg->getPosition().y-2));		//向下走	break;    case 5:	bg->setPosition(Vec2(bg->getPosition().x-1,bg->getPosition().y+1));             //向左上走	break;    case 6:	bg->setPosition(Vec2(bg->getPosition().x+1,bg->getPosition().y+1));             //向右上走	break;    case 7:	bg->setPosition(Vec2(bg->getPosition().x-1,bg->getPosition().y-1));             //向左下走	break;    case 8:	bg->setPosition(Vec2(bg->getPosition().x+1,bg->getPosition().y-1));             //向右下走	break;    default:        break;    }}


其实就是每帧都获取 方向盘的方向,

然后,根据方向,执行对应动作,

这里,我设置的,如果单纯往某个方向走,移动速度为 每帧移动2,

如果 向复合方向走(左上、左下、右上、右下),每个相应方向只是 每帧移动1。


Ok,方向盘就到这里啦,

可以再优化一下,比如 不让 小绿块 飞出界面(就在移动前加个判断就行)...



上面代码不全,上传一个JoyRocker类 和 小绿块的场景类,

里面可能有些小改动,但大体都是一样的,

百度云: >点这里 <





*******************************************

总结

以上是内存溢出为你收集整理的Cocos2d-x 之 八方向小摇杆全部内容,希望文章能够帮你解决Cocos2d-x 之 八方向小摇杆所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1069087.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-26
下一篇 2022-05-26

发表评论

登录后才能评论

评论列表(0条)

保存