Cocos2d-x 3.x basic learning: Parallax Node ParallaxNode

Generally speaking, when we move, we will see objects that are closer to us, the faster they will move, and the farther objects, such as mountains in the distance, will move very slowly, and the farthest objects, such as the sun. Almost motionless, this phenomenon is called parallax.

       And imitating the parallax in the game can make the player feel that the character in the game is indeed moving. Cocos provides the ParallaxNode parallax node class, which can easily build a parallax layer, and you can control the parallax rate, position and level of each layer.

Cocos2d-x 3.4 version parallax node ParallaxNode

【ParallaxNode】

The use of this class is very simple. Just add the nodes that you want to produce parallax effects as child nodes of ParallaxNode, and set the parallax rate, position and level.

1. Commonly used functions

There are only a few custom functions in the ParallaxNode class, which rewrite related functions of the parent class Node.

Note: For the following overridden functions, do not call the corresponding overloaded functions in the parent class Node. That is, do not call functions like addChild(child, zOrder, tag).

The core functions are as follows:

create()

addChild()

removeChild()

//

/**

* Nodes that simulate parallax scrolling

* The child node moves faster/slower than the parent node according to the parallax ratio (parallaxRatio).

**/

class CC_DLL ParallaxNode : public Node

{

public:

// Create a parallax node

static ParallaxNode* create();

// Add child nodes

// child: child node

// z: zOrder order

// ratio: Vex2(ratioX,ratioY) The ratio of movement relative to ParallaxNode in both directions

// offset: relative offset position of ParallaxNode

void addChild(Node * child, int z, const Vec2& ratio, const Vec2& offset);

// Update the location information of the child nodes

virtual void visit(Renderer *renderer, const Mat4 &parentTransform, uint32_t parentFlags) override;

// Remove child nodes

// child is the deleted child node.

// cleanup true all actions and callbacks on this node will be deleted, false will not delete.

virtual void removeChild(Node* child, bool cleanup) override;

// Remove all child nodes

// cleanup true all actions and callbacks on this node will be deleted, false will not delete.

virtual void removeAllChildrenWithCleanup(bool cleanup) override;

};

//

2. About adding child nodes: addChild()

When adding a child node to ParallaxNode, the way of adding it is different from that of Node::addChild() of the parent class.

The overridden addChild() function must be used instead of overloaded functions such as the parent class addChild(Node* child, int z, int tag).

The implementation of this function is as follows:

//

// Add child nodes

// child: child node

// z: zOrder order

// ratio: Vex2(ratioX,ratioY) The ratio of movement relative to ParallaxNode in both directions

// offset: relative offset position of ParallaxNode

void ParallaxNode::addChild(Node* child, int z, const Vec2& ratio, const Vec2& offset)

{

CCASSERT( child != nullptr, "Argument must be non-nil");

PointObject *obj = PointObject::create(ratio, offset);

obj->setChild(child);

ccArrayAppendObjectWithResize(_parallaxArray, (Ref*)obj);

Vec2 pos = this->absolutePosition();

// The position of the child node is calculated based on the offset position offset and the disparity ratio ratio

pos.x = -pos.x + pos.x * ratio.x + offset.x;

pos.y = -pos.y + pos.y * ratio.y + offset.y;

child->setPosition(pos);

Node::addChild(child, z, child->getName());

}

//

It can be found that the coordinate position (Position) of the child node is determined by the offset position (offset) and the disparity ratio (ratio).

PS: This is why the child nodes added to ParallaxNode cannot use setPosition() to manually set the position. This may be a drawback of using ParallaxNode.

3. About updating the location of child nodes: visit()

When the position of ParallaxNode changes, the position of all child nodes will be relative to the parent node, and the coordinate position of the change will be calculated according to the position, offset, and ratio of the ParallaxNode.

After the location changes, the function called is visit(), which is implemented as follows:

//

// Update the location information of the child nodes

