LoginSignup
3
4

More than 5 years have passed since last update.

cocos2d-x/ScrollViewの慣性の動きが気持ちよくないので自分で制御する。

Last updated at Posted at 2015-06-30

Cocos StudioでScrollViewを配置してみたが、慣性の動きが気持ちよくないので、自分で動かす。
ただ、バウンドはできなくなる。
ソースが美しくないのは悪しからず。。。

ScrollViewController.cpp

#include "ScrollViewController.h"

using namespace cocos2d;

const uint32_t ScrollViewController::HISTORY_FRAME = 10;

ScrollViewController::ScrollViewController():_target(nullptr),_touchNow(false),_deceleration(defaultDeceleration)
{

}
ScrollViewController::~ScrollViewController()
{

}
void ScrollViewController::setTarget(cocos2d::ui::ScrollView* scrollview)
{
  _target = scrollview;
  // もともとの慣性は無効に
  _target->setInertiaScrollEnabled(false);

  _target->addTouchEventListener([this](Ref* ref, ui::Widget::TouchEventType type){
    switch(type)
    {
        // タッチ開始時
      case ui::Widget::TouchEventType::BEGAN:
        _touchNow = true;
        _history.clear();
        _vec = Vec2::ZERO;
        _posPre = _target->getInnerContainer()->getPosition();
        break;
        // タッチ終了時
      case ui::Widget::TouchEventType::CANCELED:
      case ui::Widget::TouchEventType::ENDED:
        if( _history.size() > 0 ){
          for( auto& h : _history ){
            _vec += h;
          }
          _vec.x /= _history.size();
          _vec.y /= _history.size();
        }
        _touchNow = false;
        break;
      default:
        break;
    }
  });


  scheduleUpdate();
}

void ScrollViewController::update(float delta)
{
  if( _target == nullptr ){
    return;
  }
  auto innner = _target->getInnerContainer();
  // タッチ中は動きの履歴を貯める
  if( _touchNow ){
    auto now = innner->getPosition();
    auto vec = now - _posPre;
    _history.push_back(vec);
    while(_history.size()>HISTORY_FRAME){
      _history.pop_front();
    }
    _posPre = now;
  }
  // タッチ中じゃなかったら動かす
  else{
    auto now = innner->getPosition();
    auto pos = now + _vec;
    auto szLimit = _target->getInnerContainerSize();
    auto szTarget = _target->getContentSize();
    szLimit.width -= szTarget.width;
    szLimit.height -= szTarget.height;

    if( pos.y > 0 ){
      pos.y = 0;
    }
    if( pos.y < -szLimit.height ){
      pos.y = -szLimit.height;
    }
    if( pos.x > 0 ){
      pos.x = 0;
    }
    if( pos.x < -szLimit.width ){
      pos.x = -szLimit.width;
    }
    _vec = pos - now;
    innner->setPosition(pos);
    _deceleration(_vec);
  }
}

void ScrollViewController::defaultDeceleration(cocos2d::Vec2& vec)
{
  vec *= 0.95f;
  if( fabs(vec.x) < 0.1f && fabs(vec.y) < 0.1f ){
    vec = Vec2::ZERO;
  }
}

ScrollViewController.h

#ifndef __ScrollViewController_H__
#define __ScrollViewController_H__
#include "cocos2d.h"
#include <ui/UIScrollView.h>
#include <deque>

class ScrollViewController : public cocos2d::Node
{
  ScrollViewController();
  ~ScrollViewController();
public:

  CREATE_FUNC(ScrollViewController);
  void setTarget(cocos2d::ui::ScrollView* scrollview);
  virtual void update(float delta);
  void setDeceleration(std::function<void(cocos2d::Vec2& vec)> dec){
    _deceleration = dec;
  }

private:
  cocos2d::ui::ScrollView* _target;
  bool _touchNow;
  cocos2d::Vec2 _vec;
  cocos2d::Vec2 _posPre;
  std::deque<cocos2d::Vec2> _history;
  static const uint32_t HISTORY_FRAME;
  std::function<void(cocos2d::Vec2& vec)> _deceleration;
  static void defaultDeceleration(cocos2d::Vec2& vec);

};
#endif


使い方は

FooScene.cpp

  auto scrollview = (ui::ScrollView*)_node->getChildByName("scrollview");

  auto ctrl = ScrollViewController::create();
  ctrl->setTarget(scrollview);
  _node->addChild(ctrl);

SceneにaddChild()して参照カウンタの管理できるから、cocos2d::Nodeから継承しているが、特に意味はないです。

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4