cocos2d-xでキャラが移動しても常に画面に表示させるにはFollowアクションを使う
3Dや2Dのゲームでは通常カメラという概念で表示を固定化させるが、
cocos2d-xではFollowアクションを使うことでカメラの代用をすることができる。
むしろFollowを使うのが普通なのかも
HelloWorldScene.cpp
//Rectはスクロール範囲 普通はマップの大きさ
Follow *follow = Follow::create(player, Rect(0, 0, 2000, 1334));
//これをLayerにアクションとして実行させる
this->runAction(follow);

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

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; //追加
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;
*/
}