Million Tile Engine Beta Release

Hi, I’ve now done this. Results below…

0v844 Demo / HTC One X / Asus Transformer Prime
CastleDemo / 50 / 50
Platformer - Sonic Finale / 50 / 50
RotateConstrainStoryboard / 50 / 50

Both devices: Mostly smooth as before but occasionally drop to around 42 avg FPS, at which point a slight visual lag is noticable in the background movement. In CastleDemo and RotateConstrainStoryboard it’s barely noticable since the character plods around at a steady pace but on Sonic it is more so. It’s still very fast and smooth but I think the occasional momentary lags were just noticable enough to warrant sticking with a cap of 30 FPS for now.

Hi dyson,

I’ve been trying out something that might sound a little crazy that appears to work on the phone but not in the simulator.  I guess it’s therefore a simulator issue but I thought you might have a view on this and it might be of general interest to you anyway.

I wanted to test using an entire large picture rather than tiles repeated.  I know I could load this as a single image using Lua and move it around but I wanted the benefit of tiles as well.  I’ve also considered having it as an image background and tiling over it somehow (not sure on how I’d do that yet).  So my first route is to use Tiled to split it down and your engine to take advantage of the performance in culling and all it’s great functionality. 

The image loaded into Tiled was 5184 x 6400 pixels and split into 32 x 32 tiles.  Hence 162 x 200 tiles and therefore around 32,000 tiles (crazy eh?).   The image is jpg at about 1.7mb.

So I got it running in the simulator, I can see my buttons to move it around and an animated sprite character on the screen that moves fine.  One button’s image has gone very strange (graphics overwritten) so I suspect an odd memory issue here (not my machine, that’s got 16gb with loads of spare free mem).  The stats you setup in MTE only show about 2.7mb being used on the simulator, it also only shows 234 tiles on the stats.

The main issue is that there’s no tiles showing, it’s all black.  It’s like it’s not actually showing the tiles at all hence the low memory being shown.    However, running it on my phone it works perfectly.  I could live with that but it’s hard to develop without the simulator showing what’s on screen.

Any ideas?

Thanks

Did some more testing using the exact same image on this and found that it’s due to some sort of limitations.  When I reduced the number of tiles to 128x128 at 32x32 pixels per tile it worked, anything more than that it’s a black screen and odd looking images (like desktop menu’s) appearing on the buttons.  

I could double the number of tiles to 256x256 if I reduced the tile sizes to 16x16.  It’s not linked to the image disk size as I tried it at various levels of compression from 1.7mb to 11mb in size and all worked fine t 128x128.  

The only constant constraint seems to be that the image can’t be more than 4096x4096 pixels when cut into tiles.

On a different topic, I’ve noticed that when zoomed out, even on smallish maps 50x50 for instance) if you swipe the screen to drag the map over the image freezes momentarily and then jumps to the new location.  If you take the same action when zoomed in it’s not noticeable.   If you swipe slowly it’s fine, if you swipe at a reasonable level it’s a bit stuttery.  It happens whether you lift your finger off or keep it touching.  lifting off gives a worse result.

I’ve pinned it down to the moveCamera function and this behaviour existed in the previous version as well.  I imagine the moveCamera function is doing an awful lot when zoomed out so it’s hardly surprising.  My only fear is the complaints from users who don’t appreciate the complexity of the operation when moving large numbers of tiles (that just appear to be an image).

I don’t want to take away the ability to drag the image.  If the performance hit has no easy solutions then it might be worth considering adding an optional easing function to moveCamera to slow it down a bit and mask the issue.  Perhaps it could be eased by limiting the delta on the drag function in the code to prevent large scale movements in one go when zoomed out.  That would still allow the slower drag.

Thanks.

Thanks for the performance numbers, AppDeveloperGuy! That is good to know.

I’ll be spending the next few days finalizing and testing MTE’s new functions and features ahead of a new release on Friday of next week. 

New functions include:

getSprites(parameters)

