Just can't seem to get smooth performance...?

So…

  1. I’ve built my own tile engine.
  2. It reads from a 64x64 map of data (4096 tiles)
  3. It renders only a 16x12x2 chunk of that, adding/removing tiles as you move. (384 tiles)
  4. Each row of tiles is in an imageGroup. The imageGroups are in a displayGroup.

The problem : I’m getting noticeable “chop” (OSX Sim and iPhone4) whenever I move (thus adding rows). What am I doing to cause such a huge performance hit?

The details :

  • The tiles are the only element of this app at the moment. No other sprites, audio, etc.
  • I use an enterFrame listener; whenever the map has travelled > x pixels in a given direction, it calls either for a new row or a new column. (So it’s not trying to create a new row every frame)
  • Profiler lists the enterFrame function in red (1084ms) during a 10 second check.

**Sample Code
The enterFrame listener

local function mover(event) if pause == false and direction ~= false then engine.move(map, moveTable[direction][1], moveTable[direction][2]) end end

Finding the direction is called every frame during a touch-move if…

if direction == false or ( math.abs(event.x-last.x) \> tileSize ) or ( math.abs(event.y-last.y) \> tileSize ) then

(Basically, if the difference between your last touch and this touch is great enough, check.)

The newRow function

[code]-- FUNCTION: Creates a new row of tiles based on map core data. -----------------------------------
function newRow(map, angle)

local oldRow, xPos, yPos, newY, newX

if angle == “up” then

oldRow = 1 – the local row anchor
newY = map.vis.btm[1][1].yTile-1 – the array where tile data is stored
newX = map.vis.btm[1][1].xTile
xPos = map.vis.btm[1][1].x
yPos = map.vis.btm[1][1].y - tileSize

elseif angle == “down” then

oldRow = map.vis.btm.numChildren
newY = map.vis.btm[map.vis.btm.numChildren][1].yTile+1
newX = map.vis.btm[map.vis.btm.numChildren][1].xTile
xPos = map.vis.btm[map.vis.btm.numChildren][1].x
yPos = map.vis.btm[map.vis.btm.numChildren][1].y + tileSize

end

– Create the new row group
local btm_newRow = display.newImageGroup(map.tileset.sheet) – bottom tile layer
local top_newRow = display.newImageGroup(map.tileset.sheet) – top tile layer

– Iterate to create the tiles
for i = 1, map.vis.btm[1].numChildren do

– Create the tile
local btm_tile = newTile(map, newX, newY, “btm”)
local top_tile = newTile(map, newX, newY, “top”)

– Position the tile
btm_tile:setReferencePoint(display.TopLeftReferencePoint)
btm_tile.x = xPos; btm_tile.y = yPos

top_tile:setReferencePoint(display.TopLeftReferencePoint)
top_tile.x = xPos; top_tile.y = yPos

– Increment the X tile
newX = newX + 1

– Increment the xPos
xPos = xPos + tileSize

– Insert into the imageGroup
btm_newRow:insert(btm_tile)
top_newRow:insert(top_tile)

end

– Insert the row group
if angle == “up” then
map.vis.btm:insert(1, btm_newRow)
map.vis.top:insert(1, top_newRow)
elseif angle == “down” then
map.vis.btm:insert(btm_newRow)
map.vis.top:insert(top_newRow)
end

– Clean up
oldRow, xPos, yPos, newY, newX = nil, nil, nil, nil, nil

end --/newRow() -----------------------------------------------------------------------------------[/code]

I can understand if my code could be optimized further, but I guess I’m just not seeing how it’s causing such a noticeable slowdown given how little is actually being done.

Any ideas would be appreciated! :slight_smile: [import]uid: 41884 topic_id: 30486 reply_id: 330486[/import]**

The enterFrame listener

local function mover(event) if pause == false and direction ~= false then engine.move(map, moveTable[direction][1], moveTable[direction][2]) end end

