From 115d64f51f9f3011f7a915c6a71327f709bd894f Mon Sep 17 00:00:00 2001 From: Tim Anema Date: Fri, 30 Jan 2015 14:35:49 -0500 Subject: [PATCH] working on rotation and scaling of light bodies --- examples/short.lua | 17 +++-- lib/body.lua | 176 +++++++++++++++++++++++++++++---------------- lib/vector.lua | 19 +++++ 3 files changed, 145 insertions(+), 67 deletions(-) diff --git a/examples/short.lua b/examples/short.lua index 381c69b..581509a 100644 --- a/examples/short.lua +++ b/examples/short.lua @@ -86,12 +86,6 @@ function love.keypressed(k) if colorAberration == 0.0 then colorAberration = 3.0 end - elseif k == "f" then - lightWorld:remove(lightMouse) - elseif k == "g" then - lightWorld:remove(circleTest) - elseif k == "d" then - lightWorld:remove(rectangleTest) end end @@ -122,6 +116,17 @@ function love.update(dt) polygonTest:move((dt * 200), 0) end + if love.keyboard.isDown("f") then + polygonTest:scale(0.005) + elseif love.keyboard.isDown("a") then + polygonTest:scale(-0.005) + end + if love.keyboard.isDown("s") then + polygonTest:rotate(0.05) + elseif love.keyboard.isDown("d") then + polygonTest:rotate(-0.05) + end + if love.keyboard.isDown("-") then scale = scale - 0.01 elseif love.keyboard.isDown("=") then diff --git a/lib/body.lua b/lib/body.lua index c705f71..e9b201c 100644 --- a/lib/body.lua +++ b/lib/body.lua @@ -27,6 +27,10 @@ local function new(id, type, ...) obj.tileX = 0 obj.tileY = 0 obj.zheight = 1 + + obj.rotation = 0 + obj.scalex = 1 + obj.scaley = 1 obj.castsNoShadow = false obj.visible = true @@ -49,21 +53,19 @@ local function new(id, type, ...) obj:setShadowType('circle', args[3], args[4], args[5]) elseif obj.type == "rectangle" then - obj.x = args[1] or 0 - obj.y = args[2] or 0 + local x = args[1] or 0 + local y = args[2] or 0 + local width = args[3] or 64 + local height = args[4] or 64 + local ox = args[5] or width * 0.5 + local oy = args[6] or height * 0.5 - local rectangle_canvas = love.graphics.newCanvas(args[3], args[4]) - util.drawto(rectangle_canvas, 0, 0, 1, function() - love.graphics.rectangle('fill', 0, 0, args[3], args[4]) - end) - obj.img = love.graphics.newImage(rectangle_canvas:getImageData()) - obj.imgWidth = obj.img:getWidth() - obj.imgHeight = obj.img:getHeight() - obj.ix = obj.imgWidth * 0.5 - obj.iy = obj.imgHeight * 0.5 - obj:generateNormalMapFlat("top") - - obj:setShadowType('rectangle', args[3], args[4]) + obj:setPoints( + x - ox, y - oy, + x - ox + width, y - oy, + x - ox + width, y - oy + height, + x - ox, y - oy + height + ) elseif obj.type == "polygon" then obj:setPoints(...) elseif obj.type == "image" then @@ -106,29 +108,69 @@ local function new(id, type, ...) obj.oy = obj.height * 0.5 obj.reflection = true end - obj.old_x, obj.old_y = obj.x, obj.y + + obj:commit_changes() return obj end -- refresh function body:refresh() - if self.shadowType == "rectangle" then - self.data = { - self.x - self.ox, self.y - self.oy, - self.x - self.ox + self.width, self.y - self.oy, - self.x - self.ox + self.width, self.y - self.oy + self.height, - self.x - self.ox, self.y - self.oy + self.height - } - elseif self.shadowType == 'polygon' and (self.old_x ~= self.x or self.old_y ~= self.y) then - local dx, dy = self.x - self.old_x, self.y - self.old_y - for i = 1, #self.data, 2 do - self.data[i], self.data[i+1] = self.data[i] + dx, self.data[i+1] + dy + if self.shadowType == 'polygon' and self:has_changed() then + local dx, dy, dr, dsx, dsy = self:changes() + if self:position_changed() then + for i = 1, #self.data, 2 do + self.data[i], self.data[i+1] = self.data[i] + dx, self.data[i+1] + dy + end end - self.old_x, self.old_y = self.x, self.y + if self:rotation_changed() then + local center = vector(self.x, self.y) + for i = 1, #self.data, 2 do + self.data[i], self.data[i+1] = vector(self.data[i], self.data[i+1]):rotateAround(center, dr):unpack() + end + end + if self:scale_changed() then + for i = 1, #self.data, 2 do + self.data[i] = self.x + (self.data[i] - self.x) + ((self.data[i] - self.x) * dsx) + self.data[i+1] = self.y + (self.data[i+1] - self.y) + ((self.data[i+1] - self.y) * dsy) + end + end + self:commit_changes() end end +function body:has_changed() + return self:position_changed() or self:rotation_changed() or self:scale_changed() +end + +function body:position_changed() + return self.old_x ~= self.x or + self.old_y ~= self.y +end + +function body:rotation_changed() + return self.old_rotation ~= self.rotation +end + +function body:scale_changed() + return self.old_scalex ~= self.scalex or + self.old_scaley ~= self.scaley +end + +function body:changes() + return self.x - self.old_x, + self.y - self.old_y, + self.rotation - self.old_rotation, + self.scalex - self.old_scalex, + self.scaley - self.old_scaley +end + +function body:commit_changes() + self.old_x, self.old_y = self.x, self.y + self.old_rotation = self.rotation + self.old_scalex, self.old_scaley = self.scalex, self.scaley +end + function body:newGrid(frameWidth, frameHeight, imageWidth, imageHeight, left, top, border) return anim8.newGrid( frameWidth, frameHeight, @@ -162,6 +204,7 @@ function body:pauseAtEnd() self.animation:pauseAtEnd() end function body:pauseAtStart() self.animation:pauseAtStart() end function body:update(dt) + self:refresh() if self.type == "animation" and self.animation then local frame = self.animation.frames[self.animation.position] _,_,self.width, self.height = frame:getViewport() @@ -173,12 +216,29 @@ function body:update(dt) end end +function body:rotate(angle) + self:setRotation(self.rotation + angle) +end + +function body:setRotation(angle) + self.rotation = angle +end + +function body:scale(sx, sy) + self.scalex = self.scalex + sx + self.scaley = self.scaley + (sy or sx) +end + +function body:setScale(sx, sy) + self.scalex = sx + self.scaley = sy or sx +end + -- set position function body:setPosition(x, y) if x ~= self.x or y ~= self.y then self.x = x self.y = y - self:refresh() end end @@ -190,7 +250,6 @@ function body:move(x, y) if y then self.y = self.y + y end - self:refresh() end -- get x position @@ -218,19 +277,11 @@ function body:getImageHeight() return self.imgHeight end --- set dimension -function body:setDimension(width, height) - self.width = width - self.height = height - self:refresh() -end - -- set offset function body:setOffset(ox, oy) if ox ~= self.ox or oy ~= self.oy then self.ox = ox self.oy = oy - self:refresh() end end @@ -453,11 +504,18 @@ function body:setShadowType(type, ...) self.ox = args[2] or 0 self.oy = args[3] or 0 elseif self.shadowType == "rectangle" then + self.shadowType = "polygon" self.width = args[1] or 64 self.height = args[2] or 64 self.ox = args[3] or self.width * 0.5 self.oy = args[4] or self.height * 0.5 - self:refresh() + + self.data = { + self.x - self.ox, self.y - self.oy, + self.x - self.ox + self.width, self.y - self.oy, + self.x - self.ox + self.width, self.y - self.oy + self.height, + self.x - self.ox, self.y - self.oy + self.height + } elseif self.shadowType == "polygon" then self.data = args or {0, 0, 0, 0, 0, 0} elseif self.shadowType == "image" then @@ -507,16 +565,16 @@ function body:inRange(l, t, w, h, s) end function body:drawAnimation() - self.animation:draw(self.img, self.x - self.ix, self.y - self.iy) + self.animation:draw(self.img, self.x, self.y, self.rotation, self.scalex, self.scaley, self.ix, self.iy) end function body:drawNormal() if not self.refraction and not self.reflection and self.normalMesh then love.graphics.setColor(255, 255, 255) if self.type == 'animation' then - self.animation:draw(self.normal, self.x - self.nx, self.y - self.ny) + self.animation:draw(self.normal, self.x, self.y, self.rotation, self.scalex, self.scaley, self.nx, self.ny) else - love.graphics.draw(self.normalMesh, self.x - self.nx, self.y - self.ny) + love.graphics.draw(self.normalMesh, self.x, self.y, self.rotation, self.scalex, self.scaley, self.nx, self.ny) end end end @@ -526,8 +584,6 @@ function body:drawGlow() if self.type == "circle" then love.graphics.circle("fill", self.x, self.y, self.radius) - elseif self.type == "rectangle" then - love.graphics.rectangle("fill", self.x, self.y, self.width, self.height) elseif self.type == "polygon" then love.graphics.polygon("fill", unpack(self.data)) elseif (self.type == "image" or self.type == "animation") and self.img then @@ -541,9 +597,9 @@ function body:drawGlow() end if self.type == "animation" then - self.animation:draw(self.img, self.x - self.ix, self.y - self.iy) + self.animation:draw(self.img, self.x, self.y, self.rotation, self.scalex, self.scaley, self.ix, self.iy) else - love.graphics.draw(self.img, self.x - self.ix, self.y - self.iy) + love.graphics.draw(self.img, self.x, self.y, self.rotation, self.scalex, self.scaley, self.ix, self.iy) end love.graphics.setShader() @@ -554,10 +610,10 @@ function body:drawRefraction() if self.refraction and self.normal then love.graphics.setColor(255, 255, 255) if self.tileX == 0.0 and self.tileY == 0.0 then - love.graphics.draw(self.normal, self.x - self.nx, self.y - self.ny) + love.graphics.draw(self.normal, self.x, self.y, self.rotation, self.scalex, self.scaley, self.nx, self.ny) else self.normalMesh:setVertices(self.normalVert) - love.graphics.draw(self.normalMesh, self.x - self.nx, self.y - self.ny) + love.graphics.draw(self.normalMesh, self.x, self.y, self.rotation, self.scalex, self.scaley, self.nx, self.ny) end end @@ -566,14 +622,12 @@ function body:drawRefraction() if not self.refractive then if self.type == "circle" then love.graphics.circle("fill", self.x, self.y, self.radius) - elseif self.type == "rectangle" then - love.graphics.rectangle("fill", self.x, self.y, self.width, self.height) elseif self.type == "polygon" then love.graphics.polygon("fill", unpack(self.data)) elseif self.type == "image" and self.img then - love.graphics.draw(self.img, self.x - self.ix, self.y - self.iy) + love.graphics.draw(self.img, self.x, self.y, self.rotation, self.scalex, self.scaley, self.ix, self.iy) elseif self.type == 'animation' then - self.animation:draw(self.img, self.x - self.ix, self.y - self.iy) + self.animation:draw(self.img, self.x, self.y, self.rotation, self.scalex, self.scaley, self.ix, self.iy) end end end @@ -582,21 +636,21 @@ function body:drawReflection() if self.reflection and self.normal then love.graphics.setColor(255, 0, 0) self.normalMesh:setVertices(self.normalVert) - love.graphics.draw(self.normalMesh, self.x - self.nx, self.y - self.ny) + love.graphics.draw(self.normalMesh, self.x, self.y, self.rotation, self.scalex, self.scaley, self.nx, self.ny) end if self.reflective and self.img then love.graphics.setColor(0, 255, 0) if self.type == 'animation' then - self.animation:draw(self.img, self.x - self.ix, self.y - self.iy) + self.animation:draw(self.img, self.x, self.y, self.rotation, self.scalex, self.scaley, self.ix, self.iy) else - love.graphics.draw(self.img, self.x - self.ix, self.y - self.iy) + love.graphics.draw(self.img, self.x, self.y, self.rotation, self.scalex, self.scaley, self.ix, self.iy) end elseif not self.reflection and self.img then love.graphics.setColor(0, 0, 0) if self.type == 'animation' then - self.animation:draw(self.img, self.x - self.ix, self.y - self.iy) + self.animation:draw(self.img, self.x, self.y, self.rotation, self.scalex, self.scaley, self.ix, self.iy) else - love.graphics.draw(self.img, self.x - self.ix, self.y - self.iy) + love.graphics.draw(self.img, self.x, self.y, self.rotation, self.scalex, self.scaley, self.ix, self.iy) end end end @@ -607,9 +661,9 @@ function body:drawMaterial() love.graphics.setColor(255, 255, 255) self.materialShader:send("material", self.material) if self.type == 'animation' then - self.animation:draw(self.normal, self.x - self.nx, self.y - self.ny) + self.animation:draw(self.normal, self.x, self.y, self.rotation, self.scalex, self.scaley, self.nx, self.ny) else - love.graphics.draw(self.normal, self.x - self.nx, self.y - self.ny) + love.graphics.draw(self.normal, self.x, self.y, self.rotation, self.scalex, self.scaley, self.nx, self.ny) end love.graphics.setShader() end @@ -617,7 +671,7 @@ end function body:drawStencil() if not self.refraction and not self.reflection and not self.castsNoShadow then - love.graphics.draw(self.img, self.x - self.ix, self.y - self.iy) + love.graphics.draw(self.img, self.x, self.y, self.rotation, self.scalex, self.scaley, self.ix, self.iy) end end @@ -627,7 +681,7 @@ function body:drawShadow(light) end love.graphics.setColor(self.red, self.green, self.blue, self.alpha) - if self.shadowType == "rectangle" or self.shadowType == "polygon" then + if self.shadowType == "polygon" then self:drawPolyShadow(light) elseif self.shadowType == "circle" then self:drawCircleShadow(light) @@ -721,7 +775,7 @@ function body:drawImageShadow(light) {0, shadowStartY, 0, 1, self.red, self.green, self.blue, self.alpha} }) - love.graphics.draw(self.shadowMesh, self.x - self.ox, self.y - self.oy, 0, s, s) + love.graphics.draw(self.shadowMesh, self.x, self.y, self.rotation, self.scalex, self.scaley, self.ox, self.oy) end return setmetatable({new = new}, {__call = function(_, ...) return new(...) end}) diff --git a/lib/vector.lua b/lib/vector.lua index da10ba9..c2fade3 100644 --- a/lib/vector.lua +++ b/lib/vector.lua @@ -43,4 +43,23 @@ function vector:dist(b) return math.sqrt(math.pow(b.x - self.x, 2) + math.pow(b.y-self.y, 2)) end +function vector:unpack() + return self.x, self.y +end + +function vector:rotateAround(origin, angle) + local s = math.sin(angle) + local c = math.cos(angle) + -- translate point back to origin + self.x = self.x - origin.x + self.y = self.y - origin.y + -- rotate point + self.x = (self.x * c - self.y * s) + self.y = (self.x * s + self.y * c) + -- translate point back + self.x = self.x + origin.x + self.y = self.y + origin.y + return self +end + return setmetatable({new = new}, {__call = function(_, ...) return new(...) end})