接着上一节的代码来,上次遗留下来的BUG我们一个个的来解决。
首先,我们看向上移动,移动到顶部的时候,我们的主角还能往上移动,而地图一直不动。。。
呃,我们正确的移动方式是,当主角还在屏幕下方的时候,主角移动,等主角移动到中间的时候就开始地图移动,
当地图移动到底端的时候,主角在网上移动
有点乱了。。。。。。
先改代码吧!这个的理解了。逻辑好复杂
1.修改地图和主角移动的BUG
void HelloWorld::menuCallback(CCObject* pSender)
{
CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
CCMenuItemImage* item=(CCMenuItemImage*)pSender;
switch (item->getTag())
{
case TOPMENUITEM:
//地图的高度+地图的Y位置(Y是负数,所以用加而不是减)+一个格子的高度>屏幕的高度
//这里表示地图还没有移动到最顶部
if(m_testmap->getContentSize().height+m_testmap->getPositionY()-TMXBLOCKSIZE>visibleSize.height)
{
//屏幕高度的一半-地图的Y位置(Y是负数,所以用减)<主角的Y位置
//如果主角的位置超过了屏幕的中心位置才移动地图
if(visibleSize.height/2-m_testmap->getPositionY()<m_player->getPositionY())
{
m_testmap->setPosition(ccp(m_testmap->getPositionX(),m_testmap->getPositionY()-TMXBLOCKSIZE));
}
m_player->setPosition(ccp(m_player->getPositionX(),m_player->getPositionY()+TMXBLOCKSIZE));
}
//主角的Y位置<地图的高度-2个格子的高度
//因为地图移动到顶部了,所以只能移动主角,这里是判断主角是不是到地图的顶部了
else if(m_player->getPositionY()<m_testmap->getContentSize().height-2*TMXBLOCKSIZE)
{
m_player->setPosition(ccp(m_player->getPositionX(),m_player->getPositionY()+TMXBLOCKSIZE));
}
break;
case BUTTOMMENUITEM:
if(m_testmap->getPositionY()<0)
{
if(visibleSize.height/2-m_testmap->getPositionY()>m_player->getPositionY())
{
m_testmap->setPosition(ccp(m_testmap->getPositionX(),m_testmap->getPositionY()+TMXBLOCKSIZE));
}
m_player->setPosition(ccp(m_player->getPositionX(),m_player->getPositionY()-TMXBLOCKSIZE));
}
else if(m_player->getPositionY()>TMXBLOCKSIZE)
{
m_player->setPosition(ccp(m_player->getPositionX(),m_player->getPositionY()-TMXBLOCKSIZE));
}
break;
case LEFTMENUITEM:
if(m_testmap->getPositionX()<0)
{
if(visibleSize.width/2-m_testmap->getPositionX()>m_player->getPositionX())
{
m_testmap->setPosition(ccp(m_testmap->getPositionX()+TMXBLOCKSIZE,m_testmap->getPositionY()));
}
m_player->setPosition(ccp(m_player->getPositionX()-TMXBLOCKSIZE,m_player->getPositionY()));
}
else if(m_player->getPositionX()>TMXBLOCKSIZE)
{
m_player->setPosition(ccp(m_player->getPositionX()-TMXBLOCKSIZE,m_player->getPositionY()));
}
break;
case RIGHTMENUITEM:
if(m_testmap->getContentSize().width+m_testmap->getPositionX()-TMXBLOCKSIZE>visibleSize.width)
{
if(visibleSize.width/2-m_testmap->getPositionX()<m_player->getPositionX())
{
m_testmap->setPosition(ccp(m_testmap->getPositionX()-TMXBLOCKSIZE,m_testmap->getPositionY()));
}
m_player->setPosition(ccp(m_player->getPositionX()+TMXBLOCKSIZE,m_player->getPositionY()));
}
else if(m_player->getPositionX()<m_testmap->getContentSize().width-2*TMXBLOCKSIZE)
{
m_player->setPosition(ccp(m_player->getPositionX()+TMXBLOCKSIZE,m_player->getPositionY()));
}
break;
default:
break;
}
}
这里的逻辑很复杂,得自己编理解编写。。理解的方式不一样,写发也就不一样
接下来我们需要解决的是碰撞检测,
当主角遇到障碍物的时候,我们是走不动的,而刚刚看到的是居然可以穿越过去,这个不可以有
2.TMX不同图层进行碰撞检测
OK,我们的NPC最开始是在最坐下角的位置,我们可以按两下向上的按钮,给它向上移动两个格子,到我们标记为红色的位置。。
这时候我们输出的是,
X在第0个格子,Y在第二的格子
我们Cocos2dX用的是OpenGL坐标系统
以左下角为原点的
而Tiled是以左上角为原点的, 此时输出的应该是X:0 Y:17 是从零开始的,所以是17不是18
void HelloWorld::menuCallback(CCObject* pSender)
{
CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
CCMenuItemImage* item=(CCMenuItemImage*)pSender;
/**
获得NPC在MAP中的第几个格子
X:这个不用多说了
Y:因为坐标系统不一样,默认是OpenGL,而TiledMap是屏幕坐标系统,所以应当用地图大小的高度-1-Y
地图是20X20的格子,m_testmap->getMapSize().height其实就是20
**/
CCPoint playerCur=ccp((int)m_player->getPositionX()/TMXBLOCKSIZE,m_testmap->getMapSize().height-1-(int)(m_player->getPositionY()/TMXBLOCKSIZE));
//CCLOG("X:%f,Y:%f",playerCur.x,playerCur.y);
//下一个格子
CCPoint playerNext=playerCur;
//获得障碍物层
CCTMXLayer* Obstacles= m_testmap->layerNamed("Obstacles");
unsigned int GID=0;
/**
为了方便大家看的思路清楚,这里分为两个switch写了
等理解了之后其实搅在一个switch中就可以了的,这个没那么复杂
复杂的再于判断到底是NPC移动还是地图移动,是否移动到边缘
**/
#pragma region NPC的碰撞检测
switch (item->getTag())
{
case TOPMENUITEM:
playerNext.y-=1;
if (playerNext.y<0)return;
/**
用障碍物层中的tileGIDAt方法来获得其ID
如果当前层中相应的格子中没东西则返回0
否则返回ID,至于ID是多少,这个不清楚
**/
GID=Obstacles->tileGIDAt(playerNext);
if (GID)return;
break;
case BUTTOMMENUITEM:
playerNext.y+=1;
if (playerNext.y>m_testmap->getMapSize().height-1)return;
GID=Obstacles->tileGIDAt(playerNext);
if (GID)return;
break;
case LEFTMENUITEM:
playerNext.x-=1;
if (playerNext.x<0)return;
GID=Obstacles->tileGIDAt(playerNext);
if (GID)return;
break;
case RIGHTMENUITEM:
playerNext.x+=1;
if (playerNext.x>m_testmap->getMapSize().width-1)return;
GID=Obstacles->tileGIDAt(playerNext);
if (GID)return;
break;
default:
break;
}
#pragma endregion
#pragma region 这里的逻辑是NPC或地图的移动判断
switch (item->getTag())
{
case TOPMENUITEM:
//地图的高度+地图的Y位置(Y是负数,所以用加而不是减)+一个格子的高度>屏幕的高度
//这里表示地图还没有移动到最顶部
if(m_testmap->getContentSize().height+m_testmap->getPositionY()-TMXBLOCKSIZE>visibleSize.height)
{
//屏幕高度的一半-地图的Y位置(Y是负数,所以用减)<主角的Y位置
//如果主角的位置超过了屏幕的中心位置才移动地图
if(visibleSize.height/2-m_testmap->getPositionY()<m_player->getPositionY())
{
m_testmap->setPosition(ccp(m_testmap->getPositionX(),m_testmap->getPositionY()-TMXBLOCKSIZE));
}
m_player->setPosition(ccp(m_player->getPositionX(),m_player->getPositionY()+TMXBLOCKSIZE));
}
//主角的Y位置<地图的高度-2个格子的高度
//因为地图移动到顶部了,所以只能移动主角,这里是判断主角是不是到地图的顶部了
else if(m_player->getPositionY()<m_testmap->getContentSize().height-2*TMXBLOCKSIZE)
{
m_player->setPosition(ccp(m_player->getPositionX(),m_player->getPositionY()+TMXBLOCKSIZE));
}
break;
case BUTTOMMENUITEM:
if(m_testmap->getPositionY()<0)
{
if(visibleSize.height/2-m_testmap->getPositionY()>m_player->getPositionY())
{
m_testmap->setPosition(ccp(m_testmap->getPositionX(),m_testmap->getPositionY()+TMXBLOCKSIZE));
}
m_player->setPosition(ccp(m_player->getPositionX(),m_player->getPositionY()-TMXBLOCKSIZE));
}
else if(m_player->getPositionY()>TMXBLOCKSIZE)
{
m_player->setPosition(ccp(m_player->getPositionX(),m_player->getPositionY()-TMXBLOCKSIZE));
}
break;
case LEFTMENUITEM:
if(m_testmap->getPositionX()<0)
{
if(visibleSize.width/2-m_testmap->getPositionX()>m_player->getPositionX())
{
m_testmap->setPosition(ccp(m_testmap->getPositionX()+TMXBLOCKSIZE,m_testmap->getPositionY()));
}
m_player->setPosition(ccp(m_player->getPositionX()-TMXBLOCKSIZE,m_player->getPositionY()));
}
else if(m_player->getPositionX()>TMXBLOCKSIZE)
{
m_player->setPosition(ccp(m_player->getPositionX()-TMXBLOCKSIZE,m_player->getPositionY()));
}
break;
case RIGHTMENUITEM:
if(m_testmap->getContentSize().width+m_testmap->getPositionX()-TMXBLOCKSIZE>visibleSize.width)
{
if(visibleSize.width/2-m_testmap->getPositionX()<m_player->getPositionX())
{
m_testmap->setPosition(ccp(m_testmap->getPositionX()-TMXBLOCKSIZE,m_testmap->getPositionY()));
}
m_player->setPosition(ccp(m_player->getPositionX()+TMXBLOCKSIZE,m_player->getPositionY()));
}
else if(m_player->getPositionX()<m_testmap->getContentSize().width-2*TMXBLOCKSIZE)
{
m_player->setPosition(ccp(m_player->getPositionX()+TMXBLOCKSIZE,m_player->getPositionY()));
}
break;
default:
break;
}
#pragma endregion
}
完整的代码如上,看起来有点凌乱。。。可以收缩起来看,比较清楚
这里差不多就完了,在介绍一个,动态更新地图
3.动态更新地图
Obstacles->setTileGID(46,playerCur);
这里46是什么意思呢??
还记得碰撞检测是获得的GID吗??
一行8个,刚好在第46个。。。
OK,最后附上效果图和源代码