Author Topic: Raft script  (Read 811 times)

Diarandor

  • Hero Member
  • *****
  • Posts: 805
  • Cats are cool! (ΦωΦ)
    • View Profile
Raft script
« on: November 08, 2016, 11:15:00 pm »
Hi! I was asked by @Porksteak in a personal message if I could share the platform-raft script that I use in this video:
https://www.youtube.com/watch?v=gIKvf_0hIpU

So here goes the code. But note that some parts of the code are a bit old and could be improved (for instance, I should use "require" instead of "load_file" in the raft script, to make the code faster), and some things of the script may require other scripts. My raft script requires my platform script to work, so I include both scripts here. It is recommended that you study the code to make another script that suits better for your purposes, and remove unnecesary things from my code (for instance, you probably do not need the raft to move secondary heroes or custom entities, so you should delete these parts of the code and other similar things).

generic_platform.lua script:
Code: Lua
  1. -- Platform: entity which moves in either horizontally or vertically (depending on direction)
  2. -- and carries the hero on it.
  3. local entity = ...
  4. local map = entity:get_map()
  5. local game = entity:get_game()
  6. local hero = map:get_hero()
  7.  
  8. entity.can_save_state = true
  9.  
  10. local time_stopped = 1000
  11. local is_moving = false
  12. -- Remark: speeds bigger than 12 give problems for water platforms (rafts) when trying to enter or go out. No problem above holes.
  13. entity.speed = 50 -- Set speed.
  14.  
  15. function entity:on_created()
  16.   --self:create_sprite("entities/platform")
  17.   self:set_size(32, 32)
  18.   self:set_origin(16, 13) -- Important: the 32x32 sprite must have center in (16,13).
  19.   self:set_modified_ground("traversable")
  20.  
  21.   -- Set dynamic solid ground position for the hero to avoid problems.
  22.   sol.timer.start(entity, 10, function()
  23.     -- Do nothing if hero is not on solid ground.
  24.     local is_hero_on_solid_ground = map:is_solid_ground(hero:get_ground_position())
  25.     if hero.is_jumping or not is_hero_on_solid_ground then return true end
  26.     -- Save or clear solid ground position on this platform.
  27.     if map.current_hero_platform ~= entity and self:is_on_platform(hero) then
  28.       map.current_hero_platform = entity
  29.       self:save_hero_position() -- Save solid ground on the platform.
  30.     elseif map.current_hero_platform == entity and (not self:is_on_platform(hero)) then
  31.       map.current_hero_platform = nil
  32.       hero:reset_solid_ground() -- Clear solid ground.
  33.     end
  34.     return true
  35.   end)
  36.  
  37.   -- Custom function.
  38.   if entity.on_custom_created then
  39.     entity:on_custom_created()
  40.     return
  41.   end
  42.  
  43.   -- Initialize properties.
  44.   self:set_can_traverse("jumper", true)
  45.   self:set_can_traverse_ground("hole", true)
  46.   self:set_can_traverse_ground("deep_water", true)
  47.   self:set_can_traverse_ground("traversable", true)
  48.   self:set_can_traverse_ground("shallow_water", true)
  49.   self:set_can_traverse_ground("wall", false)
  50.  
  51.   -- Start movement.
  52.   local direction = self:get_direction()
  53.   local m = sol.movement.create("path")
  54.   m:set_path{direction * 2}; m:set_speed(entity.speed)
  55.   m:set_loop(true); m:start(self)
  56.   is_moving = true
  57.  
  58. end
  59.  
  60. -- Function to save hero position on the platform.
  61. function entity:save_hero_position()
  62.   hero:save_solid_ground(function()
  63.     --[[ When the hero reappears, the camera moves towards the new position,
  64.     which produces a delay, and the platform has already moved when the hero appers.
  65.     To fix this problem, change the position of the hero directly, so the movement
  66.     will be instantaneous with no delay. To avoid this we must not call
  67.     "hero:get_solid_ground_position()", or there will be problems with platforms.
  68.     --]]
  69.     local x, y, layer = entity:get_center_position()
  70.     -- Change position at next cycle to avoid engine problems (keep this timer!).
  71.     sol.timer.start(self, 1, function()
  72.       hero:unfreeze()
  73.       hero:set_blinking(true, 1000)
  74.       hero:set_invincible(true, 1000)
  75.       hero:set_position(x, y, layer)
  76.     end)
  77.     return x, y, layer
  78.   end)
  79. end
  80.  
  81.  
  82. -- Update shifting variables for the translation.
  83. local function get_shifts()
  84.   local direction = entity:get_direction()
  85.   local dx, dy = 0, 0 -- Variables for the translation.
  86.   if direction == 0 then dx = 1 elseif direction == 1 then dy = -1
  87.   elseif direction == 2 then dx = -1 elseif direction == 3 then dy = 1 end
  88.   return dx, dy
  89. end
  90.  
  91. -- Get movable entities that were on the previous position of the platform.
  92. function entity:get_movable_entities()
  93.   local movable_entities = {}
  94.   for other in map:get_entities_in_rectangle(entity:get_bounding_box()) do
  95.     -- Check only entities that can be moved, including the hero.
  96.     if other.moved_on_platform or other:get_type() == "hero" then
  97.       -- Check if the entity was on the platform before the movement.
  98.       if entity:was_on_platform(other) and entity:is_on_platform(other) then
  99.         -- Exclude portable entities unless they are on the ground.
  100.         if (not other.is_portable) or other.state == "on_ground" then
  101.           table.insert(movable_entities, other)
  102.         end          
  103.       end
  104.     end
  105.   end  
  106.   return movable_entities
  107. end
  108.  
  109. -- Return true if an entity is on the platform.
  110. -- IMPORTANT: This function is only used in the script generic_portable.lua.
  111. function entity:is_on_platform(other)
  112.   local x, y, layer = other:get_ground_position()
  113.   return entity:overlaps(x, y)
  114. end
  115.  
  116. -- Return true if an entity was on the platform before the movement.
  117. function entity:was_on_platform(other)
  118.   local dx, dy = get_shifts()
  119.   local ox, oy, oz = other:get_ground_position()
  120.   local bx, by, w, h = entity:get_bounding_box()
  121.   local pbx, pby = bx-dx, by-dy -- Previous position of bounding box (before the movement).
  122.   return ox >= pbx and ox < pbx+w and oy >= pby and oy < pby+h
  123. end
  124.  
  125. function entity:on_obstacle_reached(movement)
  126.   --Make the platform turn back.
  127.   local direction = self:get_direction()
  128.   movement:stop(); is_moving = false
  129.   movement = sol.movement.create("path")    
  130.   direction = (direction+2)%4
  131.   self:set_direction(direction)
  132.   movement:set_path{direction * 2}
  133.   movement:set_speed(entity.speed)
  134.   movement:set_loop(true)
  135.   sol.timer.start(self, time_stopped, function()
  136.     movement:start(self)
  137.     is_moving = true  
  138.   end)
  139. end
  140.  
  141. -- Move the movable entities that were on the platform before the movement.
  142. function entity:on_position_changed()
  143.   -- Get the movable entities that were on the platform before the change of position.
  144.   local dx, dy = get_shifts() -- Variables for the translation.
  145.   local movable_entities = entity:get_movable_entities()
  146.   local ex, ey, ez = self:get_position()
  147.   local bx, by, w, h = self:get_bounding_box()
  148.   local pbx, pby = bx-dx, by-dy -- Previous position of bounding box (before the movement).
  149.   for _, other in pairs(movable_entities) do
  150.     local ox, oy, oz = other:get_position()
  151.     -- Move the entity with the platform.
  152.     if not other:test_obstacles(dx, dy, oz) then
  153.       other:set_position(ox + dx, oy + dy, oz)
  154.     end
  155.   end
  156. end
  157.  

