document.write('
Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1.  
  2. --# Main
  3. --Main
  4. supportedOrientations(LANDSCAPE_ANY)
  5.  
  6. resolution=5
  7.  
  8. -- Use this function to perform your initial setup
  9. function setup()
  10. lineCapMode(ROUND)
  11. debugDraw = PhysicsDebugDraw()
  12. defaultGravity = physics.gravity()
  13. createContainer()
  14. parameter.boolean("Show_Outline")
  15. print("Use the 'Show outline' setting above to show/hide the graphics object behind the image")
  16. img = readImage("Tyrian Remastered:Blimp Boss")
  17. mySprite=Object(img,resolution,300-math.random(150),HEIGHT+50-math.random(75),math.random(360))
  18. mySprite2=Object(img,resolution,600-math.random(150),HEIGHT-50-math.random(75),math.random(360))
  19. end
  20.  
  21. --create container around sides and floor
  22. function createContainer()
  23. walls = {
  24. physics.body(EDGE, vec2(0, 0), vec2(WIDTH, 0)),
  25. physics.body(EDGE, vec2(0, 0), vec2(0, HEIGHT)),
  26. physics.body(EDGE, vec2(WIDTH, HEIGHT), vec2(WIDTH, 0))}
  27. for k, v in ipairs(walls) do
  28. v.restitution = .5
  29. end
  30. end
  31.  
  32. function cleanup()
  33. clearOutput()
  34. debugDraw:clear()
  35. end
  36.  
  37. -- This function gets called once every frame
  38. function draw()
  39. background(201, 213, 217, 183)
  40. physics.gravity(defaultGravity)
  41. debugDraw:draw()
  42. end
  43.  
  44.  
  45. --# Object
  46. Object = class()
  47.  
  48. local imge
  49.  
  50. function Object:init(img,res,xx,yy,angle)
  51. imge=img -- ?? I wanted to use self.image but the draw routine didn't recognise it
  52. --next two lines calculate x,y offset from start of physics object
  53. offsetX=img.width/2+1 --add 1 because vector goes round the outside of the image
  54. offsetY=img.height/2+1
  55. points = VectorOutline:CreatePhysics(img,res,true) --create physics object from image
  56. --the rest of these lines add a new physics object
  57. poly=physics.body(POLYGON, unpack(points))
  58. poly.x = xx
  59. poly.y = yy
  60. poly.angle=angle
  61. poly.sleepingAllowed = false
  62. poly.restitution = 0.25
  63. debugDraw:addBody(poly)
  64. end
  65.  
  66. function Object:draw(xx,yy,angle)
  67. pushMatrix() -- Preserve the current matrix
  68. pushStyle() -- Preserve the current style
  69. resetMatrix() -- Reset the matrix: 'origin' in the bottom left corner
  70. resetStyle() -- Reset the style
  71. translate(xx, yy) -- Shift (translate) origin of Viewer by (x, y)
  72. rotate(angle) -- Rotate the Viewer about that origin
  73. spriteMode(CENTER)
  74. sprite(imge, offsetX,offsetY) -- Draw at the (shifted, rotated) origin
  75. popStyle() -- Restore the style to what it was
  76. popMatrix() -- Restore the matrix to what it was
  77. end
  78.  
  79.  
  80.  
  81. --# PhysicsDebugDraw
  82. --# PhysicsDebugDraw
  83. PhysicsDebugDraw = class()
  84.  
  85. function PhysicsDebugDraw:init()
  86. self.bodies = {}
  87. end
  88.  
  89. function PhysicsDebugDraw:addBody(body)
  90. table.insert(self.bodies,body)
  91. end
  92.  
  93. function PhysicsDebugDraw:clear()
  94. for i,body in ipairs(self.bodies) do
  95. body:destroy()
  96. end
  97. self.bodies = {}
  98. end
  99.  
  100. function PhysicsDebugDraw:draw()
  101. for i,body in ipairs(self.bodies) do
  102. pushMatrix()
  103. translate(body.x, body.y)
  104. rotate(body.angle)
  105. if body.type == DYNAMIC then
  106. Object:draw(body.x,body.y,body.angle)
  107. if Show_Outline then
  108. local points = body.points
  109. pushStyle()
  110. strokeWidth(3.0)
  111. for j = 1,#points do
  112. a = points[j]
  113. b = points[(j % #points)+1]
  114. line(a.x, a.y, b.x, b.y)
  115. end
  116. popStyle()
  117. end
  118. end
  119. popMatrix()
  120. end
  121. end
  122.  
  123. function PhysicsDebugDraw:collide(contact)
  124. if contact.state == BEGAN then
  125. self.contacts[contact.id] = contact
  126. sound(SOUND_HIT, 2643)
  127. elseif contact.state == MOVING then
  128. self.contacts[contact.id] = contact
  129. elseif contact.state == ENDED then
  130. self.contacts[contact.id] = nil
  131. end
  132. end
  133.  
  134. --# VectorOutline
  135. VectorOutline = class()
  136.  
  137. --This code creates a vector outline of any image so you can use it as a physics object
  138. --Created by Dermot Balson (user Ignatz)
  139. --Version 1.00 Feb 2013
  140.  
  141. --USAGE
  142. -- To have the code return a set of vectors which you can copy into your own code
  143. -- points=VectorOutline:CreatePhysics(img,res)
  144. -- poly=physics.body(POLYGON, unpack(points)) --create the actual object
  145.  
  146. --To create a vector outline of our image, we need to go through several steps
  147. --1. We need to identify the outline all the way round
  148. --2. We need to mark the outline as an array of pixels, working anti clockwise (as the physics code requires)
  149. --3. We clean it up, removing any unnecessary pixels in the middle of straight lines (we only need the ends)
  150. --4. We walk around our array of pixels, taking every Nth pixel
  151. -- (N is specified by the user to balance speed and accuracy)
  152. --The result is a physics object, or, if you prefer, a set of vectors that you can turn into one yourself
  153.  
  154. --Disclaimer - at time of writing, I have just one week's experience in Codea. Improvements are welcome!
  155.  
  156. OUTERBLANK=1 --cells which are blank and outside the image, ie not enclosed by filled cells
  157. FILLED=2 --marks cells in bitmap which are used for the picture
  158. UNUSEDEDGE=3 --marks blank/transparent cells in the bitmap which border on filled cells
  159. USEDEDGE=4 --marks edge cells which have been used for creating the vector object, to avoid re-use
  160. EMPTY=0 --marks blank cells which are none of the above
  161. rows,cols=0,0
  162.  
  163. function VectorOutline:CreatePhysics(img,res)
  164. cols=img.width
  165. rows=img.height
  166. --key array to store map of image that we will work with
  167. --has 2 extra rows/cols around the edge so we can fit our border around it
  168. c=array2D(cols+4,rows+4)
  169. firstBlankCol,firstBlankRow = 0,0 --to store location of first blank cell discovered
  170. --first set values for nonblank cells
  171. for i=1,cols do
  172. for j=1,rows do
  173. r,g,b,a=img:get(i,j)
  174. if a>0 then
  175. c[i+2][j+2]=FILLED --indent two rows and cols to allow for border
  176. if firstBlankCol==0 then firstBlankCol=i+2 firstBlankRow=j+2 end
  177. end
  178. end
  179. end
  180. --now fill in outside of image, ie blank cells that are not enclosed by filled cells
  181. findEdge(c,firstBlankCol,firstBlankRow)
  182. --make path of edge cells, working anticlockwise
  183. path=FindEdgePath(c)
  184. --trim path to remove points within straight lines
  185. path=trimStraightLines(path)
  186. --create final path of vectors
  187. points=createPath(path,res)
  188. return points
  189. end
  190.  
  191. --this function works recursively to find all blank cells which are not embedded in the image. It does this
  192. --by starting with a blank cell outside the image, and looking at all neighbours. Any blank neighbours are
  193. --examined in turn.
  194. --Blank cells outside the image are labelled OUTERBLANK if they are not adjacent to a filled cell, or
  195. --UNUSEDEDGE if they are adjacent to a filled cell. These latter cells form the border around our image.
  196. function findEdge(c,i,j)
  197. c[i][j]=OUTERBLANK
  198. local filledNeighbor=false
  199. for ii=-1,1 do
  200. for jj=-1,1 do
  201. iii=i+ii
  202. jjj=j+jj
  203. if iii>0 and iii<=cols+4 and jjj>0 and jjj<=rows+4 then
  204. if c[iii][jjj]==EMPTY then
  205. findEdge(c,iii,jjj)
  206. elseif c[iii][jjj]==FILLED then
  207. filledNeighbor=true
  208. end
  209. end
  210. end
  211. end
  212. if filledNeighbor==true then c[i][j]=UNUSEDEDGE end
  213. end
  214.  
  215. --This function creates a path around the image using the chain of border cells identified above.
  216. --It has to work anticlockwise, which it does by examining the neighbours of the last cell in
  217. --the chain in a certain order, from lower left, anti clockwise round to the left. It loops
  218. --round twice, first at a distance of one cell, then two cells
  219. function FindEdgePath(c)
  220. path={} --this will be the array of vectors
  221. colA={ 0, 1, 0,-1, 0, 1, 0,-1} --these two rows specify the x,y offsets to look in
  222. rowA={-1, 0, 1, 0,-2, 0, 2, 0} --around the current cell
  223. i1=0
  224. --find first edge cell
  225. for i=1,cols+4 do
  226. for j=1,rows+4 do
  227. if c[i][j]==UNUSEDEDGE then i1,j1=i,j end
  228. end
  229. if i1>0 then break end
  230. end
  231. --add the first point
  232. n=1
  233. path[n]={i=i1,j=j1}
  234. c[i1][j1]=USEDEDGE
  235. --now work around the image anticlockwise
  236. i,j=i1,j1
  237. finished=false
  238. while finished==false do
  239. for u=1,#colA do
  240. iii,jjj=i,j
  241. ii=i+colA[u]
  242. jj=j+rowA[u]
  243. if ii>0 and ii<=cols+4 and jj>0 and jj<=rows+4 then
  244. if c[ii][jj]==UNUSEDEDGE then
  245. n = n + 1
  246. if n>1000 then
  247. print("ERROR - Infinite loop in creating outline")
  248. finished=true
  249. end
  250. path[n]={i=ii,j=jj}
  251. c[ii][jj]=USEDEDGE
  252. iii,jjj=ii,jj
  253. break
  254. elseif ii==i1 and jj==j1 and n> 5 then --are we done?
  255. finished=true
  256. break
  257. end
  258. end
  259. end
  260. if iii==i and jjj==j then
  261. --print("ERROR - Unable to complete outline")
  262. finished=true
  263. else
  264. i,j=iii,jjj
  265. end
  266. end
  267. return path
  268. end
  269.  
  270. --we only need to store the start and end cells for straight lines
  271. --This function removes cells in between
  272. function trimStraightLines(path)
  273. local i0,j0=0,0
  274. local ni,nj=0,0
  275. for p=#path,1,-1 do
  276. i,j=path[p].i,path[p].j
  277. if i==i0 then
  278. ni = ni + 1
  279. else
  280. if ni>2 then
  281. for u=p+ni-2,p+1,-1 do
  282. table.remove(path,p)
  283. end
  284. end
  285. ni=1
  286. i0=i
  287. end
  288. if j==j0 then
  289. nj = nj + 1
  290. else
  291. if nj>2 then
  292. for u=p+nj-2,p+1,-1 do
  293. table.remove(path,p)
  294. end
  295. end
  296. nj=1
  297. j0=j
  298. end
  299. end
  300. return path
  301. end
  302.  
  303. --This function creates the final vector array
  304. --it loops through the array, selecting points at least N pixels apart, where N is specified by the user
  305. --to balance accuracy and speed
  306. function createPath(path,N)
  307. NN=N*N --see below for reason for this
  308. local points={}
  309. table.insert(points,vec2(path[1].i,path[1].j))
  310. i0,j0=path[1].i,path[1].j
  311. for p=2,#path-1 do
  312. --skip points until we are at least r from the previous point
  313. --the calculation of distance between two points is the SQRT of the sum of square of the x and y diffs,
  314. --but to save doing the SQRT, we compare it with r squared instead
  315. if (path[p].i-i0)^2+(path[p].j-j0)^2>NN then
  316. table.insert(points,vec2(path[p].i,path[p].j))
  317. i0,j0=path[p].i,path[p].j
  318. end
  319. end
  320. return points
  321. end
  322.  
  323. function drawImage(img,c)
  324. local img2=image(cols+4,rows+4)
  325. for i=1,cols do
  326. for j=1,rows do
  327. r,g,b,a=img:get(i,j)
  328. if a>0 then img2:set(i+2,j+2,color(r,g,b,a)) end
  329. end
  330. end
  331. return img2
  332. end
  333.  
  334. function drawTestImage(c) --testing only
  335. local img2=image(cols+4,rows+4)
  336. for i=1,cols+4 do
  337. for j=1,rows+4 do
  338. if c[i][j]==UNUSEDEDGE then
  339. img2:set(i,j,color(255,255,255,255))
  340. elseif c[i][j]==OUTERBLANK then
  341. img2:set(i,j,color(0,0,255,50))
  342. elseif c[i][j]==FILLED then
  343. img2:set(i,j,color(255,0,0,100))
  344. elseif c[i][j]==USEDEDGE then
  345. img2:set(i,j,color(0,0,255,255))
  346. elseif c[i][j]==FLAG then
  347. img2:set(i,j,color(255,0,0,255))
  348. img2:set(i-1,j,color(255,0,0,255))
  349. img2:set(i+1,j,color(255,0,0,255))
  350. img2:set(i,j-1,color(255,0,0,255))
  351. img2:set(i,j+1,color(255,0,0,255))
  352. end
  353. end
  354. end
  355. for p=1,#path do
  356. i,j=path[p].i,path[p].j
  357. img2:set(i,j,color(255,255,0,255))
  358. end
  359. return img2
  360. end
  361.  
  362. function array1D(cols,defaultValue)
  363. if defaultValue==nil then defaultValue=0 end
  364. local A={}
  365. for i=1,cols do
  366. A[i]=defaultValue
  367. end
  368. end
  369.  
  370. function array2D(rows,cols,defaultValue,start)
  371. if defaultValue==nil then defaultValue=0 end
  372. if start==nil then start=1 end
  373. local A={}
  374. for i=start,rows do
  375. A[i]={}
  376. for j=start,cols do
  377. A[i][j]=defaultValue
  378. end
  379. end
  380. return A
  381. end
');