Trying to Autotile [Solved]

Hey all,

I recently purchased codea and have been using it nonstop since. I can’t seem to put down my ipad now. This app simply rocks!!

Now to my question. Has anyone been able to get an autotile system working for a 2d rpg type game to read tile sheets and print a flawless map?

I have been basically trying to develop an rpg “engine”, something similar to rpg maker, but exclusively for codea. I can read the tile sheets and pull out the correct tiles for the most part, but the process causes a lot of lag. I don’t understand how it could be lagging so much with such simple sprites and such a small map (20 by 20 tiles). I am essentially taking a large tile sheet and pulling out each individual 16x16 tile that is needed, then splitting that into 4 to adjust for corners and such.

I am currently only drawing the tiles needed to fill the screen, which is 19 by 15. The player is always drawn in the center so it uses the player position on the grid map to determine which tiles need to be drawn.

I am using 2 grid maps at the moment: one for ground tiles, the other for objects on the ground (Later will need to add an events grid). Every map I make will need to have their own grids.

When I draw the map, I loop through the x and y coordinates using a nested for loop. For each coordinate, I draw the autotiled ground and then the object and finally the player (only when x and y match the players current coordinates). Drawing it out this way guarantees that the player can go behind things such as walls, trees, buildings, etc.

Like I said, I got the autotile to work correctly (with a few graphical errors), but the lag it creates is horrible and I can’t seem to figure out why it would be running so slow.

Example map:
Map = {
{1,1,1,1,1,1,3,1,1,2,2,1,1,1,2,2,3,3,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2},

}

Object map is the same format. The numbers indicate a tile id. Stored in the tile array are the tiles copied from the tile sheet (I programmatically create every tile from the tile sheets).

Tiles array example:
Tiles = {readimage(tile sheet):copy(x,y,32,48), readimage(tile sheet):copy(x2,y2,32,32), …}

These x and y variables are hardcoded numbers since the position of the tile in the tile sheet will never change. The tiles above are actually 6 tiles which I further chop up to be used when autotiling.

Is the lag due to me making so many image copy calls? If so, I have no clue to work around this except to simply save out every single tile as its own individual sprite, which would definitely be a pain but I did, however, make a quick app that does just this, except every image on the tile sheet must be the same size (like character sheets).

Hopefully I didn’t just confuse you all. When I do get this autotile to work properly and without lag, I will definitely share the code as it will help many of you who are trying to develop an rpg of some sort.

Thanks,
Slashin8r

Glad to hear you’re enjoying it, we feel the same way about Codea!

The lag is probably due to all the image calls. You may get some speed improvement by creating all the tile sprites, but you should try using a mesh instead. At the moment, Codea is going through a series of steps to draw each sprite.

A mesh will batch the sprites so several of the steps will only happen once, rather than for each sprite. However, only one image can apply to a mesh. This means you can only batch tiles that use the same image, or the same tilesheet (because you can specify which part of the image to use). If you want sample code, just ask, because I am currently building some tutorials around top down 2D gaming.

I understand the next version of Codea may improve sprite performance by batching them, but that doesn’t help you right now.

Depending on your programming skills, you might want to explore “weak” tables, too. See here : http://www.lua.org/pil/17.1.html
Weak tables can store tile images as you cut them out of the tilesheet, so you can look them up from there next time - so far this is normal table behaviour - but what weak tables do is delete items if they haven’t been used recently, reducing memory requirements.

Thanks for the quick reply.

I will definitely look into using a mesh, haven’t tried one out yet, but I’m sure I will catch on fairly quick.

Here is some basic code

    --inside draw
    local mm={} --table of meshes, each one for a particular tile image, eg a tree
    for x=1,mapWidth do
       for y=1,mapHeight do
          local t=map[x][y] --look up tile we need
          if mm[t]==nil then  --add new mesh if we don't have this tile image yet
              mm[t]=mesh() 
              mm[t].texture=tiles[t]  --assumes tile images are stored in tiles table
          end
          --add tile to mesh (x,y,w,h)
          local u=mm[t]:addRect((x-1)*tileSize,-(y-1)*tileSize,tileSize,tileSize)
          --apply tile image texture (u,x,y,w,h), below assumes we use the whole image 
         --where u is the rectangle ID returned by the addRect command
          mm[t]:setRectTex(u,0,0,1,1)
       end  
    end
    --go to start of map and draw meshes
    pushMatrix()
    translate(offsetX,offsetY) --top left of map
    for i,m in pairs(mm) do
        m:draw()
    end
    popMatrix()

A couple of tutorials on here may help

http://coolcodea.wordpress.com/2013/03/

Wow, thank you so much! That code you posted is definitely a great start. I was able to implement it easily and the comments are great help.

Update:
Meshes are working way better than what I previously had, but now I got another question.

How do I get the texture of a tile at any given coordinate? Since the autotile will tile based off the tiles around it, I will need to know the new texture given to the previous tiles.

