Code:
-- Note this version of the TileEngine does not pre-render the map. The 
-- advantage is that you can use big maps. The disadvantage is that it will be 
-- slower (especially for large display area with small tiles).


------------------------ IMAGING
property Buffer                            -- offscreen image of the map
property Canvas                            -- the output image
property RectOnCanvas                      -- dest rect on the canvas

------------------------ MAPPING
property MapList                           -- map of the current tiled image
property MapLoaded


------------------------ STATIC TILE PROPERTIES
property Tile_Width, Tile_Height           -- assume all tiles are the same size
property Tile_Rect                         
property Tile_HalfWidth
property Tile_HalfHeight

------------------------ SCROLLING
property MapY, MapX                        -- current mapping (scroll)
property MapXi, MapYi                      -- integer versions of MapX and MapY 
property MapXLimit, MapYLimit              -- limits on moving the view
property MaxTilesToDrawX, MaxTilesToDrawY  -- max number of tiles to draw 
property WorldPixelSize

------------------------ DEBUGGING
property SelectedTile
property LastPath  

--------------------------------------------------------------------------------
-- Initialise
--------------------------------------------------------------------------------



on Initialise (me, outputImage, aRect)
  
  
  Canvas = outputImage
  if aRect.ilk = #rect then RectOnCanvas = aRect
  else RectOnCanvas = Canvas.rect
  MapLoaded = false
  LastPath = []
  return me
  
end


--------------------------------------------------------------------------------
-- Load Map
--------------------------------------------------------------------------------



