Skip to content

Instantly share code, notes, and snippets.

@HoraceBury
Last active March 21, 2018 09:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save HoraceBury/636e18da5f8bfc9cab6197fe3184d7e2 to your computer and use it in GitHub Desktop.
Save HoraceBury/636e18da5f8bfc9cab6197fe3184d7e2 to your computer and use it in GitHub Desktop.
Graphics extension library.
-- graphics extension library
require("mathlib") -- https://gist.github.com/HoraceBury/9431861
require("displaylib") -- https://gist.github.com/HoraceBury/1e2ce033e3441823038eb88b551ad981
-- https://math.stackexchange.com/questions/2269589/calculate-angle-of-the-next-point-on-a-circle
--[[
Generates a table of points containing the outline of a circle with each point 'step' pixels from the previous.
Parameters:
x, y: The centre of the circle
radius: The radius of the circle to generate
step: Distance between one point and the next around the edge of the circel
length: Length around the circumference to travel. Allows the generation of segments.
initialrotation: Angle of the first generated point.
innerradius: If a positive number, the generated path is copied, reversed and attach to the end of the path to make a segment.
Returns:
Table of {x,y} tables
Table of {x,y,x,y,...} point values (as accepted by physics.addBody outline parameter)
Notes:
The first and last point are not likely to be 'step' distance from each other because the circumference around a
circle is not likely to be evenly divisible by 'step'.
]]--
function graphics.newCircleOutline( ... )
local x, y, radius, step, length, initialrotation, innerradius
if (#arg == 1) then
x, y, radius, step, length, initialrotation, innerradius = arg[1].x, arg[1].y, arg[1].radius, arg[1].step, arg[1].length, arg[1].initialrotation, arg[1].innerradius
else
x, y, radius, step, length, initialrotation, innerradius = unpack(arg)
end
local tbl, pts = {}, {}
if (length == nil or length < 0 or length > 360) then length=360 end
local centre = {x=x,y=y}
local r = step/(2*radius)
local angle = math.deg(math.asin(r)) * 2
local origin = {x=0,y=-radius}
origin = math.rotateTo( origin, initialrotation or 0, {x=0,y=0} )
local a = 0
while (a < length) do
local pt = math.rotateTo( origin, a, {x=0,y=0} )
tbl[#tbl+1] = pt
pts[#pts+1] = pt.x
pts[#pts+1] = pt.y
a = a + angle
end
if (innerradius ~= nil and innerradius > 0) then
local innertbl = graphics.newCircleOutline( x, y, innerradius, step, length, initialrotation, nil )
innertbl = table.reverse( innertbl )
tbl = table.copy( tbl, innertbl )
for i=1, #innertbl do
pts[#pts+1] = innertbl[i].x
pts[#pts+1] = innertbl[i].y
end
end
return tbl, pts
end
--[[
Generates a semi-circle set of points, starting at a given angle and continuing for half a turn.
Parameters:
x, y: The centre of the would-be circle
radius: Radius of the circle
ptcount: Number of graphics location points to generate
startangle: The initial angle to have a point at. Last point will be 180 degrees rotated from this point around the x,y centre.
Returns:
tbl: Table of {x,y} locations
pts: Collection of {x,y,x,y,x,y,...} points as accepted by display.newLine(unpack(pts))
]]--
function graphics.newSemiCircle( x, y, radius, ptcount, startangle )
local tbl = {}
local pts = {}
local centre = {x=x,y=y}
local origin = {x=x,y=y-radius}
for i=0, ptcount-1 do
local pt = math.rotateTo( origin, startangle+i*(180/(ptcount-1)), centre )
tbl[#tbl+1] = pt
pts[#pts+1] = pt.x
pts[#pts+1] = pt.y
end
return tbl, pts
end
-- requires displaylib
function graphics.multiElementShapesFromGroup( group, defaultprops )
local shapes = {}
for i=1, group.numChildren do
local shape = group[i]
if (shape.type == "newRect" or shape.type == "newImage" or shape.type == "newImageRect") then
-- rect
local ax, ay = shape:localToContent( -shape.width/2, -shape.height/2 )
ax, ay = shape.parent:contentToLocal( ax, ay )
local bx, by = shape:localToContent( shape.width/2, -shape.height/2 )
bx, by = shape.parent:contentToLocal( bx, by )
local cx, cy = shape:localToContent( shape.width/2, shape.height/2 )
cx, cy = shape.parent:contentToLocal( cx, cy )
local dx, dy = shape:localToContent( -shape.width/2, shape.height/2 )
dx, dy = shape.parent:contentToLocal( dx, dy )
local body = { ax, ay, bx, by, cx, cy, dx, dy }
shapes[ #shapes+1 ] = table.replicate( defaultprops, { shape=body } )
elseif (shape.type == "newCircle") then
-- circle
local _, left = graphics.newSemiCircle( shape.x, shape.y, shape.path.radius, 8, 180 )
shapes[ #shapes+1 ] = table.replicate( defaultprops, { shape=left } )
local _, right = graphics.newSemiCircle( shape.x, shape.y, shape.path.radius, 8, 0 )
shapes[ #shapes+1 ] = table.replicate( defaultprops, { shape=right } )
elseif (shape.type == "newRoundedRect") then
-- rounded rect
local ax, ay = shape:localToContent( -shape.width/2+shape.path.radius, -shape.height/2 )
ax, ay = shape.parent:contentToLocal( ax, ay )
local bx, by = shape:localToContent( shape.width/2-shape.path.radius, -shape.height/2 )
bx, by = shape.parent:contentToLocal( bx, by )
local cx, cy = shape:localToContent( shape.width/2-shape.path.radius, shape.height/2 )
cx, cy = shape.parent:contentToLocal( cx, cy )
local dx, dy = shape:localToContent( -shape.width/2+shape.path.radius, shape.height/2 )
dx, dy = shape.parent:contentToLocal( dx, dy )
local body = { ax, ay, bx, by, cx, cy, dx, dy }
local lx, ly = shape:localToContent( -shape.width/2+shape.path.radius, 0 )
lx, ly = shape.parent:contentToLocal( lx, ly )
local rx, ry = shape:localToContent( shape.width/2-shape.path.radius, 0 )
rx, ry = shape.parent:contentToLocal( rx, ry )
local _, left = graphics.newSemiCircle( lx, ly, shape.path.radius, 8, shape.rotation+180 )
local _, right = graphics.newSemiCircle( rx, ry, shape.path.radius, 8, shape.rotation )
shapes[ #shapes+1 ] = table.replicate( defaultprops, { shape=left } )
shapes[ #shapes+1 ] = table.replicate( defaultprops, { shape=body } )
shapes[ #shapes+1 ] = table.replicate( defaultprops, { shape=right } )
end
end
return shapes
end
local function testShapesFromGroup()
physics.start()
physics.setGravity(0,0)
physics.setDrawMode("hybrid")
local group = display.newGroup()
group.x, group.y = 300, 300
local b = display.newRect( group, 200, 300, 200, 100 )
b.rotation = 45
b.fill = {0,0,0}
local c = display.newRoundedRect( group, 0, -100, 100, 50, 25 )
c.rotation = 0
c.fill = {0,0,1}
local c = display.newRoundedRect( group, 0, 100, 100, 50, 25 )
c.rotation = 0
c.fill = {0,0,1}
local a = display.newCircle( group, 0, 0, 50 )
a.fill = {1,0,0}
local bodies = graphics.multiElementShapesFromGroup( group, {} )
physics.addBody( group, "static", unpack( bodies ) )
end
--testShapesFromGroup()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment