制作摇杆的思路
摇杆应该由两部分组成:一个是背景,一个是拖动部分。这两个部分我们用ImageView来创建,使用这个来创建可以很方便的创建监听事件。 在监听事件中,有三个四个状态,分别是:按下,移动,抬起,取消。其中我们把抬起和取消放到一起来处理,是摇杆回到初始状态即可。 按下和移动的时候我们可以分为这几个步骤来写代码
- 获取触摸点的坐标
- 转换坐标系:将touchPoint从世界转到JoyStick坐标系下
- stickIv用触摸点坐标赋值
具体代码如下
JoyStick.h
#ifndef _JoyStick_H_
#define _JoyStick_H_
#include "Ui/CocosGUI.h"
#include "cocos2d.h"
class JoyStick : public cocos2d::ui::Widget{
public:
JoyStick():
onJoyStickBegan(nullptr),
onJoyStickMoved(nullptr) ,
onJoyStickEnded(nullptr),
isTouch(false),
touchAxis(cocos2d::Vec2(0, 0))
{
}
//1.背景图片 2.遥感图片
static JoyStick* create(
const std::string& bgImage,
const std::string& stickImage
);
bool init(
const std::string& bgImage,
const std::string& stickImage
);
//当遥感被拖动时调用
void onJoyStickTouch(cocos2d::Ref* pSender, cocos2d::ui::Widget::TouchEventType type);
//默认调度器
void update(float dt) override;
public:
typedef std::function<void()> ccJoyStickBeganCallback;
typedef std::function<void(cocos2d::Vec2)> ccJoyStickMovedCallback;
typedef std::function<void()> ccJoyStickEndedCallback;
ccJoyStickBeganCallback onJoyStickBegan;//当摇杆开始拖动时
ccJoyStickMovedCallback onJoyStickMoved;//当摇杆拖动时
ccJoyStickEndedCallback onJoyStickEnded;//当摇杆结束拖动时
private:
cocos2d::ui::ImageView* stickIv;
//cocos2d::ui::ImageView* bgIv;
float redius;//半径
cocos2d::Vec2 originPos;//摇杆起始坐标
bool isTouch;//是否触摸
cocos2d::Vec2 touchAxis;//触摸方向
};
#endif // !_JoyStick_H_
JoyStick.cpp
#include "JoyStick.h"
using namespace cocos2d;
using namespace cocos2d::ui;
JoyStick* JoyStick::create(const std::string& bgImage,const std::string& stickImage) {
JoyStick* ret = new(std::nothrow)JoyStick();
if (ret && ret->init(bgImage, stickImage)) {
ret->autorelease();
} else {
delete ret;
ret = nullptr;
}
return ret;
}
bool JoyStick::init(const std::string& bgImage,const std::string& stickImage) {
if (!Widget::init()) {
return false;
}
//创建背景图片 ImageView可以直接添加触摸/监听事件
ImageView* bgIv = ImageView::create(bgImage);
this->addChild(bgIv);
//创建遥感图片 可拖动
stickIv = ImageView::create(stickImage);
stickIv->setTouchEnabled(true);//必须先开启触摸:setTouchEnabled
this->addChild(stickIv);
//半径 因为还要考虑到如果图片进行了缩放,那么还得乘上缩放比例
redius = bgIv->getContentSize().width / 2 * bgIv->getScale();
//初始坐标
originPos = stickIv->getPosition();
//给stick添加触摸监听事件
stickIv->addTouchEventListener(CC_CALLBACK_2(JoyStick::onJoyStickTouch, this));
//开启调度器
scheduleUpdate();
return true;
}
void JoyStick::update(float dt) {
if (isTouch && onJoyStickMoved != nullptr) {
onJoyStickMoved(touchAxis);
}
}
void JoyStick::onJoyStickTouch(Ref* pSender, Widget::TouchEventType type) {
//判断触摸阶段
Vec2 touchPoint = Vec2::ZERO;
Vec2 pos;
Vec2 offset;
MoveTo* mt = MoveTo::create(0.5f, originPos);;
switch (type) {
case Widget::TouchEventType::BEGAN://触摸开始
isTouch = true;
if (onJoyStickBegan != nullptr) {
onJoyStickBegan();
}
//关闭移动动作
stickIv->stopAction(mt);
//获取触摸点的坐标Began
touchPoint = stickIv->getTouchBeganPosition();
//转换坐标系:将touchPoint从世界转到JoyStick坐标系下
pos = this->convertToNodeSpaceAR(touchPoint);
//stickIv用触摸点坐标赋值
stickIv->setPosition(pos);
break;
case Widget::TouchEventType::MOVED://触摸移动
//获取触摸点的坐标Move
touchPoint = stickIv->getTouchMovePosition();
//转换坐标系:将touchPoint从世界转到JoyStick坐标系下
pos = this->convertToNodeSpaceAR(touchPoint);
//将摇杆限制在半径内
offset = pos - originPos;
if (offset.getLength() > redius) {
offset = offset.getNormalized() * redius;//getNormalized:单位向量 长度为1的向量
pos = offset + originPos;
}
touchAxis = offset.getNormalized();
//stickIv用触摸点坐标赋值
stickIv->setPosition(pos);
if (onJoyStickMoved != nullptr) {
onJoyStickMoved(touchAxis);
}
break;
default://触摸结束/取消
isTouch = false;
if (onJoyStickEnded != nullptr) {
onJoyStickEnded();
}
//遥感回到原点
stickIv->runAction(mt);
break;
}
}