The Ever-Growing Tile Editor

For questions about using Classic.

Post » Mon Oct 22, 2012 8:43 am

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

https://dl.dropbox.com/u/69407974/Map%20Editor%203.cap
crowtongue2012-10-22 08:44:43
B
7
S
2
Posts: 123
Reputation: 1,061

Post » Mon Oct 22, 2012 7:51 pm

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
B
79
S
24
G
52
Posts: 4,725
Reputation: 39,713

Post » Mon Oct 22, 2012 10:07 pm

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 forwardcrowtongue2012-10-23 04:17:24
B
7
S
2
Posts: 123
Reputation: 1,061

Post » Tue Oct 23, 2012 7:35 am

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?
B
7
S
2
Posts: 123
Reputation: 1,061

Post » Tue Oct 23, 2012 9:30 pm

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. Its not as flexible as applying displacement maps, though.
Image
B
13
S
4
G
1
Posts: 113
Reputation: 1,712

Post » Wed Oct 24, 2012 3:38 am

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.
B
7
S
2
Posts: 123
Reputation: 1,061

Post » Wed Oct 24, 2012 7:00 pm

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.
B
79
S
24
G
52
Posts: 4,725
Reputation: 39,713

Post » Fri Oct 26, 2012 1:20 am

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.
B
7
S
2
Posts: 123
Reputation: 1,061

Post » Fri Oct 26, 2012 2:06 pm

[QUOTE=crowtongue]
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)
[/QUOTE] 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)
Image
B
23
S
8
G
10
Posts: 1,820
Reputation: 8,242

Post » Sat Oct 27, 2012 1:34 am

[QUOTE=tulamide] [QUOTE=crowtongue]
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)
[/QUOTE] 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?[/QUOTE]

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.

[QUOTE=tulamide]
+ 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)[/QUOTE]

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!
B
7
S
2
Posts: 123
Reputation: 1,061

Next

Return to Help & Support using Construct Classic

Who is online

Users browsing this forum: No registered users and 8 guests