Shadows

I didn’t have anything better to do, so I thought I’d try shadows without using physics objects and raycasting. Don’t know if this is usable or not, but here it is anyways. Besides, I liked working out the math to make it happen. You can show single or multiple shadow sources using the slider. Parameter points 0 shows one shadow source with multiple objects. Points 1 shows multiple shadow sources with multiple objects. Points 2 shows multiple shadow sources with a single object. The difference between points 2 and 3 is, points 2 shows a single shadow per object. Points 3 shows multiple shadows from the sources for the one object. I don’t like the way it works overall, but maybe someone could use it as a starter. Tap near an object to select it and move it around the screen.


supportedOrientations(LANDSCAPE_ANY)
displayMode(OVERLAY)

function setup()
    parameter.integer("points",0,2,0,point)
end

function point()
    tab={}    
    if points==2 then
        -- multi shadows one object
        table.insert(tab,shadow(600,HEIGHT/2+200,400,600,10))
        table.insert(tab,shadow(600,HEIGHT/2-200,400,600,10))
        table.insert(tab,shadow(600,HEIGHT/2,400,600,10))
    elseif points==1 then
        -- multiple points shadows
        table.insert(tab,shadow(600,HEIGHT/2+200,400,600,15))
        table.insert(tab,shadow(600,HEIGHT/2-200,800,400,10))
        table.insert(tab,shadow(600,HEIGHT/2,800,300,20))
        table.insert(tab,shadow(600,HEIGHT/2,300,200,25))
    else
        -- single point shadow
        table.insert(tab,shadow(600,HEIGHT/2,400,600,15))
        table.insert(tab,shadow(600,HEIGHT/2,800,400,10))
        table.insert(tab,shadow(600,HEIGHT/2,800,300,20))
        table.insert(tab,shadow(600,HEIGHT/2,300,200,25))
    end
end

function draw()
    background(51, 141, 132, 255)
    for a,b in pairs(tab) do
        b:drawCirc()
    end
    for a,b in pairs(tab) do
        b:drawMesh()
        if points==2 then
            b:drawCirc()
        end
    end
end

function touched(t)
    if t.state==BEGAN then
        local min=9999
        local key=0
        for a,b in pairs(tab) do
            local d=vec2(t.x,t.y):dist(vec2(b.x2,b.y2))
            if d<min then
                min=d
                key=a
            end
            if points==2 then
                tab[a].id=t.id
            end
        end
        tab[key].id=t.id
        return
    end
    for a,b in pairs(tab) do
        b:touched(t)
    end
end

shadow=class()

-- shadow source(x1,y1)  object(x2,y2)  object size(r2)
function shadow:init(x1,y1,x2,y2,r2)
    self.x1=x1  -- shadow source x,y position
    self.y1=y1
    self.x2=x2  -- objects x,y position
    self.y2=y2
    self.r2=r2  -- object radius
    self.tx1=0  -- tangent point 1 x,y position
    self.ty1=0
    self.tx2=0  -- tangent point 2 x,y position
    self.ty2=0
    self.m=mesh()   -- mesh
    self.fillTab=true
    self.tab={} -- shadow verticies table
    self.ex1=0  -- extented point 1 x,y position
    self.ey1=0
    self.ex2=0  -- extended point 2 x,y position
    self.ey2=0
    self.id=0   -- id of moving object
end

function shadow:drawMesh()
    self:tangentPoints()
    self:extendLines()
    self:createMeshTab()    
    self.m.vertices=self.tab
    self.m:setColors(0,0,0)
    self.m:draw()
end

function shadow:drawCirc()
    fill(255)
    ellipse(self.x1,self.y1,8)
    fill(255)
    ellipse(self.x2,self.y2,self.r2*2+2)    
end

function shadow:touched(t)
    if t.state==MOVING and self.id==t.id then
        self.x2=t.x
        self.y2=t.y
        self.fillTab=true
    end 
    if t.state==ENDED and self.id==t.id then
        self.id=0
    end
end

function shadow:tangentPoints()
    local p1r=vec2(self.x1,self.y1):dist(vec2(self.x2,self.y2))
    local dx=self.x2-self.x1
    local dy=self.y2-self.y1
    local hyp=math.sqrt(dx^2+dy^2)
    local kk=(hyp^2+p1r^2-self.r2^2)/(2*hyp)    
    self.tx1=self.x1+dx*kk/hyp+(dy/hyp)*math.sqrt(p1r^2-kk^2)
    self.ty1=self.y1+dy*kk/hyp-(dx/hyp)*math.sqrt(p1r^2-kk^2)    
    self.tx2=self.x1+dx*kk/hyp-(dy/hyp)*math.sqrt(p1r^2-kk^2)
    self.ty2=self.y1+dy*kk/hyp+(dx/hyp)*math.sqrt(p1r^2-kk^2)       
end

function shadow:extendLines()
    self.len=math.sqrt((self.x1-self.tx1)^2+(self.y1-self.ty1)^2) 
    self.ex1=self.tx1+(self.tx1-self.x1) / self.len * 1500
    self.ey1=self.ty1+(self.ty1-self.y1) / self.len * 1500  
    self.len=math.sqrt((self.x1-self.tx2)^2+(self.y1-self.ty2)^2) 
    self.ex2=self.tx2+(self.tx2-self.x1) / self.len * 1500
    self.ey2=self.ty2+(self.ty2-self.y1) / self.len * 1500        
end

function shadow:createMeshTab()
    if not self.fillTab then
        return
    end
    self.fillTab=false      
    self.tab={}
    table.insert(self.tab,vec2(self.tx1,self.ty1)) 
    table.insert(self.tab,vec2(self.tx2,self.ty2)) 
    table.insert(self.tab,vec2(self.ex1,self.ey1))   
    table.insert(self.tab,vec2(self.tx1,self.ty1)) 
    table.insert(self.tab,vec2(self.tx2,self.ty2)) 
    table.insert(self.tab,vec2(self.ex2,self.ey2))
    table.insert(self.tab,vec2(self.tx1,self.ty1)) 
    table.insert(self.tab,vec2(self.ex1,self.ey1)) 
    table.insert(self.tab,vec2(self.ex2,self.ey2))  
end

That’s cool and useful @dave1707, reminds me of a similar love2d project

http://youtu.be/6V5Dtsa6Nd4

Or for 3d: http://codea.io/talk/discussion/2373/shadow-mapping