wq右边写的。
项目所用图片资源下载:http://download.csdn.net/detail/jukai7/5096755
解压我们下载的图片资源,有三个图片,其中飞机图片是被控制的对象,剩下的两个我们组合起来制作摇杆,想必这个摇杆最后的样子大家已经猜到了吧,如下所示,即用圆圈作为控制按钮,滑动圆圈,根据其所在位置来设置飞机应该运行的方向。
首先我们新建一个工程,取名为JoyStick,并把刚才下载的图片资源添加进我们的项目。具体的添加方法就不说了,之前的文章都有过说明。在开始编写代码之前,我们先来分析一下摇杆实现的原理。我们是根据圆圈所在位置来判定飞机的移动方向的,我画了一个简单的示意图,来跟大家说明一下(图画的很粗糙,见谅……)。
从这个简单的示意图我们可以看到,我把这个摇杆图片用一个外切正方形框了起来,用虚线分成了九个大小相等的正方形区域,然后又把中间的圆圈所在正方形区域分成了大小相等的四个等腰直角三角形区域。于是我们得到了大小共12个区域,并进行了编号处理。接下来我们就可以根据这些区域来进行判定了。
当我们滑动圆圈时,触点移动到区域1,3,10,12时,我们分别规定飞机的飞行方向为:左上,右上,左下,右下。当触点移动到区域2或区域5时,我们规定飞机向上飞行;移动到区域6或11时,向下;区域4或7时,向左;区域9或8时,向右。
好了,基本原理已经说清楚了,我们就来说一下怎么具体判定触点是在哪块区域里面的?这里我们首先定义一些变量,我们规定大圆的半径为R,中间小圆的半径为r,九个相同大小的正方形的边长为d,即2r,大圆和小圆共同的中心点为O,触点为location。
首先左上,右上,左下,右下四个方向我们比较容易进行判定,左上方向即location.x<(O.x-r)&&location.y>(O.y+r);右上方向为location.x>(O.x+r)&&location.y>(O.y+r);左下为location.x<(O.x-r)&&location.y<(O.y-r);右下为location.x>(O.x+r)&&location.y>(O.y-r)。
然后是上下左右四个方向。每个方向上我们分为两个区域进行判断,首先是判定触点在区域2,11,4,9分别来决定飞机的方向为上,下,左,右。这四个区域都是正方形,比较好判断,例如判定方向上,只要证明触点在以区域2左下角为原点,边长d的正方形内即可。判定是区域2(上)的代码实现为CCRectMake(O.x-r,O.y+r,d,d).containsPoint(location);区域11(下)的代码实现为CCRectMake(O.x-r,O.y-radius1-d,d,d).containsPoint(location);区域4(左)的代码实现为CCRectMake(O.x-r-d,O.y-r,d,d).containsPoint(location);区域9(右)的代码实现为CCRectMake(O.x+r,O.y-r,d,d).containsPoint(location)。
最后是中间四个三角形区域5,6,7,8的判定。要想判定触点在一个三角形内,我们会模糊的记着以前高中是不是经常出这种证明题?对啦,我们就用三角形面积来做。如果一个点包含在一个三角形内,那么从三角形三个顶点中相邻两个顶点到这个点做连线形成新的三个小三角形,这三个新三角形的面积和一定等于原先的那个大三角形面积。相反,如果这个点在三角形外部则一定大于原先三角形的面积,如下图所示:
那么我们怎么求这四个三角形的面积呢?可以根据海伦公式来求。我们知道三角形三个顶点和触点的坐标,那么根据两点间直线距离公式来求得每个三角形的三条边的大小,假设为a,b,c。那么每个三角形的半周长为L=(a+b+c)/2。
于是我们根据海伦公式求得每个三角形的面积。根据求得的结果进行判断即可得知触点是否在四个三角形区域内。例如判断是否在区域5内,我们指定三角形的三个顶点坐标为p1(O.x,O.y),p2(O.x-r,O.y+r),P3(O.x+r,O.y+r)。触点坐标为p(location.x,location.y)。那么S为p1,p2,p3三点组成三角形的面积,S1为p1,p2,p三点组成三角形面积,S2为p2,p3,p三点,S3为p3,p1,p三点。那么判断是否S=S1+S2+s3即可。向下,左,右三方向同理可证。
讲了这么多,我们是时候用代码来具体的实现了。代码我就不做详细的注释了,因为该了解的上面都讲过了。回到我们一开始创建的项目JoyStick,我们需要的图片已经导入到工程中了。我把修改后的HelloWorld.h文件和HelloWorld.cpp文件内容粘贴出来,大家看一下,具体实现的过程我就不讲了,必要的注释也都加上了,有不懂得地方再讨论交流。
HelloWorld.h文件内容如下:
- #ifndef __HELLOWORLD_SCENE_H__
- #define __HELLOWORLD_SCENE_H__
-
- #include "cocos2d.h"
-
- #include "SimpleAudioEngine.h"
-
- class HelloWorld : public cocos2d::CCLayer
- {
- public:
-
- virtual bool init();
-
- static cocos2d::CCScene* scene();
-
- void menuCloseCallback(CCObject* pSender);
-
- virtual void ccTouchesBegan(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent);
- virtual void ccTouchesMoved(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent);
- virtual void ccTouchesEnded(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent);
-
-
- float heronsformula(float x1,float y1,float x2,float y2,float x3,float y3);
-
-
- bool triangleContainPoint(float x1,float y1,float x2,float y2,float x3,float y3,float px,float py);
-
- CREATE_FUNC(HelloWorld);
-
- private:
- void flying(float dt);
-
- cocos2d::CCSprite *joystick;
-
- cocos2d::CCPoint O;
-
- float R;
-
- cocos2d::CCSprite *plane;
-
- float speedX;
- float speedY;
-
- bool isFlying;
- };
-
- #endif // __HELLOWORLD_SCENE_H__
HelloWorld.cpp文件内容如下:
- #include "HelloWorldScene.h"
-
- using namespace cocos2d;
-
- CCScene* HelloWorld::scene()
- {
- CCScene * scene = NULL;
- do
- {
-
- scene = CCScene::create();
- CC_BREAK_IF(! scene);
-
-
- HelloWorld *layer = HelloWorld::create();
- CC_BREAK_IF(! layer);
-
-
- scene->addChild(layer);
- } while (0);
-
-
- return scene;
- }
-
-
- bool HelloWorld::init()
- {
- bool bRet = false;
- do
- {
-
-
-
-
- CC_BREAK_IF(! CCLayer::init());
-
-
-
-
-
-
-
-
- CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
- "CloseNormal.png",
- "CloseSelected.png",
- this,
- menu_selector(HelloWorld::menuCloseCallback));
- CC_BREAK_IF(! pCloseItem);
-
-
- pCloseItem->setPosition(ccp(CCDirector::sharedDirector()->getWinSize().width - 20, 20));
-
-
- CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
- pMenu->setPosition(CCPointZero);
- CC_BREAK_IF(! pMenu);
-
-
- this->addChild(pMenu, 1);
-
-
- CCSize size = CCDirector::sharedDirector()->getWinSize();
-
-
- plane = CCSprite::create("plane.png");
- CC_BREAK_IF(! plane);
-
- plane->setPosition(ccp(size.width/2, size.height/2));
- this->addChild(plane, 0);
-
-
- CCSprite *joystick1=CCSprite::create("joystick1.png");
-
- joystick1->setOpacity(191);
- joystick1->setAnchorPoint(ccp(0,0));
- joystick1->setPosition(ccp(0,0));
-
- R=joystick1->getContentSize().width/2;
-
- O=ccp(R,R);
-
- this->addChild(joystick1,1);
-
-
- joystick=CCSprite::create("joystick2.png");
-
- joystick->setPosition(ccp(O.x,O.y));
- this->addChild(joystick,2);
-
-
- this->setTouchEnabled(true);
-
-
- this->schedule(schedule_selector(HelloWorld::flying));
-
-
- isFlying=false;
- speedX=speedY=0;
-
- bRet = true;
- } while (0);
-
- return bRet;
- }
-
- void HelloWorld::menuCloseCallback(CCObject* pSender)
- {
-
- CCDirector::sharedDirector()->end();
- }
-
-
- void HelloWorld::flying(float dt)
- {
- if (isFlying&&(speedX!=0||speedY!=0)){
-
- CCPoint position=ccp(plane->getPosition().x+speedX,plane->getPosition().y+speedY);
-
- CCSize size=CCDirector::sharedDirector()->getWinSize();
- CCRect rect=CCRectMake(0,0,size.width,size.height);
-
-
- if(rect.containsPoint(position)){
- plane->setPosition(position);
- }
-
- }
- }
-
-
- void HelloWorld::ccTouchesBegan( CCSet *pTouches, CCEvent *pEvent )
- {
- CCTouch *touch = (CCTouch*)pTouches->anyObject();
- CCPoint location = touch->getLocation();
-
- CCRect rect=joystick->boundingBox();
- if (rect.containsPoint(location))
- {
- isFlying=true;
- }
- }
-
-
- void HelloWorld::ccTouchesMoved( CCSet *pTouches, CCEvent *pEvent )
- {
- CCTouch *touch = (CCTouch*)pTouches->anyObject();
- CCPoint location = touch->getLocation();
-
-
- bool inRange=pow(O.x-location.x,2)+pow(O.y-location.y,2)<pow(R,2);
-
- if(isFlying&&inRange){
- CCPoint position=plane->getPosition();
- joystick->setPosition(location);
-
- float r=R*2/6;
- float d=R*2/3;
-
- if(triangleContainPoint(O.x,O.y,O.x-r,O.y+r,O.x+r,O.y+r,location.x,location.y)
- ||CCRectMake(O.x-r,O.y+r,d,d).containsPoint(location)){
- speedX=0;
- speedY=1;
- }
-
- else if(triangleContainPoint(O.x,O.y,O.x-r,O.y-r,O.x+r,O.y-r,location.x,location.y)
- ||CCRectMake(O.x-r,O.y-r-d,d,d).containsPoint(location)){
- speedX=0;
- speedY=-1;
- }
-
- else if(triangleContainPoint(O.x,O.y,O.x-r,O.y+r,O.x-r,O.y-r,location.x,location.y)
- ||CCRectMake(O.x-r-d,O.y-r,d,d).containsPoint(location)){
- speedX=-1;
- speedY=0;
- }
-
- else if(triangleContainPoint(O.x,O.y,O.x+r,O.y+r,O.x+r,O.y-r,location.x,location.y)
- ||CCRectMake(O.x+r,O.y-r,d,d).containsPoint(location)){
- speedX=1;
- speedY=0;
- }
-
- else if(location.x-(O.x+r)>0&&location.y-(O.y+r)>0){
- speedX=0.7f;
- speedY=0.7f;
- }
-
- else if(location.x-(O.x-r)<0&&location.y-(O.y+r)>0){
- speedX=-0.7f;
- speedY=0.7f;
- }
-
- else if(location.x-(O.x-r)<0&&location.y-(O.y-r)<0){
- speedX=-0.7f;
- speedY=-0.7f;
- }
-
- else if(location.x-(O.x+r)>0&&location.y-(O.y-r)<0){
- speedX=0.7f;
- speedY=-0.7f;
- }
- }
- }
-
-
- void HelloWorld::ccTouchesEnded( CCSet *pTouches, CCEvent *pEvent )
- {
- isFlying=false;
- joystick->setPosition(O);
- speedX=speedY=0;
- }
-
-
- float HelloWorld::heronsformula(float x1,float y1,float x2,float y2,float x3,float y3)
- {
-
- float a=sqrt(pow(x1-x2,2)+pow(y1-y2,2));
-
- float b=sqrt(pow(x2-x3,2)+pow(y2-y3,2));
-
- float c=sqrt(pow(x3-x1,2)+pow(y3-y1,2));
-
- float s=(a+b+c)/2;
-
-
- return sqrt(s*(s-a)*(s-b)*(s-c));
- }
-
-
- bool HelloWorld::triangleContainPoint(float x1,float y1,float x2,float y2,float x3,float y3,float px,float py)
- {
-
- float s1=heronsformula(x1,y1,x2,y2,px,py);
-
- float s2=heronsformula(x2,y2,x3,y3,px,py);
-
- float s3=heronsformula(x3,y3,x1,y1,px,py);
-
- float s=heronsformula(x1,y1,x2,y2,x3,y3);
-
-
- return abs(s-(s1+s2+s3))<0.001f;
- }
运行,结果如下