cocos2d-x 対象のキャラを移動させても常に画面に表示させる方法

#cocos2d-xでキャラが移動しても常に画面に表示させるにはFollowアクションを使う

3Dや2Dのゲームでは通常カメラという概念で表示を固定化させるが、
cocos2d-xではFollowアクションを使うことでカメラの代用をすることができる。
むしろFollowを使うのが普通なのかも

```cpp:HelloWorldScene.cpp
//Rectはスクロール範囲 普通はマップの大きさ
Follow *follow = Follow::create(player, Rect(0, 0, 2000, 1334));
//これをLayerにアクションとして実行させる
this->runAction(follow);
```
<img width="446" alt="2016-12-23.png" src="https://qiita-image-store.s3.amazonaws.com/0/142882/c3d11a8e-a153-bb57-9974-c50e881739b4.png">


おまけ
これでは常に中央に表示される。
問題なのは横スクロールだけの場合とか縦スクロールだけとかの場合に
中央にキャラが表示されてはプレイしづらい。
オフセットの概念がFollowにはまだ実装されていないのでcocos2d-xのソースコードを修正する必要がある。
すでに修正した人がGitHubに公開しているのでそこへのURLを張ります。

コードそのもの：
https://github.com/AlwynC/cocos2d-x/blob/d22dca636182ac48f4d7f38bf33d251e427f6f10/cocos/2d/CCAction.cpp

公開しているサイト：
https://github.com/cocos2d/cocos2d-x/pull/15194/files


<img width="446" alt="2016-12-23 (1).png" src="https://qiita-image-store.s3.amazonaws.com/0/142882/35a465c7-31f3-832f-e15f-4b81d54264ee.png">

```cpp:CCAction.h
//追加
public:
 static Follow* createWithOffset(Node* followedNode, float xOffset, float yOffset, const Rect& rect = Rect::ZERO);
 bool initWithTargetAndOffset(Node *followedNode, float xOffset, float yOffset, const Rect& rect);

//修正
 Follow()
    : _followedNode(nullptr)
    , _boundarySet(false)
    , _boundaryFullyCovered(false)
    , _leftBoundary(0.0)
    , _rightBoundary(0.0)
    , _topBoundary(0.0)
    , _bottomBoundary(0.0)
	, _offsetX(0) //これを追加
	, _offsetY(0) //これを追加
    , _worldRect(Rect::ZERO)
    {}

protected:
　float _offsetX; //追加
　float _offsetY; //追加
```


```cpp:CCAction.cpp
//追加
Follow* Follow::createWithOffset(Node* followedNode, float xOffset, float yOffset, const Rect& rect/*= Rect::ZERO*/)
{
	Follow *follow = new (std::nothrow) Follow();
	bool valid;
	valid = follow->initWithTargetAndOffset(followedNode, xOffset, yOffset, rect);

	if (follow && valid)
	{
		follow->autorelease();
		return follow;
	}
	delete follow;

	return nullptr;
}

//追加
bool Follow::initWithTargetAndOffset(Node *followedNode, float xOffset, float yOffset, const Rect& rect)
{
	CCASSERT(followedNode != nullptr, "FollowedNode can't be NULL");
	if (followedNode == nullptr)
	{
		log("Follow::initWithTarget error: followedNode is nullptr!");
		return false;
	}

	followedNode->retain();
	_followedNode = followedNode;
	_worldRect = rect;
	_boundarySet = !rect.equals(Rect::ZERO);
	_boundaryFullyCovered = false;


	Size winSize = Director::getInstance()->getWinSize();
	_fullScreenSize.set(winSize.width, winSize.height);
	_halfScreenSize = _fullScreenSize * 0.5f;
	_offsetX = xOffset;
	_offsetY = yOffset;
	_halfScreenSize.x += _offsetX;
	_halfScreenSize.y += _offsetY;

	if (_boundarySet)
	{
		_leftBoundary = -((rect.origin.x + rect.size.width) - _fullScreenSize.x);
		_rightBoundary = -rect.origin.x;
		_topBoundary = -rect.origin.y;
		_bottomBoundary = -((rect.origin.y + rect.size.height) - _fullScreenSize.y);

		if (_rightBoundary < _leftBoundary)
		{
			// screen width is larger than world's boundary width
			//set both in the middle of the world
			_rightBoundary = _leftBoundary = (_leftBoundary + _rightBoundary) / 2;

		}
		if (_topBoundary < _bottomBoundary)
		{
			// screen width is larger than world's boundary width
			//set both in the middle of the world
			_topBoundary = _bottomBoundary = (_topBoundary + _bottomBoundary) / 2;
		}

		if ((_topBoundary == _bottomBoundary) && (_leftBoundary == _rightBoundary))
		{
			_boundaryFullyCovered = true;
		}
	}

	return true;
}


//修正
Follow* Follow::clone() const
{
    // no copy constructor
	return Follow::createWithOffset(_followedNode, _offsetX, _offsetY, _worldRect);
	/*
    auto a = new (std::nothrow) Follow();
    a->initWithTarget(_followedNode, _worldRect);
    a->autorelease();
    return a;
	*/
}

```