AxTilemap.getTileAt(pX:int,pY:int)

Discuss suggestions to improve the Axel library.

AxTilemap.getTileAt(pX:int,pY:int)

Postby chamberlainpi » Sun Apr 22, 2012 8:12 pm

I've fiddled so much in this library over the weekend, I think I understand what this class does...

What seems to be missing, is a way to retrieve a tile at an X an Y location. However, I understand that this class stores all the possible tiles (or a tiles pallette?) separately from the actual layout of the map. This makes sense for resource optimization and I would absolutely like to stick to it!

But it seems very hard to check if an entity is within a particular set of tiles.

I was trying hard this weekend to figure a way to tell whether or not my playable character was in a "water" tile (semi-transparent) or air (anywhere else).

Image

I managed to pull it off with some hackery, but it'd be cool if there was something out of the box to check if the player is entering / leaving a set of tiles. That would be especially useful for designing "zone-triggers" for special game events, camera movement, boss area, registering special visited areas.

I apologize if there is something like this already in your library. I don't think it was shown in your game examples though.

Thanks!
chamberlainpi
Master Sergeant
 
Posts: 32
Joined: Thu Apr 05, 2012 8:51 am
Location: Fredericton, NB

Re: AxTilemap.getTileAt(pX:int,pY:int)

Postby Arkeus » Mon Apr 23, 2012 5:18 pm

Yep, you're right, this is something I definitely want to add to the next version (along with other missing functionality from tilemaps).

One way to do it, that I usually do, is to add callbacks to specific tiles. For example, I add a callback to the water tile, that when my player collides with it it sets the player's "in water" to true (or to a number that gets decremented every frame so when it hits 0 the player is no longer in water).

However getting a tile by coordinates is something that will definitely get added, and I apologize for it not being there already. It's definitely a useful function.
Image
User avatar
Arkeus
Site Admin
 
Posts: 363
Joined: Mon Mar 26, 2012 12:43 am

Re: AxTilemap.getTileAt(pX:int,pY:int)

Postby chamberlainpi » Thu Apr 26, 2012 8:02 am

Hi Arkeus, can you tell me how to setup this tile-callback you speak of?