Finding the direction is called every frame during a touch-move if…

if direction == false or ( math.abs(event.x-last.x) \> tileSize ) or ( math.abs(event.y-last.y) \> tileSize ) then

(Basically, if the difference between your last touch and this touch is great enough, check.)

The newRow function

[code]-- FUNCTION: Creates a new row of tiles based on map core data. -----------------------------------
function newRow(map, angle)

local oldRow, xPos, yPos, newY, newX

if angle == “up” then

oldRow = 1 – the local row anchor
newY = map.vis.btm[1][1].yTile-1 – the array where tile data is stored
newX = map.vis.btm[1][1].xTile
xPos = map.vis.btm[1][1].x
yPos = map.vis.btm[1][1].y - tileSize

elseif angle == “down” then

oldRow = map.vis.btm.numChildren
newY = map.vis.btm[map.vis.btm.numChildren][1].yTile+1
newX = map.vis.btm[map.vis.btm.numChildren][1].xTile
xPos = map.vis.btm[map.vis.btm.numChildren][1].x
yPos = map.vis.btm[map.vis.btm.numChildren][1].y + tileSize

end

– Create the new row group
local btm_newRow = display.newImageGroup(map.tileset.sheet) – bottom tile layer
local top_newRow = display.newImageGroup(map.tileset.sheet) – top tile layer

– Iterate to create the tiles
for i = 1, map.vis.btm[1].numChildren do

– Create the tile
local btm_tile = newTile(map, newX, newY, “btm”)
local top_tile = newTile(map, newX, newY, “top”)

– Position the tile
btm_tile:setReferencePoint(display.TopLeftReferencePoint)
btm_tile.x = xPos; btm_tile.y = yPos

top_tile:setReferencePoint(display.TopLeftReferencePoint)
top_tile.x = xPos; top_tile.y = yPos

– Increment the X tile
newX = newX + 1

– Increment the xPos
xPos = xPos + tileSize

– Insert into the imageGroup
btm_newRow:insert(btm_tile)
top_newRow:insert(top_tile)

end

– Insert the row group
if angle == “up” then
map.vis.btm:insert(1, btm_newRow)
map.vis.top:insert(1, top_newRow)
elseif angle == “down” then
map.vis.btm:insert(btm_newRow)
map.vis.top:insert(top_newRow)
end

– Clean up
oldRow, xPos, yPos, newY, newX = nil, nil, nil, nil, nil

end --/newRow() -----------------------------------------------------------------------------------[/code]

I can understand if my code could be optimized further, but I guess I’m just not seeing how it’s causing such a noticeable slowdown given how little is actually being done.

Any ideas would be appreciated! :slight_smile: [import]uid: 41884 topic_id: 30486 reply_id: 122156[/import]

Having cleaned up my movement code some, it definitely seems to be the tile stuff slowing things down. I really don’t understand how adding 24 tiles (24 newSprites() attached to 1 of 2 imageGroups) can visibly hit the framerate this much, but maybe there is a way to reduce the number of tiles added per frame? [import]uid: 41884 topic_id: 30486 reply_id: 122171[/import]

Removed the top layer, cutting the number of tiles created in half. Still a noticeable stutter on every frame where tiles are created; virtually no improvement. Totally lost now. [import]uid: 41884 topic_id: 30486 reply_id: 122176[/import]

I doubt it will help significantly, but you can try to put your math.abs into a variable, so its function is stored in the memory (or something like this)

local mathabs = math.abs
print(mathabs(-12.2222))

Also, isn’t the “culling” feature of imagesheet/sprites/Imagegroup already taking care of the adding/removing tiles outside viewarea?!

http://www.coronalabs.com/blog/2012/03/06/image-sheets-image-groups-and-sprites/
“One of the major contributors to performance increases is the addition of “off-screen culling”, which basically means that objects that are not on-screen will not be rendered (resulting in increased performance). The good news is, you don’t have to do anything to take advantage of this improvement—you simply download the latest build to take advantage of it!” [import]uid: 162464 topic_id: 30486 reply_id: 122177[/import]

