怎样制作基于Cocos2d-x的SLG游戏-第2章
怎样制作基于Cocos2d-x的SLG游戏-第1章 上一章中,我们使用TiledMap制作了一张简单的地图,并把它加入到了程序中,紧接着本章将实现地图的双指缩放和单指移动功能。 双指缩放,单指拖动的实现 Cocos2d-x中有自己的一套事件分发机制,如果你还不是很清楚,可先阅读Cocos2d-x事件分发机制一文。
具体实现如下: virtual void onTouchesBegan(const std::vector &touches,cocos2d::Event *event); virtual void onTouchesMoved(const std::vector &touches,cocos2d::Event *event); 2、在GameScene.cpp文件的init函数中创建并绑定触摸事件。 // 1 创建一个事件监听器 auto listener = EventListenerTouchAllAtOnce::create(); // 2 绑定触摸事件 listener->onTouchesBegan = CC_CALLBACK_2(GameScene::onTouchesBegan,this);// 触摸开始时触发 listener->onTouchesMoved = CC_CALLBACK_2(GameScene::onTouchesMoved,this);// 触摸移动时触发 // 3 添加监听器 _eventDispatcher->addEventListenerWithSceneGraphPriority(listener,bgSprite);
3、最后在GameScene.cpp文件中实现触摸回调函数
掌握了这些注意事项以后,现在我们就可以开始具体的行动了。 Sprite* bgSprite; Vec2 bgOrigin; bgSprite是地图背景,需要缩放和移动的对象都是其子节点,这样我们就可以通过操作它来实现缩放和移动了。bgOrigin用于记录bgSprite的初始原点位置。 mapLayer = Layer::create(); this->addChild(mapLayer,-1); bgSprite = Sprite::create("2.jpg"); bgSprite->setAnchorPoint(Vec2::ZERO); bgSprite->setPosition(Vec2::ZERO),bgOrigin = Vec2(Vec2::ZERO); mapLayer->addChild(bgSprite); auto treeSprite = Sprite::create("1.png"); treeSprite->setAnchorPoint(Vec2::ZERO); treeSprite->setPosition(Vec2::ZERO),treeSprite->setScale(2); bgSprite->addChild(treeSprite,2); auto map = TMXTiledMap::create("mymap8.tmx"); map->setAnchorPoint(Vec2::ZERO); map->setPosition(Vec2::ZERO),bgSprite->addChild(map,1); 因为对层而言,它相比于其他的节点来说,其锚点、位置、大小都不好控制,所以我们需要通过另外的节点(比如这里的bgSprite)来执行后面的缩放和移动等动作。 void GameScene::onTouchesMoved(const std::vector&touches,Event *event) { auto winSize = Director::getInstance()->getWinSize(); if(touches.size() > 1) // 多点进行缩放 { // 得到当前两触摸点 auto point1 = touches[0]->getLocation(); auto point2 = touches[1]->getLocation(); // 计算两点之间得距离 auto currDistance = point1.distance(point2); // 计算两触摸点上一时刻之间得距离 auto prevDistance = touches[0]->getPreviousLocation().distance(touches[1]->getPreviousLocation()); // 两触摸点与原点的差向量,pointVec1和pointVec2是相对于bgSprite的位置 auto pointVec1 = point1 - bgOrigin; auto pointVec2 = point2 - bgOrigin; // 两触摸点的相对中点 auto relMidx = (pointVec1.x + pointVec2.x) / 2 ; auto relMidy = (pointVec1.y + pointVec2.y) / 2 ; // 计算bgSprite的锚点 auto anchorX = relMidx / bgSprite->getBoundingBox().size.width; auto anchorY = relMidy / bgSprite->getBoundingBox().size.height; // 相对屏幕的中点 auto absMidx = (point2.x + point1.x) / 2 ; auto absMidy = (point2.y + point1.y) / 2 ; // 缩放时,为了避免出现空白的区域,需要做以下的边界处理。 // 当bgSprite快要进入到屏幕时,修改bgSprite的位置(既absMidx和absMidy)。 if( bgOrigin.x > 0) { absMidx -= bgOrigin.x; } if( bgOrigin.x < -bgSprite->getBoundingBox().size.width + winSize.width ) { absMidx += -bgSprite->getBoundingBox().size.width + winSize.width - bgOrigin.x; } if( bgOrigin.y > 0 ) { absMidy -= bgOrigin.y; } if( bgOrigin.y < -bgSprite->getBoundingBox().size.height + winSize.height ) { absMidy += -bgSprite->getBoundingBox().size.height + winSize.height - bgOrigin.y; } // 重设bgSprite锚点和位置 bgSprite->setAnchorPoint(Vec2(anchorX,anchorY)); bgSprite->setPosition(Vec2(absMidx,absMidy)); // 根据两触摸点前后的距离计算缩放倍率 auto scale = bgSprite->getScale() * ( currDistance / prevDistance); // 控制缩放倍率在1~4倍之间,最小倍率不能太小,不让背景将不能填充满整个屏幕。 scale = MIN(4,MAX(1,scale)); bgSprite->setScale(scale); // 更新原点位置 bgOrigin = Vec2(absMidx,absMidy) - Vec2(bgSprite->getBoundingBox().size.width * anchorX,bgSprite->getBoundingBox().size.height * anchorY) ; } else if(touches.size() == 1) // 单点进行移动 { // 单点时,touches中只有一个Touch对象,所以通过touches[0]就可以得到触摸对象 auto touch = touches[0]; // 计算滑动过程中的滑动增量 auto diff = touch->getDelta(); // 得到当前bgSprite的位置 auto currentPos = bgSprite->getPosition(); // 得到滑动后bgSprite应该所在的位置 auto pos = currentPos + diff; // 得到此刻bgSprite的尺寸 auto bgSpriteCurrSize = bgSprite->getBoundingBox().size; //边界控制,约束pos的位置 pos.x = MIN(pos.x,bgSpriteCurrSize.width * bgSprite->getAnchorPoint().x); pos.x = MAX(pos.x,-bgSpriteCurrSize.width + winSize.width + bgSpriteCurrSize.width * bgSprite->getAnchorPoint().x); pos.y = MIN(pos.y,bgSpriteCurrSize.height * bgSprite->getAnchorPoint().y); pos.y = MAX(pos.y,-bgSpriteCurrSize.height + winSize.height + bgSpriteCurrSize.height * bgSprite->getAnchorPoint().y); // 重设bgSprite位置 bgSprite->setPosition(pos); // 更新原点位置 if( pos.x >= bgSpriteCurrSize.width * bgSprite->getAnchorPoint().x || pos.x <= -bgSpriteCurrSize.width + winSize.width + bgSpriteCurrSize.width * bgSprite->getAnchorPoint().x) { diff.x = 0; } if( pos.y >= bgSpriteCurrSize.height * bgSprite->getAnchorPoint().y || pos.y <= -bgSpriteCurrSize.height + winSize.height + bgSpriteCurrSize.height * bgSprite->getAnchorPoint().y) { diff.y = 0; } bgOrigin += diff; } } 以上就是onTouchesMoved函数的实现方法了,原理已在注释中解释清楚,所以我想理解起来已经不会很难。下面给出一张示意图帮助大家理解: CCEAGLView *eaglView = [CCEAGLView viewWithFrame: [window bounds] pixelFormat: kEAGLColorFormatRGBA8 depthFormat: GL_DEPTH24_STENCIL8_OES preserveBackbuffer: NO sharegroup: nil multiSampling: NO numberOfSamples: 0]; [eaglView setMultipleTouchEnabled:YES]; 总的来说,要想很好的实现这一功能不是容易的,以上就是我们实现了的一种方法,虽然细节上还有一些问题,也未在真机上测试,但还是希望能对大家的学习有所帮助。如果你有更好的方法实现,也可以提出来,大家一起进步学习。 转自:http://www.tairan.com/archives/9612/ (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |