Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Topics - Bagu

#1
Your scripts / Classic Tektite Random Jumping AI
June 09, 2018, 08:21:21 PM
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

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!
#2
Development / function vs. function:enemy
June 09, 2018, 05:29:35 AM
This is super basic but I've looked around and not found an answer and it's really bugging me.

So I find the following to be much cleaner, neater, and easier to deal with than the alternative:

Code ( lua) Select
function pause()
  local sprite = enemy:get_sprite()
  sprite:set_animation("idle")
  enemy:stop_movement()
  sol.timer.start(enemy, math.random(1, 2000), jump)
end

function jump()
  local sprite = enemy:get_sprite()
  enemy:stop_movement()
  sprite:set_animation("jumping")
  local movement = sol.movement.create("jump")
  movement:set_direction8(math.random(0, 7))
  movement:set_distance(math.random(12, 64))
  movement:start(enemy)
  sol.timer.start(enemy, 800, pause)
end


Whereas if I use "function enemy:blahblahblah" I appear to accomplish the same thing, yet the syntax on things like timers is longer and more restrictive:

Code ( lua) Select
function enemy:pause()
  local sprite = enemy:get_sprite()
  sprite:set_animation("idle")
  enemy:stop_movement()
  sol.timer.start(enemy, math.random(1, 2000), function()
    enemy:jump()
  end)
end

function enemy:jump()
  local sprite = enemy:get_sprite()
  enemy:stop_movement()
  sprite:set_animation("jumping")
  local movement = sol.movement.create("jump")
  movement:set_direction8(math.random(0, 7))
  movement:set_distance(math.random(12, 64))
  movement:start(enemy)
  sol.timer.start(enemy, 800, function()
    enemy:pause()
  end)
end


Then if I start mixing both in the same script, it gets much worse because I'll tend to forget and mismatch the syntaxes to the wrong functions and I spend extra time correcting stupid mistakes to clean up all the error messages.

I see the latter method used in a lot of scripts in enemies by the Solaris team, so there must be some advantage to it, or some reason why it's bad to avoid it. What am I missing? Is there a reason not to use the first approach for all my enemy scripts?

Sorry to ask about such basic stuff all the time!
#3
Development / Choosing a Function Randomly
June 09, 2018, 03:03:23 AM
I've looked at a few different methods of making a random selection from a table, as a means to make an enemy AI choose a function as its next action. For example:

Code ( lua) Select
choices = {"enemy:go_hero()","enemy:random_pause()","enemy:jump_pause()","enemy:go_random()"}

  sol.timer.start(enemy, math.random(1, 3000), function()
    choices[math.random( 1, #choices )]
end)


Code ( lua) Select
function enemy:pickaction()
math.randomseed(os.time())
local a = {"go_hero","random_pause","jump_pause","go_random"}
a[math.random(1,#a)]
end

  sol.timer.start(enemy, math.random(1, 3000), function()
    enemy:pickaction()
  end)


I've tried about 20 different variations of this approach and always wind up with an error message like "= expected near end" or "function arguments expected near [".

I can get it to print the desired results to the console but the engine doesn't seem to want to accept them as anything remotely resembling a function. What am I doing wrong?
#4
I'm in the process of creating a custom "tall" link sprite, and I'm running into a strange issue with shield animations. The shield's walking animations work fine, but durring sword attacks, the directions get reversed.

In other words, the shield plays the "down" animation during an upwards sword strike, and the "up" animation during a downwards sword strike. I believe Solarus is reversing the shield's left and right sword animations as well, though it's hard to tell since they appear to be clipping behind Link's body.

What could be causing this? You can see from the video that the animation frames and directions are set up just like any other situation.

https://youtu.be/t8LHJsMhSMs

(Please excuse the WIP art, the frames are very rough and I still have a lot of polishing to do.)
#5
I'm experimenting with a larger format "tall" hero sprite (placeholder ripped from Beyond Oasis) and the left direction for my sword animation is going "invisible" despite everything looking fine in quest editor.

https://youtu.be/F2vaJ-BuqLI

https://youtu.be/WAKJzgO7FBk

Is there some obvious common newbie mistake that causes this?
#6
Development / Setting Up A Basic Equipment Menu?
April 23, 2018, 04:21:56 AM
Hi I'm new and I've been following along with Christopho's youtube tutorials and reading through the documentation, but I don't see this too comprehensively answered anywhere.

Basically I just want to be able to equip items to different slots to test them out. I've been able to pull things like enemies and items from the Mystery of Solarus DX/Return of the Hylian/Oni Link Begins source github and have them drop into the map easily, and I was able to replicate the "save on pause" process from Chistopho's video tutorial. Hoever I haven't been able to spot exactly which lua scripts to copy an equipment menu and where to reference it to actually get it to show up.

Can anyone point me in the right direction?

Sorry in advance if this seems like a lazy or stupid question.