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.
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(1)
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
Please post any improvements or critiques!