I always liked the random jumping of tektites in Zelda 1 and ALTTP, and was a little disappointed by the tektites in Return of the Hylian which simply walked at the player. Thus once I figured out how to set up random jumping for some other enemies I figured I'd share this extremely basic and simple example of Nintendo tektite behavior.
This also would work for replicating Bits/Bots from Zelda 2 or Zols and Gels from Zelda 1.
example video: https://youtu.be/HGkoJe9JqEc
I probably should have used movement:on_finished() instead of a timer to close the jump function, because if you use distances greater than 64 the jump begins to get cut-off early and it looked bad.
Art-wise, if you use something like Return of the Hylian's tektite sprite, it'll look a little weird because there's a shadow drawn into the animations. Thus the shadow floats through the air with the character as he jumps, instead of staying on the ground. The easiest solution is to simply erase any shadows from your animation frames, though this will make it visually ambiguous whether the character is jumping through the air or sliding across the ground. For the best results, you'd want to use a custom entity or something to place a separate shadow sprite under the character.
Special thanks to llamazing for helping me sort out the random function selection call!
This also would work for replicating Bits/Bots from Zelda 2 or Zols and Gels from Zelda 1.
example video: https://youtu.be/HGkoJe9JqEc
Code ( lua) Select
local enemy = ...
local choices = {"pause","jump","jump","jump"}
-- these are functions the enemy will choose from randomly. I added extra copies of the jump function so he would move 75% of the time instead of 50/50. However, you could create more functions and place each one in the list only once.
function enemy:on_created()
enemy:set_life(3)
enemy:set_damage(2)
enemy:create_sprite("enemies/" .. enemy:get_breed())
end
function enemy:on_restarted()
enemy[ choices[math.random( 1, #choices )] ](enemy) --this line calls a random function from the "choices" table at the top
end
function enemy:pause()
local sprite = enemy:get_sprite()
--sprite:set_animation("idle")
-- uncomment the line above if you want to use a custom pause animation, otherwise it'll use "walking"
enemy:stop_movement()
sol.timer.start(enemy, math.random(1, 2000), function() --the timer lasts randomly between 1 and 2000 ms. You can change the minimum and maximum to taste.
enemy[ choices[math.random( 1, #choices )] ](enemy) --again picks a random function from the choices table, you could also just call enemy:restart
end)
end
function enemy:jump()
local sprite = enemy:get_sprite()
enemy:stop_movement()
--sprite:set_animation("jumping")
-- uncomment the line above if you want to use a custom jump animation, otherwise it'll keep using "walking"
local movement = sol.movement.create("jump")
movement:set_direction8(math.random(0, 7)) -- picks a random direction to jump in
movement:set_distance(math.random(24, 64)) -- sets a distance between 24 and 64px
movement:start(enemy)
sol.timer.start(enemy, 800, function() -- 800ms is the typical time for the enemy to land from a 64px jump.
enemy[ choices[math.random( 1, #choices )] ](enemy)
end)
I probably should have used movement:on_finished() instead of a timer to close the jump function, because if you use distances greater than 64 the jump begins to get cut-off early and it looked bad.
Art-wise, if you use something like Return of the Hylian's tektite sprite, it'll look a little weird because there's a shadow drawn into the animations. Thus the shadow floats through the air with the character as he jumps, instead of staying on the ground. The easiest solution is to simply erase any shadows from your animation frames, though this will make it visually ambiguous whether the character is jumping through the air or sliding across the ground. For the best results, you'd want to use a custom entity or something to place a separate shadow sprite under the character.
Special thanks to llamazing for helping me sort out the random function selection call!