Are your tiles images or sprites?

If they are sprites, it may be a good idea not to delete old/create new tiles, but reuse the old (moved off screen) tiles by :prepare-ing them with the new tiles and moving them to the right position.

Also - and this may not be a big performance booster, but on general principle - any time you are using the same upvalue in multiple lines of code, it is a good idea to localize it:

 if angle == "up" then  
   
 oldRow = 1 -- the local row anchor  
 local mapbtm=map.vis.btm[1][1]  
 newY = mapbtm.yTile-1 -- the array where tile data is stored  
 newX = mapbtm.xTile  
 xPos = mapbtm.x  
 yPos = mapbtm.y - tileSize  
 elseif angle == "down" then  
 local mapbtm=map.vis.btm[map.vis.btm.numChildren][1]  
 oldRow = map.vis.btm.numChildren  
 newY = mapbtm.yTile+1  
 newX = mapbtm.xTile  
 xPos = mapbtm.x  
 yPos = mapbtm.y + tileSize  
 end  

You can also post the “newtile” code so we could look if there are inefficiencies there. [import]uid: 160496 topic_id: 30486 reply_id: 122180[/import]

Seems to me like you would be better off trying to create as little new objects as you can in enterFrame.
Try splitting the visual representation of the map from the actual data map.

Regarding the visual part, I would have one ImageGroup for the map, in this map I would have a grid of sprites (each located in a different “virtual” tile).
This map should contain the visible tiles plus 1 column/row in each direction, up, down, left and right so you can scroll the map.
Now you need to do 2 things in enterFrame

  1. Use setFrame to change what each visual tile is showing.
  2. Scroll the map; this is the harder part. You need to allow the users to scroll the tiles, once a row/column is completely out of screen you move it to the opposite side of the map ensuring you always have a border of offscreen tiles around the map. (do that with translate and not changing the x, y properties directly)

This way you have a constant window into your world map, you can change what it is showing and you never need to create any new objects at runtime.

I think if all you change in enterFrame is the frameIndex of your sprites it should run smoothly.

Hope I was clear enough without any code example :slight_smile:
[import]uid: 80469 topic_id: 30486 reply_id: 122181[/import]

mike470/gtt:“Move the tiles” is one of the bigger “duh” moments in my life. Can’t believe I didn’t think of that one first. Beats the hell out of sprite creation (70ms!) (FWIW, display.newSprite and :setSequence are roughly 70% of the CPU workload of my newTile() function)

Now, gtt, you suggest using translate here, but is it really faster if you have to do the math first to figure out where to translate to? ie: which one of these is faster?

[code]-- 1. Calculate and translate
local distance = map.vis.btm[map.vis.btm.numChildren][32].y - currentRow.y
currentRow:translate(0, distance)
distance = nil

– 2. Set x/y
currentRow.y = map.vis.btm[map.vis.btm.numChildren][32].y[/code]

Each tile is a newSprite(), specifically because I need to be able to animate them. Likewise, it means I use setSequence instead of setFrame. And as luck would have it I’m already using 2 tiles of overdraw on each side so that I can scroll without tiles disappearing on-screen. (Likewise, :prepare is deprecated so wouldn’t use that.)

Results : Well…

  • Performance on Simulator (2011 Air OSX) is even worse visually; tons of hiccups. At a glance I’d say the framerate has dropped at least 25% below my previous solution.
  • Performance on Device (iPhone4) is clearly better than before. Instead of constant hiccups there is now just a big 300ms hiccup when you change directions but even that seems to go away after awhile.
  • In the profiler, the move function has dropped about 15% in performance use (from 1080ms to 890ms)

I’d say there is still something significantly wrong here, but I’ll attach some code and take some suggestions. :wink:

