Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Trying to Autotile [Solved]

edited July 2013 in Questions Posts: 391

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

Comments

  • IgnatzIgnatz Mod
    Posts: 5,396

    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.

  • Posts: 391

    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.

  • IgnatzIgnatz Mod
    edited June 2013 Posts: 5,396

    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()
    
  • IgnatzIgnatz Mod
    edited June 2013 Posts: 5,396

    A couple of tutorials on here may help

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

  • edited June 2013 Posts: 391

    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.

  • IgnatzIgnatz Mod
    edited June 2013 Posts: 5,396

    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 -

    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)

  • edited June 2013 Posts: 391

    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.

  • edited June 2013 Posts: 140

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

  • IgnatzIgnatz Mod
    Posts: 5,396

    @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;
    }
    
    ]]}
    
  • IgnatzIgnatz Mod
    Posts: 5,396

    Work so far looks nice!

  • edited June 2013 Posts: 140

    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.

  • IgnatzIgnatz Mod
    edited June 2013 Posts: 5,396

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

  • edited June 2013 Posts: 391

    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.

  • Posts: 725

    @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")

  • edited June 2013 Posts: 391

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

    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.

  • Posts: 725

    @Slashin8r - meant to say looks good.

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

  • edited June 2013 Posts: 391

    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.

  • edited June 2013 Posts: 391

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

  • Posts: 140

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

  • IgnatzIgnatz Mod
    edited June 2013 Posts: 5,396

    @Ric - nothing clever from me, it just kind of fell out of how it works.

    but your enthusiasm wins you the grand prize of my shader collection, here

    https://gist.github.com/dermotbalson/5868211

    (long press on Add New Project to put it into tabs)

  • Posts: 140

    It's like Christmas! I especially like your study with transparent pixels. Excellent work, as always Mr. @Ignatz.

  • Posts: 391

    So who is ready for another question? Well make it two cause that first one wasn't the real deal :P

    I now have floors and objects being generated correctly, however, the player is either always above or always below the objects, depending on which I draw first. Some objects I need the player to be able to go behind and others I want the player to be able to walk over or up to and appear partially over. How can I go about achieving this?

    I was thinking of drawing the objects the original, but I fear the lag, lol. A weak table would probably do it, but I was hoping to stick with the meshes since they are working out very well.

  • Jmv38Jmv38 Mod
    Posts: 3,295

    Thanks @ignatz.
    Works fine on ipad1 too.

  • Posts: 1,976

    At the end of drawing walls and such, check if the tile above the player is something solid the player cannot walk into, and if so, redraw the player in the same spot, after it's drawn the walls to overlap it. When you first draw the player, though, have it draw before the walls, so it could be overlapped by something below it.

  • IgnatzIgnatz Mod
    edited June 2013 Posts: 5,396

    I had this problem with my 3D tabletop scene. The only solution I found was to sort the meshes by distance from the player and draw from furthest to nearest. I have code if you want it.

    This is because if you draw a pixel on top of one that is already drawn, OpenGL will only do so if the new pixel is closer to the camera than the old pixel. This includes transparent pixels, ie OpenGL treats them as solid, and won't draw anything behind them. There is a workaround if you are having trouble with transparent pixels, and that is to use a shader to discard them altogether, then it shouldn't matter so much if your image is in the right order. It's shader number 5 in my pack just above here.

    The main problem with the sorting solution is if you have a mesh that is big, then what x,y do you use to sort on? It really works best with lots of small meshes, so the sorting is as accurate as possible.

    I'm happy to help if you need it. I also have code for drawing players on top of terrain, if you need to calculate an interpolated terrain height.

  • Posts: 391

    @skythecoder,
    That worked like a charm, thanks for the quick and easy fix.

    @ignatz,
    Time to look into those shader samples you provided. I have a feeling these will come in very handy for the rpg I have in mind.

    Thanks everyone. Now to continue coding and work towards my next question, hehe.

  • Posts: 391

    After checking and rechecking my floor auto-tile algorithm I finally figured out that the algorithm is perfect and it was the tileset I am using that has the graphical errors. Found a better tileset to use and now it looks flawless. :D

  • edited July 2013 Posts: 391

    Here are some screenshots. I have one map set to 32x32 tiles and one set to 64x64 tiles.









    I will add some detailed documentation to my code and then release it to everyone. Hopefully I will have this done sometime in the next few days.

  • BriarfoxBriarfox Mod
    Posts: 1,542

    Very neat idea, have you considered making a full blown editer for this? Shopuldnt be to hard. Load a spritesheet then have the ability to drag tiles to the screen then save the export to a tab which could be coppied into a project and run.

  • edited July 2013 Posts: 391

    @Briarfox, yep that's the plan for future. I plan to turn this into the Codea RPG Maker essentially. I will most likely need help when it comes to making the GUI for it since my mind tends to be more logical than artistic, lol.



    I forgot to post the link to the code in this discussion. Check it out here:


    http://twolivesleft.com/Codea/Talk/discussion/3058/

  • BriarfoxBriarfox Mod
    Posts: 1,542

    @Slashin8r would you consider putting the code up on github? Easier to pull it into existing project, instead of delete and re creation when there's an update.

  • edited July 2013 Posts: 391

    @Briarfox, yeah I will do that when I make it home. Have been on vacation for 10 days and am currently in the car enjoying a 15 hour drive, lol.



    Anyone know a good free app to publish to github? If I could do it from my iPad I will get it up there sooner.

  • BriarfoxBriarfox Mod
    edited July 2013 Posts: 1,542

    Well, (shameless self plug) you could use my autogist app. It version controls to github. can greate an installer and can create an update button to let users update when you release a new version :)

    You can find it under utilities on the wiki.

  • Posts: 391

    @Briarfox, wow thank you so much. That app is awesome and fast. I have uploaded my project and created and auto installer. Links will be available in my other discussion mentioned above.

Sign In or Register to comment.