(Solved) Side scrolling game help - Not jumping

Started by zutokaza, October 09, 2015, 03:30:27 AM

Previous topic - Next topic
October 09, 2015, 03:30:27 AM Last Edit: October 14, 2016, 01:02:26 AM by zutokaza
This topic:
http://forum.solarus-games.org/index.php/topic,297.msg1086.html#msg1086

I can't seem to get the jumping working for the side scroller, but everything else works. The 3 MB project can be downloaded at TinyUpload.

http://s000.tinyupload.com/index.php?file_id=02681457115274128283

game_manager.lua
Code (lua) Select
-- Script that creates a game ready to be played.

-- Usage:
-- local game_manager = require("scripts/game_manager")
-- local game = game_manager:create("savegame_file_name")
-- game:start()

local dialog_box_manager = require("scripts/dialog_box")

local game_manager = {}
local map_metatable = sol.main.get_metatable("map")

local gravity = 1
local jump_height = 10
local jumping = true
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
-------------------------------------------------------------------------------

-- Sets initial values for a new savegame of this quest.
local function initialize_new_savegame(game)
  game:set_starting_location("Test side")
  game:set_max_money(100)
  game:set_max_life(12)
  game:set_life(game:get_max_life())
end

-- Creates a game ready to be played.
function game_manager:create(file)

  -- Create the game (but do not start it).
  local exists = sol.game.exists(file)
  local game = sol.game.load(file)
  if not exists then
    -- This is a new savegame file.
    initialize_new_savegame(game)
  end

  local dialog_box

  -- Function called when the player runs this game.
  function game:on_started()

    dialog_box = dialog_box_manager:create(game)
  end

  -- Function called when the game stops.
  function game:on_finished()

    dialog_box:quit()
    dialog_box = nil
  end

  function game:on_paused()

    game:start_dialog("pause.save",function(answer)
      if answer == 2 then
        game:save()
      end
      game:set_paused(false)
  end)
end

  return game
end

return game_manager
Solarus Works on ReactOS Opensource Windows OS

https://www.reactos.org/forum/viewtopic.php?f=2&t=14759&p=120616#p120616

Hi, just to say, you can use Lua syntax coloring when you post code. In the code tag, you can set Lua like this:

[code=lua]

I edited your post to set this option ;)

First thing I see is that
local jumping = true at the top should be:
local jumping = false
That may be your only problem since the code is checking that you're not already jumping, which is indicated by jumping = true.


Other things to check in case that doesn't fix it - Do you get an error of any sort? Do you have an animation set "jumping" in your character?


An additional improvement I would recommend (unrelated to the problem) is:
if command == "up" and not jumping then
would be better as:
if command == "up" and not self:is_suspended() and not jumping then
To check that the game isn't paused or otherwise disabled, since on_command_pressed is applied to the whole game.

October 11, 2015, 01:59:08 AM #3 Last Edit: October 11, 2015, 02:16:31 AM by zutokaza
Quote from: wrightmat on October 09, 2015, 02:31:10 PM
First thing I see is that
local jumping = true at the top should be:
local jumping = false
That may be your only problem since the code is checking that you're not already jumping, which is indicated by jumping = true.


Other things to check in case that doesn't fix it - Do you get an error of any sort? Do you have an animation set "jumping" in your character?


An additional improvement I would recommend (unrelated to the problem) is:
if command == "up" and not jumping then
would be better as:
if command == "up" and not self:is_suspended() and not jumping then
To check that the game isn't paused or otherwise disabled, since on_command_pressed is applied to the whole game.

It still doesn't work when setting it to false, but the player does jump once at the start without me pressing any keys  if I set jumping to true. He doesn't jump after that.

There is an animation folder for jumping. It is named correctly.

There is no error output file.

when I set the gravity to zero.....I am able to walk on the enemies head to kill it. Although, the player still walks the way he would in an ARPG. That could be the reason the "up" key is being ignored. Maybe all the keys in the script are being ignored.....
Solarus Works on ReactOS Opensource Windows OS

https://www.reactos.org/forum/viewtopic.php?f=2&t=14759&p=120616#p120616

Hi! I don't know exactly why it does not allow jumping, but it is clear that the code is not correctly done for the nice behaviour. Some advices to improve and restructure your code (although I could be wrong in some of them):

1) I think that the "i" variable is not being used, so you can remove the lines 16 and 36.

2) You could write "local hero = self:get_game():get_hero()" to use the hero variable, avoiding to repeat the code "self:get_game():get_hero()". The same for the game variable.

3) The on_update() event is called very quickly, almost every instant, so it is not a good idea to change the position of hero when it is called. You could use also some timer to change the position of the hero with the desired speed (use a falling speed variable for this timer). Be careful so that each time the event is called you create the timer only if there is not already some timer created before.

4) Changing the position of the hero with "hero:set_position(x,y+gravity,l)" is not a good idea. If the gravity is bigger than 1, say 8 for instance, then in the case that the hero has coordinate "y" 4 coordinates above the ground he would not fall because there is an obstacle 8 coordinates under him. (The hero should fall 1 pixel each time, and set the falling speed with a timer as I suggested above.)

I will try to help you more after you rewrite/improve your code.
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

