Tile editor

BlitzMax Forums/BlitzMax Beginners Area/Tile editor

po(Posted 2006) [#1]
I'm trying to make a basic tile editor:


I've made a type that should create the set amount of tiles right from the start, then if I wanted to change the tiles all I would do is click on it and it would change the frame of that particular tile (rather than create a new tile). But it doesn't work, apparently the image inside of the Draw() method is null... I'm lost. Anyone know how to get this working? All it needs to do is fill the screen with frame 0 of the tileset:

-Thanks


ImaginaryHuman(Posted 2006) [#2]
I'm confused why you have this `tile` type which seems to be being used to describe the whole tilemap (all the tiles), while at the same time you're using this same type to define each individual tile within the map.

It obviously isn't going to draw a given tile with an image, because you haven't copied over the image data from the main master tile, to the sub tiles. In your Create() method you need to make a new tile instance, set the x and y, and also set its other flags.

I think frankly that you'd be less confused if you had two separate types. A TileMap type, and a Tile type. The tilemap type should be only used to store the tileset image and the grid of tile objects. Each Tile type should be used to store only the number of the image from the tileset. To draw a specific tile you would then go TileMap.Tile[x,y].Draw(), which would just retrieve the number of the tile to use, and then DrawImage with the image that is in the parent type (TileMap), ie DrawImage Parent.tset,x,y

Keep your tilemap in an array in the TileMap type and then just have Tile types for storing the frame number. At the moment you are confusing yourself by reusing the tile type for both purposes, and apparently you are just re-creating one tile over and over because when you Return t from the Create() method it isn't going anywhere.


H&K(Posted 2006) [#3]
@po HI
Local tset:TImage=LoadAnimImage(timg$,tsx,tsy,0,tfrms)
This isnt being attached to the Object

But angel is right, whislt doable to stick it all in one type. Unless there is some "mechanic" reason not to, Its normally a lot better to stick this sort of thing into two types

If you want to stick to a one type model, then you need to brushup on Global/Local within types


po(Posted 2006) [#4]
Ah thanks guys, that clears things up a bit.


ImaginaryHuman(Posted 2006) [#5]
Yah welcome. Seems like there is renewed interest in tilemap editors lately.


H&K(Posted 2006) [#6]
Isnt there some TileMap code in the archive? I would be very supprised if one of the early addopters hadnt written something


po(Posted 2006) [#7]
Ermm.. I'm still confused :)



I'm not too familiar with arrays unfortunately, as I've never had to use them before. I tried anyways.

I added a template type just to be tidy.

So there is supposed to be a tile array inside the Create() function in the tilemap type right? It will store the positions of all of the tiles? Then I draw each tile individually inside the Draw() method in the tile type using the tile array's data?

EDIT: H&K this was fairly helpful: http://www.blitzbasic.com/codearcs/codearcs.php?code=1361


H&K(Posted 2006) [#8]
Yes, TileMap needs to contain as a field an array of type Tile. Unless you wish to continue down your path of TLists, in which case make it a Tlist (But I wouldnt know how to do this)

Dont forget the aim is for Tile.draw to be called from TileMap.Draw


po(Posted 2006) [#9]
Ohhh.. So with the array in there, there's no need for lists..


H&K(Posted 2006) [#10]
Well....... some people would say its good practice to keep a full Tlist of your objects. But I dont bother


CS_TBL(Posted 2006) [#11]
A good universal (2d) map-editor would be handy, but many of them are too specific/limited or just have a terrible interface to work with.


po(Posted 2006) [#12]
Let me get this straight (see the above code). tile[j,i] is an array when used, will give me the x and y coords of an individual tile? If not then how do I get the x/y coords and draw all the tiles?


Amon(Posted 2006) [#13]
Hi Po. I worte this for you. It's a Single Screen TileMap editor using an Array to store the tiles.

Press space to change the tile and use the LMB to place a tile. Theres no border checking so you'll get an error when you try to draw outside the screen. It's simple to put border checking in and I'll add it if you want me to.

Hopefully you can adapt this to your game or use the method to implement a Type based Map Editor.
:)

'########################################
'###   TileMap Editor Example for Po    #
'###   Author - Amon                    #
'###   Version 0.2                      #
'###   Date 29th/June/2006              #
'########################################

SuperStrict



Graphics 800,600,32,60

Global tiles:TImage = LoadAnimImage("tileset.png",32,32,0,7)

Global TileSize:Int = 32 ' The size of our tiles

Global MapWidth:Int = 800/TileSize 'The width of our Map Array. Divide the screenwidth by the tileSize to get max tiles on screens width
Global MapHeight:Int = 600/TileSize ' Same as Above but divide by Screen Height

Global MapArray:Int[MapWidth,MapHeight] 'Setup our TileMAp Array which holds the tiles.

Global MX:Int, MY:Int ' MouseX & MouseY

Global CurrentTile:Int = 0 ' Holds the current tile number

For Local xiter:Int = 0 To MapWidth-1
	For Local yiter:Int = 0 To MapHeight-1
		MapArray[xiter,yiter] = 0 ' fill our Map Array with a number to respresent a blank tile
	Next
Next


While Not KeyHit(KEY_ESCAPE)

	Cls
	
		MX = MouseX()/TileSize*TileSize
		MY = MouseY()/TileSize*TileSize
		
		ChangeTile()
		PlaceTile()
		DrawMap()
		
		DrawImage tiles,MX,MY,CurrentTile
		
	
	Flip
	
Wend

'#######################################
'# DrawMap Function					   #
'# Returns = None                      #
'# Draws our map to screen             #
'#######################################
Function DrawMap()
		
	For Local x:Int = 0 To MapWidth-1
		For Local y:Int = 0 To MapHeight-1
			DrawImage tiles,x*TileSize,y*TileSize,MapArray[x,y]
		Next
	Next
	
End Function

'######################################
'#Place Tile Function                 #
'#Returns = none                      #
'#Places our tiles on screen          #
'######################################
Function PlaceTile()

	If MouseDown(MOUSE_LEFT)
		MapArray[ MouseX()/TileSize , MouseY()/TileSize ] = CurrentTile
	EndIf
	
End Function

'######################################
'#Change the current Tile             #
'#Returns = None                      #
'#Changes the current tile            #
'######################################
Function ChangeTile()

	If KeyHit(KEY_SPACE)
		CurrentTile:+1
	EndIf
	
	If CurrentTile >6 Then CurrentTile = 0
	
End Function




Put the tileset in the same directory as the bmx file.


ImaginaryHuman(Posted 2006) [#14]
CS_TBL I'm working on an editor at the moment which will have lots of tilemapping capabilities plus lots of other things. It should be more what you're seeking, when it gets done ;-)


po(Posted 2006) [#15]
Thanks Amon, I'll try and get it working with types.


Scott Shaver(Posted 2006) [#16]
this might give you some ideas

maxgui map editor with source

www.scottshaver2000.com/forum/viewtopic.php?t=140

and you'll need the map module from here

www.scottshaver2000.com/blitz/bmaxmods/sas.mod.zip


po(Posted 2006) [#17]
OK, I've figured some things out, and I now know what's really confusing me :)
How do you make an array of a type?
Current Code:

That damned array is the only thing stopping this thing from working, if you try to run it right now you get: Compile Error: Expression of type 'Type' cannot be indexed.
I found nothing in the docs about creating arrays of types. I think I understand how to make Int arrays, but not how to create an array of a type (in this case type tile).


H&K(Posted 2006) [#18]
That because you are putting the array into the draw of Type tile.
The array wants to be 1) A field of type Tilemap
2) Used to draw the individual tiles from Tilemap.Draw

What you want to do, is finish The Tile type BEFORE the tilemap type. In Tile.draw(x,y), pass to it the x,and y position of where it only is to be printed, and just print that one tile

Then Make the Tilemap type, and inculed in its fields an array of TILES. The when you are in TileMAP.draw loop through the tiles you have, and call the ones you need to print <ie Tilearray[i,j].draw (x*24,y*24)> , passing (X,Y)


Dont forget the "Object", in this case a TILE, does not (Well need not), know of anyother Tiles, so dont reffer to ANY tile otherthan self, when in a tile function/method <--- This is NOT a LAW


When you are happy with that. (ie when it works), try to think where it would be better to put the Graphics/Pxc/jpeg etc for the tilemap. Would it be better attached to a tile. (Each tile has its own Graphic or a pointer to a graphic), or would it be better attached to TileMap, or should you make a new Type?


po(Posted 2006) [#19]
OK, I think I've figured it out:

Still doesn't work, but at least it compiles now :)
Tells me I'm trying to access a null field/method on this line: tiles[x,y].tfrm=0
If I can't do that, then how am I going to create all the tiles from the beginning?
I'm storing what frame each tile is as a tfrm:int field inside the tile type.


H&K(Posted 2006) [#20]
Either in the create for tyle map, (Or in the field Tiles:Tile[0,0]), you need to actuaaly "Create space" for the array.

In fields What you are doing at the moment is creating an array of 0,0, then not resizing it (edit what you Might have done at the moment is crate a pointer to an [0,0], but not created any array).
I would (As you seem to only want one TileMap, or if all tilemaps will be the same size), allocate the space for the array, in the Field allocation.

BUT going the way you have chossen you are not returning your tilemap object from Create. Add a return TM, and you need to refer to the tile array as Tilemap:Tiles or TM.Tiles (When in the FUNCTION). And most impotantly you need a NEW array to allocate (This might mean you need to change the field to [,] :but Im not sure)

Po, I am impressed that you have continued with your code rather than with amons. But you do realise that there will come a point when the only person who can tell why it isnt working will be you?


po(Posted 2006) [#21]
Heh, I apologise for asking so many questions, but I have a bad habbit of not getting things finished. I am determined this time though, which is the reason for the questions.
I am sooooo close now.
So what you're saying is the I need to include the tiles[] array in this part:
Local tm:tilemap=New tilemap	
     tm.tset=LoadAnimImage(timg$,tsx,tsy,0,frms)		
Return tm

But no matter how I try and work it in there I only get errors.
Again, sorry to be a bother, but I'm new at this sory of thing, and I am too close to give up now.


H&K(Posted 2006) [#22]
You need either this

Field Tiles:Tile[,] = New Tiles[MaxMapX,MaxMapY]
In side Type Tilemap

or

Field Tiles:Tiles[,]
'Then in the create:TileMap 
TM.Tiles = new Tile[MaxMapx,MaxMapy]
As you can see You need to do two things. First tell the type that it will have an array "Field ArrayName:ArrayType[,]" then you need to make the space "New ArrayType[num,num]"
If you know how big the map in tile map is going to be, put everything into the field. To be able to have different map sizes then put it into the Create

NOTE
---------------------------------------------
Field ANY:Int[,] = New Int[20,22], will produce an error in some versions of the community IDE. If you have this problem, delete any spaces inside the [] that the ide adds, then use the up or down keys to leave the line


po(Posted 2006) [#23]
Alright, I did the second option you have there, as the amount of tiles on the map are decided by the user.


It says these two methods/fields lines are null though:
tiles[x,y].Draw(x*tsx,y*tsy)
and
tiles[MouseX()/tsx,MouseY()/tsy].tfrm=ctile

I am oblivious as to why this isn't working.. No matter what I do those lines are always null..


H&K(Posted 2006) [#24]
The return tm, wants to be at the end of the function. Anything after it isnt being run. Move it, let me know if the error disapears.


po(Posted 2006) [#25]
After moving Return tm to the bottom of the function, those two lines are fine, but now this line is attemting to access field or method of null object:
tm.tiles[x,y].tfrm=0



H&K(Posted 2006) [#26]
x and y should be from 0 to tnumx-1 and tnumy-1 respectivly

An array[10,10] runs from [0,0] to [9,9]

You need to change it in both draw and create


po(Posted 2006) [#27]
I changed it, but I still get the same error on the same line.


H&K(Posted 2006) [#28]
Sorry totaly my fault.

Do you remember when I said that the array need space given to it? Well the Int in title also needs space.

Field tfrm:Int = 0


po(Posted 2006) [#29]
I gave Field tfrm:int an =0 at the end, but I still get the same error on the same line :)


H&K(Posted 2006) [#30]
Well, Im stuck,

tm.tiles[x,y].tfrm=0
This would only give the error you have if
1) Tm doesnt exist. (Which it does)
2) X or Y are greater than tnumx or tnumy (Which you changed in both loop, right?)
3 Tiles[,] is unallocated, which it isnt
or/and
4) tfrm is unallocated, which it isnt

Post the whole code again, and Ill look, but try to see if you have made an error in any of the four above.

oh and 5) 0 (Zero), isnt a number. errr


po(Posted 2006) [#31]
Full source:

EDIT:
Let's try and cancel out the probable causes here. The full error says: Unhandled Exception:Attempt to access field or method of Null object on this line:
tm.tiles[x,y].tfrm=0


1) Tm doesnt exist. (Which it does)

You're right, tm does exist, we made a new one, then we returned it in the Create() function:
		Local tm:tilemap=New tilemap
			tm.tset=LoadAnimImage(timg$,tsx,tsy,0,frms)	
			tm.tiles=New tile[tnumx,tnumy]					
		
		For Local x:Int=0 To tnumx-1
			For Local y:Int=0 To tnumy-1								
				tm.tiles[x,y].tfrm=0									
			Next
		Next
		
		Return tm


2) X or Y are greater than tnumx or tnumy (Which you changed in both loop, right?)

Yes, as you can see both For loops are from 0 to tnumx/tnumy-1:
Draw() method:

		For Local x:Int=0 To tnumx-1
			For Local y:Int=0 To tnumy-1
				tiles[x,y].Draw(x*tsx,y*tsy)
			Next
		Next

Create() function:

		For Local x:Int=0 To tnumx-1
			For Local y:Int=0 To tnumy-1								
				tm.tiles[x,y].tfrm=0									
			Next
		Next

Also, tnumx and tnumy couldn't possibly change seeing as how they are both Const's set at the top of the code.

3 Tiles[,] is unallocated, which it isnt
or/and
4) tfrm is unallocated, which it isnt

Exactly, they both have predetermined values:
Field tset:TImage,tiles:tile[,]
and
Field tfrm:Int=0

So I just can't figure it out. Can you?


po(Posted 2006) [#32]
Any solutions anyone?


H&K(Posted 2006) [#33]
Point three is allocated here,
tm.tiles=New tile[tnumx,tnumy] 
But other than that your synopses is right. Ill actualy test it tomorrow for you.
As a "It cannot possibly be that", put the field for tiles[,] on a different line


po(Posted 2006) [#34]
Yeah, putting it on a new line doesn't cange things.
Thanks for testing it in advance though.


H&K(Posted 2006) [#35]
Doooh. @ H&K
Change
tm.tiles[x,y].tfrm = 0
to
tm.tiles[x,y] = New tile

What was happening was that Although the array had been allocated, each individual Tile had not.


This now means the types are finished, you still get an error, (In Max2d), so that probably something to do with the image, (Which Im even more usless at than this)


po(Posted 2006) [#36]
Yesssssssssssssssssssssssssssssssssss!
Thanks for all your help, it finally works!