Unresolved problem
I could not get this code to run if setContentScaleFactor is used.
Why this example
The current examples are most interesting but every items are independent.
What this code does
- Note a different size map would work the code does not use arbitrary constants.
- vRect illustrate how to support visible rect supporting
setDesignResolutionSize
it is disable in this example. - Adding decorators for a sprite and on a layer DrawAnchorPoint DrawCenterPoints DrawBoundingBox
- DisplayOnSceen keep a layer within the visible screen
- mapToIndex translate a location on a TMXTiledMap layer to a tile index
- indexToMap index to map location (if the index is an integer will give you the position of the anchor point)
- onTouches… supports dragging, panning, zooming using pinch , and inserting new sprites on the tiled map.
- zOrder is supported without using arbitrary constant but interrogating the map parameters.
- Illustrate how to center a sprite on a tile.
m_tamara[i]:setAnchorPoint((m_tamara[i]:getContentSize().width - rectForTile_1_inTileSet.width)/(2*m_tamara[i]:getContentSize().width), 0)
How to use this code
-
Change
controller.lua
add
line
screenSize = designSize
after line
local designSize = {width = 480, height = 320} -
change to file
TileMapTest.lua
after the end of functionTMXBug787()
replace all the code by the following code
local function TMXAA()
local vRect = {} function vRect:setDesignResolutionSize (scale) scale = scale or 1 --~ cc.Director:getInstance():getOpenGLView():setDesignResolutionSize(480 * scale, 320 * scale, cc.ResolutionPolicy.NO_BORDER); self.visibleOrigin = cc.Director:getInstance():getVisibleOrigin() self.size = cc.Director:getInstance():getVisibleSize() self.x, self.y = 0, 0 -- always at 0, 0 self.width = self.size.width self.height = self.size.height self.left = cc.p(0, self.height/2) self.right = cc.p(self.width, self.height/2) self.top = cc.p(self.width/2, self.height) self.bottom = cc.p(self.width/2, 0) self.center = cc.p(self.width/2, self.height/2) self.topLeft = cc.p(0, self.height) self.topRight = cc.p(self.width, self.height) self.bottomLeft = cc.p(0,0) self.bottomRight = cc.p(self.width, 0) return self end
vRect:setDesignResolutionSize()
local function CreateAPoint(p, size) local point = cc.DrawNode:create() point:drawDot(p, size or 10, cc.c4f(1.0, 0.0, 1.0, 1.0)) return point end
local function DrawAnchorPoint(sprite, size) sprite:addChild(CreateAPoint(cc.p(sprite:getContentSize().width * sprite:getAnchorPoint().x, sprite:getContentSize().height * sprite:getAnchorPoint().y), size)); end
local function DrawCenterPoints(sprite, size) local bb = sprite:getBoundingBox() sprite:addChild(CreateAPoint(cc.p(bb.width/2, 0), size)) sprite:addChild(CreateAPoint(cc.p(0, bb.height / 2), size)) sprite:addChild(CreateAPoint(cc.p( bb.width / 2, bb.height), size)) sprite:addChild(CreateAPoint(cc.p(bb.width, bb.height / 2), size)) end
local function DrawBoundingBox(sprite) local rect = cc.DrawNode:create() local bb = sprite:getBoundingBox() rect:drawRect(cc.p(0, 0), cc.p(bb.width, bb.height), cc.c4f(1.0, 0.0, 1.0, 1.0)) sprite:addChild(rect) end
local ret = createTileDemoLayer("Touch-Multitouch-Pan-Zoom-Drag", "Touch tile to add image, touch image to delete [TMXAA]") ret:getEventDispatcher():removeEventListenersForTarget(ret)
local MOVE_VS_TOUCH = 3 -- Arbitrary value local kTagTileMap = 1 local s_pPathSister1 = "Images/grossinis_sister1.png" local m_tamara = {} local insertAtPosition local hidden = cc.LayerGradient:create(); hidden:setPosition(vRect.visibleOrigin) local baseLayer = cc.LayerGradient:create(cc.c4b(100,255,100,255), cc.c4b(255,0,0,255), cc.p(100, 100)) local map = cc.TMXTiledMap:create("TileMaps/iso-test-zorder.tmx") local bottomLayer = map:getChildByTag(0) local MapTileSize = bottomLayer:getMapTileSize() local MapSize = map:getMapSize() local MapFullSize = cc.size(MapTileSize.width * MapSize.width, MapTileSize.height * MapSize.height ) local halfTileSize = cc.size(MapTileSize.width/2, MapTileSize.height/2) local tileSetInfo = bottomLayer:getTileSet() local rectForTile_1_inTileSet = tileSetInfo:getRectForGID(1)
local function DisplayOnSceen() local boundingBox = baseLayer:getBoundingBox() local x, y = baseLayer:getPosition() if boundingBox.x > 0 then baseLayer:setPositionX(x - boundingBox.x) end if boundingBox.y > 0 then baseLayer:setPositionY(y - boundingBox.y) end if cc.rectGetMaxX(boundingBox) < vRect.width then baseLayer:setPositionX(x + (vRect.width - cc.rectGetMaxX(boundingBox))) end if cc.rectGetMaxY(boundingBox) < vRect.height then baseLayer:setPositionY(y + (vRect.height - cc.rectGetMaxY(boundingBox))) end end
local function mapToIndex(where) local x = math.floor(MapFullSize.height/MapTileSize.height - MapFullSize.width / (2 * MapTileSize.width) - 1/2 - where.y/MapTileSize.height + where.x/MapTileSize.width + 0.5) local y = math.floor(MapFullSize.height/MapTileSize.height + MapFullSize.width / (2 * MapTileSize.width) - 3/2 - where.y/MapTileSize.height - where.x/MapTileSize.width + 0.5) if x == -1 then x = 0 elseif x == MapSize.width then x = x - 1 end if y == -1 then y = 0 elseif y == MapSize.height then y = y -1 end return x>=0 and x<MapSize.width and y>=0 and y<MapSize.height and cc.p(x,y) end
local function indexToMap(pt) return cc.p(halfTileSize.width * (pt.x - pt.y) + MapFullSize.width / 2 - halfTileSize.width, MapFullSize.height - halfTileSize.height * (pt.x + pt.y + 2)) end
local function onTouchesBegan(touches, event ) local where = cc.pSub(map:convertTouchToNodeSpace(touches[1]), cc.p(halfTileSize.width, halfTileSize.height)) insertAtPosition = mapToIndex(where) end
local function onTouchesEnded(touches, event ) for i,v in ipairs(touches) do local where = map:convertTouchToNodeSpace(v) for i,v in ipairs(m_tamara) do if v and cc.rectContainsPoint(v:getBoundingBox(), where) then v:stopAllActions() v:release() map:removeChild(v) table.remove(m_tamara, i) insertAtPosition = nil break end end end
if #touches == 1 and cc.pDistanceSQ(touches[1]:getStartLocation(), touches[1]:getLocation()) > MOVE_VS_TOUCH then insertAtPosition = nil end if insertAtPosition then local i = #m_tamara + 1 m_tamara[i] = cc.Sprite:create(s_pPathSister1) m_tamara[i]:setAnchorPoint((m_tamara[i]:getContentSize().width - rectForTile_1_inTileSet.width)/(2*m_tamara[i]:getContentSize().width), 0) -- center sprite on tile DrawAnchorPoint(m_tamara[i], 5) DrawCenterPoints(m_tamara[i], 3) DrawBoundingBox(m_tamara[i], 1) map:addChild(m_tamara[i], i) m_tamara[i]:retain() local fromTilePos = bottomLayer:getPositionAt(cc.p(MapSize.width-1, MapSize.height-1)) m_tamara[i]:setPosition(fromTilePos) local toTilePos = bottomLayer:getPositionAt(insertAtPosition) local move = cc.MoveBy:create(math.random(3, 10), cc.pSub(toTilePos, fromTilePos)) local back = move:reverse() local seq = cc.Sequence:create(move, back) m_tamara[i]:runAction( cc.RepeatForever:create(seq) ) end end
local function onTouchesMoved(touches, event ) if #touches == 1 then local touch = touches[1] local scale = baseLayer:getScale() local newPosition = cc.pAdd(cc.p(baseLayer:getPosition()), cc.p(touch:getDelta().x/scale,touch:getDelta().y/scale)) baseLayer:setPosition(newPosition) DisplayOnSceen() elseif #touches == 2 then local director = cc.Director:getInstance() local curPostouches, prevPostouches = {}, {} curPostouches[1] = director:convertToGL(touches[1]:getLocationInView()); curPostouches[2] = director:convertToGL(touches[2]:getLocationInView()); prevPostouches[1] = director:convertToGL(touches[1]:getPreviousLocationInView()); prevPostouches[2] = director:convertToGL(touches[2]:getPreviousLocationInView()); local curPosLayer = cc.pMidpoint(curPostouches[1], curPostouches[2]); local prevPosLayer = cc.pMidpoint(prevPostouches[1], prevPostouches[2]); local prevScale = baseLayer:getScale() local curScale = baseLayer:getScale() * cc.pGetDistance(curPostouches[1], curPostouches[2]) / cc.pGetDistance(prevPostouches[1], prevPostouches[2]) curScale = math.min(math.max(1, curScale), 4) if curScale ~= prevScale then baseLayer:setScale(curScale) local realCurPosLayer = baseLayer:convertToNodeSpaceAR(curPosLayer); local delta = cc.pMul(realCurPosLayer, (curScale - prevScale)) baseLayer:setPosition(cc.pSub(cc.p(baseLayer:getPosition()), delta)) end insertAtPosition = nil DisplayOnSceen() end end
local function onTouchesCancel(touches, event ) insertAtPosition = nil end local listener = cc.EventListenerTouchAllAtOnce:create() listener:registerScriptHandler(onTouchesBegan,cc.Handler.EVENT_TOUCHES_BEGAN ) listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED ) listener:registerScriptHandler(onTouchesEnded,cc.Handler.EVENT_TOUCHES_ENDED ) listener:registerScriptHandler(onTouchesCancel,cc.Handler.EVENT_TOUCH_CANCELLED ) local eventDispatcher = baseLayer:getEventDispatcher() eventDispatcher:addEventListenerWithSceneGraphPriority(listener, baseLayer)
local function TMXIsoZorder() local scheduler = cc.Director:getInstance():getScheduler() --~ sceneGame = cc.Scene:create() ret:addChild(hidden) hidden:addChild(baseLayer) local contentSize = map:getContentSize() baseLayer:addChild(map, 0, kTagTileMap) map:setScale(math.min(vRect.width/contentSize.width, vRect.height/contentSize.height)) map:setPositionY(cc.rectGetMidY(baseLayer:getBoundingBox()) -cc.rectGetMidY(map:getBoundingBox())) map:setPositionX(cc.rectGetMidX(baseLayer:getBoundingBox()) -cc.rectGetMidX(map:getBoundingBox())) local function repositionSprite(dt) local nLayer = 1 while map:getChildByTag(nLayer - 1) do nLayer = nLayer + 1 end for i= 1, #m_tamara do map:reorderChild(m_tamara[i], math.floor(math.max(nLayer - (cc.p(m_tamara[i]:getPosition()).y / (halfTileSize.height * 3)), 0))) end end
local schedulerEntry local function onNodeEvent(event) if event == "enter" then schedulerEntry = scheduler:scheduleScriptFunc(repositionSprite, 0, false) elseif event == "exit" then for k,v in pairs(m_tamara) do v:release() end scheduler:unscheduleScriptEntry(schedulerEntry) end end baseLayer:registerScriptHandler(onNodeEvent) return baseLayer end
TMXIsoZorder() baseLayer:setScale(2)
local tile = bottomLayer:getTileAt(cc.p(MapSize.width-1, MapSize.height-1)) local bb = tile:getBoundingBox() local pt = CreateAPoint(cc.p(cc.rectGetMidX(bb), bb.y), 2) map:addChild(pt) local rect = cc.DrawNode:create() rect:drawRect(cc.p(bb.x, bb.y), cc.p(bb.x+ bb.width, bb.y+bb.height), cc.c4f(1.0, 0.0, 1.0, 1.0)) map:addChild(rect) return ret end
function TileMapTestMain() cclog("TileMapTestMain") Helper.index = 1 cc.Director:getInstance():setDepthTest(true) local scene = cc.Scene:create()
Helper.createFunctionTable = { TMXAA, TileMapTest, TileMapEditTest, TMXOrthoTest, TMXOrthoTest2, TMXOrthoTest3, TMXOrthoTest4, TMXReadWriteTest, TMXHexTest, TMXIsoTest, TMXIsoTest1, TMXIsoTest2, TMXUncompressedTest, TMXTilesetTest, TMXOrthoObjectsTest, TMXIsoObjectsTest, TMXResizeTest, TMXIsoZorder, TMXOrthoZorder, TMXIsoVertexZ, TMXOrthoVertexZ, TMXIsoMoveLayer, TMXOrthoMoveLayer, TMXTilePropertyTest, TMXOrthoFlipTest, TMXOrthoFlipRunTimeTest, TMXOrthoFromXMLTest, TMXBug987, TMXBug787 } scene:addChild(TMXAA()) scene:addChild(CreateBackMenuItem()) return scene end
I hope this help
Andre