Zwonkie : imageGroup culling has a performance benefit but it does not actually cull the tiles per se. I imagine it’s just using some clever memory sharing. (I’m sure Corona Labs has a better explanation.)

32x32 tile grid (1024 tiles, average Dragon Quest town size): Smooth framerate
64x64 tile grid (4096 tiles, large dungeon): Serious performance issues
256x256 tile grid (65k tiles, world map): Crash device

The key takeaway here is that it does *not* let you skip culling in your code solution. You simply cannot hold so many tiles in memory, let alone translate the entire thing. It’s for this reason that I can recommend Lime for, say, average sidescroller levels but cannot recommend it for an RPG.

[import]uid: 41884 topic_id: 30486 reply_id: 122223[/import]

Sample Code: (as promised…)

EDIT: This version seems 3x faster than the old version. newRow() and newColumn() now take the majority of the hit.

[code]local function checkMapPosition(map)
– How many tiles worth of movement before redraw == true?
local pixels_over = 96 --local pixels_over = (map.overdraw - 1 or 2) * tileSize

– Localize the map data
local vis = map.vis

if vis.originX - vis.offsetX >= pixels_over and vis.btm[1][1].xTile > 1 then

return true, “left”

elseif vis.offsetX - vis.originX >= pixels_over and vis.btm[1][vis.btm[1].numChildren].xTile < map.width then

return true, “right”

elseif vis.originY - vis.offsetY >= pixels_over and vis.btm[1][1].yTile > 1 then

return true, “up”

elseif vis.offsetY - vis.originY >= pixels_over and vis.btm[vis.btm.numChildren][1].yTile < map.height then
return true, “down”
end
end --/checkMapPosition() -------------------------------------------------------------------------[/code]

And here’s what my newRow() code looks like now as a result of the suggestion. I imagine there is a way to optimize code so it doesn’t mirror so much but I’m more worried about getting down the execution time and keeping it readable.

[code]-- FUNCTION: Moves an old row of tiles into a new row and then changes their appearance to match. -
function newRow(map, angle)

– Shortcut tables
local top, btm = {}, {}

if angle == “up” then

btm.row = map.vis.btm[map.vis.btm.numChildren]
btm.pre = map.vis.btm[1]
top.row = map.vis.top[map.vis.btm.numChildren]
top.pre = map.vis.top[1]

– Move the row to it’s new position above pre.
btm.row:setReferencePoint(display.TopLeftReferencePoint)
btm.row.y = btm.pre.y - tileSize
–btm.row.x = btm.pre.x

top.row:setReferencePoint(display.TopLeftReferencePoint)
top.row.y = top.pre.y - tileSize
–top.row.x = top.pre.x

– Change the position of the group within the displayGroup array.
map.vis.btm:insert(1, btm.row)
map.vis.top:insert(1, top.row)

elseif angle == “down” then

btm.row = map.vis.btm[1]
btm.pre = map.vis.btm[map.vis.btm.numChildren]
top.row = map.vis.top[1]
top.pre = map.vis.top[map.vis.btm.numChildren]

– Move the row to it’s new position below pre.
btm.row:setReferencePoint(display.TopLeftReferencePoint)
btm.row.y = btm.pre.y + tileSize

top.row:setReferencePoint(display.TopLeftReferencePoint)
top.row.y = top.pre.y + tileSize

– Change the position of the group within the displayGroup array.
map.vis.btm:insert( btm.row )
map.vis.top:insert( top.row )

end

local adjust = { up=-1, down=1 }

– Update each tile in the row to its new identity.
for i = 1, btm.row.numChildren do

– Update the xTile and yTile
– btm.row[i].xTile = btm.pre[i].xTile
btm.row[i].yTile = btm.pre[i].yTile + adjust[angle]

– top.row[i].xTile = top.pre[i].xTile
top.row[i].yTile = top.pre[i].yTile + adjust[angle]