void ParallaxNode::visit(Renderer *renderer, const Mat4 &parentTransform, uint32_t parentFlags)

{

Vec2 pos = this->absolutePosition();

if( ! pos.equals(_lastPosition) )

{

// Calculate the position of all children relative to ParallaxNode

// Note that when we move the position of ParallaxNode, what we show is actually a change in the position of the child. This change is the core design of this class.

for( int i=0; i < _parallaxArray->num; i++ )

{

PointObject *point = (PointObject*)_parallaxArray->arr[i];

// For example, the absolute position of ParallaxNode is 100, which shows that the position of the child is -100. We cannot perceive the movement of ParallaxNode, but the position of the child has changed.

// The simple point is similar to the movement of a camera scene, the camera has not moved, the scenery has changed

// If ratio is (=1), then position == offset

// If the ratio is (0~1), then position <offset, slow moving speed

// If the ratio is (>1), then position> offset, the moving speed is fast

float x = -pos.x + pos.x * point->getRatio().x + point->getOffset().x;

float y = -pos.y + pos.y * point-> getRatio (). y + point-> getOffset (). y;

// The position of the child is calculated from the two lines above

// Therefore manually setting its postion will not have any effect

point->getChild()->setPosition(x,y);

}

_lastPosition = pos;

}

Node::visit(renderer, parentTransform, parentFlags);

}

//

4. Parallax effect of child nodes

After adding the child node to ParallaxNode, and setting the offset position offset and the parallax ratio ratio, all the child nodes of ParallaxNode will move with the movement of ParallaxNode.

The position of the child node after moving is calculated based on the position of ParallaxNode, offset, and ratio.

When the child nodes have different disparity ratios, during the movement process, there will be some fast moving and some slow moving parallax effects.

[Code combat]

0, picture material

 

1425435572168048.jpg

1. Create a parallax node class and add child nodes

Create three child nodes and add them to ParallaxNode.

bg: anchor point (0, 0), inspection ratio ratio (0.5, 0.5), offset position offset (0, 0).

ball: anchor point (0.5, 0.5), inspection ratio ratio (1, 1), offset position (the coordinate of the screen center point).

smile: anchor point (0, 0), inspection ratio ratio (4, 4), offset position offset (0, 0).

PS: Test the sprite bg, manually set the position coordinate setPosition( ).

//

//[1] Viewable area size

Size vSize = Director::getInstance()->getVisibleSize();

//[2] Create three child nodes

Sprite* bg = Sprite::create("HelloWorld.png");

bg->setAnchorPoint(Vec2(0, 0)); // anchor point (0, 0)

bg->setName("HelloWorld");

//Bug: The wizard on ParallaxNode is invalid for its setPosition

// See the running results

bg->setPosition(Vec2(100, 100)); // Set the coordinate position of bg

Sprite* ball = Sprite::create("Ball.png");

ball->setAnchorPoint(Vec2(0.5, 0.5)); // anchor point (0.5, 0.5)

ball->setName("Ball");

Sprite* smile = Sprite::create("Smile.png");

smile->setAnchorPoint(Vec2(0, 0)); // anchor point (0, 0)

smile->setName("Smile");

//[3] Create ParallaxNode and add child nodes

// Create a parallax node class

ParallaxNode* parallaxNode = ParallaxNode::create();

this->addChild(parallaxNode, 0, "parallaxNode");

// Add child nodes

// addChild(node, zOrder, ratio, offset);

parallaxNode->addChild(bg, 0, Vec2(0.5, 0.5), Vec2(0, 0));

parallaxNode->addChild(ball, 1, Vec2(1, 1), Vec2(vSize.width/2, vSize.height/2));

parallaxNode->addChild(smile, 1, Vec2(4, 4), Vec2(0, 0));

//[4] Add touch event

EventDispatcher* dispatcher = this->getEventDispatcher();

EventListenerTouchOneByOne* listener = EventListenerTouchOneByOne::create();

