Creating a custom jump

Started by Diarandor, August 04, 2015, 02:22:07 PM

Previous topic - Next topic
Greetings! I always wanted to script a jump like in Zelda games (the one given by the engine is too limited), where you can control the hero during the jump. I had an idea of how we could program this (although there may be other better ways).

The idea is, when using the item to jump, we first create a custom entity with transparent sprite and solid ground that follows the hero under him, and we start the jumping animation on the hero. (The custom entity would allow to move over holes, water and lava while we are jumping, because it has solid ground. It should have smaller size than the hero to avoid traversing walls.) When the jump animation finishes, we destroy the custom entity. It would be necessary to use the save solid ground function before the jump, just in case the hero ends in bad ground, and reset the solid ground function when the jump ends.

One of the advantages (or disadvantages) of doing it this way is that it allows the hero to jump over lower layers (in case that the current layer ends) without falling to the lower ones until the end of the jump. In other words, this would allow to jump between solid grounds on the same layer that have "empty" grounds (not holes!) between them without falling to lower layers. (I was planning to use this to make puzzles where you move boxes of the low layer to make a way on the middle layer where you can jump over the boxes without falling to the lower layer.)

I have not programmed this yet (someday I wil try it) so I am not sure if this will work as I expect. Anyway, I have hope in this trick to program the jump, so I wanted to share the idea.
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

I think it should work. I did not think of using a custom entity to change the ground along the way.

Another solution (also a hack) is to call hero:start_jumping(), but right after that, stop the jump movement created by the engine. The hero will stay in jumping state, which allows to fly over lava, holes, etc and avoids to fall on lower layers. I used this trick for the scripted hookshot and it works. Maybe this is simpler.

I was wondering for this as well. The way jumping works in Solarus was odd compared to how Roc's feather worked, for example, in Link's Awakening.

I have tested my solution and works fine (the only problem is to choose the duration of the jump).

Anyway, your solution seems better, so I will change my script again. Thanks!
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

August 04, 2015, 03:53:17 PM #4 Last Edit: August 04, 2015, 04:09:00 PM by Diarandor
How do you stop the movement while keeping the jumping state?

I have tried with hero:stop_movement(), but the hero stays frozen. If I add hero:unfreeze(), I recover the control of the hero, but this also seems to stop the jumping state... :o Am I doing something wrong? The code I am using is:

function item:on_using()
  local hero = self:get_map():get_entity("hero")
  local direction4 = hero:get_direction()
  hero:start_jumping(direction4 * 2, 32, false)
  hero:stop_movement()
  --hero:unfreeze()
  hero:set_animation("black")
  --self:set_finished()
end


EDIT: I forgot to add the methods, hero:get_solid_ground_position() and hero:reset_solid_ground().
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

With hero:stop_movement(), yes. Then you can start a new movement of your own on the hero. The engine will still consider that the hero is jumping, and is okay with the fact that you are customizing the movement.
You are right, hero:unfreeze() gets back to the free state.

August 04, 2015, 03:58:46 PM #6 Last Edit: August 04, 2015, 04:01:02 PM by Zeror
I just played Link's Awakening to watch the jump closely.

What i think what happens is this:

The hero jump into a direction (let say starting direction) any other direction's movement speed is reduced. Starting direction keeps normal speed. So when the starting direction is left, then the speed to up, down and right direction is reduced, i think by 50% or something. And i think you can only change the direction once per jump.
Then you have the jumping animation. When the animation starts the hero is considered off the ground (meaning holes, empty tiles can be bypassed) until the animation ends (reaches it last frame). The hero is considered on the ground again. Then the tile type decides what happens next. If hero is on a hole, he falls down. If he is on the edge of a hole he get a change to save himself or if he is on safe ground he will just stand.

Maybe this helps in building the new jump. :)

August 04, 2015, 04:01:19 PM #7 Last Edit: August 04, 2015, 04:08:42 PM by Diarandor
Just in case someone is interested, my trick (already tested and works fine) is:

function item:on_using()
  local hero = self:get_map():get_entity("hero")
  local jump_duration = 500 -- Change this for duration of the jump.
  sol.audio.play_sound("jump")
  hero:set_animation("black")
  hero:unfreeze()
  local x,y,layer = hero:get_position()
  local tile = self:get_map():create_custom_entity({x=x,y=y,layer=layer,direction=0,width=8,height=8})
  tile:set_origin(4, 4)
  tile:set_modified_ground("traversable")
  function tile:on_update()
    -- Follow the hero.
    tile:set_position(hero:get_position())
  end
  sol.timer.start(self, jump_duration, function()
    hero:set_animation("stopped")
    tile:remove()
    item:set_finished() 
  end)
end


EDIT: I forgot to add the methods, hero:get_solid_ground_position() and hero:reset_solid_ground().
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

I assume that for your solution I need to modify the event on_command_pressed() to create movements that control the hero? Because I think that is only way to control the hero in that freezing state.
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

August 04, 2015, 04:25:48 PM #9 Last Edit: August 04, 2015, 04:35:20 PM by Diarandor
@Zeror, I think that you are right, probably, that the movement during the jump in Link's awakening has some restrictions (I have tested it now with the gb emulator, although I am not completely sure of these restrictions). The only way to impose these restrictions would probably be using Christopho's solution and programming all the behaviour, which could be hard. I think I will keep my solution anyway, at least for some time.
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

Quote from: Diarandor on August 04, 2015, 04:05:29 PM
I assume that for your solution I need to modify the event on_command_pressed() to create movements that control the hero? Because I think that is only way to control the hero in that freezing state.
Yes. I understand now that you are avoiding that extra work with your solution, so your solution is better :)

I realized that with my solution the animation is not changed to "jumping", so you would need to define a new tunic sprite for the jumping, where the stopped and walking animations show the hero jumping (other animations could be needed too in this new tunic sprite, for instance, if you allow the hero to be hurt during the jump, etc). In the end of the jump, you have to restore the previous tunic sprite.
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."