Million Tile Engine Beta Release

Dyson, an interesting question for you. With your insight into the maps and performance challenges, do you think it would be viable to have a live mini map of the entire tile set map (or subset) displayed in a corner of the screen over the existing map?  Not asking you to do anything on this, just wondered if it’s worth persuing.

It sounds to me like having two maps on top of each other so not sure whether it would even work and I imagine it would be like doubling up on the memory demands regardless of the fact that one tile might only be one pixel for instance.  I’ve seen very little about this around, the only solution I’ve seen so far was to save the display group as an image and then display that scaled down.  

I think you could make a mini map work if you put enough work into it. You’re right that using display objects for tiles would introduce an enormous performance demand regardless of their size on the screen. Reducing the resolution of the tileset won’t help any either. I’ve found that the vast majority of the performance impact comes from the object itself, not the size of the tile texture. 

You could draw the map to the screen and save it using display.capture or one of the related functions like you describe. The performance would be great- after you finish creating the mini map. Something to keep in mind, however, is that display.capture(), display.captureBounds() and so on only work on visible, onscreen content. A tile partially offscreen will be clipped. There’s also no convenient way to update the contents of the mini map that I can think of. You’d have to load the ENTIRE map onto the screen and then take a capture of it. This could take many tens of seconds for larger maps. If the map is larger than 100 x 100 tiles or so the device hardware will slow down and you could end up with memory warnings and device crashes. 

You could make a fluidly working minimap using a snapshot object with canvas mode set to discard. The way snapshots work would allow you to process the minimap in the background without interrupting gameplay and then display it when it’s complete, with only a minor performance impact during processing and minimum memory demands. Snapshots do require a Pro or Enterprise subscription though. There would be other limitations to keep in mind. You’re limited by the maximum texture size of the device, for example.

Hmm,  I wonder if a photoshop’d version of the tiled map (either whole or a sector) at say 1 pixel (or whatever scale) per tile was displayed as an image and then a sprite over it at one pixel to move linked to the tile position?

Hmmm… I never thought of that :stuck_out_tongue:  And Tiled can save an entire map as an image file already, so there’s that.

Yeah, you’d just need to make sure that the sprite over the map image (and the map itself) remained anchored in the same place when the camera is moved/dragged.  I’m guessing by moving it in a relative direction to create the illusion of being anchored.  It would also probably be prudent to only show it at a fixed zoom level (if used) so disappears when zoom is changed.  Either that or just have it as a separate screen to bring up.

MTE doesn’t move the Stage, so you could put it in a seperate display group in front of MTE’s master group. 

Interesting!  I’ll add it to my list.  

Hey Dyson,

Does the displayObject reference “group” work in addSprite?  I was using it in the older version and can’t seem to figure it out.  Also, in your documentation it seems you call it “groupObject”.  I think you also have “vector object” in there which should say vector.  Any help would be great!

Curt

Oh, whoops… forgot to switch my mte require call for other .lua files… haha.  That’d be the problem!

A couple updates; First, the MTE 40% discount ends at midnight tonight! Well, actually it will end tomorrow morning. I never specified a timezone, so I’m going to wait until everyone has had a chance to reach midnight. The price will then go back to $24.99

I’m pushing the date of the price increase back to April 2nd! Why? A lot of people now have commented about the April 1st date, pointing out that it is April Fools day and that this may cause confusion. The last thing I want is for people to believe that this price increase is an April Fools joke. It is not.

The MTE update this week will include minor new functionality. You’ll be able to set the color of a sprite and still have that sprite respond to tile and layer lighting. Tile and layer lighting will now also effect “group” sprites, which are group objects into which multiple sprites have been loaded. A common use of this is character customization; for example, a player character might be composed of arm sprites, a body sprite, and a hat sprite, each of which can be individually colored. These sprite groups will now respond to lighting without losing their colors.  Aside from lighting, I’ve moved the touchScroll and pinchZoom functions into MTE for your convenience. You can enable and disable these independently, and you can specify the maximum and minimum zoom. 

The update will go out on Friday. I’ll keep everyone posted as I get more done. You can expect addition pieces of sample codes as well and, if time allows, a tutorial or two.

Hi,

