Ninja invincible-Examples of Cocos2d-x tile map, examples of cocos2d-x
The instance is relatively simple. There is a ninja genie on the map, and the player clicks the top, bottom, left, and right of his surroundings to walk in this direction. When he encounters an obstacle, the obstacle cannot be crossed, except for the grass, including trees, mountains, and rivers.
Ninja instance map (TODO replaces the map with this genie)
Design Map
We use the David collections file. In this tutorial, I used photoshopto convert to dg_grounds32.jpg.
The tile set provided by David Gervais is 32x32 pixels, and the size of the map we created is 32x32 tiles. First, we add the common layer and Object layer for the map. The common layer adds several rectangular area objects in the object Layer according to the design. Results of Design completion at this stage. Save the file name as MiddleMap. tmx and save the directory Resources \ map.
Design Map
Program Load Map
After the map design is complete, we can load the map in the program. Next let's take a look at the specific program code. First, let's take a look at the HelloWorldScene. h file. Its code is as follows:
#ifndef __HELLOWORLD_SCENE_H__#define __HELLOWORLD_SCENE_H__#include "cocos2d.h"class HelloWorld : public cocos2d::Layer{cocos2d::TMXTiledMap* _tileMap;① cocos2d::Sprite *_player; ②public: static cocos2d::Scene* createScene(); virtual bool init(); CREATE_FUNC(HelloWorld);};#endif // __HELLOWORLD_SCENE_H__
The code line ① defines the member variable MAP member _ tileMap ,. The second line of code defines the sprite member Variable _ player.
The HelloWorldScene implementation code HelloWorldScene. ccp file. Its HelloWorld: init () code is as follows:
bool HelloWorld::init(){if ( !Layer::init() ){return false;}Size visibleSize = Director::getInstance()->getVisibleSize();Point origin = Director::getInstance()->getVisibleOrigin();_tileMap = TMXTiledMap::create("map/MiddleMap.tmx");①addChild(tileMap,0,100);②TMXObjectGroup* group = _tileMap ->getObjectGroup("objects");③ValueMap spawnPoint = group->getObject("ninja");④float x = spawnPoint["x"].asFloat();⑤float y = spawnPoint["y"].asFloat();⑥_player = Sprite::create("ninja.png");⑦_player ->setPosition(Point(x,y));⑧addChild(_player, 2,200);return true;}
The Code ① above is to create a TMXTiledMap object. The map file is MiddleMap. tmx, and the map is a subdirectory under the Resources directory. The TMXTiledMap object is also a Node object and needs to be added to the current scenario through the Code in line ②.
The Code in line ③ obtains the object group set in the layer through the Object layer name objects. Line 4 of the Code obtains ninja object information from the object group through the object name. Its return value type is ValueMap, and ValueMap is a "key-value" structure. The code float x = spawnPoint ["x"]. spawnPoint ["x"] in asFloat () is to extract its value from the x key, that is, the x axis coordinate. The return Value of spawnPoint ["x"] is the Value type. You also need to use the asFloat () function to convert it to the basic int type. Similarly, line 6 is used to obtain the Y axis coordinate.
The Code in line 7 creates the sprite _ player. The Code in line 7 sets the sprite position, which is obtained from the ninja object information in the Object layer.
Load the map (TODO captures the map again or change the sprite)
Mobile genie
The mobile genie moves by touch events. event processing is required at the layer. The following functions need to be rewritten at the layer:
Bool onTouchBegan (Touch * touch, Event * unused_event)
Void onTouchEnded (Touch * touch, Event * unused_event)
Void onTouchMoved (Touch * touch, Event * unused_event)
Next let's take a look at the specific program code. First, let's take a look at the HelloWorldScene. h file. Its code is as follows:
#ifndef __HELLOWORLD_SCENE_H__#define __HELLOWORLD_SCENE_H__#include "cocos2d.h"class HelloWorld : public cocos2d::Layer{cocos2d::TMXTiledMap* _tileMap; cocos2d::Sprite *_player; public: static cocos2d::Scene* createScene(); virtual bool init(); virtual bool onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event); ① virtual void onTouchMoved(cocos2d::Touch *touch, cocos2d::Event *event); virtual void onTouchEnded(cocos2d::Touch *touch, cocos2d::Event *event); ② CREATE_FUNC(HelloWorld);};#endif // __HELLOWORLD_SCENE_H__
Code ① ~ ② The line of code declares the touch event function. The HelloWorldScene implementation code HelloWorldScene. ccp file. Its HelloWorld: init () code is as follows:
Bool HelloWorld: init (){... ... SetTouchEnabled (true); // set it to single-Touch setTouchMode (Touch: DispatchMode: ONE_BY_ONE); return true ;}
The above code setTouchEnabled (true) is used to enable Layer-start touch event support. The Code setTouchMode (Touch: DispatchMode: ONE_BY_ONE) is to set the Touch mode to single-Touch.
The Touch event function code of the HelloWorldScene. ccp file is as follows:
bool HelloWorld::onTouchBegan(Touch* touch, Event* event){ log("onTouchBegan"); return true;}void HelloWorld::onTouchMoved(Touch *touch, Event *event){ log("onTouchMoved");}void HelloWorld::onTouchEnded(Touch *touch, Event *event){ log("onTouchEnded");Point touchLocation = touch->getLocation(); ① Point playerPos = _player->getPosition();② Point diff = touchLocation - playerPos;③ if (abs(diff.x) > abs(diff.y)) {④ if (diff.x > 0) {⑤ playerPos.x += _tileMap->getTileSize().width; _player->runAction(FlipX::create(false));⑥ } else { playerPos.x -= _tileMap->getTileSize().width; _player->runAction(FlipX::create(true));⑦ } } else { if (diff.y > 0) {⑧ playerPos.y += _tileMap->getTileSize().height; } else { playerPos.y -= _tileMap->getTileSize().height; } }_player->setPosition(playerPos);⑨}
The above code touch-> getLocation () is obtained in the Open GL coordinate, the coordinate origin of the Open GL coordinate is in the lower left corner, and the touch object encapsulates the touch point object. Line ② code _ player-> getPosition () is the location for obtaining the genie.
The Code in line ③ is the difference between the touch point and the sprite position. Line 4 of the Code compares the difference between the touch point and the sprite position, whether the difference between the Y axis is big or the difference between the X axis is big, and the difference between the axis is big, it moves along that axis, (abs (diff. x)> abs (diff. y) The difference between the X axis is big; otherwise, the difference between the y axis is big. Line ⑤ Of code, where diff. x> 0 moves along the positive direction of the x axis; otherwise, it moves along the negative direction of the x axis. Line 6 code _ player-> runAction (FlipX: create (false) refers to turning the genie back to the original state. Line 7 code _ player-> runAction (FlipX: create (true) is to flip the genie horizontally along the Y axis.
The code in the nth line moves along the y axis, and diff. y> 0 moves along the positive direction of the y axis; otherwise, it moves along the negative direction of the y axis.
The first line of code is to reset the sprite coordinates.
Collision Detection
The genie in our game so far can cross any obstacle. To detect whether the genie has collided with obstacles, we need to add another common layer (collimable) to detect collisions instead of realistic maps. In the collision detection layer, we use tiles to overwrite obstacles in the background layer ,.
The detection collision layer detects that the tile set in the collision layer can be any image file that meets the format requirements. In this example, we use a 32x32 pixel monochrome jpg image file collidable_tiles. jpg, which has the same size as the tile size, that is, this tile set has only one tile. After importing the tile set to the map, we need to add a custom attribute for the tile. the tile also has some attributes, such as the coordinate attributes x and y.
The name of the attribute to be added is "colretriable" and the attribute value is "true ". To add a property, select the tile in the collidable_tiles tile set. Then, click the "+" button in the lower left corner of the property view to add custom properties. A dialog box is displayed. In the dialog box, enter the custom property name "colretriable" and click "OK. Return to the attribute view. You can enter the content after the attribute. Here, we enter "true ".
After adding the map of the detection collision attribute, we need to modify the code. It is preferred to add a member variable and two function declarations to the header file HelloWorldScene. h.
#ifndef __HELLOWORLD_SCENE_H__#define __HELLOWORLD_SCENE_H__#include "cocos2d.h"#include "SimpleAudioEngine.h"class HelloWorld : public cocos2d::Layer{cocos2d::TMXTiledMap* _tileMap;cocos2d::TMXLayer* _collidable;① cocos2d::Sprite *_player;public: static cocos2d::Scene* createScene(); virtual bool init(); virtual bool onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event); virtual void onTouchMoved(cocos2d::Touch *touch, cocos2d::Event *event); virtual void onTouchEnded(cocos2d::Touch *touch, cocos2d::Event *event);void setPlayerPosition(cocos2d::Point position);②cocos2d::Point tileCoordFromPosition(cocos2d::Point position);③ CREATE_FUNC(HelloWorld);};#endif // __HELLOWORLD_SCENE_H__
The first line of the above Code declares a member variable of the TMXLayer type, which is used to save the map collision layer object. The setPlayerPosition function of the Code in line ② is used to reset the location of the genie. In this function, it can detect whether the genie collided with obstacles. The code line ③ tileCoordFromPosition function converts the pixel coordinate point to the map tile coordinate point.
Modify the HelloWorld: init () code in HelloWorldScene. cpp as follows:
Bool HelloWorld: init () {if (! Layer: init () {return false;} Size visibleSize = Director: getInstance ()-> getVisibleSize (); Point origin = Director: getInstance () -> getVisibleOrigin (); _ tileMap = TMXTiledMap: create ("map/MiddleMap. tmx "); addChild (_ tileMap, 0,100); TMXObjectGroup * group = _ tileMap-> getObjectGroup (" objects "); ValueMap spawnPoint = group-> getObject (" ninja "); float x = spawnPoint ["x"]. asFloat (); float y = spawnPoint ["y"]. asFloat (); _ player = Sprite: create ("ninja.png"); _ player-> setPosition (Point (x, y); addChild (_ player, 2,200 ); _ colcyclable = _ tileMap-> getLayer ("colcyclable"); ① _ colcyclable-> setVisible (false); ② setTouchEnabled (true); // set it to single-Touch setTouchMode (Touch:: DispatchMode: ONE_BY_ONE); return true ;}
We need to create and initialize the collision layer in the HelloWorld: init () function. The Code in line ① Is _ colexternable = _ tileMap-> getLayer ("colexternable"), which creates a layer by using the layer name colexternable. The Code in line ② _ colexternable-> setVisible (false) is to set layer hiding. We can either hide it here, or make the layer transparent during map editing. In the layer view, select a layer, then, you can slide the transparency slider above to change the transparency of the layer. In this example, you need to set the transparency to 0, so the _ colconfigurable-> setVisible (false) Statement is no longer needed.
Note: In the map editor, the transparency of the Set layer is 0, which is the same as that of the Set layer hidden. The map looks the same, but there are essential differences, you cannot use the _ coltailable = _ tileMap-> getLayer ("coltailable") statement to hide the settings layer.
Set layer transparency
We also mentioned earlier that the collimable layer is used not to display the map content, but to detect collision. Modify
HelloWorld: onTouchEnded code: void HelloWorld: onTouchEnded (Touch * touch, Event * event) {log ("onTouchEnded "); // obtain the coordinates in OpenGL: Point touchLocation = touch-> getLocation (); Point playerPos = _ player-> getPosition (); Point diff = touchLocation-playerPos; if (abs (diff. x)> abs (diff. y) {if (diff. x> 0) {playerPos. x + = _ tileMap-> getTileSize (). width; _ player-> runAction (FlipX: create (false);} else {playerPos. x-= _ tileMap-> getTileSize (). width; _ player-> runAction (FlipX: create (true) ;}} else {if (diff. y> 0) {playerPos. y + = _ tileMap-> getTileSize (). height;} else {playerPos. y-= _ tileMap-> getTileSize (). height ;}} this-> setPlayerPosition (playerPos); ①}
HelloWorld: onTouchEnded has some changes. The Code in line ① this-> setPlayerPosition (playerPos) replaces _ player-> setPosition (playerPos). setPlayerPosition is our custom function, this function is used to move the genie and detect collisions.
The setPlayerPosition code is as follows:
Void HelloWorld: setPlayerPosition (Point position) {// convert the pixel coordinate to the tile coordinate Point tileCoord = this-> tileCoordFromPosition (position ); ① // obtain the GIDint tileGid = _ collidable-> getTileGIDAt (tileCoord) of the tile; ② if (tileGid> 0) {③ Value prop = _ tileMap-> getPropertiesForGID (tileGid ); ④ ValueMap propValueMap = prop. asValueMap (); ⑤ std: string collision = propValueMap ["Collidable"]. asString (); ⑥ if (collision = "true") {// collision detection successful 7cocosdenshion: SimpleAudioEngine: getInstance ()-> playEffect ("empty.wav "); repeated return; }}_ player-> setPosition (position );}
The first line of the above Code, this-> tileCoordFromPosition (position), is to call a function to convert the pixel coordinates into tile coordinates. Line ② code _ colcyclable-> getTileGIDAt (tileCoord) obtains the GID value through the tile coordinate.
Line ③ code tileGid> 0 to determine whether the tile exists. tileGid = 0 indicates that the tile does not exist. Line ④ code _ tileMap-> getPropertiesForGID (tileGid) is returned through the getPropertiesForGID of the map object, and its return Value is of the Value type.
The Value type can represent many types. Therefore, the fifth line of code prop. asValueMap () is to convert the Value type into ValueMap, And the ValueMap class is a "key-Value" pair. The Code in line 6 propValueMap ["colaluable"]. asString () is used to retrieve the Collidable attribute in the propValueMap variable. The asString () function can convert the Value type to the std: string type. Line 7 Code collision = "true" indicates the successful collision detection. The first line of code is processed when the collision detection is successful. In this example, we play the sound effect.
The tileCoordFromPosition code is as follows:
Point HelloWorld::tileCoordFromPosition(Point pos) {int x = pos.x / _tileMap->getTileSize().width; ①int y = ((_tileMap->getMapSize().height * _tileMap->getTileSize().height) - pos.y) / _tileMap->getTileSize().height; ②return Point(x,y);}
In this function, line ① code pos. x/_ tileMap-> getTileSize (). width is to obtain the X axis tile coordinate (unit: number of tiles), pos. x is the x-axis coordinate of the touch point (in pixels), _ tileMap-> getTileSize (). width is the width of each tile, in pixels. Line ② of the code is to obtain the coordinate of the Y axis tile (unit: number of tiles). This calculation is a bit troublesome. The origin of the tile coordinate is in the upper left corner, and the coordinate used by the touch point is the Open GL coordinate, the coordinate origin is in the lower left corner, and the expression (_ tileMap-> getMapSize (). height * _ tileMap-> getTileSize (). height)-pos. y) is to reverse the coordinate axis. The result is divided by the height of each tile _ tileMap-> getTileSize (). height to obtain the coordinate of the Y axis tile.
Rolling Map
Because the map is bigger than the screen, when we move the genie to the edge of the screen, the map that is out of the screen should scroll to the screen. These require us to reset the viewpoint (center of the screen) so that the genie remains in the center of the screen. However, when the genie is too close to the border of the map, it may not be in the center of the screen. The border distance between the genie and the map is defined as that the distance between the left and right borders is no less than half the width of the screen. Otherwise, the black borders shown in the figure may appear. The distance between the upper and lower boundary is not less than half of the screen height. Otherwise, the black border may also occur.
There are many ways to reset the viewpoint. This effect is achieved by moving the map position in this chapter.
We add another setViewpointCenter function in HelloWorldScene. cpp. The code after adding the function is as follows:
Void HelloWorld: setViewpointCenter (Point position) {Size visibleSize = Director: getInstance ()-> getVisibleSize (); int x = MAX (position. x, visibleSize. width/2); ① int y = MAX (position. y, visibleSize. height/2); ② x = MIN (x, (_ tileMap-> getMapSize (). width * _ tileMap-> getTileSize (). width)-visibleSize. width/2); ③ y = MIN (y, (_ tileMap-> getMapSize (). height * _ tileMap-> getTileSize (). height)-visibleSize. height/2); ④ // the center Point of the screen Point pointA = Point (visibleSize. width/2, visibleSize. height/2); ⑤ // place the genie in the center of the screen, move the map's target location Point pointB = Point (x, y); ⑥ log ("target location (% f, % f) ", pointB. x, pointB. y); // map movement offset Point offset = pointA-pointB; 7log ("offset (% f, % f)", offset. x, offset. y); this-> setPosition (offset); Limit}
In the above Code ① ~ ④ This is important to ensure that the genie will not move any more when moving to the map boundary and prevent the screen from going beyond the map. The first line of code is to prevent the screen from exceeding the map on the left, MAX (position. x, visibleSize. width/2) the statement indicates when position. x <visibleSize. in width/2, the X axis coordinates are always visibleSize. width/2, that is, the genie no longer moves to the left. The Code in line ② is similar to that in line ① and will not be explained. The Code in line ③ prevents MIN (x, (_ tileMap-> getMapSize () beyond the map on the right of the screen (). width * _ tileMap-> getTileSize (). width)-visibleSize. width/2) the statement indicates that when x> (_ tileMap-> getMapSize (). width * _ tileMap-> getTileSize (). width)-visibleSize. when width/2, the X axis coordinates are always (_ tileMap-> getMapSize (). width * _ tileMap-> getTileSize (). width)-visibleSize. the result of the width/2 expression calculation.
The prompt visibleSize indicates the screen width, _ tileMap-> getMapSize (). width * _ tileMap-> getTileSize (). width)-visibleSize. the width/2 expression calculates the map width minus half of the screen width.
Line 4 code is similar to line 3 code and will not be explained.
Map exceeded on the left of the screen
Code 5 ~ The ghost row moves the map and keeps the genie at the center of the screen. Point A is the center of the current screen and the position of the genie. Players touch point B and the genie will move to point B. To keep the genie in the center of the screen, the map must move in the opposite direction.
Line ⑤ Code Point pointA = Point (visibleSize. width/2, visibleSize. height/2) is to obtain the center Point of the screen (a Point ). The Code in line 6 is to obtain the target location of the mobile map (point B ). The Code in line 7 calculates the difference between point A and point B. The difference is the distance from the map to be moved. Since the global coordinates of the genie are the model coordinates of the map layer, that is, the coordinate origin of the genie is the lower left corner of the map, the first line of code this-> setPosition (offset) is to move the map coordinate origin offset position.
Mobile Map
For more information, please refer to the first domestic Swift book "Swift development guide" for discussion. Website: http://www.51work6.com/swift.phpwelcome to the swifttechnology discussion group: 362298.pdf
Welcome to Zhijie iOS public classroom Platform
Similarities and differences between right-angle tile maps and diagonal tile maps in Cocos2D
Right-angle tile maps are commonly used in 2D game views.
The diagonal tile map uses the Axis Test projection to enable the player to observe the scene from an angle, thus generating the visual depth.
Detailed usage of tile map in COCOS2d-iphone
1. You need to import tmx and your tileset (usually png images) into the project.
2. Copy to project
3. Put the tmx and tile in the same directory to take the relative path, and remove the path in xml.
4. The map you need to add is CCTMXTiledMap, And the CCTMXLayer is one of the layers, which can be seen from the class name.