getTilesWithProperty(key, value, level, layer)

preloadMap(src, directory)

getLoadedMaps()

unloadMap(mapPath)

drawObjects()

drawObject(name)

redrawObject(name)

I’ve changed loadMap() and refresh() to support selective map unloading. A developer can now choose to hold maps in memory to facilitate loading into them quickly at a later time. 

The new cullingMargin parameter for goto() will allow the dev to specify how far the active culling region should extend beyond the edges of the screen. The Physics simulation will also continue to run in this enlarged region.

MTE is now better at filling the screen when “letterbox” scaling is set in the config.lua file. 

I’ve made several improvements to MTE’s handling of physics objects. Physics objects may now be moved with MTE’s standard movement functions such as moveSpriteTo(). 

Non-physics sprites will no longer automatically park unless their “park” flag is set to true. 

Finally, of course, there is the addition of physics and draw support for Tiled’s Polygon, Polyline, Ellipse, and Box/Rectangle objects. All of these objects can be rendered to the screen as vector objects and given physics bodies. They will all automatically self-generate matching physics shapes if their “shape” property is set to auto or nil. Developers can now also modify a Tiled Object’s physics/display properties and redraw that object. 

You may have found a bug in the Simulator. In either case, you have to keep in mind that devices have a maximum texture size. I believe most modern computers have a limit of 4096x4096, while the older phones have a limit of 1024x1024 and newer devices 2048x2048. When you try to load an image, like a tileset, larger than these dimensions Corona SDK automatically scales it down to fit inside this maximum size. This will lead to degraded quality if the scale difference is large enough. 

Even though your 5184x6000 pixel tileset loaded fine on your phone, I recommend sticking to 2048x2048. 

MTE’s memory readout is most useful for gauging how much memory your maps use. It does not report on texture memory. You can use Corona’s system API to see the texture memory in use:

print(system.getInfo("textureMemoryUsed"))

Very large images can take enormous amounts of texture memory. Unfortunately I don’t think we have a function for reporting a device’s total texture memory.

As for the touch scroll performance issue, how far have you zoomed out/what blockScale and screen resolution are you using? I’ve noticed stuttering issues myself, and I’ll certainly look into it today. It’s possible the touch event is calling moveCamera more often than necessary.

The slight stutter with moderate motion is probably just the performance impact of moving large numbers of tiles very quickly. The momentary freeze at high speeds happens because the camera movement functions call a goto() if the effective velocity in a single frame exceeds blockScale * 4. This is normally unnoticeable until you increase the number of onscreen tiles, which both slows down the goto() operation and increases the effective speed of a swipe on the map.

A super easy fix is to simply clamp the velocity you’re sending to moveCamera to just under blockScale * 4 in any direction. In the pinch zoom touch scroll code I’ve posted before, the following code in the enterFrame event achieves just that:

if isDragging then local velX = (startX - currentX) / scaleFactor / mapObj.xScale local velY = (startY - currentY) / scaleFactor / mapObj.yScale if velX \> mte.blockScaleX \* 4 then velX = mte.blockScaleX \* 4 - 1 elseif velX \< mte.blockScaleX \* -4 then velX = mte.blockScaleX \* -4 + 1 end if velY \> mte.blockScaleY \* 4 then velY = mte.blockScaleY \* 4 - 1 elseif velY \< mte.blockScaleY \* -4 then velY = mte.blockScaleY \* -4 + 1 end print(velX, velY) mte.moveCamera(velX, velY) startX = currentX startY = currentY end

Our robot really gets around!

z1co.png

Wow, iso looks really nice Dyson :slight_smile:

Wow! - That’s absolutely amazing! I can’t wait for Isometric! :smiley:

Nice stuff! :slight_smile:

Check out the new examples, videos, and documentation:

https://devs.ouya.tv/developers/docs/corona.md

I have an Ouya, and have run MTE’s Sonic example and it runs great. Just FYI :slight_smile:

ooooooo nice! This sounds great!

