Page 1 of 1

[WIP] Shadows

Posted: Mon Sep 08, 2014 1:54 am
by muso96
Small game I started for my major software project in year 12. Currently would appreciate any feedback, criticisms and such. I will be going through and adding comments describing what is going on now so if nothing makes sense, (which I assume it won't), I'll have that version up soon.
I'm new to programming in general and especially lua and love, so any improvements would be appreciated.
I'll include my test file which I used as a proof of concept of generating shadows. This /should/ help understanding.

Title is more placeholder than actual name.

Current bugs/needs improvement
- Shadows are jittery, especially noticeable when enemies are larger, not evident in test.
- Enemies aren't removed once off screen (I couldn't figure out how to implement this)

Re: [WIP] Shadows

Posted: Mon Sep 08, 2014 7:09 am
by rmcode
Can't move far before getting this:

Code: Select all

Error:
main.lua:39: Need at least three vertices to draw a polygon.

Re: [WIP] Shadows

Posted: Mon Sep 08, 2014 7:55 am
by muso96
rmcode wrote:Can't move far before getting this:

Code: Select all

Error:
main.lua:39: Need at least three vertices to draw a polygon.
Edit: I accidentally uploaded the wrong file, many apologies. New one up now :)

Re: [WIP] Shadows

Posted: Mon Sep 08, 2014 8:31 am
by rmcode
Ah it looks like a game now too :D Runs really smooth and the shadows look fine.

Not sure if it's a bug or a joke, but on the hardest difficulty there is no light.

Re: [WIP] Shadows

Posted: Mon Sep 08, 2014 8:55 am
by muso96
rmcode wrote:Ah it looks like a game now too :D Runs really smooth and the shadows look fine.
They look fine only because they're so small, I'll up the size so its more obvious what I meant.
rmcode wrote:Not sure if it's a bug or a joke, but on the hardest difficulty there is no light.
Its intended that way as a joke. It's still possible to see all the cubes if you look hard enough, which is the only reason I left it in.

Re: [WIP] Shadows

Posted: Mon Sep 08, 2014 11:15 am
by ivan
muso96 wrote:Currently would appreciate any feedback, criticisms and such. I will be going through and adding comments describing what is going on now so if nothing makes sense, (which I assume it won't), I'll have that version up soon.
I'm new to programming in general and especially lua and love, so any improvements would be appreciated.
I'll include my test file which I used as a proof of concept of generating shadows. This /should/ help understanding.
Looking at _DynLightV2.love I have some suggestions regarding the code.
I think the shadows code could be generalized using the following algorithm (pseudocode):

Code: Select all

-- light source (point) in world coordinates
local wox, woy = 0, 0
-- cast distance
local cast = 500

local si, ei = 1, #polygon
-- get the last vertex (A) of the polygon
local ls = polygon[ei]
-- (optional) if the vertex is in local coords, transform to world coords
local wax, way = get_world_point(enemy.x, enemy.y, ls.x, ls.y)
-- cast a line from vertex A (wax, way) away from the source (wox, woy)
local wpax, wpay = extend(wox, woy, wax, way, cast)

-- for each edge in the polygon
for i = si, ei do
  -- get the "next" vertex (B)
  local le = vertices[i]
  -- (optional) transform vertex B to world coords
  local wbx, wby = get_world_point(enemy.x, enemy.y, le.x, le.y)
  -- cast a line from vertex B (wax, way) away from the source (wox, woy)
  local wpbx, wpby = extend(wox, woy, wbx, wby, cast)

  -- (optional) don't cast front shadows
  local dx, dy = wox - wbx, woy - wby
  local hx, hy = wbx - wax, wby - way
  hx, hy = -hy, hx
  local dot = dx*hx + dy*hy
  -- don't draw if it's a front shadow
  if dot > 0 then
    -- draw a polygon:
    -- wax, way (vertex A)
    -- wpax, wpay (extended vertex A)
    -- wpbx, wpby (extended vertex B)
    -- wbx, wby (vertex B)
  end
  -- make vertex B the "last" vertex
  wax, way = wbx, wby
  wpax, wpay = wpbx, wpby
end
Helper function:

Code: Select all

-- Moves one point (x2, y2) away from another (x, y) by the given distance (dist)
local extend = function(x, y, x2, y2, dist)
  local dx, dy = x2 - x, y2 - y
  local d = math.sqrt(dx*dx + dy*dy)
  d = 1/d*dist
  return dx*d + x, dy*d + y
end
-- Transforms local point lx, ly to world coordinates
local get_world_point = function(x, y, lx, ly)
  -- translation only (optional: add rotation and scale)
  return lx + x, ly + y
end
To use the code above you have to represent the rectangles like so:

Code: Select all

enemy =
{
  -- position
  x = 0, y = 0,
  -- local vertices: top left, top right, bottom right, bottom left
  vertices = { { x = 0, y = 0 }, { x = w, y = 0 }, { x = w, y = h }, { x = 0, y = h } }
}
For circle shapes the code becomes even simpler.

Re: [WIP] Shadows

Posted: Mon Sep 08, 2014 12:08 pm
by muso96
I'll look more deeply into that code at a later time, but thank you so much. I'd like to continue working with lighting in different ways, so in future I may refer to your method. The biggest issue I have with my method currently is the excessive lists for each enemy. I knew going in that there were simpler ways, but this being my first stab at a game, I'm quite happy just to see that it works. Now that I'm finished I can see that even the list itself has a lot of redundancy, but I'm sure you've noticed by now that efficiency wasn't my aim, as I had roughly 4 days to have something which worked.

I see you referencing the front shadow a bit in the pseudocode. As the _DynLightV2 was simply proof of concept for myself, I was lazy and just drew the polygon from the light source. I did this to save me the trouble of figuring out which vertexes I needed to draw from. So the shadow between the light source and the cube isn't intentional, and you can see its omission in the final version.

Re: [WIP] Shadows

Posted: Mon Sep 08, 2014 1:59 pm
by Zilarrezko
with some magic I determined that when staying on the bottom right, you will definitely survive forever.

Here's a video

Re: [WIP] Shadows

Posted: Mon Sep 08, 2014 2:04 pm
by rmcode
One small thing that would make it feel more like a "complete" game would be saving and loading of the highscore.

This is a quick example from one of my games:

Code: Select all

local Handler = {};

-- ------------------------------------------------
-- Public Functions
-- ------------------------------------------------

function Handler.save(profile)
    local file = love.filesystem.newFile('player.sav', 'w');

    file:write('return {\n');
    for key, value in pairs(profile) do
        file:write(string.format('    %s = %s,\n', key, tostring(value)));
    end
    file:write('};');
end

function Handler.load()
    local file = love.filesystem.load('player.sav');

    if file then
        return file();
    end
end

function Handler.delete()
    return love.filesystem.remove('player.sav');
end

return Handler;
Pass in a table and it writes it to a file. Use load to get the same table back.