on LoadMap (me, aMap, baseTile, feedbackObj)
  -- Parameters:
  -- * aMap is a list of lists containing tile objects  
  -- * base tile is a member reference of a 'base tile' (used 
  --   to get width, height and regpoint)
  -- Returns
  -- "OK" for success or an error description
  
  
  -- check input parameters
  if (aMap.ilk <> #list) then return \
      "Bad parameter: supplied Map is not a list"
  if (count(aMap) < 1) then return \
      "Bad parameter: supplied Map is empty"
  if (aMap[1].ilk <> #list) then return \
       "Bad parameter: supplied Map is incorrectly populated (first row is not a list)"
  if (aMap[1].count < 1) then return 
      "Bad parameter: supplied Map is incorrectly populated (first row is empty)"
  if (baseTile.ilk <> #member) then return \
      "Bad parameter: need a member reference for a base tile"
  if (baseTile.type <> #bitmap) then return \
      "Bad parameter: need a bitmap member reference for a base tile"
  
  me._InitialiseMap(aMap, baseTile, feedbackObj)
  MapLoaded = true
  return "OK"
end


--------------------------------------------------------------------------------
-- Mapping Methods

-- MapLoc is the position of the tile in the map ie. point(TilesX, TilesY)
-- WorldLoc is the position is the 'world' (in pixels)
-- ViewLoc is the position in the view (ie. WorldLoc - scrollAmount)
--------------------------------------------------------------------------------



on WorldToMap (me, worldLoc)
  if MapLoaded then
    x = floor((worldLoc.locH)/float(Tile_Width)) + 1
    y = floor((worldLoc.locV)/float(Tile_Height)) + 1
    x = Max(1, Min(MapList[1].count, x))
    y = Max(1, Min(MapList.count, y))
    return point(x,y)
  end if
end


on MapToWorld (me, mapLoc)
  if MapLoaded then
    -- return the point in the middle of the specified tile
    x = (mapLoc.locH-1)*Tile_Width + Tile_HalfWidth
    y = (mapLoc.locV-1)*Tile_Height + Tile_HalfHeight
    return point(x,y)
  end if
end


on ViewToWorld (me, viewLoc)
  -- translates a point in the current view to a its 
  -- position in the world
  return point(viewLoc.locH -MapX, viewLoc.locV-MapY)
end

on WorldToView (me, p)
  -- translates a point in the world to a its 
  -- relative position in the current view
  return point(p.locH +MapX, p.locV+MapY)
end


on ViewToMap (me, viewLoc)
  -- translates a point in the current view to a its 
  -- position in the world
  
  return me.WorldToMap(point(viewLoc.locH -MapX, viewLoc.locV-MapY))
end

on MapToView (me, p)
  -- translates a point in the world to a its 
  -- relative position in the current view
  p = me.MapToWorld(p)
  return point(p.locH +MapX, p.locV+MapY)
end


on OffsetToMiddleOfView (me, PntOnMap)
  -- return a vector (point) from the specifed point
  -- to the middle of the current view
  p1 = point(PntOnMap.locH , PntOnMap.locV)
  p2 = point( RectOnCanvas.width/2-MapX, RectOnCanvas.height/2-MapY)
  return (p2-p1)
end


--------------------------------------------------------------------------------
-- Update Event
-- Redraw all the visible tiles
--------------------------------------------------------------------------------



on Update (me) 
  if MapLoaded then
     -- update the visible tiles
      
    -- work out the start and end of the x/y coordinates to draw
    startX = (-MapXi/Tile_Width) + 1
    startY = (-MapYi/Tile_Height) + 1
    endX = Min(MapList[1].count, startX + MaxTilesToDrawX)
    endY = Min(MapList.count, startY + MaxTilesToDrawY)
    
    -- now draw the visible tiles
    repeat with y = startY to endY
      repeat with x = startX to endX
        thisTile = MapList[y][x]
        thisTile.Paint(canvas, MapXi,MapYi)
      end repeat
    end repeat
    
    -- now paint the hilight 
    if SelectedTile <> VOID then
      aColor = rgb("#000")
      PaintRect = SelectedTile.destRect.offset(MapXi,MapYi)
      Canvas.draw( PaintRect, [#ShapeType:#rect, #Color: aColor])
    end if
    
  end if
end


--------------------------------------------------------------------------------
-- Painting Methods
--------------------------------------------------------------------------------



on PaintFullMap (me, intoThisImage)
  -- paint the map into a supplied image, returning the scale 
  -- of the rendered map and an offset to the top-left of the 
  -- canvas the map has been painted into. This method is used
  -- by the 'minimap' to get small version of the whole map
  
  PaintRect = intoThisImage.rect
  worldTileSize = [maplist[1].count, maplist.count]
  --
  TileOffset = [0,0]
  if worldTileSize[1] = worldTileSize[2] then 
    tileDrawWidth = PaintRect.width/float(maplist[1].count)
    tileDrawHeight = PaintRect.height/float(maplist.count)
    tileDrawRect = rect(0, 0, tileDrawWidth, tileDrawHeight)
    
  else if worldTileSize[1] > worldTileSize[2] then 
    tileDrawWidth = PaintRect.width/float(maplist[1].count)
    tileDrawHeight = tileDrawWidth
    tileDrawRect = rect(0, 0, tileDrawWidth, tileDrawHeight)
    gap = PaintRect.height - (worldTileSize[2]*tileDrawHeight) 
    TileOffset = TileOffset + [0, gap*0.5]
    
  else 
    tileDrawHeight = PaintRect.height/float(maplist.count)
    tileDrawWidth = tileDrawHeight
    tileDrawRect = rect(0, 0, tileDrawWidth, tileDrawHeight)
    gap = PaintRect.width -  (worldTileSize[1]*tileDrawWidth) 
    TileOffset = TileOffset + [gap*0.5, 0]
    
  end if
  MapScale =  float(tileDrawWidth) / tile_width
  CurrentOffset = TileOffset.duplicate()
  repeat with y = 1 to worldTileSize[2]
    aRow = maplist[y]
    repeat with x = 1 to worldTileSize[1]
      destRect = tileDrawRect + rect(CurrentOffset[1], CurrentOffset[2],\
               CurrentOffset[1], CurrentOffset[2])
      imageRef = maplist[y][x].image
      intoThisImage.copyPixels(imageRef, destRect, tile_Rect)
      CurrentOffset[1] = CurrentOffset[1] + tileDrawWidth
    end repeat
    CurrentOffset[1] = TileOffset[1]
    CurrentOffset[2] = CurrentOffset[2] + tileDrawHeight
  end repeat
  
  return [#MapScale: MapScale,#TileOffset:TileOffset] 
end


--------------------------------------------------------------------------------
-- Pathfinding
--------------------------------------------------------------------------------

on GetPathCost (me, x,y)
  -- return the cost to make a path across the specified tile
  x = mapList[y][x].GetCost()
  return x
end

on ShowPath (me, aPath)
  -- just for debugging
  
  repeat with T in LastPath
    T.RestoreImage()
  end repeat
  
  LastPath.deleteAll()
  
  repeat with aLoc in aPath
    t = MapList[aLoc.locV][aLoc.locH]
    T.PathHilight()
    LastPath.append(T)
  end repeat
end


--------------------------------------------------------------------------------
-- Scrolling the view
--------------------------------------------------------------------------------



on MoveView (me, x, y) 
  -- Shifts the current map coordinates by the specified 
  -- amount and updates the buffer
  
  if MapLoaded then
    MapX = MIN(0, MAX(MapXLimit, MapX-x)) 
    MapY = MIN(0, MAX(MapYLimit, MapY-y))
    MapXi = integer(MapX)
    MapYi = integer(MapY)
  end if
end

on MoveViewTo (me, newLoc)
  -- shifts the current map coordinates to the specified point

  if MapLoaded then 
    amnt = newLoc + point(RectOnCanvas.width/2, RectOnCanvas.height/2)
    MapX = MIN(0, MAX(MapXLimit, amnt.locH)) 
    MapY = MIN(0, MAX(MapYLimit, amnt.locV))
    MapXi = integer(MapX)
    MapYi = integer(MapY)
  end if
end

on GetViewRect(me)
  return RectOnCanvas.offset(-MapXi,-MapYi)
end

--------------------------------------------------------------------------------
-- Get and Set Tile Objects
--------------------------------------------------------------------------------

on GetTile  (me, iPnt)
  -- returns a reference to the specified tile object 
  iy = iPnt.locV
  ix = iPnt.locH
  return mapList[iy][ix]
end

on SetTile  (me, iPnt, thisTile)
  -- returns a reference to the specified tile object
  
  iy = iPnt.locV
  ix = iPnt.locH
  
  x_offset = (ix-1)*Tile_Width
  y_offset = (iy-1)*Tile_Height
  mappedTile = script("TileEngine.Tile.Mapped").new(thisTile,\
                                                 x_offset, y_offset)
  MapList[iy][ix] = mappedTile
  return MapList[iy][ix]
end

--------------------------------------------------------------------------------
-- Interacting with Map
--------------------------------------------------------------------------------

on  GetMovedPoint(me, startPnt, endPnt, rectToMove)
  -- return the point furthest along the line from 
  -- startPnt to endPnt that the rectToMove can move to
  
  -- in this version, simply ensure that the rect stays 
  -- within the world rect
  x = 0
  y = 0
  r = rectToMove.offset(endPnt.locH, endPnt.locV)
  if r.left < 0 then x = -r.left
  else if r.right > WorldPixelSize[1] then x = WorldPixelSize[1]-r.right
  if r.top < 0 then y = -r.top
  else if r.bottom > WorldPixelSize[2] then y = WorldPixelSize[2]-r.bottom
  return endPnt + point(x,y)
end


--------------------------------------------------------------------------------
-- Hilight a tile
--------------------------------------------------------------------------------



on HilightTile (me, aTile)
  if aTile.ilk = #instance then
    SelectedTile = aTile
  end if
end

on DeselectTile (me)
  SelectedTile = VOID
end





--------------------------------------------------------------------------------
-- Private Methods
--------------------------------------------------------------------------------


on _InitialiseMap (me, aMap, basetile, feedbackObj)
  
  MapList = aMap
  MapY = 0
  MapX = 0
  
  Tile_Width = basetile.width
  Tile_Height = basetile.height
  Tile_Rect = rect(0,0,Tile_Width,Tile_Height)
  
  Tile_HalfWidth = Tile_Width/2
  Tile_HalfHeight = Tile_Height/2
  
  WorldTileSize = [MapList[1].count, MapList.count]
  WorldPixelSize = WorldTileSize * [Tile_Width, Tile_Height]
  
  MaxTilesToDrawX = RectOnCanvas.width/Tile_Width +1
  MaxTilesToDrawY = RectOnCanvas.height/Tile_Height +1
  
  MapXLimit = -(((MapList[1].count) * Tile_Width) - RectOnCanvas.width - 1)
  MapYLimit = -(((MapList.count) * Tile_Height) - RectOnCanvas.height - 1)
  
  x_offset = 0
  y_offset = 0
  
  steps = float(MapList.count)

  repeat with y = 1 to MapList.count
    repeat with x = 1 to MapList[y].count
      thisTile = MapList[y][x]
      mappedTile = script("TileEngine.Tile.Mapped").new(\
            thisTile, x_offset, y_offset)
      MapList[y][x] = mappedTile
      x_offset = x_offset + Tile_Width 
    end repeat
    x_offset = 0
    y_offset = y_offset + Tile_Height
    
    call(#ShowProgress, [feedbackObj], "Loading Map...", (y/steps))
  end repeat
  
  buffer = image(WorldPixelSize[1], WorldPixelSize[2], 16)
end
My TileEngine

Error:

Code:
Script error: Command expected

"Bad parameter: supplied map is incorrectly populated (first row is empty)"?