Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --# Main
- --Main
- supportedOrientations(LANDSCAPE_ANY)
- resolution=5
- -- Use this function to perform your initial setup
- function setup()
- lineCapMode(ROUND)
- debugDraw = PhysicsDebugDraw()
- defaultGravity = physics.gravity()
- createContainer()
- parameter.boolean("Show_Outline")
- print("Use the 'Show outline' setting above to show/hide the graphics object behind the image")
- img = readImage("Tyrian Remastered:Blimp Boss")
- mySprite=Object(img,resolution,300-math.random(150),HEIGHT+50-math.random(75),math.random(360))
- mySprite2=Object(img,resolution,600-math.random(150),HEIGHT-50-math.random(75),math.random(360))
- end
- --create container around sides and floor
- function createContainer()
- walls = {
- physics.body(EDGE, vec2(0, 0), vec2(WIDTH, 0)),
- physics.body(EDGE, vec2(0, 0), vec2(0, HEIGHT)),
- physics.body(EDGE, vec2(WIDTH, HEIGHT), vec2(WIDTH, 0))}
- for k, v in ipairs(walls) do
- v.restitution = .5
- end
- end
- function cleanup()
- clearOutput()
- debugDraw:clear()
- end
- -- This function gets called once every frame
- function draw()
- background(201, 213, 217, 183)
- physics.gravity(defaultGravity)
- debugDraw:draw()
- end
- --# Object
- Object = class()
- local imge
- function Object:init(img,res,xx,yy,angle)
- imge=img -- ?? I wanted to use self.image but the draw routine didn't recognise it
- --next two lines calculate x,y offset from start of physics object
- offsetX=img.width/2+1 --add 1 because vector goes round the outside of the image
- offsetY=img.height/2+1
- points = VectorOutline:CreatePhysics(img,res,true) --create physics object from image
- --the rest of these lines add a new physics object
- poly=physics.body(POLYGON, unpack(points))
- poly.x = xx
- poly.y = yy
- poly.angle=angle
- poly.sleepingAllowed = false
- poly.restitution = 0.25
- debugDraw:addBody(poly)
- end
- function Object:draw(xx,yy,angle)
- pushMatrix() -- Preserve the current matrix
- pushStyle() -- Preserve the current style
- resetMatrix() -- Reset the matrix: 'origin' in the bottom left corner
- resetStyle() -- Reset the style
- translate(xx, yy) -- Shift (translate) origin of Viewer by (x, y)
- rotate(angle) -- Rotate the Viewer about that origin
- spriteMode(CENTER)
- sprite(imge, offsetX,offsetY) -- Draw at the (shifted, rotated) origin
- popStyle() -- Restore the style to what it was
- popMatrix() -- Restore the matrix to what it was
- end
- --# PhysicsDebugDraw
- --# PhysicsDebugDraw
- PhysicsDebugDraw = class()
- function PhysicsDebugDraw:init()
- self.bodies = {}
- end
- function PhysicsDebugDraw:addBody(body)
- table.insert(self.bodies,body)
- end
- function PhysicsDebugDraw:clear()
- for i,body in ipairs(self.bodies) do
- body:destroy()
- end
- self.bodies = {}
- end
- function PhysicsDebugDraw:draw()
- for i,body in ipairs(self.bodies) do
- pushMatrix()
- translate(body.x, body.y)
- rotate(body.angle)
- if body.type == DYNAMIC then
- Object:draw(body.x,body.y,body.angle)
- if Show_Outline then
- local points = body.points
- pushStyle()
- strokeWidth(3.0)
- for j = 1,#points do
- a = points[j]
- b = points[(j % #points)+1]
- line(a.x, a.y, b.x, b.y)
- end
- popStyle()
- end
- end
- popMatrix()
- end
- end
- function PhysicsDebugDraw:collide(contact)
- if contact.state == BEGAN then
- self.contacts[contact.id] = contact
- sound(SOUND_HIT, 2643)
- elseif contact.state == MOVING then
- self.contacts[contact.id] = contact
- elseif contact.state == ENDED then
- self.contacts[contact.id] = nil
- end
- end
- --# VectorOutline
- VectorOutline = class()
- --This code creates a vector outline of any image so you can use it as a physics object
- --Created by Dermot Balson (user Ignatz)
- --Version 1.00 Feb 2013
- --USAGE
- -- To have the code return a set of vectors which you can copy into your own code
- -- points=VectorOutline:CreatePhysics(img,res)
- -- poly=physics.body(POLYGON, unpack(points)) --create the actual object
- --To create a vector outline of our image, we need to go through several steps
- --1. We need to identify the outline all the way round
- --2. We need to mark the outline as an array of pixels, working anti clockwise (as the physics code requires)
- --3. We clean it up, removing any unnecessary pixels in the middle of straight lines (we only need the ends)
- --4. We walk around our array of pixels, taking every Nth pixel
- -- (N is specified by the user to balance speed and accuracy)
- --The result is a physics object, or, if you prefer, a set of vectors that you can turn into one yourself
- --Disclaimer - at time of writing, I have just one week's experience in Codea. Improvements are welcome!
- OUTERBLANK=1 --cells which are blank and outside the image, ie not enclosed by filled cells
- FILLED=2 --marks cells in bitmap which are used for the picture
- UNUSEDEDGE=3 --marks blank/transparent cells in the bitmap which border on filled cells
- USEDEDGE=4 --marks edge cells which have been used for creating the vector object, to avoid re-use
- EMPTY=0 --marks blank cells which are none of the above
- rows,cols=0,0
- function VectorOutline:CreatePhysics(img,res)
- cols=img.width
- rows=img.height
- --key array to store map of image that we will work with
- --has 2 extra rows/cols around the edge so we can fit our border around it
- c=array2D(cols+4,rows+4)
- firstBlankCol,firstBlankRow = 0,0 --to store location of first blank cell discovered
- --first set values for nonblank cells
- for i=1,cols do
- for j=1,rows do
- r,g,b,a=img:get(i,j)
- if a>0 then
- c[i+2][j+2]=FILLED --indent two rows and cols to allow for border
- if firstBlankCol==0 then firstBlankCol=i+2 firstBlankRow=j+2 end
- end
- end
- end
- --now fill in outside of image, ie blank cells that are not enclosed by filled cells
- findEdge(c,firstBlankCol,firstBlankRow)
- --make path of edge cells, working anticlockwise
- path=FindEdgePath(c)
- --trim path to remove points within straight lines
- path=trimStraightLines(path)
- --create final path of vectors
- points=createPath(path,res)
- return points
- end
- --this function works recursively to find all blank cells which are not embedded in the image. It does this
- --by starting with a blank cell outside the image, and looking at all neighbours. Any blank neighbours are
- --examined in turn.
- --Blank cells outside the image are labelled OUTERBLANK if they are not adjacent to a filled cell, or
- --UNUSEDEDGE if they are adjacent to a filled cell. These latter cells form the border around our image.
- function findEdge(c,i,j)
- c[i][j]=OUTERBLANK
- local filledNeighbor=false
- for ii=-1,1 do
- for jj=-1,1 do
- iii=i+ii
- jjj=j+jj
- if iii>0 and iii<=cols+4 and jjj>0 and jjj<=rows+4 then
- if c[iii][jjj]==EMPTY then
- findEdge(c,iii,jjj)
- elseif c[iii][jjj]==FILLED then
- filledNeighbor=true
- end
- end
- end
- end
- if filledNeighbor==true then c[i][j]=UNUSEDEDGE end
- end
- --This function creates a path around the image using the chain of border cells identified above.
- --It has to work anticlockwise, which it does by examining the neighbours of the last cell in
- --the chain in a certain order, from lower left, anti clockwise round to the left. It loops
- --round twice, first at a distance of one cell, then two cells
- function FindEdgePath(c)
- path={} --this will be the array of vectors
- colA={ 0, 1, 0,-1, 0, 1, 0,-1} --these two rows specify the x,y offsets to look in
- rowA={-1, 0, 1, 0,-2, 0, 2, 0} --around the current cell
- i1=0
- --find first edge cell
- for i=1,cols+4 do
- for j=1,rows+4 do
- if c[i][j]==UNUSEDEDGE then i1,j1=i,j end
- end
- if i1>0 then break end
- end
- --add the first point
- n=1
- path[n]={i=i1,j=j1}
- c[i1][j1]=USEDEDGE
- --now work around the image anticlockwise
- i,j=i1,j1
- finished=false
- while finished==false do
- for u=1,#colA do
- iii,jjj=i,j
- ii=i+colA[u]
- jj=j+rowA[u]
- if ii>0 and ii<=cols+4 and jj>0 and jj<=rows+4 then
- if c[ii][jj]==UNUSEDEDGE then
- n = n + 1
- if n>1000 then
- print("ERROR - Infinite loop in creating outline")
- finished=true
- end
- path[n]={i=ii,j=jj}
- c[ii][jj]=USEDEDGE
- iii,jjj=ii,jj
- break
- elseif ii==i1 and jj==j1 and n> 5 then --are we done?
- finished=true
- break
- end
- end
- end
- if iii==i and jjj==j then
- --print("ERROR - Unable to complete outline")
- finished=true
- else
- i,j=iii,jjj
- end
- end
- return path
- end
- --we only need to store the start and end cells for straight lines
- --This function removes cells in between
- function trimStraightLines(path)
- local i0,j0=0,0
- local ni,nj=0,0
- for p=#path,1,-1 do
- i,j=path[p].i,path[p].j
- if i==i0 then
- ni = ni + 1
- else
- if ni>2 then
- for u=p+ni-2,p+1,-1 do
- table.remove(path,p)
- end
- end
- ni=1
- i0=i
- end
- if j==j0 then
- nj = nj + 1
- else
- if nj>2 then
- for u=p+nj-2,p+1,-1 do
- table.remove(path,p)
- end
- end
- nj=1
- j0=j
- end
- end
- return path
- end
- --This function creates the final vector array
- --it loops through the array, selecting points at least N pixels apart, where N is specified by the user
- --to balance accuracy and speed
- function createPath(path,N)
- NN=N*N --see below for reason for this
- local points={}
- table.insert(points,vec2(path[1].i,path[1].j))
- i0,j0=path[1].i,path[1].j
- for p=2,#path-1 do
- --skip points until we are at least r from the previous point
- --the calculation of distance between two points is the SQRT of the sum of square of the x and y diffs,
- --but to save doing the SQRT, we compare it with r squared instead
- if (path[p].i-i0)^2+(path[p].j-j0)^2>NN then
- table.insert(points,vec2(path[p].i,path[p].j))
- i0,j0=path[p].i,path[p].j
- end
- end
- return points
- end
- function drawImage(img,c)
- local img2=image(cols+4,rows+4)
- for i=1,cols do
- for j=1,rows do
- r,g,b,a=img:get(i,j)
- if a>0 then img2:set(i+2,j+2,color(r,g,b,a)) end
- end
- end
- return img2
- end
- function drawTestImage(c) --testing only
- local img2=image(cols+4,rows+4)
- for i=1,cols+4 do
- for j=1,rows+4 do
- if c[i][j]==UNUSEDEDGE then
- img2:set(i,j,color(255,255,255,255))
- elseif c[i][j]==OUTERBLANK then
- img2:set(i,j,color(0,0,255,50))
- elseif c[i][j]==FILLED then
- img2:set(i,j,color(255,0,0,100))
- elseif c[i][j]==USEDEDGE then
- img2:set(i,j,color(0,0,255,255))
- elseif c[i][j]==FLAG then
- img2:set(i,j,color(255,0,0,255))
- img2:set(i-1,j,color(255,0,0,255))
- img2:set(i+1,j,color(255,0,0,255))
- img2:set(i,j-1,color(255,0,0,255))
- img2:set(i,j+1,color(255,0,0,255))
- end
- end
- end
- for p=1,#path do
- i,j=path[p].i,path[p].j
- img2:set(i,j,color(255,255,0,255))
- end
- return img2
- end
- function array1D(cols,defaultValue)
- if defaultValue==nil then defaultValue=0 end
- local A={}
- for i=1,cols do
- A[i]=defaultValue
- end
- end
- function array2D(rows,cols,defaultValue,start)
- if defaultValue==nil then defaultValue=0 end
- if start==nil then start=1 end
- local A={}
- for i=start,rows do
- A[i]={}
- for j=start,cols do
- A[i][j]=defaultValue
- end
- end
- return A
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement