Author Topic: Complex movements  (Read 464 times)

BlisterB

  • Newbie
  • *
  • Posts: 3
    • View Profile
Complex movements
« on: June 24, 2018, 07:12:08 pm »
Hello  :)

I'm starting with Solarus engine and I was wondering : is it possible to create complex movements including changement of directions and pause?
Something like :
movement.add(straight_movement(east))
movement.add(wait(5))
movement.add(facing(east))
movement.add(jumping(right))

For the moment, I don't understand how to include a pause in a movement, and the only way I find to change a direction after a movement is to create a lot of movement:on_finished() which is pretty redundant.
Sorry if the solution already exist, I didn't manage to find it in the documentation :S.

BlisterB

  • Newbie
  • *
  • Posts: 3
    • View Profile
Re: Complex movements
« Reply #1 on: June 24, 2018, 07:56:18 pm »
For example, I want that a character named Sheik does this pattern at the map's loading :
- few steps upward
- face left
- wait few time
- few steps downward

Here is the quicker way to code that I found :

Code: [Select]
function sheik_intro_movement()
  local step = 0
  local movement = sol.movement.create("path")
  movement:set_speed(64)
  movement:start(sheik)
  function movement:on_finished()
    if step == 0 then
      movement:set_path{2,2,2,2,2,2}
      movement:start(sheik)
      step = step + 1
    elseif step == 1 then
      sheik:get_sprite():set_direction(2)
      sol.timer.start(200, function()
        step = step + 1
        movement:on_finished()
      end)
    elseif step == 2 then
      movement = sol.movement.create("path")
      movement:set_speed(64)
      movement:set_path{6,6,6,6,6,6}
      movement:start(sheik)
      step = step + 1
    end
  end
end

Please note that in step 2 I'm realocating the movement variable
Code: [Select]
movement = sol.movement.create("path") because if I just do
Code: [Select]
movement:set_path{2,2,2,2,2,2}, the character is teleported at the destination for some reason.

Diarandor

  • Hero Member
  • *****
  • Posts: 1008
  • Cats are cool! (ΦωΦ)
    • View Profile
Re: Complex movements
« Reply #2 on: June 24, 2018, 07:58:22 pm »
Watch the videos in my YouTube chanel to see what is possible to do with normal enemies. You have their code in the repository of Children of Solarus, in github and gitlab. We recently moved to gitlab (because Microsoft bought github), so the github repo will not be updated. Use the scripts to study and make tests (some are quite complex).

PS: if you like my videos, click on "thumbs up". :)
I am temporarily on pause mode for now, due to too much work in my real life. When I come back I will keep adding more cool enemies.
“If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you.”

Diarandor

  • Hero Member
  • *****
  • Posts: 1008
  • Cats are cool! (ΦωΦ)
    • View Profile
Re: Complex movements
« Reply #3 on: June 24, 2018, 07:59:41 pm »
If you are doing basic stuff, better not to read my code and try it yourself with timers and movements. Always start with short code and basic stuff.
“If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you.”

Christopho

  • Administrator
  • Hero Member
  • *****
  • Posts: 1130
    • View Profile
Re: Complex movements
« Reply #4 on: June 24, 2018, 08:10:02 pm »
stdgregwar made an experimental script to make this kind of custscenes more easily: https://gitlab.com/solarus-games/zelda-mercuris-chest/blob/dev/data/scripts/maps/cutscene.lua
You can chain movements but also dialogs, pauses, etc.

BlisterB

  • Newbie
  • *
  • Posts: 3
    • View Profile
Re: Complex movements
« Reply #5 on: June 24, 2018, 08:44:02 pm »
Wow thank you for the extra quick answers  ;D !

Christopho, that seems to perfectly fit, thank you ! Diarandor I'll watch your videos on the train :).

Max

  • Full Member
  • ***
  • Posts: 155
    • View Profile
Re: Complex movements
« Reply #6 on: June 25, 2018, 06:59:12 pm »
stdgregwar made an experimental script to make this kind of custscenes more easily: https://gitlab.com/solarus-games/zelda-mercuris-chest/blob/dev/data/scripts/maps/cutscene.lua
You can chain movements but also dialogs, pauses, etc.

This is a really cool script! it seems like it might make cutscenes easier to debug. Does anyone know what actions this can be used to preform? It gives the example of .wait(length of pause), and .dialog(dialog)

Would any method work if you use the right syntax? There's also an example of .hero_start_treasure(), would something like .map_create_enemy(enemy info) work? Or .game_set_ability("swim", 1)?

llamazing

  • Full Member
  • ***
  • Posts: 118
    • View Profile
Re: Complex movements
« Reply #7 on: June 26, 2018, 01:13:26 am »
Does anyone know what actions this can be used to preform? It gives the example of .wait(length of pause), and .dialog(dialog)

Looks like the actions are defined between lines 128 & 259.

You could add your own functions to that section if you need to do something else not included.

MetalZelda

  • Hero Member
  • *****
  • Posts: 551
    • View Profile
Re: Complex movements
« Reply #8 on: July 08, 2018, 12:53:33 pm »
That's weird, I try to use the script but

Code: Lua
  1.   cutscene.builder(game, map, hero)
  2.   cutscene.wait(500)
  3.   cutscene.exec(function() print("test") end)
  4.   cutscene.start()

Edit: It works now, should have read the tutorial above.
« Last Edit: July 08, 2018, 01:03:31 pm by MetalZelda »

Christopho

  • Administrator
  • Hero Member
  • *****
  • Posts: 1130
    • View Profile
Re: Complex movements
« Reply #9 on: July 08, 2018, 12:58:50 pm »
Here is an example of how the custscene builder should be used (example from Zelda OLB SE):

Code: Lua
  1.   cutscene.builder(game, map, hero)
  2.   .dialog("out.e4.pit_hello")
  3.   .exec(function()
  4.       hero:freeze()
  5.     end)
  6.   .movement({
  7.     type = "straight",
  8.     entity = pit,
  9.     properties = {
  10.       angle = 0,
  11.       speed = 64,
  12.       max_distance = 176,
  13.       ignore_obstacles = true,
  14.     },
  15.   })
  16.   .exec(function()
  17.       pit:remove()
  18.       hero:unfreeze()
  19.     end)
  20.   .start()
  21.  
  22.  

MetalZelda

  • Hero Member
  • *****
  • Posts: 551
    • View Profile
Re: Complex movements
« Reply #10 on: July 08, 2018, 01:04:30 pm »
Here is an example of how the custscene builder should be used (example from Zelda OLB SE):

Code: Lua
  1.   cutscene.builder(game, map, hero)
  2.   .dialog("out.e4.pit_hello")
  3.   .exec(function()
  4.       hero:freeze()
  5.     end)
  6.   .movement({
  7.     type = "straight",
  8.     entity = pit,
  9.     properties = {
  10.       angle = 0,
  11.       speed = 64,
  12.       max_distance = 176,
  13.       ignore_obstacles = true,
  14.     },
  15.   })
  16.   .exec(function()
  17.       pit:remove()
  18.       hero:unfreeze()
  19.     end)
  20.   .start()
  21.  
  22.  

Thanks ! It works now

Christopho

  • Administrator
  • Hero Member
  • *****
  • Posts: 1130
    • View Profile
Re: Complex movements
« Reply #11 on: August 04, 2018, 11:24:38 pm »
More complex example from stdgregwar:
this is the final custcene of Zelda XD2 rewritten with his script.
Code: Lua
  1. -- Final cinematic, but flat
  2. function map:start_cinematic_redux()
  3.   cutscene.builder(game,map,hero)
  4.     .wait(500)
  5.     .dialog('final.zelda_4',player_name)
  6.     .set_direction(hero,1)
  7.     .dontWaitFor.hero_animation('walking')
  8.     .movement{ --movement 1
  9.         type='target',
  10.         entity=hero,
  11.         movement_properties={
  12.           target = {104,192},
  13.           speed = 50,
  14.           smooth = true,
  15.           ignore_obstacles = true,
  16.         }
  17.              }
  18.     .set_direction(hero,0)
  19.     .dontWaitFor.hero_animation('stopped')
  20.     .wait(500)
  21.     .dialog('final.zelda_5',player_name)
  22.     .wait(500)
  23.     .dialog('final.mr_grump_3')
  24.     .wait(500)
  25.     .dialog('final.zelda_6',player_name)
  26.     .set_direction(hero,2)
  27.     .dontWaitFor.hero_animation('walking')
  28.     .movement{--movement 2
  29.         type = 'target',
  30.         entity=hero,
  31.         movement_properties={
  32.           target = {-32,192},
  33.           speed = 80,
  34.           smooth = true,
  35.           ignore_obstacles = true
  36.         }
  37.              }
  38.     .wait(500)
  39.     .set_direction(hero,0)
  40.     .dontWaitFor.hero_animation('carrying_walking')
  41.     .dontWaitFor.sprite_animation(cocktails:get_sprite(),'walking')
  42.     .movement(--movement 3
  43.       {
  44.         type='target',
  45.         entity=hero,
  46.         movement_properties={
  47.           target = {104,192},
  48.           speed = 80,
  49.           smooth = true,
  50.           ignore_obstacles = true
  51.         }
  52.       },
  53.       function(mov)
  54.         function mov:on_position_changed()
  55.           if cocktails then
  56.             local hero_x,hero_y = hero:get_position()
  57.             cocktails:set_position(hero_x,hero_y-16)
  58.           end
  59.         end
  60.       end)
  61.     .dontWaitFor.hero_animation('carrying_stopped')
  62.     .dontWaitFor.sprite_animation(cocktails:get_sprite(),'on_ground')
  63.     .wait(1500)
  64.     .exec(
  65.       function()
  66.         cocktails:remove()
  67.       end)
  68.     .dontWaitFor.hero_animation('stopped')
  69.     .dialog('final.zelda_7',player_name)
  70.     .wait(500)
  71.     .dontWaitFor.hero_animation('dying')
  72.     .wait(2000)
  73.     .dontWaitFor.hero_animation('walking')
  74.     .set_direction(hero,2)
  75.     .movement{--movement 4
  76.         type='target',
  77.         entity=hero,
  78.         movement_properties = {
  79.           target = {-32,192},
  80.           speed = 80,
  81.           smooth = true,
  82.           ignore_obstacles = true
  83.         }
  84.       }
  85.     .wait(1000)
  86.     .dialog('final.zelda_8')
  87.     .wait(500)
  88.     .and_then(
  89.       function(cont)
  90.         fade_sprite = sol.sprite.create('entities/heart_fade')
  91.         local camera_x, camera_y = map:get_camera():get_position()
  92.         local zelda_x, zelda_y = grump_and_zelda:get_position()
  93.         fade_x = zelda_x - camera_x
  94.         fade_y = zelda_y - camera_y - 16
  95.         fade_sprite:set_animation('close',cont)
  96.       end)
  97.     .exec(
  98.       function()
  99.         -- Fill screen with black.
  100.         local quest_w, quest_h = sol.video.get_quest_size()
  101.         black_surface = sol.surface.create(quest_w, quest_h)
  102.         black_surface:fill_color({0, 0, 0})
  103.       end)
  104.     .wait(1000)
  105.     .exec(
  106.       function()
  107.         local menu_font, menu_font_size = language_manager:get_menu_font()
  108.         end_text = sol.text_surface.create{
  109.           horizontal_alignment = "center",
  110.           vertical_alignment = "middle",
  111.           color = {255, 255, 255},
  112.           font = menu_font,
  113.           font_size = menu_font_size * 2,
  114.           text_key = "final.end_text",
  115.         }
  116.       end)
  117.     .wait(2000)
  118.     .exec(
  119.       function()
  120.         -- Launch Ending credits.
  121.         local dialog_box = game:get_dialog_box()
  122.         dialog_box:set_position("bottom")
  123.       end)
  124.     .dialog('final.credits')
  125.     .exec(
  126.       function()
  127.         local statistics = statistics_manager:new(game)
  128.         game:set_suspended(true)
  129.         sol.menu.start(game, statistics)
  130.         function statistics:on_finished()
  131.           -- Reset game.
  132.           sol.main.reset()
  133.         end
  134.       end)
  135.     .start()
  136. end
  137.