Million Tile Engine Beta Release

Thanks a lot for the update.

Can’t wait to see its coming out.

I hope everyone enjoyed their holiday! Mine was short and hectic, as it always is! 

I’m feeling quite confident in a late January release of the engine rewrite. Progress has been steady and quick, if not swift. I’m wrapping up work on the physics implementation over the next few days and moving on to re-enable Isometric support. From there I’ll add in a few of the nifty new features I’ve teased, and get everything ready for release. 

The new release will have an arbitrary version number below 1.0 until I’m confident we’ve hammered out the bugs, but it will essentially be the release candidate. No new features will be added after that point is reached and I will be diverting all my attention to coming up with some nicely written, thorough tutorials. 

Rewrite news aside, I do have a minor update to the current code for all of you:

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

This minor update fixes a bug in the sprite sorting algorithm and adds an optional onComplete parameter to the function moveCameraTo(). You can try out the new functionality by opening the Lighting 0v958 sample and uncommenting the code block at line 201 in main.lua.

[media]http://www.youtube.com/watch?v=MuMKrG7T1jY[/media]

 

Thanks for the update.

Looking forward to your new rewrite.

Happy 2014. 

Why display one map when you can display four? Might as well use perlin noise to come up with some nice mountainous landscapes while we’re at it. And we might as well rotate each one at a different rate for the sake of vertigo.

[media]http://www.youtube.com/watch?v=aOjzaA7KYyY[/media]

Perlin noise is convenient, but we might as well run a couple completely different map types at once.

[media]http://www.youtube.com/watch?v=ohuxJg48peM[/media]

Why settle for moving a map when you can move the Container holding the map? Using a Container object is optional, but it does conveniently clip the edges of the viewport to nice clean lines.

[media]http://www.youtube.com/watch?v=Q2_GSSbXn1Q[/media]

Of course, any given hardware device can only handle so much. The iPad2 can handle on the order of 1500 simultaneous tiles. If you display four different maps simultaneously you’ll want to make sure the total tiles across all of them is within the 1500 limit, or whatever performance envelope your target device has. Each instance comes with overhead as well, so the total tiles should be somewhat lower than what you would aim for while displaying a single map.

I’ll have more information for you all over the next few days.

Wow!! Great work, dyson! :slight_smile:

Speechless… Feeling spoiled!!! Thank you very much.

Wow!!!

Desperate for more information on the Perlin noise functionality…

MTE’s perlin noise function is highly configurable.

[media]http://www.youtube.com/watch?v=FqkytvbCzO4[/media]

I generated the entirety of the world above from a blank 200x200 tile map using the following code:

mte1.enableHeightMaps() local layer = {layer = 1, scale = 6, roundResults = true, perlinLevels = {{min = 0, max = 1, value = 33}, {min = 1, max = 2, value = 33}, {min = 2, max = 3, value = 33}, {min = 3, max = 4, value = 36}, {min = 4, max = 5, value = 37}, {min = 5, max = 7, value = 38} } } local heightMap = {layer = 1, scale = 1, offset = -0.5, perlinLevels = {{min = -0.5, max = 0, value = 0}, {min = 0, max = 1.1} } } local lighting = {layer = 1, scale = 255, offset = 90 } mte1.perlinNoise({freqX = 0.05, freqY = 0.05, oct = 4, layer = layer, heightMap = heightMap, lighting = lighting})

The perlin noise function will generate pseudo-random noise, process that noise based on input you give it, and load the results into either a world data (tile) table, a heightMap table, a perlinLighting table (which takes precedent over the layer lighting configured in Tiled), or an output table you specify- or any combination of the above. 

Within each of these outputs you can set the scale of the output. For example, layer data is scaled so that the noise falls between the values of 0 and 100 by default. In the example above I’ve changed it to a scale of 6, because I want to assign six possible tiles to the layer based on the perlin noise value. The result is that the noise is scaled so that it falls into a range of from 0 to 6. You can offset the scale if you’d like as well. An offset of 3 and a scale of 6 will give you data ranging from 3 to 9. Tile data likes to be in whole numbers. You can use the roundResults, floorResults, and ceilResults boolean parameters to get whole number values from the noise, otherwise the noise will have a decimal value. These parameters are available for all output modes, and can be set individually for each mode.

A perlinLevel is a table assigning an arbitrary output value to a range in the perlin data. In the above example the output is scaled to 0 to 6. I assign the tileID of my water tile to the lower perlin values and various other tiles to the upper perlin values. PerlinLevels can be set independently for each of the four output modes.

Within perlinLevels you can set masks. A mask is a table assigning an arbitrary output to a range of PRE-EXISTING DATA. If you call a perlin operation on a world table which already contains tiles, masks can be setup to produce an output based on the pre-existing tileID’s, within each perlinLevel. Say you’ve generated a world with sandy beaches, grassy midlands, and rocky mountains, and now you want to add forests to this world. You could run the perlin noise function a second time to determine the location of forests, using perlinLevels to define forests and voids. You could then use masks within those levels to choose the type of tree tile; palm trees on sand tiles, leafy trees on grasslands, and scraggly mountain trees on mountains.

All this is optional. If you call perlinNoise({}) with an empty set of parameters it’ll spit out a 2D table of noise ranging from 0 to 100, the size of the map array. 

Speaking of size, you can specify the size of the perlin noise output. For the world data, heightMaps and lighting the size should be equal to the size of the layer, but in other cases you can set any arbitrary size.