I kinda don't understand why the key commands are not working. If anyone can get a side platform script working, them that would be great.
Solarus Works on ReactOS Opensource Windows OS

https://www.reactos.org/forum/viewtopic.php?f=2&t=14759&p=120616#p120616

http://forum.solarus-games.org/index.php/topic,297.15.html

I updated the script on the original topic. Feel free to try it out and let me know if it works.

I confirm that the new script works. No bugs encountered yet for your script.
Solarus Works on ReactOS Opensource Windows OS

https://www.reactos.org/forum/viewtopic.php?f=2&t=14759&p=120616#p120616

Using the Solarus sample quest:
His enemy script still works with the new script. The hero freezes because he has "no death animation" or transition after death (not a script bug), but the hero shows that damage flickering animation if hurt with life beyond 1.

Code ( lua) Select
    game:set_max_life(3)


Freeze death and jump on enemy:


Damage flicker:


slime_green.lua
Code ( lua) 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/slime_green")
  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("prepare_jump")
    sol.timer.start(self, 500, function() self:unpause() end)
  end
end

function enemy:unpause()
  self:get_sprite():set_animation("prepare_jump")
  state = "stopped"
end


game_manager.lua
Code ( lua) Select
local game_manager = {}
local game_over_menu = {}
local map_metatable = sol.main.get_metatable("map")

local gravity = 5       -- How often to update gravity in milliseconds (move the hero down one pixel this often). Default is every 10 ms.
local jump_height = 40  -- How high to make the hero go when he jumps (in pixels). Default is 40.
local multi_jump = 2    -- How many times to allow the character to jump. Default is 1, or enter 0 to disable jumping entirely.
local state             -- "stopped", "walking", "jumping", "ladder", "dying", "action", "attack"
local last_anim

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(3)
    game:set_life(game:get_max_life())
    game:set_starting_location("2")
  end
  game:start()
 
  function game:on_started()
    sol.timer.start(gravity, function()
      if self:get_map() ~= nil then
        -- Gravity: move entities down one pixel on every update if there's no collision.
        --   (like with the ground or a platform) and hero not jumping or on a ladder.
        local hero = self:get_hero()
        local x, y, l = hero:get_position()
        if state ~= "jumping" and self:get_map():get_ground(hero:get_position()) ~= "ladder" then
          if not hero:test_obstacles(0, 1) then hero:set_position(x, (y + 1), l) end
        elseif state == "jumping" then
          for i = 1, jump_height do
            if not hero:test_obstacles(0, -1) then hero:set_position(x, (y - 1), l) end
          end
          sol.timer.start(gravity * jump_height, function()
            if self:is_command_pressed("right") or self:is_command_pressed("left") then
              state = "walking"
            else
              state = "stopped"
            end
          end)
          hero:set_animation(state)
        end
       
        for entity in self:get_map():get_entities("g_") do
          local gx, gy, gl = entity:get_position()
          if not entity:test_obstacles(0, 1) then
            entity:set_position(gx, (gy + 1), gl)
          end
        end
      end
      return true
    end)
  end
 
  function game:on_command_pressed(command)
    local hero = game:get_map():get_hero()
    local multi_jump_temp = multi_jump
    if command == "up" then
      if not self:is_suspended() and not jumping and multi_jump_temp > 0 then
        if game:get_map():get_ground(hero:get_position()) ~= "ladder" then
          -- Override default behavior and make the hero jump up!
          state = "jumping"
          multi_jump_temp = multi_jump_temp - 1
        else
          state = "ladder"
        end
      else
        state = "stopped"
      end
    elseif command == "action" and not self:is_suspended() then
      state = "action"
    elseif command == "attack" and not self:is_suspended() then
      state = "attack"
    else
      state = "stopped"
    end
    last_anim = hero:get_animation()
    hero:set_animation(state)
  end
 
  function game:on_command_released(command)
    state = last_anim
    if state == nil then state = "stopped" end
    game:get_map():get_hero():set_animation(state)
  end
 
  function game:on_game_over_started()
    sol.menu.start(game:get_map(), game_over_menu)
  end
 
  function game_over_menu:on_started()
    local hero = game:get_hero()
    local map = game:get_map()
    local camera_x, camera_y = map:get_camera():get_position()
    local hero_x, hero_y = hero:get_position()
    hero_dead_x = hero_x - camera_x
    hero_dead_y = hero_y - camera_y

    hero_dead_sprite = sol.sprite.create("hero/tunic1")
    hero_dead_sprite:set_animation("hurt")
    state = "dying"

    sol.audio.stop_music()
    hero:set_visible(false)
    hero_dead_sprite:set_animation("dying")
    hero_dead_sprite.on_animation_finished = function()
      sol.timer.start(self, 500, function()
        game:stop_game_over()
        game:start()
      end)
    end
  end
 
  function game_over_menu:on_finished()
    local hero = game:get_hero()
    if hero ~= nil then hero:set_visible(hero_was_visible) end
    music = nil
    hero_dead_sprite = nil
    fade_sprite = nil
    sol.timer.stop_all(self)
  end
 
  function game_over_menu:on_draw(dst_surface)
    hero_dead_sprite:draw(dst_surface, hero_dead_x, hero_dead_y)
  end
end


return game_manager