listener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);

listener->onTouchMoved = CC_CALLBACK_2(HelloWorld::onTouchMoved, this);

listener->onTouchEnded = CC_CALLBACK_2(HelloWorld::onTouchEnded, this);

dispatcher->addEventListenerWithSceneGraphPriority(listener, this);

//

2. Realize touch events

Touch to start: No operation.

Touch to move: ParallaxNode moves with it.

Touch end: output the location information of each node to see the difference.

//

bool HelloWorld::onTouchBegan(Touch* pTouch, Event* pEvent)

{

return true;

}

// Move ParallaxNode node

void HelloWorld::onTouchMoved(Touch* pTouch, Event* pEvent)

{

Vec2 delta = pTouch->getDelta();

// Move ParallaxNode node

// The position of all child nodes will also change accordingly

ParallaxNode* parallaxNode = (ParallaxNode*)this->getChildByName("parallaxNode");

parallaxNode->setPosition(parallaxNode->getPosition() + delta);

}

// After the touch is over, output the position information of each node

void HelloWorld::onTouchEnded(Touch* pTouch, Event* pEvent)

{

ParallaxNode* parallaxNode = (ParallaxNode*)this->getChildByName("parallaxNode");

// Get child nodes by name

Sprite* bg = (Sprite*)parallaxNode->getChildByName("HelloWorld");

Sprite* ball = (Sprite*)parallaxNode->getChildByName("Ball");

Sprite* smile = (Sprite*)parallaxNode->getChildByName("Smile");

// Output coordinate position information

CCLOG("parallax : %f %f", parallaxNode->getPositionX(), parallaxNode->getPositionY());

CCLOG("HelloWorld : %f %f", bg->getPositionX(), bg->getPositionY());

CCLOG("ball : %f %f", ball->getPositionX(), ball->getPositionY());

CCLOG("smile : %f %f", smile->getPositionX(), smile->getPositionY());

CCLOG("---------------------------------------");

}

//

3. Running results

 

wKioL1TnOiejChx-ABW2cm3i2hI264.gif

During the movement, the output data result is:

//

parallax : 0.000000 0.000000

HelloWorld : 0.000000 0.000000

ball : 240.000000 160.000000

smile : 0.000000 0.000000

---------------------------------------

parallax : 101.836441 20.723732

HelloWorld : -50.918221 -10.361866

ball : 240.000000 160.000000

smile : 305.509338 62.171196

---------------------------------------

parallax : 19.378311 64.557907

HelloWorld : -9.689156 -32.278954

ball : 240.000000 160.000000

smile : 58.134933 193.673721

---------------------------------------

parallax : -1.778305 -81.284264

HelloWorld : 0.889153 40.642132

ball : 240.000000 160.000000

smile : -5.334915 -243.852783

---------------------------------------

//

4. Data analysis

(0)HelloWorld: setPosition() is set at the beginning, but it is invalid. Because its coordinates are only affected by ratio and offset.

(1) HelloWorld: Why did the coordinates become negative during the movement? This is because the coordinates of the child nodes are offset relative to ParallaxNode. Because the disparity ratio of HelloWorld is 0.5 times, when parallaxNode moves 100 pixels, then HelloWorld only moves 50 pixels. So its offset position relative to parallaxNode is -50.

(2) Ball: During the movement, the coordinate position has not changed. Because its parallax ratio is 1.0 times, how much the parallaxNode moves, and how much the ball moves. So the position of the ball relative to the parallaxNode is still the original offset position.

(3) smile: This moves quickly, with a parallax ratio of 4.0 times. But why its coordinate position is always 3 times that of parallaxNode??? Haha, because parallaxNode has moved 100 pixels, and it has moved 400 pixels, then its position relative to parallaxNode coordinates is not 400-100 = 300 is there.

Guess you like

Origin blog.csdn.net/qq_21743659/article/details/108595904