I am using a custom entity for the dash rock, which was pulled from Book of Mudora. I have everything all set up and it's working perfectly for me. I have created a dynamic tile using the large dirt patch you would find under large rocks in a Link to the past. I tried using the event entity:on_removed(}, which the description in the API says this event is called when an entity is about to be destroyed.
However the dynamic tile does not appear until the 'destroy' animation completely finished. I want this dynamic tile to appear During the destroy animation, as it would in a Link to the Past. I wasn't able to get it to work.
Here is the Dash Rock custom entity (from Book of Mudora), changed just slightly to use my tileset's entities:
local entity = ...
local game = entity:get_game()
-- Stone pile: a pile of stones which
-- can only be blown apart by a bomb.
function entity:on_created()
self:set_size(32, 32)
self:set_origin(16, 29)
self:set_traversable_by(false)
self:add_collision_test("touching", function(self, other)
ex, ey, el = entity:get_position()
if other:get_type() == "explosion" then
self:get_sprite():set_animation("destroy")
sol.timer.start(self, 500, function() self:remove() end)
elseif other:get_type() == "hero" and game:get_hero():get_state() == "running" then
self:get_sprite():set_animation("destroy")
sol.timer.start(self, 500, function() self:remove() end)
end
end)
end
Here is the lua script for the current map this entity is located (for the time being):
local map = ...
local game = map:get_game()
function dash_rock_1:on_removed()
dash_rock_dirt_1:set_enabled(true)
end
As explained before, the dynamic tile for the dirt patch appears after the 'destroy' animation finishes, and not when it starts, like it should.
Maybe I am not trying hard enough to figure out the exact method needed here xD
That behavior is normal because you are removing the entity (and hence enabling the tile) half second after the "destroy" animation is started (you have a 500ms timer). You should just write the line
dash_rock_dirt_1:set_enabled(true)
immediately after the line
self:get_sprite():set_animation("destroy")
and remove the event "dash_rock_1:on_removed()".
More advices:
-To avoid repeating code unnecessarily, you should join both conditions in the same "if" block. Something like this may work:
if other:get_type() == "explosion"
or ( other:get_type() == "hero" and game:get_hero():get_state() == "running" ) then
--blah blah blah, cats cats cats,... put your code here :)
end
-I think it would be more natural to use a sprite attached to the custom entity, if possible, instead of the dynamic tile. But this would make your sprite to follow the dashing rock; I don't know if that is what you need (if not, then just keep your current code).
Well I am still learning how the code works. This script was a direct copy from Book of Mudora. The 'on_removed' callback was placed in the map script separate from the dash rock script entirely, and if I place the line of code to enable the dynamic tile within the dash rock script, it does not work that way. In fact altering the dash rock script in any way kind of breaks it. The only way to make it work with the code written this way was to add scripts to the map
I don't know this specific code, but I can confirm that entity:on_removed() is called just before an entity is removed from the map (destroyed). If a sprite happens to have an animation named "destroy", such an animation name is a bit confusing, but there is no special rule. If you can see any animation, it means that the entity still exists on the map.
Maybe you can try to replace the event entity:on_removed() by sprite:on_animation_changed(animation), to detect when the destroy animation starts.
Oh that happen to me long time ago, on_animation_changed solved the thing
One workaround is (not tested but if you are starting let's give you some help)
http://www.solarus-games.org/doc/latest/lua_api_sprite.html#lua_api_sprite_on_animation_changed
function entity:on_created()
-- Store the sprite in a local variable, we want to remove this entity when a specific animation starts
local sprite = self:get_sprite()
self:set_size(32, 32)
self:set_origin(16, 29)
self:set_traversable_by(false)
self:add_collision_test("touching", function(self, other)
ex, ey, el = entity:get_position() -- Ehm, why ?
if other:get_type() == "explosion" or (other:get_type() == "hero" and game:get_hero():get_state() == "running") then
sprite:set_animation("destroy")
-- The collision has been detected, we no longer need to check.
self:clear_collision_tests()
end
end)
function sprite:on_animation_changed(animation)
if animation == "destroy" then
-- Do your stuffs here
entity:remove()
-- Hint: Don't use self:remove() here, self = sprite
end
end
end
Yet, when removed, the sprite is removed as well, so the destroy animation will not be played ... The solution is to enable the dynamic tile in on_animation_changed() and remove the entity in on_animation_finished()
function entity:on_created()
-- Store the sprite in a local variable, we want to remove this entity when a specific animation starts
local sprite = self:get_sprite()
self:set_size(32, 32)
self:set_origin(16, 29)
self:set_traversable_by(false)
self:add_collision_test("touching", function(self, other)
ex, ey, el = entity:get_position() -- Ehm, why ?
if other:get_type() == "explosion" or (other:get_type() == "hero" and game:get_hero():get_state() == "running") then
sprite:set_animation("destroy")
-- The collision has been detected, we no longer need to check.
self:clear_collision_tests()
end
end)
function sprite:on_animation_changed(animation)
if animation == "destroy" then
-- enable the entity here
end
end
function sprite:on_animation_finished(animation)
if animation == "destroy" then
entity:remove()
end
end
end
Simple yet it does the same thing, your entity is removed after an animation is played, and it enable an entity when the animation starts
And, if you use add_collision_test, use clear_collision_tests if the condition is met. It would avoid strange things.
Okay. so I swapped out the code you wrote here, and when I did I started running into more problems. I had the code working before I made any changes to it at all. For starters, is all of this code to be placed within the custom entity script, or in the map script? Because, for whatever reason, if I make ANY changes to the custom entity script, then it no longer works as intended. It only works if it is left completely alone and no changes are made to it :( The ONLY change I can make to the original code is removing the line containing 'ex, ey, el' and it will still detect collisions, and it will still properly be destroyed upon running into it.
This is the original (and works as intended)
local entity = ...
local game = entity:get_game()
function entity:on_created()
self:set_size(32, 32)
self:set_origin(16, 29)
self:set_traversable_by(false)
self:add_collision_test("touching", function(self, other)
--ex, ey, el = entity:get_position()
if other:get_type() == "explosion" then
self:get_sprite():set_animation("destroy")
sol.timer.start(self, 500, function() self:remove() end)
elseif other:get_type() == "hero" and game:get_hero():get_state() == "running" then
self:get_sprite():set_animation("destroy")
sol.timer.start(self, 500, function() self:remove() end)
end
end)
end
This code is the custom entity script itself. If I make any change to it whatsoever, it either stops working as a non-traversable entity that, upon being dashed into, is removed, or it is removed as intended, but does not remove the collision detection at all. In either case, the dynamic tile still is not enabled upon "on_animation_changed()' I even placed 'on_animation_changed(destroy) in the map script and it did not work there either, so either this entire code must be scrapped or I simply have not learned enough to alter it. I had assumed that all custom entities were plug-and-play with a few minor tweaks here and there. This has proven me wrong and I must own up to that xD
Is there any error or anything when changing the code ?
No there wasn't.
That's strange indeed.
I'm gonna re-download Book of Mudora and check this
That would be great :) I won't be home part of tomorrow and all day sunday. I'll be back on monday though so if you get around to it while I'm gone please feel free to share your findings :) In the meantime have a merry christmas or happy holiday depending on where in the world you live <3
Disclaimer: I make no promises that my code is any good - use at your own risk :)
It's perfectly fine though. The only thing I had difficulty with was enabling a dynamic tile at the beginning of the 'destroy' animation sequence. I tried to use the 'on_removed()' condition within the map script and it worked, but only after the 'destroy' animation for the entity was finished, when the entity was destroyed :)
Other than this the entity did exactly what I wanted it to do <3
Nah that's fine wrightmat, I used your ressource as a base for my project, remember :P
I should redownload the latest version of BoM and test that ...
I can confirm that MetalZelda's code works perfectly. Make sure that when you set up your custom entity on the map, you assign the sprite you'd like it to have there. Thanks MetalZelda!
local entity = ...
local game = entity:get_game()
-- Stone pile: a pile of stones which
-- can only be blown apart by a bomb.
function entity:on_created()
local sprite = self:get_sprite()
self:set_size(32, 32)
self:set_origin(16, 27)
self:set_traversable_by(false)
self:add_collision_test("touching", function(self, other)
if other:get_type() == "explosion" or (other:get_type() == "hero" and game:get_hero():get_state() == "running") then
sprite:set_animation("destroy")
self:clear_collision_tests()
end
end)
function sprite:on_animation_finished(animation)
if animation == "destroy" then entity:remove() end
end
end
Sorry guys, I just wasn't able to get the entity to work the way I intended it to work. However I did find a workaround.
It's essentially using the same custom entity twice. I create the entity once using the dash rock, and a second one using a solid ground tile that matches the color of the ground where the dash rock is to be placed. The solid color entity is used to cover up the dash rock dirt, and when Link dashes into both entities they will both be destroyed at once.
It's not the most efficient way to make the entity work absolutely perfect, but this way does serve my purposes.