help with seamless tile maps

Monkey Forums/Monkey Programming/help with seamless tile maps

pantson(Posted 2012) [#1]
Hi

I'm having issues trying to draw seamless tilemaps and getting tiny gaps due to the floating points.

Heres my drawing code (I'm using drawrect instead of drawimage at the mo)
	Translate -player_x,0
	SetColor 255,0,0
	gap# = player_x-Floor(player_x)
	i = player_x/60
	j = 0
	While j<800
		DrawRect i*60+j+gap,150,60,60
		j=j+60
	Wend


can anyone help me and explain why its leaving gaps?
many thanks


therevills(Posted 2012) [#2]
Normally when you get this issue, you move your tiles in floats, but display them at ints:

	Translate -player_x,0
	SetColor 255,0,0
	gap# = player_x-Floor(player_x)
	i = player_x/60
	j = 0
	While j<800
		DrawRect Int(i*60+j+gap),150,60,60
		j=j+60
	Wend


I havent yet tried this with Monkey though, so YMMV.


pantson(Posted 2012) [#3]
cheers for the tip..
I tried that, but it still leaved gaps,
This could be due to the fact I'm also scaling the screen to fit different devices

I'll try to fix the int to pixels on screen as well


benmc(Posted 2012) [#4]
Are you rendering on Android? This is still severely messed up on Android. I have to draw all my tiles to overlap or there are lots of gaps. Seems to not happen on iOS or Flash, but Android and HTML5 always leave gaps.


muddy_shoes(Posted 2012) [#5]
It would help if you posted something that ran that shows the problem. As is it's hard to quite understand what your code is meant to be doing. Are i and j ints? What's gap for?

From inspection I'd guess that TheRevills is on the right track but there's one more thing involved. You need to pin the integer starting position of your loop and make the translate input an integer too:

    Translate( Int(-player_x), 0 )
    SetColor 255,0,0
    Local x_start:Int = Int(player_x/60) * 60
    Local j:Int = 0
    While j<800
	DrawRect( x_start+j,150,60,60 )
	j += 60
    End


I still don't know what that's meant to do exactly, but it does a thing without gaps in the rectangles.


pantson(Posted 2012) [#6]
cheers for the pointers everyone

OK after playing around a bit more its to with the scale of the display for different devices.
Heres some self contained running code
Strict

Import mojo

Function Main:Int()
	New Test()
		
	Return 0
End Function

Class Test Extends App
	Field game_counter:Int
	Const GAME_WIDTH:=800
	Field scale:Float
	
	Field player_y:Float
	Field player_x:Float
			
	Method OnCreate:Int()
		Local i:Int
		
		scale = 1.0 'DeviceWidth()/Float(GAME_WIDTH)
	    SetUpdateRate(30)
		game_counter=0
		
		player_x=0
		player_y=0
				
    	Return True
	End Method

  Method OnUpdate:Int()
	If KeyHit(KEY_UP) Then scale=scale+0.25
	If KeyHit(KEY_DOWN) Then scale=scale-0.25
	player_x=player_x+3.0
		
	game_counter = game_counter+1
    Return True
  End Method
  
  Method OnRender:Int()
	Local i:Int,j:Int
	Local tilex:Float
	
    PushMatrix()
	Scale scale,scale
	
    Cls(200,230,230)

	Translate -player_x,0
	SetColor 0,0,0
	i = (player_x)/60
	j = 0
	While j<900
		DrawRect i*60 + j,100,60,60
		j=j+60
	Wend
    PopMatrix()
	
	SetColor 255,255,255
	DrawText ("device width = "+DeviceWidth(),10,30)
	DrawText ("player_x = "+player_x,10,50)
	DrawText ("scale = "+scale,10,70)

    Return True
  End Method

End Class


USE up and down to change the scale factor.

[EDIT] I've been running this in HTML5 (and can also see gaps on Android)

For me when the scale is whole (1, 2, 3 etc) there are no gaps
But when the scale is a fraction (like most displays will be) there are gaps in the solid bar.
Question is that I can't seem to work out how to patch them up and keep it smooth. I have a feeling that if I lock to integers for drawing, its going to be jerkier than using floats


invaderJim(Posted 2012) [#7]
From what I can tell, it's something to do with the scaling of DrawRect. I don't know if you've tried this with images yet, but when I use a 60x60 black image instead of DrawRect, I don't have gaps.


Dima(Posted 2012) [#8]
Try drawing textured tiles instead of rects, those should use sub-pixel accuracy with the help of texture filtering, I don't think non-textured polygons can be drawn between pixels.


muddy_shoes(Posted 2012) [#9]
A slightly ridiculous way to deal with this is to try to ensure that the scaled result is rounded to a known pixel boundary:

    Local scalePlayerX:Int = Int(-player_x * scale)
    Translate scalePlayerX / scale, 0
    SetColor 0,0,0
    i = (player_x) / 60
    i *= 60
    j = 0
    Local scale_start:Int = (i + j) * scale
    Local scale_width:Int = 60 * scale
		    
    While j < 900
        j += 60
        DrawRect scale_start / scale, 100, scale_width / scale, 60
        scale_start += scale_width
    Wend
   


Not sure how robust that is and it's certainly not optimal.


teremochek(Posted 2012) [#10]
Great idea.


pantson(Posted 2012) [#11]
Many thanks for the many solutions.

Weirdly I'm getting a lot different results. (I think it depends on the images too)

The solution in the end (for me) is to not bother locking to true ints and use images with a 1 pixel (copied) border.
I'm getting nice results now at all screen scales and offset floats

Also I'm using DrawImageRect to copy from one image onto the screen and not using individual frames for each tile

again, many thanks


silentshark(Posted 2012) [#12]
Did this ever get resolved, or is Rich's workaround still the best approach? Think I'm seeing the same issue with android using v60


silentshark(Posted 2012) [#13]
ok, well I've used an approach similar to that advocated by Rich, and it seems to work.

a) resized my tiles to 33x33 (they were 32x32)
b) used DrawImageRect to render, rather than DrawImage with the usual image offset
c) DrawImageRect draws them as 33x33 (in terms of their size), but they are still laid out as previously (i.e. they are still positioned on the screen as when they were 32x32). Sorry if this is unclear.

What a horrible hack!

Quick testing with HTML5 on Opera (which was showing the issue), and things look good. Now, let's see if it is better on Android.. I'll pop into onto my galaxy s2..

Update: did this, and it worked fine.. good stuff!