Dusk Engine

I have one question regarding accessing a sprite tile…

When setting a frame the animation is still running. How can I stop (pause) a sprite animation on one specific tile?

UPDATE: I guess accessing one tile is not possible, so my question is now :)… How can I make sure the sprite animation is not played, but still can be accessed with :setFrame() ?

UPDATE2: Looking into dusk_core/run/anim.lua I found from line 142 on the following code:

if d.watchTile then                         d.watchTile:setFrame(((d.currentFrame + 1) % d.frameCount) + 1)                         d.watchTile:play()                         anim.sync(d, d.watchTile.frame) end

I think this code is preventing accessing :setFrame() and :pause() correctly, because whenever I try to use it the frames still are jumping or the animation still is running. I tried to pause() the animation to jump between different frames, but I’m not able to pause the sprite animation from the beginning. The animations is running for some frames before pausing OR not pausing at all.

Is anyone else accessing the sprite animation and give me some tips on how to handle frame changing and pausing animations correctly?

(Sure I could change the code in anim.lua, but then it would influence all sprite animations and with an update I have to keep track of my own code changes.)

AND ONE MORE THING: I noticed when playing with the anim.lua when removing the “d.watchTile:play()” and then setting a sprite anim frame with “:setFrame(1)” things seem to work BUT when moving the map forth and back all the tiles which were outside the visible screen borders are using a different sprite frame when being back on screen or moving on the screen for the first time. So culling tiles and setting frames seem to be a problem. Any idea on how to use culling but also the correct set frames on all tiles (visible and off screen)?

Can you please explain this more in detail Caleb? I still can’t figure out how to do this.

UPDATE: I did it! :slight_smile: … added a 1px border around the image sheet and a 2px space between the tiles in the sheet. I then filled the empty space between the tiles with an expanded border of each tile and now I don’t have any more gaps when scrolling around the map.

But I still have a question: How can I show animated tiles on a map?

local tile2 = map.layer["tiles"].tileByPixels(eventposX, eventposY)

When using this code to get the coordinates of tiles it only works if I do not use the camera! When I position the camera on the player the map is moved and the moved distance is not calculated in the tile detection which results in the wrong tiles being detected.

How can I use the code above to get the right tiles AND use the camera features?

Thx for your help!

Daniela

Is it possible calling the function to get a tile by coordinates like this:

tile=map.layer"tiles".tile(PosX,PosY)

is very slow?

If so, is there a way to speed up this part to make it possible to get this kind of tiles fast?

I’m using this to get tiles by having for example the player X-Position and player Y-Position, but when I’m getting more tiles this way in a short time it is slowing down the performance a LOT.

UPDATE and one more question:

The speed in the simulator is faster now… don’t know why, but maybe the function call isn’t the problem at all!?

One more important question:

I’m using

map.layer["tiles"].\_lockTileDrawn(x,y)

when I have loaded the complete map. There are a lot of tiles outside the visible screen area and because I have to access them I’m cycling through all tiles with a for loop and doing the lockTileDrawn above to make sure they all stay.

BUT when accessing tiles outside the screen they aren’t known sometimes. Is there a way to access tiles outside the visible area correctly?

I need to give each tile a :setFrame() value, even when not on screen. And I have to check the tiles for their frame value outside of the screen sometimes. But this is causing problems.

I’m assuming eventposX and eventposY are touch event position coordinates? If so, you need to first use Corona’s contentToLocal function to transform the touch position to the “real” pixel position in group coordinates:

[lua]

local localEventX, localEventY = map.layer[“tiles”]:contentToLocal(eventposX, eventposY)

local tile2 = map.layer[“tiles”].tileByPixels(localEventX, localEventY)

[/lua]

  • Caleb

@d.mach: Good to hear you figured it out :)!

Dusk doesn’t currently support animated tiles. This is a feature on the roadmap, but I’m not sure when I’ll be able to add it. Dusk is open-source, though (hint, hint :D)…

  • Caleb

Thank you for your fast feedback!

Regarding animated tiles can you please hint where to start? Is it possible to access tiles by their number, so this tiles can be ‘overwritten’ by animated sprites? Or something like this? :slight_smile:

So for example you can edit a map with static images and then manually change some of the tiles from the map with animated sprite tiles.

  • Daniela

You can do one of two things:

  1. Edit the Dusk code itself and add animated tiles
    This would be the “feature” I was referring to. The way I was planning to implement this was through properties. Those properties will have a special prefix, like physics:, tiles:, etc. Like so:
    [lua]
    animation:enabled     :     true
    animation:options     :     !json! {“start”: 1, “count”: 5}
    [/lua]
    Or something like that. Then, the animation data is added to the object. Right now, Dusk creates tiles with display.newImageRect; for animated tiles, you’d need to make a check for whether the tile enables animation, then build a sprite if it does. Each tileset is a plain image sheet internally.

You can start with checking out line 93+ in Dusk/dusk_core/layers/tilelayer.lua. That’s where the tile creation code starts.

  1. Use object layers or properties to make animated tiles
    This is more of a temporary but quick fix. Basically, you’d be creating either objects at specific locations with custom properties, or one big property table data element for them and load the animations manually (by iterating through with an object iterator) in your code.
  • Caleb

@sakid.farib:

Map wrapping is something I’d love to add when I have time. At the moment, you can try keeping a placeholder object to keep the layer from “snapping” and swapping their locations when you need to wrap. Kind of a kludgy workaround, though :(. I’ll add this to my list of Dusk features to work on.

@d.mach:

Hm… I assume that it’s being offset like that because Tiled uses zero-indexing and Dusk uses Lua’s 1-indexing. That’s just my initial guess, though. I’ll check into this.

Also, you can currently not have control over a sprite when you’ve set it to be animated. Instead, you can use !isSprite!, which builds the tile as a sprite object, then set the frame accordingly. If you need a tile to be both animated and editable, you’ll have to wait until I implement that (not so long, I *hope* - I’ve got it just about fully implemented in my personal version). The watchTile troubles you’re having are because of Dusk’s animation method. Basically what it does is wait until a tile is created, then targets it as the “watch tile”. Every time that tile changes frames, Dusk changes the other tiles in the map with that animation scheme to the correct frame. If the watch tile is removed, Dusk takes care of the switching with a runtime event to wait for the next frame time. When you stop the watch tile from playing, the other tiles also stop from playing. The version I’m developing on allows you to “decouple” a tile from the animation system and keep it from syncing with the watch tile.

[EDIT:] The ‘get tile’ method should be taking almost zero time. It’s just an “if tile exists return it” method.

Also, if you’re locking a tile, it shouldn’t be being culled. Are you sure you’re locking the same tile? Optionally, you could also, when you need to query the frame, draw the tile, get the frame, and delete it; Dusk ought to take care of the frame setting automatically. It might be faster or it might be slower than your current approach, depending on how many tiles you have.

  • Caleb

Thank your for all the useful information and tips. I will try some changes to my code and will wait for the animated and editable tiles then :slight_smile:
Regarding the culling I used _lockTileDrawn(x,y) for each tile I’ve changed the frame on and I had no problems since then. I don’t know why cycling through all existing tiles and locking them didn’t have the same effect, but my guess is this has all to do with the “watch tile”, so I will wait for your new version to look into this again.

At last let me tell you that working with dusk really is great and until now I don’t see any bigger problems with creating the game I want to make :slight_smile: Cool stuff!

Ok. I’ve just pushed a commit that allows you to “un-sync” a single tile from the animation. Basically what you’ll do is this:

map.layer[1].tile(x, y):setSyncAnimation(false)

Then, it’ll drop off the grid and let you use it just as a sprite tile. It’ll still be culled, though, so beware. It just won’t automatically animate in sync to the other tiles.

And thanks for the kind words :).

  • Caleb

Thx for this update!

I still can’t figure out how to prevent the tiles which aren’t on the visible screen but outside from animating? I can’t access them because of the culling I guess? How is it possible to give each tile a static (not animated) :setFrame(X) value… on screen or not?

The only way it seems to work (most of the time) is to disable the following lines in dusk_core/run/anim.lua:

(lines 179+)

if d.watchTile then                         --d.watchTile:setFrame(((d.currentFrame + 1) % d.frameCount) + 1)                         --d.watchTile:play()                         --anim.sync(d, d.watchTile.frame) end

Then I can access the tiles like this (on screen and off screen):

for x=1,16 do        for y=1,16 do              if map.layer["tiles"].tile(x,y) then                     if map.layer["tiles"].tile(x,y).sequence then                         -- lock tile                         map.layer["tiles"].\_lockTileDrawn(x,y)                         map.layer["tiles"].tile(x,y):play()                     end                     if map.layer["tiles6"].tile(x,y).sequence  then                         map.layer["tiles6"].\_lockTileDrawn(x,y)                         map.layer["tiles6"].tile(x,y):setFrame(2)                         map.layer["tiles6"].tile(x,y):pause()                                              end              end        end end

BUT I don’t know what removing the lines in anim.lua is doing to the whole code and I guess it will cause problems in some other areas!?

The :setSyncAnimation() stops or resumes the tile from syncing with other tiles’ animation. Like so:

 if map.layer["tiles6"].tile(x,y).sequence then map.layer["tiles6"].\_lockTileDrawn(x,y) map.layer["tiles6"].tile(x,y):setSyncAnimation(false) -- Turns off auto animation syncing map.layer["tiles6"].tile(x,y):setFrame(2) -- Now this tile animates independently from others end
  • Caleb

Thx for the details Caleb.

One thing I just found out: When you are using the following lines to get sharp graphics:

display.setDefault("minTextureFilter", "nearest") display.setDefault("magTextureFilter", "nearest")

you have to use images or image sheets (frames) with the power of two! Otherwise the graphics will not look 100% like the originals! Some pixels can be off or will be off when the images are moved for example. To avoid this problem the images should always use the power of two (means for example have the size 16,32,64,128 and so on)

Is it possible to prevent object culling when objects move outside of the visible screen?

I just noticed their x and y value is unknown, when they move outside of the screen… but sometimes I need to access them.

The only things that are culled are tiles. So if Dusk is culling objects as well… That’s unexpected :slight_smile:

What exactly is happening?

  • Caleb

I wondered dusk is doing this :wink: but I just figured it out: It was a coincidence in my function call. I forgot to start the function with a parameter and it happened exactly when the objects where moving out of the screen… :slight_smile:

Ok. Glad you got it figured out.

  • Caleb

Hello,

Great work here Caleb. My tiled map that I’m using with Dusk is 1800x1800 with the tiles at 32px. My pc has a hard time loading it, and my phone just crashes. I know it’s a big map, but maybe you have some advice. I’ve thought about loading multiple maps that would equal up to the desired size, and moving them along the x/y grid simultaneously. What do you think?

Well… Over three million tiles is a lot, though technically enough memory allows you to have however big of a map you want (as a test, I once loaded twenty-five million tiles into the simulator). Unfortunately, some devices don’t have that much free memory (although the iPad handled the 25,000,000 nicely). You can move your maps as you said, or, for a better solution, split your game up into multiple stages and load the new map when the player goes through a door or passage or something. You could work and make this pretty seamless if you want to go for a giant “world” feel. That would have the dual purpose of keeping things smooth and fast, because you don’t have 10 or 15 maps loaded at the same time.

  • Caleb