– Update the tile ID and type
btm.row[i].id = map.properties.btm[btm.row[i].yTile][btm.row[i].xTile].id
btm.row[i].type = map.properties.btm[btm.row[i].yTile][btm.row[i].xTile].type

top.row[i].id = map.properties.top[top.row[i].yTile][top.row[i].xTile].id
top.row[i].type = map.properties.top[top.row[i].yTile][top.row[i].xTile].type

– Update the visual appearance
btm.row[i]:setSequence( map.tileset.properties[btm.row[i].type ].name )
btm.row[i]:play()

top.row[i]:setSequence( map.tileset.properties[top.row[i].type ].name )
top.row[i]:play()

end

– Clean up
table.remove(top)
table.remove(btm)
top, btm = nil, nil

end --/newRow() -----------------------------------------------------------------------------------[/code] [import]uid: 41884 topic_id: 30486 reply_id: 122224[/import]

Try to localize. For example, in the innermost loop above, you have multiple references to btm.row[i] and top.row[i]. Make those local vars and refer to them. That will speed things up. Same with btm.row[i].yTile and top.row[i].xTile.

Other that that, it is hard to figure out what to optimize without having the whole project in front of me. There is a pretty good sticky: http://developer.coronalabs.com/forum/2011/12/03/tips-optimization-101 - take a look and follow its advice. For example, newrow seems to be a global function - make it local.

[import]uid: 160496 topic_id: 30486 reply_id: 122251[/import]

I see what you mean, although top and btm are already local to the function so Im not sure further localization will save more time than declaring the variable. Will give it a try!

I’ve been following that thread pretty closely, actually. And using Profiler to test some of its assumptions.

newRow is not actually global. The variable is set ahead of time for forward referencing, and then I add it to the module output later. :slight_smile:

Anyway, I think it’s about as fast as its going to get, some minor localization aside. I’ll continue on and start adding the NPC layer, but I’m guessing I’ll have another performance thread coming up soon, if only because the simulator performance in this project is just so poor. Thanks for your advice! :slight_smile: [import]uid: 41884 topic_id: 30486 reply_id: 122260[/import]

The simulator performance depends quite a bit on your desktop’s CPU and graphics card. Mine, for example, performs a LOT better than the devices. [import]uid: 160496 topic_id: 30486 reply_id: 122261[/import]

Some notes from my experience building my first Tile based application in Corona:
* Corona is not well suited for Tile based games. these games are graphics demanding compraed to other games and this is not one of the best sides in corona compared to native development. despite that, it is possible with a lot of tweaking to get reasonable performance, especially using Build 841 and above, which solved some offscreen culling issues.

Some things I ended up doing:
* I pre-create the entire map (between 4-10k tiles, depending on level) with all 7 layers before game start. as mike said, if you can reuse tiles instead of pre-creating them, even better.
* In enterFrame, try to do as little as possible - I mostly move the NPC,enemies and the scene view. specifically try to avoid creating new things there.
* If possible, you can calculate some things only every n frames, saving a lot of time in between.
* localize everything and avoid OO methodology where you can without makeing the code unmaintainable - function calling across modules has penalties in Lua.
* reduce amount of event listeners. use one for the main UI.
* when using physics:

  • use collision filters
  • set friction to 0.0 unless specifically needed, otherwise can cause stuttering.
  • i’ve found that on iOs its good to use time step = 1/fps for a smooth game, where on android it will
    not work well and time step need to be set to 0.
  • let the physics engine do most of the checks for you ( for example, collision between NPCs, walls etc.) and use events instead of checking yourself using lua functions.
    * note that there are BIG differences between iOS and Android - on Android the game will suffer much more from lags and on low end devices it will be much slower.
    * single core android devices also suffer from severe audio problems. I still do not know how to completely avoid these, but I try to resample music to lower rates and optimize SFX. another problem is that you cannot detect if a device is single core, so you will end up hurting at least some of your potential clients either way.