raft.lua script:
Code: Lua
  1. local entity = ...
  2. -- Raft entity.
  3.  
  4. sol.main.load_file("entities/generic_platform")(entity)
  5. local sea_foam_sprite -- Foam sprite for the raft.
  6. entity.speed = 20 -- Set speed.
  7.  
  8. function entity:on_custom_created()
  9.   -- Set custom properties.
  10.   time_stopped = 1000
  11.   self:set_can_traverse_ground("deep_water", true)
  12.   self:set_can_traverse_ground("wall", false)
  13.   self:set_can_traverse("jumper", false)
  14.   self:set_can_traverse_ground("hole", false)
  15.   self:set_can_traverse_ground("traversable", true)
  16.   self:set_can_traverse_ground("shallow_water", false)
  17.   self:set_can_traverse_ground("grass", false)
  18.  
  19.   -- Customize movement.
  20.   local direction = self:get_direction()
  21.   local m = sol.movement.create("path")
  22.   m:set_path{direction * 2}; m:set_speed(entity.speed)
  23.   m:set_loop(true); m:start(self)
  24.   is_moving = true
  25.  
  26.   -- Start the sea foam and wavering.
  27.   self:add_sea_foam()
  28.   self:start_wavering() -- Start moving raft sprite to simulate the waves.
  29. end
  30.  
  31. ----------------- Raft functions:
  32.  
  33. -- Add the sea foam sprite.
  34. function entity:add_sea_foam()
  35.   -- Remark: The variable sea_foam_sprite is already local in this script!
  36.   sea_foam_sprite = self:create_sprite("things/platform")
  37.   sea_foam_sprite:set_animation("sea_foam")
  38.   sea_foam_sprite:set_xy(-8,24)
  39. end
  40.  
  41. -- Make the sprite move up and down.
  42. function entity:start_wavering()
  43.   local sprite = self:get_sprite()
  44.   -- Define vectors with the shifts of each "frame" of the sprite and time for each pause between "frames".
  45.   local raft_dy = {0,-1,-2,-1} -- Shifts for the "y" coordinate of the sprite.
  46.   local entities_dy = {1,-1,-1,1} -- Shifts for the "y" coordinate of position of entities.
  47.   local pause_time = {200,1000,200,1000} -- Pause times between "frames".
  48.  
  49.   -- Move the movable entities located over the platform, if possible.
  50.   local function shift_entities(dy_shift)
  51.     local movable_entities = entity:get_movable_entities()
  52.     local x, y, z = self:get_position()
  53.     local bx, by, w, h = self:get_bounding_box()
  54.     for _, something in pairs(movable_entities) do  
  55.       if entity:is_on_platform(something, bx, by, w, h) then    
  56.               local sx, sy, sz = something:get_position()
  57.         -- Move only entities that can be moved.
  58.         local needs_move = false
  59.         if something:get_type() == "hero" then
  60.           if something:get_animation() ~= "walking" then
  61.             needs_move = true
  62.           end
  63.         elseif something:get_sprite() then
  64.           if something:get_sprite():get_animation() ~= "walking" then
  65.             needs_move = true
  66.           end
  67.         end
  68.         -- Check for obstacles.
  69.         local found_obstacles = something:test_obstacles(0, dy_shift, sz)
  70.         -- Finally check if the entity is not in the "bad border" to move it without getting out the platform.
  71.         if needs_move and (not found_obstacles) then
  72.           if (sy + dy_shift) >= by+2 and (sy + dy_shift) <= by+h-3 then sy = sy +dy_shift end
  73.           something:set_position(sx, sy, sz)
  74.         end
  75.       end
  76.     end
  77.   end
  78.  
  79.   -- Shift sprite and move entities.
  80.   local function set_frame_loop(frame_nb)
  81.     -- Shift the sprite. Shift entities above the rift, if possible.
  82.     sprite:set_xy(0, raft_dy[frame_nb])
  83.     shift_entities(entities_dy[frame_nb])
  84.     -- Restart the loop.
  85.     frame_nb = (frame_nb %4) +1 -- Next frame index.
  86.     sol.timer.start(entity, pause_time[frame_nb], function() set_frame_loop(frame_nb) end)
  87.   end
  88.  
  89.   -- Start the wavering loop.  
  90.   set_frame_loop(1)
  91. end
  92.  

Porksteak

  • Newbie
  • *
  • Posts: 8
    • View Profile
Re: Raft script
« Reply #1 on: November 08, 2016, 11:17:06 pm »
Thanks so much, Diarandor! ^-^

Diarandor

  • Hero Member
  • *****
  • Posts: 805
  • Cats are cool! (ΦωΦ)
    • View Profile
Re: Raft script
« Reply #2 on: November 08, 2016, 11:37:01 pm »
No problem! :)

However my code is not clean, and there are probably other scripts that are needed to run this code without errors (there should be "requires" in the above part of this script for those other scripts to make this easier to share). I might make a clean version someday that can be shared easily, but not for now. I don't have time now (I am working on free art). So you will need to study/modify the code to be able to run it without errors.

If you need my raft image just ask for it. I think I have not shared it yet in my deviantart account.