Tile-based platforming

Previous topic - Next topic

eddhead

Hey everyone!

I'm working on a single-screen platformer (ala donkey kong, snow bros., mario bros., etc.) and I was wondering, what is the easiest way to map tiles? I've been trying to do it with arrays, but try as I may, I can't quite wrap my head around it. Since each screen will probably only have around 40 tiles (or less), an external tile-mapping program seems excessive (plus I already tried that and it blew my mind). And if doing tiles with arrays IS the easiest way, is there a tutorial someone could point me to? This stuff is KILLING me!!

Thanks a lot!!


ampos

you can try to define a type per tile. Something like
Code (glbasic) Select

type tile
x
y
image
endtype


and if each level has a max of 40 tiles, and you have... 10 level, try to define omething like
Code (glbasic) Select

global map[][] as tile
dim map[10][40]

lev=1
for til=0 to 39
   drawsprite map[lev][til].image,map[lev][til].x,map[lev][til].y
next


more or less.
check my web and/or my blog :D
http://diniplay.blogspot.com (devblog)
http://www.ampostata.org
http://ampostata.blogspot.com
I own PC-Win, MacBook 13", iPhone 3G/3GS/4G and iPAC-WinCE

eddhead

#2
Thanks for the quick answer!

I understand it all up to that point. I guess what I don't get is how to define each tile's x,y,image. I'm guessing that you would somehow use dimdata?
Or would you have to do it on an individual basis? i.e.:

Code (glbasic) Select
map[lev][0].x=100
map[lev][0].y=100
map[lev][0].image=6
map[lev][1].x=132 ..............


Thanks again!

matchy

A tile is part of a bitmap, so draw the image portion according to a tile-set value which can be used to select a tile from a set from LOADANIM.  8)

Code (glbasic) Select

// --------------------------------- //
// Project: tile
// Start: Wednesday, October 13, 2010
// IDE Version: 8.125
// tile scroll demo - matchy's pixel mario
// arrows/spacebar, no collision

TYPE tiles
x
y
width
height
num
ENDTYPE

GLOBAL tile[] AS tiles
GLOBAL map$[],map_color[]
GLOBAL screen_width,screen_height,map_width,map_height,sprite_tile,anim_tile,tile_width,tile_height
GLOBAL player_x,player_y,player_jump,player_x_last,player_y_last

CONSTANT TILE_AIR=0
CONSTANT TILE_GROUND=1
CONSTANT TILE_SHELF=2
CONSTANT TILE_COIN=3
CONSTANT TILE_PLAYER=4
CONSTANT TILE_MONSTER=5

CONSTANT TILE_COUNT=6

CONSTANT KEY_LEFT=203
CONSTANT KEY_RIGHT=205
CONSTANT KEY_SPACE=57

init()

FUNCTION mapinit:
DIM map$[1][1]

map$[0]=".................................................................."
map_width=LEN(map$[0])
map_height=10
REDIM map$[map_width][map_height]
map$[0]=".................................................................."
map$[1]=".................................................................."
map$[2]=".................................................................."
map$[3]=".................................................................."
map$[4]=".................................................................."
map$[5]="....................................................*.*..........."
map$[6]="...................................................-----....===..."
map$[7]=".............................................................=...."
map$[8]="=========.............!..................=======............===..."
map$[9]="=================================================================="
ENDFUNCTION

FUNCTION tilemap: cell$
LOCAL mapcell

SELECT cell$
CASE "."
mapcell=TILE_AIR
CASE "="
mapcell=TILE_GROUND
CASE "-"
mapcell=TILE_SHELF
CASE "*"
mapcell=TILE_COIN
CASE "!"
mapcell=TILE_PLAYER
CASE "#"
mapcell=TILE_MONSTER
DEFAULT
mapcell=TILE_AIR
ENDSELECT
RETURN mapcell
ENDFUNCTION

FUNCTION init:
// SETSCREEN 480,320
GETSCREENSIZE screen_width,screen_height
mapinit() // get the map

tile_width=32
tile_height=32
tileinit() // map the tiles

colorinit()
sprite_tile=spriteinit(TILE_COUNT,tile_width,tile_height)
anim_tile=animinit() // create tileset bitmap

animate()
ENDFUNCTION

FUNCTION animinit:
LOCAL file$,anim

file$=PLATFORMINFO$("DOCUMENTS")+"/temp.png"
SAVESPRITE file$,sprite_tile
anim=GENSPRITE()
LOADANIM file$,anim,tile_width,tile_height
KILLFILE file$
RETURN anim
ENDFUNCTION


FUNCTION tileinit:
LOCAL map_x,map_y,num,cell$