Firstly fantastic engine and just what I need for a number of projects I’ll soon be working on. purchased it weeks ago and I was wondering however if there were any video tutorials showcasing the many API’s ?

Thanks

Danny

There aren’t any video tutorials yet, Danny, but they’re coming! Though, the tutorials will be oriented more to accomplishing certain tasks and gameplay mechanics than demonstrating the API. For example, one of the first tutorials will cover creating a project, setting up its directory structure, creating a map and things of that nature. Video tutorials of API’s might come later, but really I think sample code serves that purpose better. You can load sample code and see the output yourself, and modify it experimentally, rather then simply watching it unfold in a video.

Hi Dyson,

I was just taking a look at the mte.updateTile function.   Firstly, can I check that this uses whatever map is currently loaded as the map to change?

In my main map I have several tilesets in use and would rather keep it like that.  The ‘tile’ parameter references a numeric occurrence of a tile in the tileset for the map.  So how do I point to the correct tile number in the correct tileset?

Thanks!

Yes, updateTile only ever updates the active map- the one currently visible onscreen. It won’t touch any of the other map’s you’ve loaded.

As for how to deal with maps using multiple tilesets, the tile parameter of updateTile is a global tile ID. What Tiled does is add the numbers of tiles from each tileset together and represent tiles in relation to that total. If you have two sets with 100 tiles, and you want the 50th tile from the second set, the global ID would be 150. A useful bit of data to have on hand is the “firstgid”, or “first global id”, of the tileset. You can retrieve that from map.tilesets[aTileset].firstgid as follows;

local map = mte.getMap() local firstgid = map.tilesets[2].firstgid print(firstgid)

MTE 0v980 - https://gum.co/staO

MTE 0v980 will appear in customers’ inboxes shortly! This is a 1.0 release candidate. I will be adding no new features leading up to the final 1.0 release, and I won’t be changing any of the API available in this release, though I won’t rule out minor additions in response to a bug or something I missed.

All sample projects now use TMX maps with CSV layer data encoding. I recommend all developers do the same for the sake of ease of use and performance. Exported Json files are still the smallest and fastest, but each change to the map in Tiled requires exporting the map again. TMX files with CSV encoding are nearly as small and nearly as fast, and they can be directly edited and saved in Tiled, no exporting necessary.

I’ve removed the Tiled Map folders for each sample. Everything you need to open and edit the maps is now integral to each sample’s project folder.

I gave the current documentation a good scrubbing paying particular attention to the API reference document. Additional sample projects, sample code for many of MTE’s functions, and a few tutorials will be coming further down the line. We may also see some thorough tutorials coming from one or more third-party sources, which would just be fantastic!

In the past I’ve treated the Beta as more of an early access program, but at this point I really need developers to report on any problems they encounter! It is time to really polish the engine to a shine! As always you can ask questions, leave feedback, and track engine development progress here on the MTE forum. I’ll be keeping an eye out for bug reports in particular. 

Thanks for your support! Please read on for more details on the changes since 0v958.

Updates:

  • It used to be that constraining the camera and then changing the scale of the map would cause the camera constraints to ‘move.’ Even though you had zoomed in, you could not get any closer to the constraint. MTE 0.980 applies constraints continuously, taking into account the scale of the map and it’s rotation. 

  • MTE 0.980 calculates the size of the culling region each frame. If you zoom out it will spawn more tiles to fill in the empty screen space. If you zoom in it will cull the tiles no longer visible to improve performance.

  • It is no longer strictly required that users add sprites to the map using addSprite(). Users are now free to add sprites directly to the layer’s group object if they so desire (the engine may automatically insert these sprite’s into a subgroup in certain situations). Furthermore, on orthographic maps the sprites can be moved using transitions and other native Corona SDK calls instead of MTE’s movement functions. Corona’s native transition and translation functions remain between 25% and 50% more efficient than MTE’s movement functions where large numbers of sprites are in motion. 

