The Ever-Growing Tile Editor

This forum is currently in read-only mode.
  • So I've come a ways since starting my map editor, thanks to loads of help from this forum (mainly R0j0hound.)

    I can create a map of any size I choose. The bigger ones don't lag horribly thanks to the technique R0j0hound taught me of cycling through tiles using their private variables. I can put different tiles down and then save my map, and load my maps back. If maps are a different size, it will re size them automatically. If I have a huge map and I want to work on a part on the opposite side, I can teleport there with the mini-map by right clicking on it.

    The mini-map shows the tiles that are drawn on it (even if it is kind of glitchy.)

    These are all things I'm very proud of. So what's next?

    Tilesets!

    I want to be able to create custom tilesets inside the map editor during runtime. I have decided to do this using animation frames so I can continue to use the power of private variables, thus I won't be switching to the tiled background technique people talk about.

    So here's my current thinking...

    I have an array called "Tileset." It is 4 x 25 in size. There is a button where you can click "add tile." this will create a new animation frame with a user selected graphic (I believe this is possible with the image manipulator plugin.) I have a canvas and a scrollbar beside the canvas. For each tile added, there is an entry in the array. For each entry in the array there is a tile into the canvas. The canvas will fit 3 rows of 4 tiles each before scrolling.

    The scrollbar will work by an up and down button as well as dragging the middle part. The middle part will have a Y size determined by the size of the array. I believe I can get the scrollbar to work by combining the space between rows and the height of the tiles with the size of the array, and using the lerp function for the scrollbar. This is pretty vague right now but it seems possible.

    The tileset array will be saved along with each map. That way there is always something to point to which images each time a map loads. This way every map should be able to have a different tileset.

    I realize there are some shortcomings, I would ideally like the tiles to all be saved into each map so no one could screw with them, but right now I am just trying to get the basics down.

    Eventually there will also be a system to assign attributes to a given tile (or tile range) so events can be made on each map.

    I am making this thread to ask you for feedback and for advice:

    • Has anyone tried anything like this before? Is what I'm talking about possible?
    • Am I missing any long term considerations?
    • How do I start with this? Everything seems to be so intertwined that I'm not actually sure where to start and how to go about this.

    I appreciate any and all comments. I realize this is ambitious for my second Construct project, but I have a knack for sticking with it. I'd love to share this with the community when it's finished so others can work with it and learn from it as I have.

    Here's my current .cap if anyone wants to take a gander.

    *As a disclaimer it is quite messy and full of bugs. I promise I will clean it up after the basic functionality is intact.*

    dl.dropbox.com/u/69407974/Map%20Editor%203.cap

  • The main roadblock you will encounter is you can't add frames at runtime. But it's key to the design and is probably the first thing you should tackle. Here are 3 different methods to do it:

    Method #1

    You can use the tiledBackground object with power of two sized textures and the image offset action to display only a subset of the texture.

    Here is an example:

    http://www.scirra.com/forum/using-tiled-background-for-image-fonts_topic41196_post253858.html#253858

    The disadvantage of this method is vram usage will be very high if you load a different tileset texture. Loaded textures are unique for each tiled background, so the vram used would be vram_the_texture_uses*number_of_tile_objects.

    Method#2

    Another method would be to keep using sprites with one big frame with all the textures and select the sub-image of the texture with distort maps. When you load another texture all the tiles will be updated since they all reference the same texture.

    Here is an example:

    http://www.scirra.com/forum/rotating-sprites-from-a-spritesheet_topic56037_post349803.html#349803

    The pros of this method is only the vram of one texture is used.

    The con is you still have to deal with all the tiles on one image which could prove laborious to update a single tile.

    Method#3

    Use a different instance of a tiledBG object for each tile. Adding another tile at runtime is as simple as creating another instance and loading the texture.   Keeping the actual tiles as sprites you can select the texture by giving it the texture of one of the tiledBG instances using this plugin http://www.scirra.com/forum/plugin-texture-setter_topic43143.html.

    Here is an example:

    http://dl.dropbox.com/u/5426011/examples15/tiles_TextureSetter.zip

  • OK this is good to know...

    But now this puts me in a tricky spot. On one hand your plugin (Method #3) seems to be the best decision with no obvious downside to it. But if I do that my editor revolves around using the private variables of a sprite in order to reuse tiles and stop from slowing to a crawl if I make a huge map.

    I have no idea how I would achieve the same thing if I switch to Tiled BG.

    On the other hand I could probably keep what I have intact if I use Method #2. But would updating a single tile in one big image be harder than rewriting the code if I switched to Tiled BG?

    *EDIT* I realize after going through the examples that this is irrelevant. Method 3 is a combination of sprites and Tiled BG. This will be how I go forward

  • So I understand Texture Setter and it's pretty brilliant. The hard part of this whole thing isn't going to actually be importing textures or adding textures, it's going to be having the UI elements work how I want them too.

    For starters, I'm trying to import the names of all 100 images in my images folder into my array then display them all in seperate text objects

    For Each File in apppath & "/images"

    For Each Element

    Set Value Array.CurrentX, Array.CurrentY to File.CurFile

    Create Object Text on Layer 1 at (Array.CurrentX * 30 + 20) (Array.CurrentY * 30 +20)

    I then have text items set to display all of the names. For some reason this won't work. I get either all 0's, or nothing at all. I've got a "clear array with 0" event on layout start too.

    What am I doing wrong here?

  • Another variant to maneuver around the roadblock is to insert dummy frames into your sprite, 1x1 pixels in size, as many times as you might want to use at once during runtime. It will be a damn pain to organize them however, but you can use different animations for your tile "classes", like 200 possible tiles for walls, floors, etc. and predefine some rules. It�s not as flexible as applying displacement maps, though.

  • Inserting dummy frames... I hadn't actually thought of that. I'm not sure how that impacts VRAM or whether there is an obvious downside to that. Anyone else care to share? Thanks for the input though I think I may play around with that on my own.

    As an aside I still can't figure out how to use the File Object in tandem with my arrays like I was talking about in my previous post. It dawned on me while I was doing that last night even though I was just starting it for organizational purposes, it's probably a good feature to allow you to automatically load a tileset by setting a directory.

  • Use a global variable to store the list of files in the directory.

    Then set the array size to be the the same as the number of files.

    Then the only loop will be "for each element".

    Start of layout

    +set var to File.FileList("c:\matt\cap\images")

    +Array: set size to len(global('var')), 1, 1

    for each element

        Create Object Text on Layer 1 at (Array.CurrentX * 30 + 20), (50)

        Set text to global('var') at Array.CurrentX

    global('var') at Array.CurrentX

    is a valid expression since File.FileList() is an array data type.

  • This works in theory, just wanted to point out it somehow overloads Construct if there are more than (rough estimate) 40 files in the directory. I think it'll be pretty easy to make an event to split it up into multiple variables.

  • For Each File in apppath & "/images"

    For Each Element

    Set Value Array.CurrentX, Array.CurrentY to File.CurFile

    Create Object Text on Layer 1 at (Array.CurrentX * 30 + 20) (Array.CurrentY * 30 +20)

    Maybe I don't understand what you are trying to do? This code can't work. 'For each file' loops through all the 100 images, and for each image found the array loops through all elements in the array.

    I thought you would want to store each name to one array cell?

    ROJOhound provided an efficient example. Another (not so efficient) way is to stick with 'For each file':

    + some condition that indicates loading begins

    -> Array: Set size to File.FileCount(apppath & "/images") x 1 x 1

    -> System: Set global variable 'count' to 0

    ++ For Each File in apppath & "/images"

    --> System: Add 1 to global variable 'count'

    --> Array: Set index global('count') to File.CurFile

    ++ For each element

    --> Create Object Text on Layer 1 at ((Array.CurrentX % 10) * 30 + 20), (floor(Array.CurrentX / 10) * 30 + 20)

    (Last one assuming you want to place the text boxes on a 10x10 grid)

  • >

    > For Each File in apppath & "/images"

    > For Each Element

    >

    > Set Value Array.CurrentX, Array.CurrentY to File.CurFile

    > Create Object Text on Layer 1 at (Array.CurrentX * 30 + 20) (Array.CurrentY * 30 +20)

    > Maybe I don't understand what you are trying to do? This code can't work. 'For each file' loops through all the 100 images, and for each image found the array loops through all elements in the array.

    I thought you would want to store each name to one array cell?

    This makes sense to me now that you explain it that way, but at the time I thought that it would loop through the 100 images, and for each image it went through it would also go through the array, hence adding a file each time it did it.

    I find Construct makes programmy stuff easy because you don't have to worry about syntax, but sometimes that is only half of the equation. You have to have the understanding of the tools you are using and good old sound logic too. For me, it doesn't sink in to read the problem as much as when I come against it myself. Now I understand 'For Each' better.

    + some condition that indicates loading begins

    -> Array: Set size to File.FileCount(apppath & "/images") x 1 x 1

    -> System: Set global variable 'count' to 0

    ++ For Each File in apppath & "/images"

    --> System: Add 1 to global variable 'count'

    --> Array: Set index global('count') to File.CurFile

    ++ For each element

    --> Create Object Text on Layer 1 at ((Array.CurrentX % 10) * 30 + 20), (floor(Array.CurrentX / 10) * 30 + 20)

    (Last one assuming you want to place the text boxes on a 10x10 grid)

    This actually seems to be cleaner in a way, since with R0j0hound's example the global variable seemed to crash Construct if I tried to store more than 40 things in it, and I essentially had to duplicate that event. Thank you for your help and explanations, Tulamide!

  • I'm glad that I could be of help <img src="smileys/smiley1.gif" border="0" align="middle" />

    I wished there was some similar way of helping for drawing and painting. That's where I'm helpless. (Imagine a 3-years-old painting dad and mom, that's close to my results <img src="smileys/smiley21.gif" border="0" align="middle" /> )

  • So the text objects are all created and they now have all the right file names in them... But they all overlap

    Which way do I change that? If I create an event based on text overlapping text, it effects everything.

    I think I could maybe set the UIDs of every text object to an array, then check each array value against the UID it represents and somehow the position... but I can't quite wrap my brain around this. Is there an easier way?

  • This is where I am as of now.

    <img src="https://dl.dropbox.com/u/69407974/textobject.jpg" border="0" />

    This is supposed to cycle through the array in the subevent and move each Text object, but currently it doesn't do anything. I haven't been able to find which part isn't working right now.

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • + some condition that indicates loading begins

    -> Array: Set size to File.FileCount(apppath & "/images") x 1 x 1

    -> System: Set global variable 'count' to 0

    ++ For Each File in apppath & "/images"

    --> System: Add 1 to global variable 'count'

    --> Array: Set index global('count') to File.CurFile

    ++ For each element

    --> Create Object Text on Layer 1 at ((Array.CurrentX % 10) * 30 + 20), (floor(Array.CurrentX / 10) * 30 + 20)

    I basically used this for creating text objects. There are 71 files in my images directory.

    ... 5042 text objects are created. This is where my troubleshooting has left me.

  • Turns out the best way to do this was with a generic loop:

    or Each File in apppath & "/images/"       

    - Add 1 to var 'count'

    - Array: set index:global('count')to file.CurFile

    Is global('count') equal to             

    File.FileCount(apppath & "/images/"       

    - Start Loop "createtext" and run Array.SizeX times

    On loop "createtext"                    

    - Create Text                            

    - set text to Array(Loopindex)

    This created only the necessary objects. I left positioning the text to another probably unnecessarily long chain of events, but am happy to report that all the objects are created as planned. I can essentially just copy these for my tile objects when I get there.

    Now my new problem... Making the scrollbar control the position of the text.

    The first thing I've done is created a global variable that records the position of the scrollbar as a percentage of how far along it's track it is.

    Then I've created a global variable for how tall all of the text objects are. With simple math I find the beginning of all the text objects, and the end.

    Then on my scrollbar buttons I've created an event

    Mouse is over Downbutton              

    Left Mouse button is down            

    - Set Scrollbar.Y to Srollbar.Y + 1

    - Text: Set Text.Y to lerp(global('beginning'),global('end'),global('scrollposition')

    Since 'scrollposition' is a decimal should it not set Text.Y to the proportionate position? Instead it scrunches all the text objects together at the top of the screen. I can change it to:

    Text.Y + lerp(global('beginning'),global('end'),global('scrollposition')

    This stops it from scrunching all the objects up on top of eachother, but it scrolls through everything so fast there is still about 75% of the scrollbar left.

    Any ideas on how to do this?

Jump to:
Active Users
There are 1 visitors browsing this topic (0 users and 1 guests)