More. The code here (https://gist.github.com/dermotbalson/5864694) will give you a nice lighting effect, using a shader (If you don’t know what that is, treat it as black magic for the moment). You can vary the lighting distance with the parameter I provided, or set it in the code. This is much “cheaper” on processing time than true ray tracing.

Image - http://instagram.com/p/bAhxb5hHRq/

To run this code, you’ll need to substitute your own images in for floor and walls, any size, as long as they tile nicely. You move the little girl by touching inside the map on any side of her.

I’ve done some tutorials on shaders, from here:
http://coolcodea.wordpress.com/2013/06/page/2/
(but don’t let me distract you from the job at hand)

Here is where I am so far:

Image: http://i42.tinypic.com/ndrg9e.jpg

I am really happy with the results so far. The meshes worked out great and everything runs so much smoother. I did have a problem with crashes, but now I generate the map outside the draw function and that fixed the crashing. Now to setup a mesh for objects and then a table for events. Pretty soon I will have fully functional maps, woot!

As you can see in the picture, the autotile still needs some tweaking. Outer corners and inner corners work perfectly, but the straight edges have 2 tiles per side and it obviously gets it wrong about 50% of the time. Being able to figure out what textures the function gave previous tiles would fix this in no time. Right now my only thoughts are to make a table to track the autotile process so it can reference the changed tiles at any time.

Let me know if you have any further thoughts.

@Ignatz, I copied your code from your Github account, but it gives me an error: “trying to index darkShader, a nil value.” I believe Codea can’t find the vertex and fragment information (for your darkShader shader).

@Ric - dang, I keep forgetting one tab, add this too

darkShader = {
vertexShader = [[
//
// A basic vertex shader
//

//This is the current model * view * projection matrix
// Codea sets it automatically
uniform mat4 modelViewProjection;

//This is the current mesh vertex position, color and tex coord
// Set automatically
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;

//This is an output variable that will be passed to the fragment shader
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
varying mediump vec4 vPos;

void main()
{
    vColor=color;
    vTexCoord = texCoord;
    vPos=position;

    //Multiply the vertex position by our combined transform
    gl_Position = modelViewProjection * position;
}

]],
fragmentShader = [[
//
// A basic fragment shader
//

//Default precision qualifier
precision highp float;

//This represents the current texture on the mesh
uniform lowp sampler2D texture;
uniform lowp vec2 pos;
uniform float dist;

//The interpolated vertex color for this fragment
varying lowp vec4 vColor;
varying mediump vec4 vPos;

//The interpolated texture coordinate for this fragment
varying highp vec2 vTexCoord;

void main()
{
    float d=distance(pos,vec2(vPos.x,vPos.y));
    float j=clamp(1.-d/dist,0.,1.);
    vec4 col=texture2D( texture, vTexCoord);
    col.rgb=col.rgb*j;
    gl_FragColor = col;
}

]]}

Work so far looks nice!

Thanks for the code Brother! Wow, that darkShader looks great. It’s like the character is carrying a torch around the room. I love it.

@Ric - how would you like two effects in one?

There’s a line at the end of the shader: col.rgb=col.rgb*j;

Change it to add “a” after rgb, ie: col.rgba=col.rgba*j;

Then you get mist instead. It won’t look so good unless you darken the screen background to create a contrast.

The difference is simply that we are dialling down the brightness of all the colours, and if we keep alpha the same, then as r,g,b get small, everything goes black. However, if we reduce alpha as well, everything goes transparent rather than blank.

Image: http://i42.tinypic.com/30bky10.jpg

Added in an auto tracker table to follow the changes when auto tiling. It looks a bit smoother in most parts, some are still choppy. As you can see, there are visible lines between each of the 32x32 tiles I placed. I can’t figure out why this is happening. I thought maybe I was cutting up the tile sheet wrong, but I double checked it and that is all good. Then I checked the placement of the tiles, and they are exactly 32 pixels from each other, so there shouldn’t be a line there…

I did upload my tile sheet with retina checked, would that cause this issue? I did notice retina made the image half it’s size, but I figured it would still scale appropriately.

@Slashin8r - it may be an issue with smoothing. Try adding

noSmooth()

I have encountered issues in the past with colour bleeding from one tile to the next (not sure of the exact reason, but think it has to do with the retina displays and their “half pixels”)

Quick and easy fix, thank you very much.

AutoTile

Without those lines, I’d say I’m just about ready to make another map and create an event to go between the 2 maps. :smiley:

A few more tweaks needed as you can see the new tile I added in, cobblestone, is having some difficulty.

Edit: Removed images above. Only need the latest one showing.

@Slashin8r - meant to say looks good.

As an alternative to having two maps, you could have one large scrollable map…

Well the world map will be one large scrollable map, but all the towns, buildings, caves, etc. will be separate maps. I’m just gonna test it with 2 basic maps such as the current one I have.

I also have plans for maybe making multiple worlds in the rpg I want to build.

Events are working, yay!

I added 2 event types so far: Teleport and Popup

Popup is simply popup text that displays at the top of the screen when the player walks over a certain coordinate. Teleport will move the player between maps, coordinates, or both.

Now to combine the two into a third event: Entrance

This event will display the name of the place you are about to enter, then tap screen and teleport to that location. This is perfect for towns and hidden locations (like a camp in the middle of a forest). I never liked it how old school hidden locations were entered automatically, so now you have to pay attention to the popup text or you may miss something.

Here is a short video demonstrating the teleport and popup events.
http://tinypic.com/r/nye904/5

In the video you will notice that the same event can be placed on multiple coordinates (I move up and down and the popup text stays and I teleport from different locations).

@Ignatz, the Mist version of the darkShader is also cool. This could be really useful in a top-down adventure game. You could make it so the map is revealed only after the player explores that region. Otherwise, it remains wrapped in mist. Awesome stuff my friend.