I still recommend using removeSprite() to remove unneeded sprites, rather than doing so directly with object:removeSelf().

  • You can set the engine to update a tiny area of the map around offscreen physics objects by setting their offscreenPhysics property to true. This will allow dynamic physics objects to remain in motion anywhere on the map. Keep in mind that these offscreen areas contribute to the performance demands of your app. You’ll want to keep an eye on how many tiles you have active at any given time.

  • MTE 0.958 and previous versions were hardcoded for a 2:1 Isometric Ratio. Isometric tiles had to be exactly twice as wide as they were tall on the tileset image and in Tiled or the display would be corrupted. MTE 0.980 calculates the Isometric Ratio when the map loads and adjusts accordingly.

API Changes:

  1. Calling require(mte) is no longer enough to begin using the engine. You’ll have to create the engine instance as well with the createMTE() function. You can combine both operations into a single line if you like:

    local mte = require(“mte”).createMTE()

Or you can keep things seperate:

local mteConstructor = require(“mte”) local mte = mteConstructor.createMTE()

This will also allow you to create additional instances of the engine as needed.

  1. The goto() function is gone. It has been replaced with setCamera() to avoid a conflict with future versions of Lua and to more precisely describe what it does. 

  2. The loadMap() function now returns the map table, not MTE’s masterGroup object.

  3. The setCamera() function now returns MTE’s masterGroup object.

  4. All functions which took an easing parameter now take a transition parameter. The transition parameter holds an easing function, such as easing.inOutQuad. For example, this is a movement command from 0.958:

    mte.moveSpriteTo( { sprite = player, locX = xTile, locY = yTile, time = moveTime, easing = “linear”} )

This is the same function from 0.980:

mte.moveSpriteTo( { sprite = player, locX = xTile, locY = yTile, time = moveTime, transition = easing.linear } )

Because of this the built-in movement functions now support all of Corona’s easing functions.

  1. The functions for converting to and from grid coordinates are gone. For example, mte.convert(“gridToLoc”, x, y, layer) and mte.convert(“levelPosToGrid”, x, y, layer) are no longer available. The map’s tile objects are now held in a map.layers[layer].tileObjects table. If you know the location of the tile object you want, you can easily retrieve it from the table without any converting. For example, the tile at 43,56 on layer 3 is stored in map.layers[3].tileObjects[43][56].

  2. The convert() function is still available at the moment, but it now calls the new direct conversion functions internally. I recommend switching over to the new functions to avoid performing the string comparison needed by convert(). The conversion functions now work correctly regardless of map scale.

    screenToLevelPos(xArg, yArg, layer) screenToLevelPosX(xArg, layer) screenToLevelPosY(yArg, layer) screenToLoc(xArg, yArg, layer) screenToLocX(xArg, layer) screenToLocY(yArg, layer) levelToScreenPos(xArg, yArg, layer) levelToScreenPosX(xArg, layer) levelToScreenPosY(yArg, layer) locToScreenPos(xArg, yArg, layer) locToScreenPosX(xArg, layer) locToScreenPosY(yArg, layer) locToLevelPos(xArg, yArg) locToLevelPosX(xArg) locToLevelPosY(yArg) levelToLoc(xArg, yArg) levelToLocX(xArg) levelToLocY(yArg)

  3. The valid values for the ‘kind’ parameter of addSprite are now “sprite”, “imageRect”, “vector”, “group”

  4. The constrainCameraToScreen() function is gone. It’s behavior is now the default behavior of constrainCamera().

  5. Sprites no longer include the getX(), getY(), getLevelPosX(), and getLevelPosY() functions. The coordinate system of each layer is equal to that of the map. If a tile is 32x32 according to tiled, then it will be 32x32 according to Corona and MTE. If sprite.x = 100, then the sprite is at x = 100 on the tile map as well. 

This breaks down at the edge of maps when worldWrap is enabled. As the camera approaches the wrap, sprites on the other side are moved into the camera view so that they are visible across the wrap. In these cases sprite.levelPosX and sprite.levelPosY are equal to the sprite’s position on the map while sprite.x and sprite.y are equal to the sprite’s position on the layer as always. 

Isometric maps use an arbitrary coordinate system maintained by the engine. On isometric maps a sprite’s .x and .y parameters will almost never match their level positions. Use sprite.levelPosX and sprite.levelPosY to read their position in relation to the tile map. This is caused by the isometric perspective.

MTE 0v984 - https://gumroad.com/l/staO/

