Trying to figure out best solution for this in defold.
I have a spell factory that fires a spell and it has two animation one when it shots and one when it hits or travels X distance.
When I fire this and it collides with an enemy I have it send out a message “hit” and then play the animation for when it hits. There is a delay to this animation and then it is deleted. But due to this 0.3 delay the “hit” message gets sent and received multiple times by the enemy.
If I call go.delete right away only one hit message is sent and everything works as expected. But then I don’t get my second animation. If I call the function even without a delay it still sends two hit messages before deletion.
What is the best way to handle this when your spells have more than one animation? Or should you simply avoid this and trigger a second factory that spawns the new animation on hit/target?
--cosmic_shot script
go.property("dir", vmath.vector3(1, 0, 0))
local SPEED = 900
local DISTANCE = 700
local DAMAGE_AMOUNT = 2
local BLAST_DURATION = 0.3 -- Adjust based on actual animation length
function init(self)
sound.play("#sound", { delay = 0, gain = 0.5, pan = -1.0, speed = 1.25 })
-- Ensure self.dir is correctly set; default to right if missing
self.dir = self.dir or vmath.vector3(1, 0, 0)
self.start_pos = go.get_position()
self.target_x = self.start_pos.x + (self.dir.x * DISTANCE)
-- Animate movement
local duration = DISTANCE / SPEED
go.animate(".", "position.x", go.PLAYBACK_ONCE_FORWARD, self.target_x, go.EASING_LINEAR, duration, 0, function()
play_blast_animation(self)
end)
end
function play_blast_animation(self)
-- Flip the sprite properly instead of setting negative scale
sprite.set_vflip("#sprite", self.dir.x < 0)
-- Play explosion animation
sprite.play_flipbook("#sprite", "blast")
-- Ensure projectile gets deleted after animation duration
timer.delay(BLAST_DURATION, false, function()
go.delete()
end)
end
function on_message(self, message_id, message, sender)
if message_id == hash("collision_response") and message.group == hash("enemy") then
msg.post(message.other_id, "hit", { damage = DAMAGE_AMOUNT })
-- Stop movement and play explosion effect
-- go.cancel_animations(".", "position")
play_blast_animation(self)
end
end
-- enemy script
local SPEED = 150 -- Adjust speed as needed
local GRAVITY = -300 -- Gravity force applied to enemy
local is_grounded = false -- Track if enemy is touching the ground
local STARTING_HEALTH = 10
-- Store hash values at the top for easy changes
local HASH_HIT = hash("hit")
local HASH_CONTACT = hash("contact_point_response")
local HASH_GROUND = hash("ground")
local HASH_PLAYER = hash("player")
local HASH_DINO_ATTACK = hash("dino_attack")
function init(self)
self.player_id = "/player/player" -- Use the correct path for player
self.speed = SPEED
self.velocity = vmath.vector3(-50, 0, 0) -- Store velocity for movement
self.health = STARTING_HEALTH
end
function update(self, dt)
if not self.player_id then return end -- Ensure player exists
local enemy_pos = go.get_position()
local player_pos = go.get_position(self.player_id)
-- Calculate direction to player (only move horizontally)
local direction = player_pos.x - enemy_pos.x
if math.abs(direction) > 1 then
direction = direction / math.abs(direction) -- Normalize to -1 or 1
else
direction = 0 -- Stop moving if very close
end
-- Update velocity based on direction
self.velocity.x = direction * SPEED
-- Apply gravity if not grounded
if not is_grounded then
self.velocity.y = self.velocity.y + GRAVITY * dt
else
self.velocity.y = 0 -- Prevents gravity from interfering with movement
end
-- Move enemy
local new_position = enemy_pos + self.velocity * dt
go.set_position(new_position)
end
function take_damage(self, amount)
self.health = self.health - amount
print("Enemy took damage! Health:", self.health)
if self.health <= 0 then
die(self)
end
end
function die(self)
print("Enemy has died!")
go.delete()
end
function on_message(self, message_id, message, sender)
print(message.other_id)
if message_id == HASH_HIT then
local damage = message.damage or 1 -- Default to 1 if no value is provided
take_damage(self, damage)
end
if message_id == HASH_CONTACT then
-- Check if the enemy is colliding with the ground
if message.group == HASH_GROUND then
is_grounded = true
self.velocity.y = 0 -- Stop falling
end
-- Stop enemy from pushing through objects
if message.group == HASH_PLAYER then
self.velocity.x = 0
end
end
end