Solarus Forum

Solarus => Development => Topic started by: wrightmat on June 25, 2015, 04:24:13 am

Title: Side scrolling functionality
Post by: wrightmat on June 25, 2015, 04:24:13 am
As a proof-of-concept, I've been figuring out how to build side-scrolling functionality with Solarus (like the sections of Link's Awakening). I can get jumping, gravity and movement pretty well down, but the part I can't figure out is enemy collisions.

I'd like to have it work like Mario where if you jump on certain enemy's heads, they are hurt, but I can't figure out how to detect that the hero has touched only the top of the enemy. If the hero touched the side of the enemy, the hero should be hurt.

I'm guessing that this can't be accomplished with the built-in enemy class, but even with a custom entity and add_collision_test(), I don't see how to detect what was touching what.
Title: Re: Side scrolling functionality
Post by: wrightmat on June 25, 2015, 04:26:18 am
If anyone is curious, I have a game_manager script that takes care of most of the heavy lifting. The script will cause gravity to act on the hero and any entity with a name prefaced by "g_". This will effect any map of the game, but could be limited to only certain ones easily enough.

Updated code is in a post below...
Title: Re: Side scrolling functionality
Post by: Christopho on June 25, 2015, 08:03:37 am
Wow, I did not suspect that it was possible to implement side-scrolling only with scripts!
There is an old issue for that: https://github.com/christopho/solarus/issues/118