Hi dyson - Haven’t been using MTE just yet but was hanging out with the new version that lets me use physics calls normally (versus having to use the MTE physics calls) if you recall.   Is this now available in the latest release?  

Also is Tiled the only map tool supported?  I’m really after (ideally) effectively Tiled, but with good support for adding non-tiles images for placement, such that how it appears in Tiled visually will be how it will look in Corona.  Idea is to be able to hand out such a map generator to my friends so they can develop levels, and then run them on Corona to see how they look, then hand me the result back.  But again I really need the WYSIWYG type approach for image placement on top of the tile layouts.  

So wondering if you there is an alternative to Tiled that might support this?

There is Level Director I see (unfortunately only for windows I think - http://www.retrofitproductions.com/level-director/ ) but perhaps is a possibility.  Not sure if MTE could suck in data from it?

Hello greg886,

MTE contains a require statement for the physics library so that it can spawn and cull tiles with physics bodies attached. The call mte.physics.addBody, for example, is in fact exactly the same as physics.addBody. It just happens to be routing through the MTE library file, so to speak. In fact you could just use your own require statement and make the physics calls directly if you wanted to.

Tiled is the only map tool supported. Tiled does support WYSIWYG placement of images on object layers- those images just have to be from a tileset. You could load any image you want as a tileset of 1 big tile and drag that to any position on an object layer. Or you could store many of your level elements in an imagesheet and use that as your tileset- just make sure each “tile” has the same dimensions and they’re arranged in a grid within the tileset. It isn’t the perfect solution, but expanding MTE to support other editors is just way beyond the scope of the project. I’m slammed as it is trying to bring it to retail release! It wouldn’t be all that difficult to do, really, but I can’t afford to slip it in before 1.0.

On an unrelated note, the rewrite will have limited support for Normal Maps driven by a single point light source assigned to a sprite. This is one of those things I’ll need people to test after its out this friday, as I don’t have the time, tools, or expertise to create normal maps myself. The normal mapped floor in the video below comes curtesy of DeadPixel, who may or may not still be hanging around the forums somewhere.

[media]http://www.youtube.com/watch?v=tO3-Jgydetg[/media]

Keep in mind that normal maps require Premium Graphics restricted to Corona Pro and Enterprise users. It is also a pretty big performance hog best saved for high-end devices.

thanks Dyson - Thanks for the work around tip with Tiled.  So would I be correct in saying one might then:

* create a tileset(spritesheet) for each set of image sizes you might want to use. Say have a 100x100 tileset, then 200x200, etc

* then as you create a new image for the game you create it in the tileset that fits it, such that you keep that image size to the that of the tileset

A few questions:

a) does MTE then place the image in the precise place on the screen? i.e. will it be a what you see on Tiled will be what you get in Corona re the image placement?

b) any guide re what size tileset you should be using, or I guess the answer to this would be the same as the general answer to how big a spritesheet should/could be for a corona app?  (i.e. depends on target device etc)

c) does MTE support using the Tield objects, e.g. such as a line.  That is if I put an image (from a tileset) and place it, MTE will display it where I want.  But then if I drew a zig-zag line also in Tiled, could I within my app (using MTE) pick up the coordinates of the line and use it for moving the image along the line?  

regards

Greg

I recommend having a look at the Platformer - Angled PHYSICS 0v958 sample project as it does a lot of what you’re asking about. Specifically check out AngledPhysics3.tmx in the Platformer Angled Tiled Map folder. It includes examples of every kind of Tiled vector object as well as pixel-perfect placement of tiles on an object layer(the metallic tiles near the big red pipes). The brighter of the three off-grid tile objects also has properties set to change it’s size when the map loads, helping to mitigate the need for multiple tilesets of different sizes. It isn’t a perfect solution, but its workable. 

MTE will load the entire contents of the map into memory, including objects like polylines. You can set properties to display the polyline if you want, or you can just use it’s data for your own purposes. MTE won’t automatically move an object along a polyline of course, but you could program this behavior easily enough. For example, if you created a line and named it zigZag1, you could retrieve it by calling “local zigZag = mte.getObject({name = zigZag1})” The line data would be at zigZag.polyline, if memory serves.

Hi,

I just purchased MTE a few days ago, and today I was reading the documentation and I see in the FAQ that “MTE does not mesh with Box2D or other black box physics systems. Integrated physics functionality may come in a later release, but not anytime soon.”  I’ve seen samples where physics has been implemented with MTE, so I’m not sure I understand the limitation mentioned in the FAQ. Could you please expand a bit more?

Thanks in advance

Hector

The FAQ is outdated - MTE has been working well with Box2D for quite some time…

Apologies, some of the documentation is pretty badly outdated. The most up-to-date elements are the API and the Reserved Properties lists. The whole of the documentation will be overhauled after the rewrite is complete, towards the 1.0 release.

MTE does indeed support physics and has for some time, as SegaBoy stated. The Platformer - Angled PHYSICS 0v958 sample project makes extensive use of Corona’s Box2D physics implementation.

Great, thanks very much I’m getting started with MTE and it looks fantastic

Regards

Hector

Hi, can I pay you using PayPal?

Thank you in advance!

Of course, egruttner. What I do in these situations is send a paypal invoice for the cost of MTE. When the invoice is paid I generate a 100% sale code to use on the Gumroad sales page. Using the code will reduce the price on Gumroad to $0 and prevent Gumroad from asking for payment information. The reason I do it this way is to make sure all my customers are represented in the Gumroad customer database, so that I can easily send updates out to all of them. If this will work for you please send me your paypal-registered email address in a personal message and we can get started.

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 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.