2
\$\begingroup\$

So recently I have been working on a Legend of Zelda: A Link to the Past clone, and I am wondering how I could handle certain map interactions (like cutting grass, lifting rocks, etc).

The way I am currently doing the tilemap is with 2 PNGs. The first is the "tilemap" where each pixel represents a 16x16 tile and the (red, green) values are the (x, y) coords for the tile in the second PNG (the "tileset"). I am then using the blue channel to store collision data.

Each tile is split into 4 8x8 tiles and represented by a 2 bit value (0 = empty, 1 = Jumpdown point, 2 = unused right now, 3 = blocking). 4 of these 2 bit values make up the full blue channel (1 byte). So collisions work great, and I am moving on to putting interactive units on the level; but I am not sure what a good way is to do it.

I have experimented with spawning an entity for each grass and rock, but there are just WAY to many; FPS just dies even if I confine it to the current "zone" the user is in (for those who remember LTTP it had zones you moved between). It does make a difference that this is a browser-based JavaScript game.

tl;dr: What is a good way to have an interactive map without using full blown entities for each interactive item?

\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

You could use just red to store the type of the tile.
And you have a function/ a table that gives you x,y in the tileset for the type.
So now green is free and you can use it to store a state ( for grass : 0:normal, 1:cut, 2 : burnt, ... ). Then when you draw you use both type and state to find the right tile.
In fact you need also to provide a few functions for each type to react.

expl : hitBySword(tileType, state) returns -1 if no state change, and the new state if change.

hitBySword(water,0) == -1 ; hitBySword(grass, 0) == 1; hitBySword(grass, 1) == -1;

Edit : 1) my suggestion is to use TYPE in the red, something like :

tileTypeEnum = {
roof : 0,
grass : 1,
water : 2,
rock  : 3
}

and 256 types might be enough.

and then you have a lookup table :

typeToTileIndex=[];
typeToTileIndex[roof]=0;  typeToTileIndex[grass]=5; 

and finally you might setup your png and/or your tile array such as :

finalIndex = typeToTileIndex[red]+blue;

if you use animated tiles, the above could become :

 typeToTileIndex[grass]={ i:0, anLength : 3, anTime:0.3};   

((if you use several tyles for one type (example to do grass/water transition North/South/...) store it in the blue, and the state would be in the transparency.))

or you can have full flexibility other animations with :

  typeToTileIndex[grass]=[];
  typeToTileIndex[grass][normal] = { i:0, anLength : 3, anTime:0.3}; 
  typeToTileIndex[grass][cut]    = { i:4, anLength : 1, anTime:0.0}; // no anim if cut 
  typeToTileIndex[grass][burnt]  = { i:5, anLength : 6, anTime:0.1}; 

3 others remarks :
1) you might use transparency to store other data .
2) since your map is not used as bitmap but rather as a proprietary format you can go for your own format, using JSON to stringify for instance and using XMLHTTPRequests to load it. Advantage is that you could store the type / state -> tile anim lookup table here, and other info maybe. But you'll have to code an editor, maybe in html+javascript.
3) Even if you stick to a png, you could still move the map data, once loaded, in another data structure that would be more easy to handle or contain more data. So drawing all tiles would become, for instance :

for (xt=cameraX; xt<cameraX + cameraWidth ; xt++) 
       for (yt=cameraY; yt<cameraY + cameraHeight ;yt++)
             map[xt][yt].draw();

two level editors :

http://dambots.com/dame-editor
http://www.ogmoeditor.com/

\$\endgroup\$
6
  • \$\begingroup\$ Interesting, if my tileset was small enough to have only 256 tiles this would work; but the tilesets can be up to 256x256 which is why I need both bytes. \$\endgroup\$
    – Chad
    Nov 17, 2012 at 17:18
  • \$\begingroup\$ i edited my answer. \$\endgroup\$ Nov 17, 2012 at 19:23
  • \$\begingroup\$ what about saying this is an answer ? \$\endgroup\$ Nov 19, 2012 at 18:25
  • \$\begingroup\$ This wasn't what really answered my question, though it did lead me in a research direction that eventually did. \$\endgroup\$
    – Chad
    Nov 19, 2012 at 19:07
  • \$\begingroup\$ yes, that is what is called an 'answer' on a forum like this one. I never got better than that when asking, and i never complained. If you want a solution you just have to insert in your project, you have to pay for it. Life is cruel. \$\endgroup\$ Nov 19, 2012 at 20:18
0
\$\begingroup\$

Since the number of entities directly affects your FPS overall i have to ask, do you draw everything on every frame? In browsers this is often the bottleneck, remember back in the time of ALTTP we used blitting engines, only drawing dirty-marked rectangles, aswell as caching images.

For example:

1 entity + 1 layer of grass + 1 layer of ground get rendered into one image and you only draw that combined image. This allready saves performance if the combination has to be drawn 3 times.

EDIT: if you implement a scenegraph, you can query that graph for boundry boxes of your dirty space, then only draw that dirty space onto the canvas.

i allready made a huge post once about a scene graph in js: https://stackoverflow.com/questions/13099845/collision-detection-in-html5-canvas-optimization-too/13100287#13100287

\$\endgroup\$
1
  • \$\begingroup\$ I'm not redrawing everything all the time, though I didn't do any optimizations for the rendering on these entities. I'm sure that would help, but I feel like spawning 200+ entities every zone isn't how people do this sort of thing. \$\endgroup\$
    – Chad
    Nov 17, 2012 at 17:23

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .