cocos2d学习笔记----制作摇杆

318 阅读3分钟

制作摇杆的思路

摇杆应该由两部分组成:一个是背景,一个是拖动部分。这两个部分我们用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;
    }
}