* On a side note, personally, I think it was a mistake to make my first game a tile based game - its one of the more complicated games to develop, and corona is not the best tool for that. It took me around 5months to complete with graphics and all.
* despite the above note, if you’re not under money/time pressure and develop mostly for fun, I totally understand the joy in building a tile based game! It was fun. Enjoy. [import]uid: 118978 topic_id: 30486 reply_id: 122271[/import]

Interesting stuff, rune7.
* I hadn’t considered using physics for my collision since there’s so little of it to actually measure, but I may try that later. I do have an existing function based method that seems to work fairly well since there’s no measurement involved. Will see how it does combined with this culling solution.

* My current performance plan is just to use the i4 as a baseline. I’m well aware that Android could have a variety of problems, but I’d much rather have a working iOS game first. :slight_smile:

* Not really sure what you mean by time-step…I assume that’s some sort of “if” filter within the enterFrame listener? ie: within enterFrame don’t do anything until X amount of time has past?

* My current plan is to create and store NPCs based on when they enter view, but you’re right, I may just have to create them all at the start and have them hang out in space somewhere. I tried to do a 4k tile load once but that just wasn’t working well, hence my current solution.

* mike470, I agree, but I would say that 400 tiles giving serious problems on my MBA strikes me as a bit odd…maybe tiles really are that hard for Corona to handle. (You’re right though, although localizing the xTile/yTile would have been overkill, just localizing again within the loop seemed to cut 50ms!) [import]uid: 41884 topic_id: 30486 reply_id: 122293[/import]

The enterFrame listener

local function mover(event) if pause == false and direction ~= false then engine.move(map, moveTable[direction][1], moveTable[direction][2]) end end

Finding the direction is called every frame during a touch-move if…

if direction == false or ( math.abs(event.x-last.x) \> tileSize ) or ( math.abs(event.y-last.y) \> tileSize ) then

(Basically, if the difference between your last touch and this touch is great enough, check.)

The newRow function

[code]-- FUNCTION: Creates a new row of tiles based on map core data. -----------------------------------
function newRow(map, angle)

local oldRow, xPos, yPos, newY, newX

if angle == “up” then

oldRow = 1 – the local row anchor
newY = map.vis.btm[1][1].yTile-1 – the array where tile data is stored
newX = map.vis.btm[1][1].xTile
xPos = map.vis.btm[1][1].x
yPos = map.vis.btm[1][1].y - tileSize

elseif angle == “down” then

oldRow = map.vis.btm.numChildren
newY = map.vis.btm[map.vis.btm.numChildren][1].yTile+1
newX = map.vis.btm[map.vis.btm.numChildren][1].xTile
xPos = map.vis.btm[map.vis.btm.numChildren][1].x
yPos = map.vis.btm[map.vis.btm.numChildren][1].y + tileSize

end

– Create the new row group
local btm_newRow = display.newImageGroup(map.tileset.sheet) – bottom tile layer
local top_newRow = display.newImageGroup(map.tileset.sheet) – top tile layer

– Iterate to create the tiles
for i = 1, map.vis.btm[1].numChildren do

– Create the tile
local btm_tile = newTile(map, newX, newY, “btm”)
local top_tile = newTile(map, newX, newY, “top”)

– Position the tile
btm_tile:setReferencePoint(display.TopLeftReferencePoint)
btm_tile.x = xPos; btm_tile.y = yPos

top_tile:setReferencePoint(display.TopLeftReferencePoint)
top_tile.x = xPos; top_tile.y = yPos

– Increment the X tile
newX = newX + 1

– Increment the xPos
xPos = xPos + tileSize

– Insert into the imageGroup
btm_newRow:insert(btm_tile)
top_newRow:insert(top_tile)

end

– Insert the row group
if angle == “up” then
map.vis.btm:insert(1, btm_newRow)
map.vis.top:insert(1, top_newRow)
elseif angle == “down” then
map.vis.btm:insert(btm_newRow)
map.vis.top:insert(top_newRow)
end

