[Script] Fog Effect & Map Name

Started by MetalZelda, January 11, 2016, 10:47:22 PM

Previous topic - Next topic
January 11, 2016, 10:47:22 PM Last Edit: January 12, 2016, 04:57:15 PM by MetalZelda
Script Information :
- Fog Effect : Display and move a surface, creating a fog moving effect.

This script is heavily inspired by the Day/Night / Fog effect tuto made by Christopho (most of the code is from the tutorial.), but this is more generalized since it use metatable (so it avoid copies over maps script.).

How it works ?
- place the script in quest_manager (or other file that regroup all metatable)
- copy/paste the script in a function that hold the map metatable.
- Place your fogs png in /sprites/fogs
- The fog surface should be higher or equal to 320x240 (or else it would do strange thing where you will need to duplicate the fog, which will result in higher map loading time and framerate issue)
- In your map script, in on_started(), add

Code (lua) Select

function map:on_started(destination)
map:display_fog("filename", speed, angle, opacity)
end


where :

filename must be a string pointing to an existing file in /sprites/fog
speed a number (0 = immobile, higher value = faster)
angle a number between 0 and 7 (0 = right, 7 = south-east
opacity a number between 0 and 255 (0 = transparent, 255 = opaque)

- A savegame value that check if there is any fog graphic. If yes, it is drawn.

Problems :

- If you use map:on_draw(surface) in your map script, the function in the metatable is overwritten, but, this script is temporary before solarus allows shader

What's next :

- add a parameter that analyse the size of the map, if higher then 320x240, automatically multiply the surface to fit the map.
- add a boolean, if true, the fog will slightly follow the camera movement
- fade in/fade out with user custom timer. (Useful for sunrays-like fog)

Code (lua) Select


  function map_metatable:display_fog(fog, speed, angle, opacity)
   local  fog = fog or nil
local speed = speed or 1
local angle = angle or 0
local opacity = opacity or 16

if type(fog) == "string" then

  self.fog = sol.surface.create("fogs/"..fog..".png")
      self.fog:set_opacity(opacity)
  self.fog_size_x, self.fog_size_y = self.fog:get_size()
      self.fog_m = sol.movement.create("straight")
 
  function restart_overlay_movement()
self.fog_m:set_speed(speed)
self.fog_m:set_max_distance(self.fog_size_x)
self.fog_m:set_angle(angle * math.pi / 4)
self.fog_m:start(self.fog, function()
restart_overlay_movement()
self.fog:set_xy(0,0)
end)
      end
  restart_overlay_movement()

self:get_game():set_value("current_fog", fog)
     end
  end
 
  function map_metatable:get_current_fog()
    return self:get_game():get_value("current_fog")
  end

  function map_metatable:on_draw(dst_surface)
local scr_x, scr_y = dst_surface:get_size()
if self:get_current_fog() ~= nil then
  local camera_x, camera_y = self:get_camera_position()
  local overlay_width, overlay_height = self.fog:get_size()
  local x, y = camera_x, camera_y
  x, y = -math.floor(x), -math.floor(y)
  x = x % overlay_width - 4 * overlay_width
  y = y % overlay_height - 4 * overlay_height
  local dst_y = y
  while dst_y < scr_y + overlay_height do
local dst_x = x
while dst_x < scr_x + overlay_width do
  self.fog:draw(dst_surface, dst_x, dst_y)
  dst_x = dst_x + overlay_width
end
dst_y = dst_y + overlay_height
  end
end
end

  function map_metatable:on_finished()
self:get_game():set_value("current_fog", nil)
  end


This is an example of what you can do.

January 12, 2016, 05:11:17 PM #1 Last Edit: January 13, 2016, 03:57:03 PM by MetalZelda
Script 2: Map name
- Display a map name. Simple.
- Can be converted into a hud menu and be a part of the hud so it is started when the hud starts. (PM if interested.)


How it works

-Plug and play, the only thing you need is adding things in strings.dat and call a function in map:on_started(destination)
-You need the map_name font, a utf-8 png (file at the end of the post.) that you need to declare in project.db

Code (lua) Select

text{ key = "map.gameplay.boss_name.0", value = "- Boss Name - $ Some Text about him" }
text{ key = "map.gameplay.map_name.graveyard", value = "Map Name" }


- Careful, do not remove the "$" in boss_name if you want to display a quick info (like OOT boss presentation), it automatically skip a line.

and in your map script :

The script can be called anywhere in the map script.
Code (lua) Select
map:show_map_name("graveyard")

For a map name, example, we are in a dungeon and I want to display a map name only when the destination is the entrance, my destination name is "from_outside" in the map editor.

Code (lua) Select

function map:on_started(destination)
if destination == from_outside then
self:show_map_name("graveyard") -- self is the map.
end
end


for a boss name, it use the same thing, but it use an extra parameter, you can call it from anywhere (after a cutscene for example), the only limit is that it need the map object.

Code (lua) Select

map:show_map_name("0", "boss_name")
-- 0 = the boss_name pointer in string.dat


The script :
Insert it in quest_manager o in another script that manage metatable.

Code (lua) Select

  function map_metatable:show_map_name(map_name, display_extra)
    local map_name = map_name or nil
local display_extra = display_extra or nil

      if type(map_name) == "string" then
      self.map_name = sol.text_surface.create{
horizontal_alignment = "center",
vertical_alignment = "middle",
font = "map_name",
  }
 
  self.boss_presentation_text = sol.text_surface.create{
horizontal_alignment = "center",
vertical_alignment = "middle",
font = "map_name",
  }
 
  if (type(display_extra) == "string" and display_extra ~= "boss_name") or type(display_extra) == "nil" then
    self.map_name:set_text_key("map.gameplay.map_name."..map_name)
self.mx, self.my = self.map_name:get_size()
    self.map_name_surface = sol.surface.create(self.mx * 2, self.my)
    self.map_name:draw(self.map_name_surface, self.mx, self.my * 0.5)  
    self.map_name_surface:set_opacity(0)
self.display_boss_name = false
  else
    self.display_boss_name = true
local i = 0
local text_group = sol.language.get_string("map.gameplay.boss_name."..map_name)
for text_lines in string.gmatch(text_group, "[^$]+") do
  i = i + 1
   if i == 1 then
   self.map_name:set_text(text_lines)
   self.mx, self.my = self.map_name:get_size()
   self.map_name_surface = sol.surface.create(self.mx * 2 , self.my * 4)
   self.map_name:draw(self.map_name_surface, self.mx, self.my * 0.5)
   self.map_name_surface:set_opacity(0)
   else
   self.boss_presentation_text:set_text(text_lines)
   local tw, th = self.boss_presentation_text:get_size()
   self.boss_presentation_text:draw(self.map_name_surface, self.mx - 7 , (self.my * 0.5) + (i*7))
   if tw > self.mx then self.mx = tw end
   if th > self.my then self.my = th end
   end
end
  end

sol.timer.start(self, 500, function()
self.map_name_surface:fade_in(40)
sol.timer.start(self, 3500, function()
self.map_name_surface:fade_out(40, function()
  self.map_name_surface:clear()
  self:get_game():set_value("previous_map_name_displayed", nil)
end)
end)
end)
      end
self:get_game():set_value("previous_map_name_displayed", map_name)
  end
 
  function map_metatable:get_displaying_map_name()
    return self:get_game():get_value("previous_map_name_displayed")
  end

  function map_metatble:on_draw(dst_surface)
if self:get_displaying_map_name() ~= nil then
  local map_name_width, map_name_height = self.map_name:get_size()
  if self.display_boss_name then
     self.map_name_surface:draw(dst_surface, (scr_x / 2) - (map_name_width) + 3, (scr_y / 2) + (map_name_height * 4.8))
  else
     self.map_name_surface:draw(dst_surface, (scr_x / 2) - (map_name_width), (scr_y / 2) - (map_name_height * 3))
  end
end
  end 

  function map_metatable:on_finished()
self:get_game():set_value("previous_map_name_displayed", nil)
end


In game :
Regular Map name


Boss name


These will definitely come in handy especially that fog script. Just thought I'd let you know that your work has not gone unnoticed!

January 14, 2016, 01:21:54 PM #3 Last Edit: January 14, 2016, 01:32:42 PM by MetalZelda
The fog script is just a temporary solution before shaders and that's a simple script (a surface and a movement)
Though I noticed that the repeating thing is buggy, but that's fixable.

The next script would be the time system, but I am facing some issues with it, here's a sneek peak.



It works, the clock movement work as well (https://www.youtube.com/watch?v=jtfXwwu7MaE) but the tone surface overlap with the "warp transition" and need custom timers to do nice transition between tone

Anyway, thanks :)