zoukankan      html  css  js  c++  java
  • 【Cocos2dx 3.x Lua】TileMap使用

    1、编辑TileMap地图资源
    2、Cocos2dx 3.x Lua中使用TileMap
     
    local TileMap=class("TileMap",function()
        local tilemap="scene/map/nearbg.tmx"
        return ccexp.TMXTiledMap:create(tilemap)
    end)
    
    TileMap.ctor=function(self)
        self._map={}
        self:init()
        self._rate=1.8 --TileMap在cc.ParallaxNode中的移动速率
    end
    
    TileMap.init=function(self)
        self._mapSize=self:getMapSize()
        local size=self._mapSize
        local obstacleLayer=self:getLayer("obstacle")
        local moveLayer=self:getLayer("move")
        obstacleLayer:setVisible(false)
        moveLayer:setVisible(false)
    
        for i=0,size.width-1 do
            self._map[i]={}
            for j=0,size.height-1 do
                if obstacleLayer:getTileAt(cc.p(i,j))~=nil then
                    self._map[i][j]=0   --障碍物
                elseif moveLayer:getTileAt(cc.p(i,j))~=nil then
                    self._map[i][j]=1   --可移动
                end
            end
        end
    
        self._scale=0.5
        self:setScale(self._scale)
        local s=self:getTileSize()
        self._tileSize=cc.size(s.width,s.height)
    end
    
    TileMap.getTileAtLayer=function(self,pTile)
        local obstacleLayer=self:getLayer("obstacle")
        local moveLayer=self:getLayer("move")
        if self._map[pTile.x][pTile.y]==0 then
            return obstacleLayer
        else
            return moveLayer
        end
    end
    
    --TileMap中添加Sprite
    TileMap.addSprite=function(self,sprite,pTile)
        self:addChild(sprite, table.getn(self:getChildren()))
        sprite:retain()
        sprite:setPosition(self:tileToPixel(pTile))
        sprite:setAnchorPoint(cc.p(0.5,0.5))
    
        if sprite._name~=nil then
            sprite._moveBoard:setTileMap(self)
        end
    end
    
    --TileMap中删除Sprite
    TileMap.removeSprite=function(self,sprite)
        self:removeChild(sprite)
    end
    
    ----------------------------------------------------------------
    --  说明:
    --      由于使用tilemap,所有的sprite都是直接加入到tilemap中
    --      对象使用的坐标系都是基于tilemap的,随着tilemap的移动
    --      对象仍然是在地图上跟随地图移动,因此不需要加入地图相对屏幕
    --      移动的相对坐标,使用sprite:getPosition()得到的坐标也是
    --      基于tilemap的坐标系,例如,tilemap的格点大小为32*32,
    --      sprite在tilemap上的格点为(2,11),同时地图缩放0.5,那么
    --      使用sprite:getPosition得到的坐标为cc.p(2*32,11*32)
    ----------------------------------------------------------------
    --TileMap坐标转换为TileMap格点坐标
    TileMap.pixelToTile=function(self,point)
        --local pointMap=getRolePositionTable(self)
        --point=cc.pSub(point,pointMap)
        point.x =math.ceil(point.x / self._tileSize.width);
        point.y = math.ceil((self._tileSize.height * self._mapSize.height
            - point.y) /self._tileSize.height)
        return point
    end
    
    --TileMap格点坐标转换为屏幕坐标
    TileMap.tileToPixel=function(self,pTile)
        local width = pTile.x * self._tileSize.width
        local height = (self._mapSize.height-pTile.y) * self._tileSize.height
        local point=cc.p(width,height)
        --local pointMap=getRolePositionTable(self)
        --point=cc.pAdd(pointMap,point)
        return point
    end
    
    TileMap.isTileMovable=function(self,pTile)
        if pTile.x >= self._mapSize.width or pTile.y >= self._mapSize.height then
            return false
        elseif self._map[pTile.x][pTile.y]==0 then
            return false
        else
            return true
        end
    end
    
    --在地图上添加Sword特效
    TileMap.addSwordEffect=function(self,role,factor,callback)
        local pTile=self:pixelToTile(getRolePositionTable(role))
        local add=BaseDirection:getInstance():addWithDirection(factor,role._rotation)
        cclog(string.format("addSwordEffect:pTile(%f,%f),add:(%f,%f)",pTile.x,pTile.y,add.x,add.y))
        pTile=cc.pAdd(pTile,add)
        cclog(string.format("after added pTile(%f,%f)",pTile.x,pTile.y))
        if self:isTileMovable(pTile)==false then
            cclog("tilemap obstacle NA SwordEffect")
            if callback then
                callback()
            end
            return  --障碍物格点,不能释放技能
        end
        local sword=EffectManage:getInstance():trickEffectSword(callback)
        self:addSprite(sword,pTile)
        return pTile
    end
    
    TileMap.viewFollowX=function(self,point)
        local screenSize=cc.Director:getInstance():getVisibleSize()
        local mapSize=cc.size(self._mapSize.width*self._tileSize.width,
            self._mapSize.height * self._tileSize.height)
        local scale=self:getScale()
        mapSize=cc.size(mapSize.width*scale,mapSize.height*scale)
        local x=Max(point.x*scale,screenSize.width/2)
        local realPointX=cc.p(x,0)
        local scrollPoint=cc.pSub(cc.p(screenSize.width/2,0),realPointX)
    
        local mapXMin=-mapSize.width+screenSize.width
        if scrollPoint.x > mapXMin then --到达地图右边界,不能继续滑动
            return scrollPoint
        else
            return nil
        end
    end
    
    TileMap.create=function(self)
        return TileMap.new()
    end
    
    return TileMap

    注:
        如上红色部分标出了tilemap使用的一些用法,包括获取tilemap标记的层,在tilemap中动态添加对象,获取指定tile的精灵等
     
    2、TileMap中添加视角跟随
     
    void HelloWorld::setViewPosition(CCPoint pos)  
    {  
        CCSize winSize = CCDirector::sharedDirector()->getWinSize();  
        int x = max(pos.x,winSize.width/2);  
        int y =max(pos.y,winSize.height/2);  
      
    //  x = min(x,(m_tileMap->getMapSize().width*m_tileMap->getTileSize().width-winSize.width/2));  
    //  y = min(y,(m_tileMap->getMapSize().height*m_tileMap->getTileSize().height-winSize.height/2));  
      
        x = min(x,(m_tileMap->getContentSize().width-winSize.width/2));  
        y = min(y,(m_tileMap->getContentSize().height-winSize.height/2));  
        this->setPosition(ccp(winSize.width/2-x,winSize.height/2-y));  
    }  

    参考资料2(http://blog.csdn.net/jukaiblog/article/details/8739021)   

    接下来,我们为游戏加入场景滚动的效果。设想一下,随着人物的移动,原本不在视野内的地图需要逐渐显示出来。为了便于理解,先只讨论y轴上的场景滚动。假设勇士已经移动到Tilemap的(1,4)位置,对应cocos2d-x坐标为(32,224),如何计算出场景应该滚动多少距离?首先,将屏幕高度的1/2作为滚动的临界位置,y值小于1/2高度的不需要滚动,大于1/2的才开始滚动。为什么要把屏幕的1/2作为临界位置呢?因为这样可以保证场景在滚动时,人物始终处于屏幕高度的1/2处,这样的视觉效果最佳。当然也可以使用其他高度。现在计算出了屏幕的一半高度是320/2=160像素,而人物的y值为224,那么场景需要滚动的距离就是224-(320/2)=64像素。此外,还需要注意几点:

    (1)如果地图总宽/高小于屏幕的宽/高,那么直接可以断定不需要滚动。

    (2)场景滚动的最大距离不能超过地图总宽高减去屏幕宽高的1/2,否则在人物走到地图边缘时,场景继续滚动,会造成屏幕周围显示黑边。

    (3)这里使用的“移动”是场景移动,而不是单纯的地图移动。实际上,我们需要连人带地图一起移动!人物相对屏幕的位置没有发生变化,仍然在屏幕1/2处。

     好了,我们已经知道了场景滚动的原理,下面用代码来实现它。我们添加一个方法:setSceneScrollPosition。它有一个参数,是人物当前在cocos2d-x坐标系内的位置。此方法可以将场景移动到相应位置。首先在HelloWorldScene.h里面声明它,即添加“void setSceneScrollPosition(CCPoint position);”,然后在HelloWorldScene.cpp里实现此方法,在最后增加如下代码:

    void HelloWorld::setSceneScrollPosition(CCPoint position)  
    {  
        //获取屏幕尺寸  
        CCSize screenSize=CCDirector::sharedDirector()->getWinSize();  
        //计算Tilemap的宽高,单位是像素  
        CCSize mapSizeInPixel=CCSizeMake(map->getMapSize().width*map->getTileSize().width,  
            map->getMapSize().height*map->getTileSize().height);  
        //取人物当前x坐标和屏幕中点x的最大值,如果人物的x值较大,则会滚动  
        float x=MAX(position.x,screenSize.width/2.0f);  
        float y=MAX(position.y,screenSize.height/2.0f);  
        //地图总宽度大于屏幕宽度的时候才有可能滚动  
        if(mapSizeInPixel.width>screenSize.width)  
        {  
            x=MIN(x,mapSizeInPixel.width-screenSize.width/2.0f);  
        }  
        if(mapSizeInPixel.height>screenSize.height)  
        {  
            y=MIN(y,mapSizeInPixel.height-screenSize.height/2.0f);  
        }  
        //人物的实际位置  
        CCPoint heroPosition=ccp(x,y);  
        //屏幕中点位置  
        CCPoint screenCenter=ccp(screenSize.width/2.0f,screenSize.height/2.0f);  
        //计算人物实际位置和中点位置的距离  
        CCPoint scrollPosition=ccpSub(screenCenter,heroPosition);  
        //将场景移动到相应位置  
        this->setPosition(scrollPosition);  
        CCLog("%f,%f",scrollPosition.x,scrollPosition.y);  
    }  
          那么,什么时候使用setSceneScrollPosition方法呢?我们只能在游戏的每帧里做这件事情。我们新建一个schedule_selector:HelloWorld::update,设置其调用间隔为每帧,在里面实现对场景位置的更新。然后在场景初始化的时候启动定时器,并在析构函数里销毁定时器。

      首先,我们在HelloWorldScene.h文件里声明update方法,添加代码“void update(float dt);”,然后在.cpp文件里实现它,即将下面代码添加到文件的最后。

    void HelloWorld::update(float dt)  
    {  
        //如果勇士不在行走状态,不需要更新场景位置  
        if (isHeroWalking)  
        {  
            setSceneScrollPosition(heroSprite->getPosition());  
        }  
    }  
     


     
  • 相关阅读:
    Mybaits利用插件generator自动生成sql
    idea设置
    centos虚拟机的相关知识
    nginx部署
    apollo配置
    分布式报错解决方案
    搭建springconfigCenter遇到的坑
    idea中git配置
    SpringCloudDay1_概念
    03.2020 MB SD Connect C4 Software “set_SDconnect.bat” File Lost Error Solution
  • 原文地址:https://www.cnblogs.com/luosongchao/p/4337918.html
Copyright © 2011-2022 走看看