I think I may have done something similar with a Collider, and funny thing is, I had to use a counter as well to make sure the player was still in the water as it leaves the water tiles to the next water tiles (because sometimes it would indicate the player wouldn't be touching any water tiles... kinda weird!)

Are you referring to being able to assign a callback directly on the Tile, or the Tilemap?

Thanks!
chamberlainpi
Master Sergeant
 
Posts: 32
Joined: Thu Apr 05, 2012 8:51 am
Location: Fredericton, NB

Re: AxTilemap.getTileAt(pX:int,pY:int)

Postby Arkeus » Thu Apr 26, 2012 10:03 am

chamberlainpi wrote:Hi Arkeus, can you tell me how to setup this tile-callback you speak of?

I think I may have done something similar with a Collider, and funny thing is, I had to use a counter as well to make sure the player was still in the water as it leaves the water tiles to the next water tiles (because sometimes it would indicate the player wouldn't be touching any water tiles... kinda weird!)

Are you referring to being able to assign a callback directly on the Tile, or the Tilemap?

Thanks!


The way I'm referring to is assigning it directly to the tile type. For example, if your water has an ID of 7, you can do something like the following:

Code: Select all
tilemap.tile(7).callback = function(tile:AxTile, object:AxEntity):void {
  if (object is Player) {
    (object as Player).swim();
  }
};


However, this method still requires a counter, since it would be inefficient to also keep checking for collisions against NOT a tile.
Image
User avatar
Arkeus
Site Admin
 
Posts: 363
Joined: Mon Mar 26, 2012 12:43 am

Re: AxTilemap.getTileAt(pX:int,pY:int)

Postby KunoNoOni » Thu May 10, 2012 8:59 am

Here are the two functions which set a tile in Flixel. _data is the array which holds the entire tilemap.

Code: Select all
      /**
       * Change the data and graphic of a tile in the tilemap.
       *
       * @param   X            The X coordinate of the tile (in tiles, not pixels).
       * @param   Y            The Y coordinate of the tile (in tiles, not pixels).
       * @param   Tile         The new integer data you wish to inject.
       * @param   UpdateGraphics   Whether the graphical representation of this tile should change.
       *
       * @return   Whether or not the tile was actually changed.
       */
      public function setTile(X:uint,Y:uint,Tile:uint,UpdateGraphics:Boolean=true):Boolean
      {
         if((X >= widthInTiles) || (Y >= heightInTiles))
            return false;
         return setTileByIndex(Y * widthInTiles + X,Tile,UpdateGraphics);
      }


Code: Select all
      /**
       * Change the data and graphic of a tile in the tilemap.
       *
       * @param   Index         The slot in the data array (Y * widthInTiles + X) where this tile is stored.
       * @param   Tile         The new integer data you wish to inject.
       * @param   UpdateGraphics   Whether the graphical representation of this tile should change.
       *
       * @return   Whether or not the tile was actually changed.
       */
      public function setTileByIndex(Index:uint,Tile:uint,UpdateGraphics:Boolean=true):Boolean
      {
         if(Index >= _data.length)
            return false;
         
         var ok:Boolean = true;
         _data[Index] = Tile;
         
         if(!UpdateGraphics)
            return ok;
         
         setDirty();
         
         if(auto == OFF)
         {
            updateTile(Index);
            return ok;
         }
         
         //If this map is autotiled and it changes, locally update the arrangement
         var i:uint;
         var row:int = int(Index/widthInTiles) - 1;
         var rowLength:int = row + 3;
         var column:int = Index%widthInTiles - 1;
         var columnHeight:int = column + 3;
         while(row < rowLength)
         {
            column = columnHeight - 3;
            while(column < columnHeight)
            {
               if((row >= 0) && (row < heightInTiles) && (column >= 0) && (column < widthInTiles))
               {
                  i = row*widthInTiles+column;
                  autoTile(i);
                  updateTile(i);
               }
               column++;
            }
            row++;
         }
         
         return ok;
      }


Axel doesn't use an array to hold the tiles per se, it uses a vector which is a fancy word for 1D array and this variable is named data. Most of, if not all of, setTileByIndex can be removed. If this is the case then this should be what set tile would look like for Axel

Code: Select all
      /**
       * Change the data and graphic of a tile in the tilemap.
       *
       * @param   X            The X coordinate of the tile (in tiles, not pixels).
       * @param   Y            The Y coordinate of the tile (in tiles, not pixels).
       * @param   Tile         The new integer data you wish to inject.
       * @return   Whether or not the tile was actually changed.
       */
      public function setTile(X:uint,Y:uint,Tile:uint):Boolean
      {
         if((X >= cols) || (Y >= rows))
            return false;
         return data.[Y * cols + X] = Tile;
      }


Also while looking through the code for AxTilemap I did noticed a getTile and getTiles, but these did not function like I thought they did. They are for retrieving a tile from the tile image

If we use the above function and modify it a little we should be able to create a get tile which will retrieve a tile from the tilemap like this

Code: Select all
public function getTileAt(X:uint, Y:uint):uint {
   return data.[Y * cols + X];



Arkeus please correct me if I am wrong as I very well could be. Also if someone wants to test my code, please feel free to! I'm at work right now so I can't test.

-KunoNoOni
KunoNoOni
Corporal
 
Posts: 19
Joined: Mon Apr 02, 2012 1:35 pm

Re: AxTilemap.getTileAt(pX:int,pY:int)

Postby Arkeus » Thu May 10, 2012 11:12 pm

Set tile will actually be a bit more complicated for Axel, as it has to rebuild the index buffer and vertex buffer and upload that to the GPU. Because I don't store any data for tiles not in the map, it may not be a very efficient method (but since you shouldn't be calling it often, it should be fine); especially in a giant tilemap since uploading all that data can definitely get slow. However, I'll need to see whether it's actually noticeable or not (perhaps other people use tilemaps in a way that requires updating the tilemap every frame...)
Image
User avatar
Arkeus
Site Admin
 
Posts: 363
Joined: Mon Mar 26, 2012 12:43 am

Re: AxTilemap.getTileAt(pX:int,pY:int)

Postby KunoNoOni » Fri May 11, 2012 10:50 am

Hmmm.... I see your point, I checked the code again and saw where does happen at. Alright So setTile may not work correctly, but what about the getTileAt function

Code: Select all
public function getTileAt(X:uint, Y:uint):uint {
   return data.[Y * cols + X];


By all rights this should work.

-KunoNoOni
KunoNoOni
Corporal
 
Posts: 19
Joined: Mon Apr 02, 2012 1:35 pm


Return to Suggestions

Who is online

Users browsing this forum: No registered users and 1 guest

cron