This week’s update sees the addition of a color parameter for sprites to support the combination of sprite tinting and MTE lighting, new pinchZoom and touchScroll routines built right into the engine for user convenience, a minor expansion of the removeSprite function to support the removal of sprites from MTE without destroying the sprite’s displayObject, an update to the map table structure to allow users to json.encode the map manually, and minor bug fixes.

Tinting a sprite is a common method of customizing sprites while reducing file size among Corona users. However MTE also tints sprites in order to apply tile-and-layer lighting. Before this update the original tint of the sprite would be lost forever in this situation. Now, by giving the sprite a .color parameter, users can specify and preserve the tint of a sprite. MTE will apply the light levels TO the color by blending them instead of overriding the original color. The format of color is {red, green, blue}. So mySprite.color = {255, 0, 0} will turn the sprite bright red. You can also use .color in the sprite’s setup table for addSprite(). Going even further, you can apply the .color parameter to each sprite stored in a group object, and then add that group object to MTE using addSprite. This allows sprites to be assembled from many sub-sprites, each of which can be tinted to customize the appearance of the sprite.

I’ve had a good dozen requests to integrate pinchZoom and touchScroll code directly into MTE, and I’ve done just that! Call enablePinchZoom() or enableTouchScroll() to activate the routines and disablePinchZoom() or disableTouchScroll() to disable them. Keep in mind that you must call system.activate( “multitouch” ) in order for pinchZoom to work, and you can’t actually test pinchZoom in the simulator; you need two fingers, not a single mouse pointer!

Lets see, what else is there. Oh yes. Before this update, adding a sprite to a map basically trapped it there. You could insert the sprite into a different group, but MTE would still attempt to delete it when a new map loads. There is now an additional argument in the removeSprite function: removeSprite(sprite, destroyObject). DestroyObject is a boolean specifying whether MTE should destroy the sprite’s displayObject on removal. This argument is optional; it’s default behavior is true, which conforms to the way MTE has always worked. If you set it to false, the engine will insert the sprite into Corona’s Stage object and remove internal references to it, leaving it intact and reusable (see display.getCurrentStage() in the Corona SDK documentation).

The rewrite moved the table storing the map’s tile displayObjects into the map table. This has caused some trouble when users try to json.encode the map for saving and storage. The saveMap() function did take care of this for you, but the solution was clunky and ultimately unnecessary. I’ve moved the table storing the tile objects back out of map. Previously you could reach a layer’s tile objects at map.layers[layer].tileObjects[locX][locY]. Now you can reach a layer’s tile objects at mte.tileObjects[layer][locX][locY].

Lastly I’ve squashed a few bugs here and there relating to how the engine treats lineObjects and anything which doesn’t have a setFillColor() method, as well as unrelated bugs throughout.

This week’s update will hopefully clear the way for more work on the documentation. I had intended to work on at least one tutorial this week if time allowed, but it turns out time did not allow! The new plan is to work on documentation and map stitching next week and to continue the work on map stitching the next week. 

Enjoy!

Dyson,

I found a bug in this latest update. Seems like sprites that are composed of vectors (newCircle() in my case) and those that are groups with vectors inside of them, are having their fill values overridden with white ignoring what I set them to prior to adding them into mte.

Thanks for bringing this to my attention. Could you try assigning the vector objects a color property as described above and see if they maintain that color? 

Setting the .color property of the vector to the same color as the fill allows for it to preserve the intended fill value. It took a moment to figure out why everything was filling with black though. You reverted to pre graphics 2.0 colors of 255 instead of 0-1 per channel. I never tried the lighting system so if they use this same method, i understand why you did it this way, though breaking continuity with the rest of corona.

I assume setting the .color property is a temporary fix?

MTE 0v980-6 - https://gum.co/staO

​I just sent a new mte.lua out to everybody with some bug fixes and corrections. I recommend getting rid of the mte.lua file you got with the update yesterday and replacing it with the new file. Don’t forget the sample projects! If you’re ever confused just check the top of the file. The newest version is labelled --mte 0v980-6.

  • Fix for offscreenPhysics objects erasing parts of the map they pass through.

  • New code for detecting the orientation of the device and adjusting the map display accordingly.

  • Fix for refresh() deleting the map from memory.