That’s great news! Out of curiosity, were you running it at 30 or 60fps? I’d think with it’s overclocked Tegra 3 the Ouya could handle 60fps.

After fiddling around with isometric(staggered) maps I’ve decided to shift my focus to true isometric maps. My reason is that staggered maps do not visually fit to the actual data in an easily visualized or understood fashion. For example, moving a sprite from location 1,1 to 1,2 to 1,3 and so forth causes the sprite to move in a zigzag pattern rather than a straight line. In order to move diagonally across the screen you must move the sprite in a bizarre 1 to 2 to 1 to 2 stepping pattern such that it’s true movement against the map data is something like a sharp 15 degree angle. On even tile rows the Up direction is to the right, while on odd rows the Up direction is actually to the left. As you move through the map the orientation of the sprite in its local environment flips wildly around. 

True isometric maps are so much easier for the end user to use. Taking into account that everything is rotated, up is always up, left is always left, etc. Moving a sprite in a straight line will, in fact, move the sprite in a straight line! Those of you using A* algorithms won’t have a near-impossible situation to contend with. It really is just a square map rotated 45 degrees and squashed slightly. 

The plan currently is for all of MTE’s movement functions to conform to the isometric projection of the map data. So, if you set your Y velocity to 10, the sprite will move at an angle down screen along the Y axis of the isometrically projected map rather than straight down the screen (which would be diagonal movement through the map data).

Isometric and Isometric(staggered) maps are visually indistinguishable except at the map edges. Staggered maps are square, while isometric maps are diamond shaped. Tiled v0.9 supports both map types.

Putting the finishing touches on two last-minute additions for Friday’s update:

  1. In Tiled it is possible to load a tileset with larger tiles than the tile size of the map. These large tiles now display correctly in MTE.

  2. Listeners. The function addPropertyListener(property, listener) will dispatch an event whenever a tile with the specified property loads into MTE’s active culling region; essentially, the event fires when a tile generates a display object for itself. The function addObjectDrawListener(name, listener) dispatches an event when MTE draws an object with the matching name. This only happens when the player calls one of the object draw methods, for example drawObjects(). 

plb.png

In the above image every tile with the “orientation” property is tinted red, every tile with the obsolete “m” property is rotated 45 degrees, and the static physics object named “testRect1” is rotated 45 degrees.

local onOrientationProperty = function(event) event.target:setFillColor(255, 0, 0) end mte.addPropertyListener("orientation", onOrientationProperty) local onMProperty = function(event) event.target.rotation = 45 end mte.addPropertyListener("m", onMProperty) local onTestRectObject = function(event) event.target.rotation = 45 end mte.addObjectDrawListener("testRect1", onTestRectObject) mte.goto({locX = locX, locY = locY, blockScale = blockScale, cullingMargin = {top = 400, bottom = 400, right = 400, left = 400}}) mte.drawObjects()

You can also generate sprites from tiles as in the following image:

2y9a.png

Every tile with the “m” property generates a sprite duplicate and then destroys itself.

local myObjects = {} local onMProperty = function(event) myObjects[#myObjects + 1] = event.target:makeSprite() myObjects[#myObjects].bodyType = "dynamic" mte.updateTile({locX = event.target.locX, locY = event.target.locY, tile = 0, layer = event.target.layer }) end mte.addPropertyListener("m", onMProperty)

How would enemies be handled if it doesn’t support corona’s built in physics engine. I bought it today!

Ah, but MTE does support Corona’s built-in physics engine, and it’ll have even better support this Friday! I suggest checking out the CastleDemo, RotateConstrainStoryboard, and non-physics Platformer sample projects to see what non-physics movement and collision detection entails. It does get rather difficult as you try to handle more complicated movement and collision detection, which is one of the reasons I’ve been working to bring Physics support to the engine.

Cool. Im also trying to make the player move using the accelormeter? 

Hi, just a quick question. I’m trying to make a game that has a destructible map. How can I overwrite a block at a specific x,y in the map?