– Clean up
oldRow, xPos, yPos, newY, newX = nil, nil, nil, nil, nil

end --/newRow() -----------------------------------------------------------------------------------[/code]

I can understand if my code could be optimized further, but I guess I’m just not seeing how it’s causing such a noticeable slowdown given how little is actually being done.

Any ideas would be appreciated! :slight_smile: [import]uid: 41884 topic_id: 30486 reply_id: 122156[/import]

Having cleaned up my movement code some, it definitely seems to be the tile stuff slowing things down. I really don’t understand how adding 24 tiles (24 newSprites() attached to 1 of 2 imageGroups) can visibly hit the framerate this much, but maybe there is a way to reduce the number of tiles added per frame? [import]uid: 41884 topic_id: 30486 reply_id: 122171[/import]

Removed the top layer, cutting the number of tiles created in half. Still a noticeable stutter on every frame where tiles are created; virtually no improvement. Totally lost now. [import]uid: 41884 topic_id: 30486 reply_id: 122176[/import]

I doubt it will help significantly, but you can try to put your math.abs into a variable, so its function is stored in the memory (or something like this)

local mathabs = math.abs
print(mathabs(-12.2222))

Also, isn’t the “culling” feature of imagesheet/sprites/Imagegroup already taking care of the adding/removing tiles outside viewarea?!

http://www.coronalabs.com/blog/2012/03/06/image-sheets-image-groups-and-sprites/
“One of the major contributors to performance increases is the addition of “off-screen culling”, which basically means that objects that are not on-screen will not be rendered (resulting in increased performance). The good news is, you don’t have to do anything to take advantage of this improvement—you simply download the latest build to take advantage of it!” [import]uid: 162464 topic_id: 30486 reply_id: 122177[/import]

Are your tiles images or sprites?

If they are sprites, it may be a good idea not to delete old/create new tiles, but reuse the old (moved off screen) tiles by :prepare-ing them with the new tiles and moving them to the right position.

Also - and this may not be a big performance booster, but on general principle - any time you are using the same upvalue in multiple lines of code, it is a good idea to localize it:

 if angle == "up" then  
   
 oldRow = 1 -- the local row anchor  
 local mapbtm=map.vis.btm[1][1]  
 newY = mapbtm.yTile-1 -- the array where tile data is stored  
 newX = mapbtm.xTile  
 xPos = mapbtm.x  
 yPos = mapbtm.y - tileSize  
 elseif angle == "down" then  
 local mapbtm=map.vis.btm[map.vis.btm.numChildren][1]  
 oldRow = map.vis.btm.numChildren  
 newY = mapbtm.yTile+1  
 newX = mapbtm.xTile  
 xPos = mapbtm.x  
 yPos = mapbtm.y + tileSize  
 end  

You can also post the “newtile” code so we could look if there are inefficiencies there. [import]uid: 160496 topic_id: 30486 reply_id: 122180[/import]

Seems to me like you would be better off trying to create as little new objects as you can in enterFrame.
Try splitting the visual representation of the map from the actual data map.

Regarding the visual part, I would have one ImageGroup for the map, in this map I would have a grid of sprites (each located in a different “virtual” tile).
This map should contain the visible tiles plus 1 column/row in each direction, up, down, left and right so you can scroll the map.
Now you need to do 2 things in enterFrame

  1. Use setFrame to change what each visual tile is showing.
  2. Scroll the map; this is the harder part. You need to allow the users to scroll the tiles, once a row/column is completely out of screen you move it to the opposite side of the map ensuring you always have a border of offscreen tiles around the map. (do that with translate and not changing the x, y properties directly)

This way you have a constant window into your world map, you can change what it is showing and you never need to create any new objects at runtime.

I think if all you change in enterFrame is the frameIndex of your sprites it should run smoothly.

Hope I was clear enough without any code example :slight_smile:
[import]uid: 80469 topic_id: 30486 reply_id: 122181[/import]