To detect if the hero is above the enemy, you can probably call enemy:get_angle(hero) from a callback and check if the angle is in a specific range.
Title: Re: Side scrolling functionality
Post by: Diarandor on June 25, 2015, 10:21:15 pm
These are good news. I was planning trying to script something like this in the future. I guess that the script can be modified to simulate diving with this side scrolling (like in Link's awakening), which would be cool.

I have been working on several scripts with other functionalities that I would like to share when I finish making the game to the end of the first level. (I don't have too much free time, and drawing all the sprites takes a lot of time and patience, so it will probably be ready by the end of this year or a bit later).

Some scripts I have done allow to have 3 heroes and switch between the heroes on the current map with space bar (or using a switching menu in case the heroes are in different maps, but this menu is not done yet). I also have scripts to carry custom entities which are not destroyed when thrown (I make them bounce when they fall), and they can be thrown from one hero to another (they are picked in the air). Also I made custom buttons that can be pressed by any of the three heroes or custom entities (like weights that can be carried and thrown). Platforms also work well with custom entities that can be carried and the secondary heroes.

The only technical problem I had is that if you leave one map with some secondary hero and come back, the destructible entities, platforms, etc are reseted, which can make a secondary hero to appear overlapping a destructible entity (that had been destroyed before) or to appear over a hole (in case a platform was moved), etc. I solved this easily using a script that saves the state/position of the entities if necessary (it does not work in the current version of Solarus because of a bug that has already been fixed by Christopho, but I hope it to work in the next release).

These are some of the things I made, just in case you are interested. My (maybe too ambitious) goal is to make a hybrid game between Lost Vikings 2 and Link's awakening, but it will take some years of work until it is finished.
Title: Re: Side scrolling functionality
Post by: Neovyse on June 26, 2015, 10:28:05 pm
Oh it could be so cool ! I really like these parts in Zelda games, but I've always thought they should have been more polished. Maybe the focus wasn't put on them to be sure the game would be different than Metroid or Castlevania.
Solarus might become a good Metroidvania engine someday.  ;)
Title: Re: Side scrolling functionality
Post by: wrightmat on June 28, 2015, 12:24:26 am
Christopho, your idea worked! I believe I got the basics working, if anyone would like to use it.

game_manager.lua (gravity and jumping):
Code: [Select]
local game_manager = {}
local map_metatable = sol.main.get_metatable("map")

local gravity = 2
local jump_height = 8
local jumping = false
local i = 0

function game_manager:start_game()

  local exists = sol.game.exists("save1.dat")
  local game = sol.game.load("save1.dat")
  if not exists then
    -- Initialize a new savegame.
    game:set_max_life(1)
    game:set_life(game:get_max_life())
  end
  game:start()

  function game:on_command_pressed(command)

    if command == "up" and not jumping then
      -- override default behaviour and make the hero jump up!
      jumping = true
      i = 0
    end
  end
end

function map_metatable:on_update()

  -- gravity: move entities down one pixel on every update if there's no collision
  --          (like with the ground or a platform)
  local x,y,l = self:get_game():get_hero():get_position()
  if not jumping then
    if not self:get_game():get_hero():test_obstacles(0,gravity) then
      self:get_game():get_hero():set_position(x,y+gravity,l)
    end
  else
    self:get_game():get_hero():set_animation("jumping")
    for i=1, jump_height do
      if not self:get_game():get_hero():test_obstacles(0,-1) then
        self:get_game():get_hero():set_position(x,(y-1),l)
      end
    end
    sol.timer.start(50*jump_height, function()
      jumping = false
      if self:get_game():is_command_pressed("right") or self:get_game():is_command_pressed("left") then
        self:get_game():get_hero():set_animation("walking")
      else
        self:get_game():get_hero():set_animation("stopped")
      end
    end)
  end

  for entity in self:get_entities("g_") do
    local gx,gy,gl = entity:get_position()
    if not entity:test_obstacles(0,gravity) then
      entity:set_position(gx,gy+gravity,gl)
    end
  end

end

return game_manager


monster.lua (example of a goomba-like enemy that you jump on to kill):
Code: [Select]
local enemy = ...

local state = "stopped"  -- "stopped", "moving", "going_back" or "paused".
local initial_xy = {}
local activation_distance = 24

function enemy:on_created()
  self:set_life(1)
  self:set_damage(2)
  self:create_sprite("enemies/monster")
  self:set_size(32, 32)
  self:set_origin(16, 29)
  initial_xy.x, initial_xy.y = self:get_position()
end

function enemy:on_update()
  local hero = self:get_map():get_entity("hero")
  if state == "stopped" and self:get_distance(hero) <= 192 then
    -- Check whether the hero is close.
    local x, y = self:get_position()
    local hero_x, hero_y = hero:get_position()
    local dx, dy = hero_x - x, hero_y - y

    if math.abs(dy) < activation_distance then
      if dx > 0 then
self:go(0)
      else
self:go(2)
      end
    end
    if state == "stopped" and math.abs(dx) < activation_distance then
      if dy > 0 then
self:go(3)
      else
self:go(1)
      end
    end
  end
end

function enemy:go(direction4)
  local dxy = {
    { x =  8, y =  0},
    { x =  0, y = -8},
    { x = -8, y =  0},
    { x =  0, y =  8}
  }

  -- Check that we can make the move.
  local index = direction4 + 1
  if not self:test_obstacles(dxy[index].x * 2, dxy[index].y * 2) then
    state = "moving"
    self:get_sprite():set_animation("walking")
    local x, y = self:get_position()
    local angle = direction4 * math.pi / 2
    local m = sol.movement.create("straight")
    m:set_speed(40)
    m:set_angle(angle)
    m:set_max_distance(104)
    m:set_smooth(false)
    m:start(self)
  end
end

function enemy:on_obstacle_reached()
  self:go_back()
end

function enemy:on_movement_finished()
  self:go_back()
end

function enemy:on_collision_enemy(other_enemy, other_sprite, my_sprite)
  if other_enemy:get_breed() == self:get_breed() and state == "moving" then
    self:go_back()
  end
end

function enemy:on_attacking_hero(hero, enemy_sprite)
  -- If hero is above the enemy (jumping on its head), kill it; otherwise, hurt the hero
  if self:get_angle(hero) >= 0.8 and self:get_angle(hero) <= 2.2 then
    self:remove_life(2)
  else
    hero:start_hurt(self, 1)
  end
end

function enemy:go_back()
  if state == "moving" then
    state = "going_back"
    self:get_sprite():set_animation("walking")
    local m = sol.movement.create("target")
    m:set_speed(32)
    m:set_target(initial_xy.x, initial_xy.y)
    m:set_smooth(false)
    m:start(self)
  elseif state == "going_back" then
    state = "paused"
    self:get_sprite():set_animation("immobilized")
    sol.timer.start(self, 500, function() self:unpause() end)
  end
end

function enemy:unpause()
  self:get_sprite():set_animation("immobilized")
  state = "stopped"
end
Title: Re: Side scrolling functionality
Post by: DementedKirby on July 25, 2015, 07:52:48 am
Wow! That's some great work indeed! Now maybe some more difficult 2D scrolling parts a la Link's Awakening can be done? That would be awesome. But, the game did have some in depth use of the 2D scrolling besides mere underground passages linking 2 places: Manbo's Cave and 2 boss battles. That would be sweet if it could be implemented as smoothly as you're all working on it! A ZeldaII/Link to the Past hybrid sounds pretty effin' epic!
Title: Re: Side scrolling functionality
Post by: DementedKirby on July 25, 2015, 05:00:16 pm
These are good news. I was planning trying to script something like this in the future. I guess that the script can be modified to simulate diving with this side scrolling (like in Link's awakening), which would be cool.

I have been working on several scripts with other functionalities that I would like to share when I finish making the game to the end of the first level. (I don't have too much free time, and drawing all the sprites takes a lot of time and patience, so it will probably be ready by the end of this year or a bit later).

Some scripts I have done allow to have 3 heroes and switch between the heroes on the current map with space bar (or using a switching menu in case the heroes are in different maps, but this menu is not done yet). I also have scripts to carry custom entities which are not destroyed when thrown (I make them bounce when they fall), and they can be thrown from one hero to another (they are picked in the air). Also I made custom buttons that can be pressed by any of the three heroes or custom entities (like weights that can be carried and thrown). Platforms also work well with custom entities that can be carried and the secondary heroes.

The only technical problem I had is that if you leave one map with some secondary hero and come back, the destructible entities, platforms, etc are reseted, which can make a secondary hero to appear overlapping a destructible entity (that had been destroyed before) or to appear over a hole (in case a platform was moved), etc. I solved this easily using a script that saves the state/position of the entities if necessary (it does not work in the current version of Solarus because of a bug that has already been fixed by Christopho, but I hope it to work in the next release).

These are some of the things I made, just in case you are interested. My (maybe too ambitious) goal is to make a hybrid game between Lost Vikings 2 and Link's awakening, but it will take some years of work until it is finished.

That sounds amazing! Have you been able to finish the script that at least makes liftable objects bounce and not break?
Title: Re: Side scrolling functionality
Post by: Diarandor on July 25, 2015, 08:38:03 pm
Yes and no. It works "almost" fine. The only problem is that I get a crash sometimes after the item falls if you walk where the shadow was removed, because the shadow entity I used was not removed correctly or something like that. I think that bug was already solved by Christopho in the development version, so my script should work in the next version (or it may become an error of my script that I should be able to correct).

I want to put my scripts on github after the next version of solarus is released (to check if it works and repair it if necessary), but I can put it now if you want. (Note that to make this script work you will also need to modify slightly the game:on_command_pressed() event, but this is not a problem.)
Title: Re: Side scrolling functionality
Post by: DementedKirby on July 25, 2015, 09:03:46 pm
Sure! Just tell me what I'd need to do! I have the latest version of Solarus Quest Editor installed (1.4.2).
Title: Re: Side scrolling functionality
Post by: Diarandor on July 25, 2015, 11:05:26 pm
Hi DementKirby!

I have created my first github repository and put some of my scripts. You have the one you want in entities/generic_portable.lua. You should study the code and delete/modify the things you don't need. Also you need the sprites and animations and sounds to be compatible with the script. (Recall that there is still a crash with these entities. I will try to repair it someday.)

You will find my repository here: https://github.com/Diarandor

Also, you will find the scripts for entities button and weight. Weights are generic_portable entities (so these can be carried, etc) that can push my button entities. I will put more stuff in the repository someday soon.
Title: Re: Side scrolling functionality
Post by: DementedKirby on July 26, 2015, 12:22:15 am
Thanks! I will study them shortly and see what it is you're accomplishing from a coding standpoint. As for the sprites, I take it you're working it around something like the heavy metal ball in the Eagle's Tower in Link's Awakening?
Title: Re: Side scrolling functionality
Post by: Diarandor on July 26, 2015, 07:31:10 pm
Yes, I'm using that script to make things similar to that metal ball (Link's awakening is great!), but also more complex entities with several sprites that can be carried. (I haven't tried to script the flying rooster since I don't need it, but it should be scriptable, with a lot of work of course.)

Also, in my game, instead of pickable, keys will be carried, so I will be able to annoy the hero with bird enemies that steal the key you are carrying, or forcing you to throw the keys between the three heroes (since they have different abilities and must take different paths sometimes), or using other things like conveyor belts and platforms with keys, or even using the magneto with metal keys. I think this would give more originality/personality to my game than usual keys.
Title: Re: Side scrolling functionality
Post by: DementedKirby on July 26, 2015, 09:31:32 pm
Wow! That seems pretty ambitious and original! I can't wait to see it finished!

Do you think you're having problems with the shadow and whatnot because you're trying to make a bouncing effect? What if they just fell on the ground and didn't bounce before getting still? Would that solve your problem?
Title: Re: Side scrolling functionality
Post by: Diarandor on July 26, 2015, 10:39:51 pm
The problem can be avoided if you do not create the shadow. I still don't know what produces the crash.
Title: Re: Side scrolling functionality
Post by: DementedKirby on July 26, 2015, 10:43:47 pm
So it will work as long as there's no shadow? But no shadow while moving or no shadow altogether?
Title: Re: Side scrolling functionality
Post by: Diarandor on July 26, 2015, 11:42:50 pm
The shadow is made with a custom entity, created when you throw the entity and removed after the item has fallen. If you don't create it there are no crashes. Maybe it's a problem of my script...
Title: Re: Side scrolling functionality
Post by: DementedKirby on July 27, 2015, 12:12:13 am
In that case, don't use the shadow created with the custom entity. Shadows already appear correctly when destructible items are thrown. Is there any way to work around that?
Title: Re: Side scrolling functionality
Post by: Diarandor on July 27, 2015, 01:45:09 am
But I am not using a destructible entity. With my scripts, what you lift is a custom entity. The lifting, carrying and throwing states of the hero and the entity are fully scripted. So there is no shadow if you do not create it. (And probably the crash is due to something that I did wrong. But I don't have much time this summer to work in my game...)

You should do your own scripts for your purposes, or wait until the day that custom entities can be carried. There is no other workaround. You have to be patient and don't underestimate the programming, since it takes a lot of effort and months (or years) of work.
Title: Re: Side scrolling functionality
Post by: DementedKirby on July 27, 2015, 02:31:25 am
Lol, trust me, I know how much time programming can take (studied Computer Sciences in college) that's why I'm dedicating myself more to the graphical aspect and story and map design aspect of my game while I'm able to then get my bearings to make my own menu system. Also, I plan on scripting other items as well besides the ones available thanks to Christopho and his Solarus DX. So I got the patience as well (since I also don't have the time  :P).

What I meant by the shadow created by the destructible object is to see if you can mimic that particularity of the code for a destructible object. But I understand that you're trying to take this route from scratch - which is damn near amazing. I'm fully aware of the effort needed to code something so complex. When I can, I can help look over the section of the code pertaining to the shadow. I'm still a fledgling in lua but I know my C++ so I can at least get a feel of what I'm reading.

I really think you got something going here. This would be useful to make cuccos that you can hold to help you glide or even the rooster from Koholint (as you also suggested). This could also be used to carry around a helpless NPC like a young Princess Ruto from Ocarina of Time. The possibilities really are endless and I give you some well deserved kudos.  I'm merely rooting for you to be able to fully achieve this to your own expectations ;).
Title: Re: Side scrolling functionality
Post by: Diarandor on July 27, 2015, 03:28:02 am
Thanks for the compliments! :D
With your knowledge of programming you won't have problems, since Lua is much easier and flexible than C++ (actually, I forgot C++ many years ago :P).

As a workaround for the generic_portable.lua script, you can comment/delete the lines of the script where shadow:remove() appears (there are two of them), which would avoid the crash, but the shadow will not be deleted, so each time you throw the entity a shadow will appear and stay where the entity has fallen. To test the script, you can try to use my script key.lua, which uses the code of the script generic_portable.lua.

I think the cause of the crash was already solved here:
https://github.com/christopho/solarus/issues/690
so I am still waiting for the next bugfix 1.4.3 to see if it works. There was another bug fixed in
https://github.com/christopho/solarus/issues/691
that did not allow to recover the information of any entity when the player leaves the map (since the entities were removed before the event map:on_finished() was called). This could also give some problems, maybe, to save the position of generic_portable entities when changing maps, so I am also waiting for the next bugfix 1.4.3 because of this, before repairing/improving my script.

EDIT: I think it would be better to open a new topic to talk about this, since it has nothing to do with the side scrolling.
Title: Re: Side scrolling functionality
Post by: DementedKirby on July 27, 2015, 04:33:07 am
Well, the good thing is that you found a bug which allows Cristopho to fix for later releases of Solarus. So I guess you're in the right to wait for the update to check your code again. If it looks good and does what it's supposed to do I guess time will determine whether you have to change some things in your lua code or it's resolved with the latest changes.

One thing you can try in the mean time is to change the direction of the entity carried in the same direction as the hero (if you were carrying an "npc", for example) in the case of carrying a cucco or a Princess Ruto type situation. Does your script already do this?
Title: Re: Side scrolling functionality
Post by: Diarandor on July 27, 2015, 04:55:54 am
Of course, you can change the direction of the carried entity while it is carried. It should be very easy to simulate carrying the princess or the cucco (but unfortunately this is not so easy to make the flying rooster).

I can put some examples (including graphics) in my repository, so you can understand better how to make it. But before I want to put my graphics in opengameart.org or other website like that (I will do it someday soon, today I am a bit lazy, and before I need to separate my graphics from the ones of "A Link to the past"). I made a ball of yarn entity that can be carried and changes direction when the hero does, and cats that can interact (playing) with it and follow it (even when you carry it). I will put this example in my repository when I add more things.

Both bugs were solved by Christopho (thanks!!! ;D), so we just need to wait. (If you know how to compile Solarus from the development version on github, you could check if it works.)
Title: Re: Side scrolling functionality
Post by: DementedKirby on July 27, 2015, 05:37:26 am
Nah, I'll just wait for it to be released in the next release :P. That'll build the anticipation of being able to look forward to it when it's released :D. It's great that he was able to solve the problem, though! Entities you can carry that can be thrown around without exploding or breaking is a Zelda staple. It's also great to design puzzles around the concept. I'll do some map designs in the mean time! Sweet!

Do you know if Christopho is going to release a 1.4.3 version with those bugs fixed or is he going to wait to have 1.5 ready to release it altogether?
Title: Re: Side scrolling functionality
Post by: Diarandor on July 27, 2015, 06:19:50 am
I don't know for sure (he should answer this), but probably in 1.4.3. You can check how much work remains to be done in his github repositories.

I have opened another post to talk about the generic_portable entities of my script, since this post is not the good place to talk about it. It's here: http://forum.solarus-games.org/index.php/topic,332.0.html
Title: Re: Side scrolling functionality
Post by: zutokaza on October 08, 2015, 05:27:33 am
I can't seem to get the jumping working. (3MB)
http://s000.tinyupload.com/index.php?file_id=02681457115274128283
Title: Re: Side scrolling functionality
Post by: Christopho on January 19, 2016, 06:25:24 pm
In Link's Awakening and Zelda 1 side-view caves, there are ladders.
The hero should not fall when on a ladder. There is already a "ladder" ground type in the engine it should be easy to take it into account in the script (if I understand correctly, this is not the case yet).
I think we just need to check the ground below the hero:

Code: Lua
  1. if entity:get_type() == "hero" and map:get_ground(hero:get_position()) ~= "ladder" then
  2.   -- Gravity
  3. end
  4.  
Title: Re: Side scrolling functionality
Post by: wrightmat on January 20, 2016, 02:31:06 am
Very true, christopho! Thanks for the addition!
Title: Re: Side scrolling functionality
Post by: wrightmat on October 11, 2016, 01:08:36 am
I realize this is kind of grave digging, and I apologize, but I decided to do some work and this script and wanted to post it in the original topic.

I generalized the script a bit and built it around a state engine for the hero. The animations used for the hero sprite are the same as the state names.

The gravity updating is not done via a timer rather than the map's on_update routine, as Diarandor had suggested in another topic. I also added a "multi jump" option to allow the player to press the jump key several times. It doesn't work the way I would like yet, but the basics are there. Finally, I added a ladder option that Christopho had suggested on another topic.

Code: Lua
  1. local game_manager = {}
  2. local game_over_menu = {}
  3. local map_metatable = sol.main.get_metatable("map")
  4.  
  5. local gravity = 5       -- How often to update gravity in milliseconds (move the hero down one pixel this often). Default is every 10 ms.
  6. local jump_height = 40  -- How high to make the hero go when he jumps (in pixels). Default is 40.
  7. local multi_jump = 2    -- How many times to allow the character to jump. Default is 1, or enter 0 to disable jumping entirely.
  8. local state             -- "stopped", "walking", "jumping", "ladder", "dying", "action", "attack"
  9. local last_anim
  10.  
  11. function game_manager:start_game()
  12.   local exists = sol.game.exists("save1.dat")
  13.   local game = sol.game.load("save1.dat")
  14.   if not exists then
  15.     -- Initialize a new savegame.
  16.     game:set_max_life(1)
  17.     game:set_life(game:get_max_life())
  18.     game:set_starting_location("2")
  19.   end
  20.   game:start()
  21.  
  22.   function game:on_started()
  23.     sol.timer.start(gravity, function()
  24.       if self:get_map() ~= nil then
  25.         -- Gravity: move entities down one pixel on every update if there's no collision.
  26.         --   (like with the ground or a platform) and hero not jumping or on a ladder.
  27.         local hero = self:get_hero()
  28.         local x, y, l = hero:get_position()
  29.         if state ~= "jumping" and self:get_map():get_ground(hero:get_position()) ~= "ladder" then
  30.           if not hero:test_obstacles(0, 1) then hero:set_position(x, (y + 1), l) end
  31.         elseif state == "jumping" then
  32.           for i = 1, jump_height do
  33.             if not hero:test_obstacles(0, -1) then hero:set_position(x, (y - 1), l) end
  34.           end
  35.           sol.timer.start(gravity * jump_height, function()
  36.             if self:is_command_pressed("right") or self:is_command_pressed("left") then
  37.               state = "walking"
  38.             else
  39.               state = "stopped"
  40.             end
  41.           end)
  42.           hero:set_animation(state)
  43.         end
  44.        
  45.         for entity in self:get_map():get_entities("g_") do
  46.           local gx, gy, gl = entity:get_position()
  47.           if not entity:test_obstacles(0, 1) then
  48.             entity:set_position(gx, (gy + 1), gl)
  49.           end
  50.         end
  51.       end
  52.       return true
  53.     end)
  54.   end
  55.  
  56.   function game:on_command_pressed(command)
  57.     local hero = game:get_map():get_hero()
  58.     local multi_jump_temp = multi_jump
  59.     if command == "up" then
  60.       if not self:is_suspended() and not jumping and multi_jump_temp > 0 then
  61.         if game:get_map():get_ground(hero:get_position()) ~= "ladder" then
  62.           -- Override default behavior and make the hero jump up!
  63.           state = "jumping"
  64.           multi_jump_temp = multi_jump_temp - 1
  65.         else
  66.           state = "ladder"
  67.         end
  68.       else
  69.         state = "stopped"
  70.       end
  71.     elseif command == "action" and not self:is_suspended() then
  72.       state = "action"
  73.     elseif command == "attack" and not self:is_suspended() then
  74.       state = "attack"
  75.     else
  76.       state = "stopped"
  77.     end
  78.     last_anim = hero:get_animation()
  79.     hero:set_animation(state)
  80.   end
  81.  
  82.   function game:on_command_released(command)
  83.     state = last_anim
  84.     if state == nil then state = "stopped" end
  85.     game:get_map():get_hero():set_animation(state)
  86.   end
  87.  
  88.   function game:on_game_over_started()
  89.     sol.menu.start(game:get_map(), game_over_menu)
  90.   end
  91.  
  92.   function game_over_menu:on_started()
  93.     local hero = game:get_hero()
  94.     local map = game:get_map()
  95.     local camera_x, camera_y = map:get_camera():get_position()
  96.     local hero_x, hero_y = hero:get_position()
  97.     hero_dead_x = hero_x - camera_x
  98.     hero_dead_y = hero_y - camera_y
  99.  
  100.     hero_dead_sprite = sol.sprite.create("hero/tunic1")
  101.     hero_dead_sprite:set_animation("hurt")
  102.     state = "dying"
  103.  
  104.     sol.audio.stop_music()
  105.     hero:set_visible(false)
  106.     hero_dead_sprite:set_animation("dying")
  107.     hero_dead_sprite.on_animation_finished = function()
  108.       sol.timer.start(self, 500, function()
  109.         game:stop_game_over()
  110.         game:start()
  111.       end)
  112.     end
  113.   end
  114.  
  115.   function game_over_menu:on_finished()
  116.     local hero = game:get_hero()
  117.     if hero ~= nil then hero:set_visible(hero_was_visible) end
  118.     music = nil
  119.     hero_dead_sprite = nil
  120.     fade_sprite = nil
  121.     sol.timer.stop_all(self)
  122.   end
  123.  
  124.   function game_over_menu:on_draw(dst_surface)
  125.     hero_dead_sprite:draw(dst_surface, hero_dead_x, hero_dead_y)
  126.   end
  127. end
  128.  
  129. return game_manager

Please post any improvements or critiques!
Title: Re: Side scrolling functionality
Post by: Zefk on October 11, 2016, 03:16:54 am
Everything is looking good now. I am just wondering....what broke the old jump function?

(https://media.giphy.com/media/l0HlBNX6tlVUZn7Bm/giphy.gif)
Title: Re: Side scrolling functionality
Post by: Zefk on August 08, 2018, 02:40:59 am
I found a bug when holding down keys.  The hero glides around if I continue to hold the up and right keys at the same time and the hero retains the jump animation if I were to jump while holding the keys.

You can see it near the end of the gif. Ignore the water....I was testing something with a black tile.
(https://media.giphy.com/media/ctJ98FXEpYFMn98Zsy/giphy.gif)
Title: Re: Side scrolling functionality
Post by: Zefk on August 08, 2018, 08:14:53 am
Here is a little patch until wrightmat fixes the problem. The hero will not float and get stuck on the jumping animation. Although, it will not prevent the hero from standing still and moving when the right/down or left/down is being pressed at the same time.

Wrightmat's sidescroller script: here (http://forum.solarus-games.org/index.php/topic,297.msg4237.html#msg4237)
Wrightmat's monster script: here (http://forum.solarus-games.org/index.php/topic,297.msg1101.html#msg1101)

(https://media.giphy.com/media/XK9bNMxDjfRVU5C2Yf/giphy.gif)

I think I heard a key on_pressing function was being made. Maybe that could fix the problem.

Patch for game:on_started():
Code: Lua
  1.   function game:on_started()
  2.    local hero = game:get_hero()
  3.     hero:set_tunic_sprite_id("main_heroes/eldran")
  4.     sol.timer.start(gravity, function()
  5.       if self:get_map() ~= nil then
  6.         -- Gravity: move entities down one pixel on every update if there's no collision.
  7.         --   (like with the ground or a platform) and hero not jumping or on a ladder.
  8.         local hero = self:get_hero()
  9.         local x, y, l = hero:get_position()
  10.         if state ~= "jumping" and self:get_map():get_ground(hero:get_position()) ~= "ladder" then
  11.           if not hero:test_obstacles(0, 1) then hero:set_position(x, (y + 1), l) end
  12.         elseif state == "jumping" then
  13.           for i = 1, jump_height do
  14.             if not hero:test_obstacles(0, -1) then hero:set_position(x, (y - 1), l) end
  15.           end
  16.           sol.timer.start(gravity * jump_height, function()
  17.             if self:is_command_pressed("right") or self:is_command_pressed("left") then
  18.               state = "walking"
  19.             else
  20.               state = "stopped"
  21.             end
  22.             --right
  23.             if self:is_command_pressed("right") and self:is_command_pressed("left") then
  24.               hero:set_animation("walking")
  25.               state = "walking"
  26.             else
  27.               state = "stopped"
  28.             end
  29.             if self:is_command_pressed("right") and self:is_command_pressed("up") then
  30.               hero:set_animation("walking")
  31.               state = "walking"
  32.             else
  33.               state = "stopped"
  34.             end
  35.             --left
  36.             if self:is_command_pressed("left") and self:is_command_pressed("right") then
  37.               hero:set_animation("walking")
  38.               state = "walking"
  39.             else
  40.               state = "stopped"
  41.             end
  42.             if self:is_command_pressed("left") and self:is_command_pressed("up") then
  43.               hero:set_animation("walking")
  44.               state = "walking"
  45.             else
  46.               state = "stopped"
  47.             end
  48.             --up
  49.             if self:is_command_pressed("up") and self:is_command_pressed("right") then
  50.               hero:set_animation("walking")
  51.               state = "walking"
  52.             else
  53.               state = "stopped"
  54.             end
  55.             if self:is_command_pressed("up") and self:is_command_pressed("left") then
  56.               hero:set_animation("walking")
  57.               state = "walking"
  58.             else
  59.               state = "stopped"
  60.             end
  61.             if self:is_command_pressed("up") and self:is_command_pressed("down") then
  62.               hero:set_animation("walking")
  63.               state = "walking"
  64.             else
  65.               state = "stopped"
  66.             end
  67.           end)
  68.           hero:set_animation(state)
  69.         end
  70.  
  71.   function game:on_key_pressed(key)
  72.     local hero = game:get_hero()
  73.  
  74.     if key == "up" and key == "down" and key == "left" and key == "right"  then
  75.       hero:set_animation("walking")
  76.     else
  77.       hero:set_animation("walking")
  78.     end
  79.   end

Explanation:

I added some checks function game:on_started() to prevent the hero from floating around.

Code: Lua
  1.             --right
  2.             if self:is_command_pressed("right") and self:is_command_pressed("left") then
  3.               hero:set_animation("walking")
  4.               state = "walking"
  5.             else
  6.               state = "stopped"
  7.             end
  8.             if self:is_command_pressed("right") and self:is_command_pressed("up") then
  9.               hero:set_animation("walking")
  10.               state = "walking"
  11.             else
  12.               state = "stopped"
  13.             end
  14.             --left
  15.             if self:is_command_pressed("left") and self:is_command_pressed("right") then
  16.               hero:set_animation("walking")
  17.               state = "walking"
  18.             else
  19.               state = "stopped"
  20.             end
  21.             if self:is_command_pressed("left") and self:is_command_pressed("up") then
  22.               hero:set_animation("walking")
  23.               state = "walking"
  24.             else
  25.               state = "stopped"
  26.             end
  27.             --up
  28.             if self:is_command_pressed("up") and self:is_command_pressed("right") then
  29.               hero:set_animation("walking")
  30.               state = "walking"
  31.             else
  32.               state = "stopped"
  33.             end
  34.             if self:is_command_pressed("up") and self:is_command_pressed("left") then
  35.               hero:set_animation("walking")
  36.               state = "walking"
  37.             else
  38.               state = "stopped"
  39.             end
  40.             if self:is_command_pressed("up") and self:is_command_pressed("down") then
  41.               hero:set_animation("walking")
  42.               state = "walking"
  43.             else
  44.               state = "stopped"
  45.             end

I added this function to prevent the hero from being stuck on the jumping animation.

Code: Lua
  1.   function game:on_key_pressed(key)
  2.     local hero = game:get_hero()
  3.  
  4.     if key == "up" and key == "down" and key == "left" and key == "right"  then
  5.       hero:set_animation("walking")
  6.     else
  7.       hero:set_animation("walking")
  8.     end
  9.   end
Title: Re: Side scrolling functionality
Post by: Christopho on August 08, 2018, 09:11:43 am
This is a known issue. The side-scrolling script does not support jumping correctly yet.
Title: Re: Side scrolling functionality
Post by: Zefk on August 09, 2018, 01:14:13 am
@Christopho
Ah, I had no idea.

Updated:

Download Quest: here (https://github.com/Zefk/Solarus-ARPG-Game-Development-Book_2/blob/master/Lessons/Chapter_16/chapter_16_sidescroller_setup.zip)

(https://media.giphy.com/media/Zxo86ojesa0TdQc2os/giphy.gif)
(https://media.giphy.com/media/jamE5MP3FgAmALJUVw/giphy.gif)

The thing I cannot figure out. The hero jumps faster and faster after every death. The only thing I can think of is to use a fake game:start().

Code: Lua
  1.         local map = game:get_map()
  2.         --Fake death
  3.         --map1
  4.         if game:get_value("map1") == true and map:get_id() == "first_map" then
  5.           if game:get_life() == 1 then
  6.             hero:teleport("first_map", "map1", "fade")
  7.             game:set_life(game:get_max_life())
  8.           end
  9.          --map2
  10.          elseif game:get_value("map2") == true and map:get_id() == "map_leave_test" then
  11.           if game:get_life() == 1 then
  12.             hero:teleport("map_leave_test", "map2", "fade")
  13.             game:set_life(game:get_max_life())
  14.           end
  15.         end

(https://media.giphy.com/media/1jXz8UOyaimlfQzArp/giphy.gif)
Title: Re: Side scrolling functionality
Post by: Zefk on August 11, 2018, 02:13:31 am
I updated my post and made the side-scroling script somewhat stable: here (http://forum.solarus-games.org/index.php/topic,297.msg7164.html#msg7164)

It is not perfect, but I could make a side-scroller game with it. I hope it helps someone out there.

Remember to credit Wrightmat because it is his script. I just patched it up.

P.S. I will just silently update the post above if I find bugs.
Title: Re: Side scrolling functionality
Post by: Ender on September 03, 2018, 01:45:08 pm
I can't figure out how to make this run. I put it in my Solarus folder, and it seems have roughly the same contents as the other quests there, but for some reason, the app won't detect it.
Title: Re: Side scrolling functionality
Post by: Diarandor on September 03, 2018, 03:42:17 pm
A custom feather allowing to jump in sideview maps was done recently, as an improved version of Wrightmat's script. But it will be slightly rewritten again, and using custom states, when Solarus 1.6 (with its custom states) is released.