前言:
我们在做经典的格斗类的游戏的时候,场景常常用的是45°斜地图来创建的。下面我就来实现一个简单的Demo来展现一下斜地图的使用。
功能实现:
1.倾斜地图的加载;
2.点击地图居中;
3.主角只能在一定的范围内移动;
4.鼠标点击屏幕,主角移动一格,如果连续点击则主句不断的移动;
5.具备碰撞检测的效果,实现人物在某些地方不能走动。
地图的设计:
用Tiled软件设计自己的瓦片地图。
图层要设置z轴属性,方便可以隐藏主角:
在图层的属性中加上 cc_vertexz -400
如果前面的图层那就设置为automatic
代码实现:
在AppDelegate添加代码:
//深度测试,方便实现遮盖效果 CCDirector::sharedDirector()->setDepthTest(true); //Opengl渲染设置,如果地图有背景图层的话就需要加这句 CCDirector::sharedDirector()->setProjection(kCCDirectorProjection2D);
Player类:
#ifndef ___5tilemap__Player__ #define ___5tilemap__Player__ #include <iostream> #include "cocos2d.h" using namespace cocos2d; class Player : public CCSprite { public: static Player * create(); virtual bool initPlayer(); //获取地图中某瓷砖快的z轴属性 void updateVertextZ(CCPoint tilePos,CCTMXTiledMap * tileMap); }; #endif /* defined(___5tilemap__Player__) */
#include "Player.h" static Player *s; Player* Player::create() { s = new Player(); if (s&&s->initPlayer()) { s->autorelease(); return s; } else { delete s; s = NULL; return NULL; } } //初始化一个对象 bool Player::initPlayer() { if (!CCSprite::initWithFile("ninja.png")) { return false; } return true; } void Player::updateVertextZ(cocos2d::CCPoint tilePos, cocos2d::CCTMXTiledMap *tileMap) { //获取最小的z轴属性 float lowestZ = -(tileMap->getMapSize().width + tileMap->getMapSize().height); //以瓷砖块的x,y坐标来计算当前瓷砖块的z轴属性 float currentZ = tilePos.x + tilePos.y; //设置z轴属性 this->setVertexZ(lowestZ+currentZ - 1); }
HelloWorld.h:
#ifndef __HELLOWORLD_SCENE_H__ #define __HELLOWORLD_SCENE_H__ #include "cocos2d.h" #include "Player.h" using namespace cocos2d; //枚举列出移动的方向 typedef enum { MoveDirectionNone = 0, MoveDirectionUpperLeft, MoveDirectionLowerLeft, MoveDirectionUpperRight, MoveDirectionLowerRight, MAX_MoveDirections }EMoveDirection; class HelloWorld : public cocos2d::CCLayer { public: // Method 'init' in cocos2d-x returns bool, instead of 'id' in cocos2d-iphone (an object pointer) virtual bool init(); // there's no 'id' in cpp, so we recommend to return the class instance pointer static cocos2d::CCScene* scene(); CREATE_FUNC(HelloWorld); virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent); //获取屏幕点击的坐标 CCPoint locationFromTouches(CCSet *touches); Player * player; //限定获取区域 CCPoint playableAreaMin,playableAreaMax; //获取瓷砖块的坐标 CCPoint tilePosFromLocation(CCPoint location,CCTMXTiledMap * tilemap); //图层居中 void centerTileMapOnTileCoord(CCPoint tilePos,CCTMXTiledMap *tileMap); //设置不可移动 virtual void ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent); CCPoint screenCenter; //记录下当前的地图 CCTMXTiledMap * tileMap; //屏幕以中点为划分点,将屏幕分成四份 CCRect upperLeft,lowerLeft,upperRight,lowerRight; //移动数组记录5个移动状态 CCPoint moveOffsets[MAX_MoveDirections]; //当前移动的状态 EMoveDirection currentMoveDirection; //不断的更新监听是否移动 void update(float delta); //检测移动的地图是否越界 CCPoint ensureTilePosIsWithinBounds(CCPoint tilePos); //添加碰撞检测 bool isTilePosBlocked(CCPoint tilepos,CCTMXTiledMap * tileMap); }; #endif // __HELLOWORLD_SCENE_H__
HelloWorldScene.cpp
#include "HelloWorldScene.h" #include "SimpleAudioEngine.h" #include "Player.h" using namespace cocos2d; using namespace CocosDenshion; CCScene* HelloWorld::scene() { // 'scene' is an autorelease object CCScene *scene = CCScene::create(); // 'layer' is an autorelease object HelloWorld *layer = HelloWorld::create(); // add layer as a child to scene scene->addChild(layer); // return the scene return scene; } // on "init" you need to initialize your instance bool HelloWorld::init() { // 1. super init first if ( !CCLayer::init() ) { return false; } CCSize size = CCDirector::sharedDirector()->getWinSize(); //添加一个地图 CCTMXTiledMap * tileMap = CCTMXTiledMap::create("huohuo.tmx"); // CCTMXTiledMap * tileMap = CCTMXTiledMap::create("isometric.tmx"); // tileMap->setAnchorPoint(CCPointMake(size.width/2, size.height/2)); // tileMap->setPosition(CCPointMake(size.width/2, size.height/2)); //获取碰撞检测的图层,并设置为不可见 CCTMXLayer * layer = tileMap->layerNamed("Collisions"); layer->setVisible(false); CCSize s = tileMap->getContentSize(); CCLog("width:%f",-s.width/2); tileMap->setPosition(ccp(-s.width/2,0)); this->addChild(tileMap,-1,1); this->setTouchEnabled(true); this->tileMap = tileMap; //添加主角精灵 player = Player::create(); player->setPosition(CCPointMake(size.width / 2, size.height / 2)); player->setAnchorPoint(ccp(0.3f,0.1)); this->addChild(player); /********设置可以活动的区域***********************************************/ //外围不可活动区域的瓷砖块数 const int borderSize = 10; //最小活动区域 playableAreaMin = CCPointMake(borderSize, borderSize); //最大活动区域的瓷砖块数(总块数-不可活动的区域瓷砖块) playableAreaMax = CCPointMake(tileMap->getMapSize().width - 1 - borderSize, tileMap->getMapSize().height - 1 - borderSize); //获取屏幕的中点 screenCenter = CCPointMake(size.width/2, size.height/2); /**********设置鼠标点击屏幕四个方位区域(起始坐标左下角)************************/ upperLeft = CCRectMake(0, screenCenter.y, screenCenter.x, screenCenter.y); lowerLeft = CCRectMake(0, 0, screenCenter.x, screenCenter.y); upperRight = CCRectMake(screenCenter.x, screenCenter.y, screenCenter.x, screenCenter.y); lowerRight = CCRectMake(screenCenter.x, 0, screenCenter.x, screenCenter.y); /**********定义四个方向的坐标点********************************************/ moveOffsets[MoveDirectionNone] = CCPointZero; moveOffsets[MoveDirectionUpperLeft] = CCPointMake(-1, 0); moveOffsets[MoveDirectionLowerLeft] = CCPointMake(0, 1); moveOffsets[MoveDirectionUpperRight] = CCPointMake(0, -1); moveOffsets[MoveDirectionLowerRight] = CCPointMake(1, 0); currentMoveDirection = MoveDirectionNone; //通过预约的更新方法来检查角色的移动 this->scheduleUpdate(); return true; } //不断的检测是否按下鼠标 void HelloWorld::update(float delta) { //如果当前地图没有移动 if (tileMap->numberOfRunningActions() == 0) { //如果有按下鼠标方向 if (currentMoveDirection != MoveDirectionNone) { //获取瓷砖块的坐标 CCPoint tilePos = this->tilePosFromLocation(screenCenter, tileMap); //获取当前要移动一个位置的相对坐标 CCPoint offset = moveOffsets[currentMoveDirection]; //计算获得要移动到那个位置的绝对坐标 tilePos = CCPointMake(tilePos.x + offset.x, tilePos.y + offset.y); //确保主角不会超出屏幕的边界,如果超出则按照边界点来算 tilePos = this->ensureTilePosIsWithinBounds(tilePos); //判断目标位置是否能移动 if (this->isTilePosBlocked(tilePos, tileMap) == false) { //将要移动的那个坐标的瓷砖块移动到当前屏幕的中央 this->centerTileMapOnTileCoord(tilePos, tileMap); } } } //连续不断的修改角色的vertexz的值 CCPoint tilePos = this->tilePosFromLocation(tilePos, tileMap); player->updateVertextZ(tilePos, tileMap); } //添加碰撞检测,是否走到不可碰撞的区域 bool HelloWorld::isTilePosBlocked(cocos2d::CCPoint tilepos, cocos2d::CCTMXTiledMap *tileMap) { CCTMXLayer * layer = tileMap->layerNamed("Collisions"); bool isBokcked = false; unsigned int tileGID = layer->tileGIDAt(tilepos); if (tileGID > 0) { CCDictionary * tileProperties = tileMap->propertiesForGID(tileGID); void * blocks_movement = tileProperties->objectForKey("blocks_movement"); isBokcked = (blocks_movement != NULL); } return isBokcked; } //获取瓷砖块相对地图的坐标 CCPoint HelloWorld::tilePosFromLocation(cocos2d::CCPoint location, cocos2d::CCTMXTiledMap *tilemap) { //减去地图的偏移量 CCPoint pos = ccpSub(location, tilemap->getPosition()); float halfMapWidth = tilemap->getMapSize().width * 0.5f; float mapHeight = tilemap->getMapSize().height; float tileWidth = tilemap->getTileSize().width; float tileHeight = tilemap->getTileSize().height; CCPoint tilePasDiv = ccp(pos.x / tileWidth, pos.y / tileHeight); float inverseTileY = mapHeight - tilePasDiv.y; float posX = (int)(inverseTileY + tilePasDiv.x - halfMapWidth); float posY = (int)(inverseTileY - tilePasDiv.x + halfMapWidth); // posX = MAX(0, posX); // posX = MIN(tilemap->getMapSize().width - 1, posX); // posY = MAX(0, posY); // posY = MIN(tilemap->getMapSize().height - 1, posY); posX = MAX(playableAreaMin.x,posX); posX = MIN(playableAreaMax.x, posX); posY = MAX(playableAreaMin.y, posY); posY = MIN(playableAreaMax.y, posY); pos = CCPointMake(posX, posY); CCLog("X:%f,Y:%f",pos.x,pos.y); return pos; } //将地图居中 void HelloWorld::centerTileMapOnTileCoord(cocos2d::CCPoint tilePos, cocos2d::CCTMXTiledMap *tileMap) { //获取屏幕大小和屏幕中心点 CCSize size = CCDirector::sharedDirector()->getWinSize(); CCPoint screenCenter = CCPointMake(size.width/2, size.height/2); //获取地板层 CCTMXLayer * layer = tileMap->layerNamed("Ground"); //CCTMXLayer * layer = tileMap->layerNamed("GroundLayer1"); //仅仅在内部使用;瓷砖的Y坐标减去1 tilePos.y -=1; //获取瓷砖块坐标 CCPoint scrollPosition = layer->positionAt(tilePos); //考虑到地图移动的情况,我将像素坐标信息乘以-1,从而得到负值 scrollPosition = ccpMult(scrollPosition, -1); //为屏幕中央坐标添加位移值 scrollPosition = ccpAdd(scrollPosition, screenCenter); CCMoveTo * move = CCMoveTo::create(.2f, scrollPosition); tileMap->stopAllActions(); tileMap->runAction(move); } //确保主角不会超出屏幕的边界 CCPoint HelloWorld::ensureTilePosIsWithinBounds(CCPoint tilePos) { tilePos.x = MAX(playableAreaMin.x,tilePos.x); tilePos.x = MIN(playableAreaMax.x, tilePos.x); tilePos.y = MAX(playableAreaMin.y,tilePos.y); tilePos.y = MIN(playableAreaMax.y, tilePos.y); return tilePos; } //返回点击屏幕的坐标点 CCPoint HelloWorld::locationFromTouches(cocos2d::CCSet *touches) { CCTouch *touch = (CCTouch *)touches->anyObject(); return touch->getLocation(); CCLog("点击屏幕的坐标点%f,%f",touch->getLocation().x,touch->getLocation().y); } void HelloWorld::ccTouchesBegan(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent) { // CCNode * node = this->getChildByTag(1); // CCTMXTiledMap *tileMap = (CCTMXTiledMap *)node; // CCPoint touchLocation = this->locationFromTouches(pTouches); // CCPoint tilepos = this->tilePosFromLocation(touchLocation, tileMap); // CCLog("%f,%f",tilepos.x,tilepos.y); // // this->centerTileMapOnTileCoord(tilepos, tileMap); // // player->updateVertextZ(tilepos, tileMap); CCTouch *touch = (CCTouch *)pTouches->anyObject(); CCPoint touchLocation = touch->getLocation(); if (upperLeft.containsPoint(touchLocation)) { currentMoveDirection = MoveDirectionUpperLeft; } else if (lowerLeft.containsPoint(touchLocation)) { currentMoveDirection = MoveDirectionLowerLeft; } else if(upperRight.containsPoint(touchLocation)) { currentMoveDirection = MoveDirectionUpperRight; } else if(lowerRight.containsPoint(touchLocation)) { currentMoveDirection = MoveDirectionLowerRight; } } void HelloWorld::ccTouchesEnded(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent) { currentMoveDirection = MoveDirectionNone; }
实现效果:
源码下载:
==================== 迂者 丁小未 CSDN博客专栏=================
MyBlog:http://blog.csdn.net/dingxiaowei2013 MyQQ:1213250243
Unity QQ群:375151422 cocos2dx QQ群:280818155
====================== 相互学习,共同进步 ===================
转载请注明出处:http://blog.csdn.net/dingxiaowei2013/article/details/11894879