FOR map_y=0 TO map_height-1
FOR map_x=0 TO map_width-1
cell$=MID$(map$[map_y],map_x,1)
num=tilemap(cell$)
IF num=TILE_PLAYER
player_x=map_x*tile_width
player_y=map_y*tile_height
tileadd(map_x*tile_width,map_y*tile_height,TILE_AIR)
ELSE
tileadd(map_x*tile_width,map_y*tile_height,num)
ENDIF
NEXT
NEXT
ENDFUNCTION

FUNCTION tileadd: tile_x,tile_y,num
LOCAL tilecount

tilecount=BOUNDS(tile[],0)
REDIM tile[tilecount+1]
tile[tilecount].x=tile_x
tile[tilecount].y=tile_y
tile[tilecount].width=tile_width
tile[tilecount].height=tile_height
tile[tilecount].num=num
// DEBUG "tile add: "+num+" "+tile_x+","+tile_y+" "+"\n"
ENDFUNCTION

FUNCTION colorinit:
DIM map_color[TILE_COUNT]

map_color[TILE_AIR]=     RGB(255,255,255)
map_color[TILE_GROUND]=  RGB(  0,128,  0)
map_color[TILE_SHELF]=   RGB(128, 64,  0)
map_color[TILE_COIN]=    RGB(255,255,  0)
map_color[TILE_PLAYER]=  RGB( 16,  0,196)
map_color[TILE_MONSTER]= RGB(196,  0, 64)
ENDFUNCTION


FUNCTION spriteinit: tilecount,tile_width,tile_height
LOCAL sprite,num,spots

sprite=GENSPRITE()
CREATESCREEN 0,sprite,tile_width*tilecount,tile_height
USESCREEN 0
CLEARSCREEN
FOR num=0 TO TILE_COUNT-1
DRAWRECT tile_width*num,0,tile_width,tile_height,map_color[num]
NEXT
spots=RND(300)
ALPHAMODE -0.2
FOR spot=0 TO spots
DRAWRECT RND(tile_width*tilecount),RND(tile_height),RND(tile_width/4),RND(tile_height/4),RGB(255,255,255)
NEXT
ALPHAMODE 0
FOR num=0 TO TILE_COUNT-1
IF num=TILE_AIR OR num=TILE_PLAYER OR num=TILE_COIN
DRAWRECT tile_width*num,0,tile_width,tile_height,map_color[num]
ENDIF
NEXT
USESCREEN -1
RETURN sprite
ENDFUNCTION

FUNCTION animate:
WHILE TRUE
key_input()
tile_draw()
player_draw()
SHOWSCREEN
WEND
ENDFUNCTION

FUNCTION key_input:
player_x_last=player_x
player_y_last=player_y

IF KEY(KEY_LEFT)
DEC player_x,tile_width/8
ENDIF
IF KEY(KEY_RIGHT)
INC player_x,tile_width/8
ENDIF
IF KEY(KEY_SPACE)
IF player_jump=0
player_jump=180
ENDIF
ENDIF
IF player_jump<>0
DEC player_jump,4
INC player_y,SIN(player_jump*2)*tile_height/4
ENDIF
ENDFUNCTION

FUNCTION tile_draw:
FOREACH cell IN tile[]
DRAWANIM anim_tile,cell.num, cell.x-player_x,cell.y
NEXT
ENDFUNCTION

FUNCTION player_draw:
DRAWANIM anim_tile,TILE_PLAYER,screen_width/2,player_y
ENDFUNCTION


Moebius

If your level is defined as a grid of tiles, in fixed locations and with fixed widths, i.e. something like this:
Code (glbasic) Select
---------------------
| 1 | 2 | 3 | 4 | 5 |
---------------------
| 6 | 7 | 8 | 9 | 10|
---------------------

Then all you will need is an 2D array of numbers, the numbers representing what each tile is.  There would be no need to store the width and height of each tile, because they are fixed.  There would be no need to store (x,y) locations because the position in the array (e.g. Tiles[4][3]) tells you the (x,y) position - (4 * tilewidth, 3 * tileheight).

If you are considering a level creator with saveable (if that's a word) levels, Matchy's code for loading the map could easily be used to read maps from files.
Endless Loop: n., see Loop, Endless.
Loop, Endless: n., see Endless Loop.
- Random Shack Data Processing Dictionary

matchy

Yes, I think the issue here is creating the map for tiling and in my case I demonstrate a visual string array of simple mario world. It is easy to plot off the 2D array but there are time where not all tiles require plotting like layers. In my example, I should have excluded the AIR (empy white) tiles from drawing. Also mappy exports 3D arrays, such as layers and animation which can be imported.

eddhead

Thanks a lot guys!!

I haven't got a chance yet, but I'm gonna look through matchy's code today and try Serpent's suggestion and see if I can get it all figured out.

Thanks again everyone!

matchy