PageRenderTime 51ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/flave-code/Flave/World.as

http://flave.googlecode.com/
ActionScript | 544 lines | 279 code | 112 blank | 153 comment | 114 complexity | 1dfead0c0bd520e3d4d2b80b8ba89283 MD5 | raw file
  1. /*
  2. Flave v0.6b Copyright (c) 2010 Luiz Fernando
  3. Permission is hereby granted, free of charge, to any person
  4. obtaining a copy of this software and associated documentation
  5. files (the "Software"), to deal in the Software without
  6. restriction, including without limitation the rights to use,
  7. copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. copies of the Software, and to permit persons to whom the
  9. Software is furnished to do so, subject to the following
  10. conditions:
  11. The above copyright notice and this permission notice shall be
  12. included in all copies or substantial portions of the Software.
  13. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  14. EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  15. OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  16. NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  17. HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  18. WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20. OTHER DEALINGS IN THE SOFTWARE.
  21. */
  22. // THIS ACTIONSCRIPT FILE IS PART OF THE FLASH PHYSICS TOY ENGINE (FPE)
  23. // THIS ACTIONSCRIPT FILE IS PART OF THE FLASH VERLET ENGINE (Flave)
  24. //
  25. // This is the main script for the world, where everything happens.
  26. //
  27. // CURRENT VERSION (Engine): 0.6.2b
  28. // CURRENT VERSION (File) : 1.0
  29. package Flave {
  30. // Import needed classes:
  31. import flash.display.Sprite;
  32. import flash.geom.Rectangle;
  33. import flash.geom.Point;
  34. import flash.utils.*;
  35. import Flave.Util.*;
  36. import Flave.*;
  37. // World class. This is the root of the engine
  38. // and this guy here runs the simulation for you!
  39. public class World extends Sprite {
  40. // Really, not used yet.
  41. public var timeStep:Number = 1.0/50.0;
  42. // Ammount of iterations for constraint solver
  43. public var consIterations:uint = 2;
  44. // Ammount of iterations for the collision solver
  45. public var iterations:uint = 2;
  46. // Grid file, the broad-phase that the engine uses
  47. public var grid:Grid;
  48. // Whether the engine can be interacted with (drag particles
  49. // around, etc)
  50. public var interactible:Boolean = true;
  51. // Array of partices, constraints, polygons and raycasters
  52. public var parts:Array = new Array();
  53. public var cons:Array = new Array();
  54. public var polys:Array = new Array();
  55. public var rays:Array = new Array();
  56. // Default particle size, used when creating particles:
  57. public var defPartSize:Number = 10;
  58. // Gravity speed
  59. public var grav:Number = 0.1;
  60. // Clipping bounds used to keep elements inside. Any element
  61. // exiting the boundaries is quickly sent back inside
  62. public var clipBounds:Rectangle;
  63. // Whether to draw the boundaries as a outlined rectangle
  64. // on the .Draw() function
  65. public var drawBounds:Boolean = false;
  66. // Offset to which particles will be add. Keep this as
  67. // (0,0), just in case
  68. public var offset:Point;
  69. // If the engine is active. If not, no iterations are given
  70. public var active:Boolean = true;
  71. // Constructor:
  72. public function World() {
  73. offset = new Point();
  74. grid = new Grid();
  75. grid.MCMov = new Sprite();
  76. addChild(grid.MCMov);
  77. }
  78. // Step event. Solves particle, constraint and raycast iteration
  79. // along with the broad-phase grid.
  80. public function Step() : void {
  81. // Not active? Skip it!
  82. if(!active) return;
  83. // Basic verlet:
  84. var i:int = 0;
  85. for each(var p:Particle in parts){
  86. if(!p.fixed) { // We don't want to move fixed particles
  87. // Step the particle:
  88. p.step();
  89. // Pushes it down:
  90. p.Y += grav;
  91. // Clip the particle inside the boundaries:
  92. clipParticle(p);
  93. }
  94. // If it can collide with other particles, add it to the
  95. // grid:
  96. if(p.collideWithPart || p.collideWithCons)
  97. grid.addParticle(p);
  98. }
  99. // Constraints:
  100. for(var k:int = 0; k < consIterations; k++){
  101. for each(var c:Constraint in cons){
  102. c.resolve();
  103. }
  104. }
  105. // Check for rupturing:
  106. for each(c in cons){
  107. c.rupture();
  108. if(c != null && c.collidable)
  109. grid.addConstraint(c);
  110. }
  111. // Rays:
  112. /*for(i=0;i<rays.length;i++){
  113. rays[i].trim(clipBounds.x, clipBounds.y, clipBounds.width, clipBounds.height);
  114. if(rays[i].fixOnCaster && rays[i].Caster != null){
  115. rays[i].updateBeam(rays[i].Caster.X, rays[i].Caster.Y, rays[i].Direction, rays[i].Range);
  116. } else {
  117. rays[i].updateBeam(rays[i].sx, rays[i].sy, rays[i].Direction, rays[i].Range);
  118. }
  119. // Don't need to add 'em anymore!
  120. // grid.addRay(rays[i]);
  121. }*/
  122. // Resolve the broadphase:
  123. // var t = getTimer();
  124. if(Configuration.PartPart){
  125. for(i=0;i<iterations;i++)
  126. grid.resolveBroadPhase();
  127. }
  128. // Resolve the ray-trace:
  129. for(i=0;i<rays.length;i++){
  130. rays[i].trim(clipBounds.x, clipBounds.y, clipBounds.width, clipBounds.height);
  131. if(rays[i].fixOnCaster && rays[i].Caster != null){
  132. rays[i].updateBeam(rays[i].Caster.X, rays[i].Caster.Y, rays[i].Direction, rays[i].Range);
  133. } else {
  134. rays[i].updateBeam(rays[i].sx, rays[i].sy, rays[i].Direction, rays[i].Range);
  135. }
  136. // Don't need to add 'em anymore!
  137. grid.testRay(rays[i]);
  138. }
  139. // trace("Resolve time: " + (getTimer() - t));
  140. // Reset the grid:
  141. grid.resetGrid(grid.subdiv);
  142. // Bound clip:
  143. if(clipBounds != null)
  144. for(i = 0; i<parts.length; i++){
  145. clipParticle(parts[i]);
  146. }
  147. }
  148. // Drawing function. Draws the particles, constraints, boundaries
  149. // rays, etc.
  150. public function Draw() : void {
  151. // Not active? Skip it!
  152. if(!active) return;
  153. // Constraints:
  154. for(var i:int = 0; i < cons.length; i++){
  155. cons[i].draw();
  156. }
  157. // Particles:
  158. for(i = 0; i<parts.length; i++){
  159. parts[i].draw();
  160. }
  161. // Rays:
  162. for(i = 0; i<rays.length; i++){
  163. rays[i].trim(clipBounds.x, clipBounds.y, clipBounds.width, clipBounds.height);
  164. rays[i].redraw();
  165. }
  166. // Boundaries:
  167. if(drawBounds){
  168. this.graphics.clear();
  169. this.graphics.lineStyle(1, 0, 0.5);
  170. this.graphics.drawRect(clipBounds.x, clipBounds.y, clipBounds.width, clipBounds.height);
  171. }
  172. }
  173. // Adds a particle to the simulation
  174. // @param _x The X position to add the particle at
  175. // @param _y The Y position to add the particle at
  176. // @param fixed Whether the particle will remain fixed in place
  177. // @param rad The particle radius
  178. public function addParticle(_x:Number, _y:Number, fixed:Boolean = false, rad:Number = -1) : Particle {
  179. // Create the particle instance:
  180. var p:Particle = new Particle(_x + offset.x, _y + offset.y);
  181. // Set the variables:
  182. p.fixed = fixed;
  183. p.index = parts.length;
  184. p.rad = (rad == -1 ? defPartSize : rad);
  185. // Push it into the particle list:
  186. parts.push(p);
  187. // Add the displayable object to the world:
  188. addChild(p);
  189. // Init the logic after adding it to the display list:
  190. p.init();
  191. // Return the particle created:
  192. return p;
  193. }
  194. // Add a constraint to the simulation:
  195. // @param p1 The first particle to link
  196. // @param p2 The second particle to link
  197. // @param dis The restlen. Distance that the resolver will try to keep the particles at.
  198. // @param e The error delta. Should be keep at 0.5.
  199. // @param coll Whether this constraint can collide with other particles and rays.
  200. public function addConstraint(p1:Particle, p2:Particle, dis:Number = -1, e:Number = 0.5, coll:Boolean = true) : Constraint {
  201. // Create the constraint, setting the particles and restLen:
  202. var c:Constraint = new Constraint(p1, p2, dis);
  203. // Set the error and collision flag:
  204. c.error = e;
  205. c.collidable = coll;
  206. // Pushes it into the constraints list:
  207. cons.push(c);
  208. // Add it to the display list, at the bottom:
  209. addChildAt(c, 0);
  210. // Return the constraint created:
  211. return c;
  212. }
  213. // Adds a polygon. A polygon is just cosmetic. It links particles with a cool
  214. // polygon shape. They have no influence on the simulation whatsoever.
  215. // @param spots The list of particles to link
  216. // @param col The color used to draw
  217. // @param _a The alpha used to draw
  218. public function addPoly(spots:Array, col:uint=0, _a:Number=1) : Polygon {
  219. // Creates and pushes the polygon to the polygon list:
  220. polys.push(new Polygon(spots, col, _a));
  221. // Adds it to the display list, at the bottom:
  222. this.addChildAt(polys[polys.length-1], cons.length);
  223. // Redraw it:
  224. polys[polys.length-1].redraw();
  225. // Return the polygon created:
  226. return polys[polys.length-1];
  227. }
  228. // Adds a raycast to the simulation
  229. // @param sx The ray starting X point
  230. // @param sy The ray starting Y point
  231. // @param dir The ray direction
  232. // @param range The ray range
  233. public function addRay(sx:Number, sy:Number, dir:Number, range:Number) : Ray {
  234. var r:Ray = new Ray();
  235. this.addChildAt(r, 0);
  236. r.updateBeam(sx, sy, dir, range);
  237. r.redraw();
  238. rays.push(r);
  239. return r;
  240. }
  241. // Loads a simulation from a strind code
  242. public function loadFromCode(input:String) : Boolean {
  243. // Clear current simulation:
  244. clearEverything();
  245. // Trim the string:
  246. input = trim(input);
  247. //if(input.substr(0, 8) == "COMPRESS"){
  248. input = Util.decompress(input);
  249. //}
  250. // Split strings between '|':
  251. var tempS:Array = input.split('|');
  252. var tempA:Array = new Array();
  253. // Split one more time and decode:
  254. for(var i:int = 0; i < tempS.length; i++){
  255. tempA[i] = tempS[i].split(",");
  256. }
  257. // Temp variables:
  258. var obs:Object = {};
  259. var A:*, B:*, D:*, Hand:String, S:*, X:Number, Y:Number, currentType:String;
  260. for(i = 0; i < tempA.length; i++){
  261. if(tempA[i][0] != undefined/* && tempA[i][1] != undefined && tempA[i][2] != undefined*/){
  262. if(tempA[i][0] == "p" || tempA[i][0] == "f" || tempA[i][0] == "d" || tempA[i][0] == "o"){
  263. currentType = tempA[i][0];
  264. } else if(tempA[i][0] == "c" || tempA[i][0] == "x") {
  265. currentType = tempA[i][0];
  266. } else if(tempA[i][0] == "n") {
  267. currentType = "n";
  268. var ta:Array = new Array();
  269. for(var j:int=0;j<tempA[i].length-2;j++){
  270. ta.push(obs[tempA[i][j+2]]);
  271. }
  272. addPoly(ta, parseInt(tempA[i][1]));
  273. }
  274. if((currentType == "p" || currentType == "f" || currentType == "d" || currentType == "o") && tempA[i].length >= 3){
  275. var offset:int = -1;
  276. if(tempA[i][0] == currentType) offset = 0;
  277. X = parseFloat(tempA[i][2 + offset]);
  278. Y = parseFloat(tempA[i][3 + offset]);
  279. Hand = tempA[i][1 + offset];
  280. obs[Hand] = addParticle(X, Y, currentType == "f" || currentType == "d");
  281. obs[Hand].collideWithPart = currentType == "p" || currentType == "f";
  282. obs[Hand].mass = tempA[i][4 + offset] == undefined ? 30 : parseFloat(tempA[i][4 + offset]);
  283. }
  284. if((currentType == "c" || currentType == "x") && tempA[i].length > 1){
  285. offset = -1;
  286. if(tempA[i][0] == currentType) offset = 0;
  287. A = tempA[i][1 + offset];
  288. B = tempA[i][2 + offset];
  289. addConstraint(obs[A], obs[B], -1, 0.5, currentType == "c");
  290. }
  291. }
  292. }
  293. return true;
  294. }
  295. // Removes a particle and all traces of it from the code
  296. public function removeParticle(p:Particle) : Boolean {
  297. if(parts.indexOf(p) != -1 && p.parent != null){
  298. // Delete from memory:
  299. // delete parts[parts.indexOf(p)];
  300. p.cleanGarbage();
  301. // Remove from screen:
  302. removeChild(p);
  303. // Exclude from array:
  304. parts.splice(parts.indexOf(p), 1);
  305. // Succeful!
  306. return true;
  307. }
  308. return false;
  309. }
  310. // Removes a constraint and all traces of it from the code
  311. public function removeConstraint(c:Constraint) : Boolean {
  312. if(cons.indexOf(c) != -1){
  313. // Exclude from array:
  314. cons.splice(cons.indexOf(c), 1);
  315. // Delete from memory:
  316. delete cons[cons.indexOf(c)];
  317. // Remove from screen:
  318. removeChild(c);
  319. // Succeful!
  320. return true;
  321. }
  322. // This constraint was not found
  323. return false;
  324. }
  325. // Remove a poly and any and all traces of it from the code
  326. // correctly cleaning for garbage collecting.
  327. public function removePoly(poly:Polygon) : void {
  328. if(poly == null) return;
  329. var n:int = polys.indexOf(poly);
  330. poly.clearGarbage();
  331. if(poly.parent != null)
  332. this.removeChild(poly);
  333. if(n != -1){
  334. polys[n] = null;
  335. polys.splice(n, 1);
  336. }
  337. poly = null;
  338. }
  339. // Removes a ray and all traces of it from the code
  340. public function removeRay(r:Ray) : void {
  341. if(r == null) return;
  342. var n:int = rays.indexOf(r);
  343. if(r.parent != null)
  344. this.removeChild(r);
  345. if(n != -1){
  346. rays[n] = null;
  347. rays.splice(n, 1);
  348. }
  349. r = null;
  350. }
  351. // Clip a particle inside the boundaries:
  352. public function clipParticle(p:Particle) : void {
  353. var dx:Number = 0, dy:Number = 0;
  354. if(p.X < clipBounds.x + p.rad){
  355. dx = (p.X - p.oldx) * 0.8;
  356. }
  357. if(p.Y < clipBounds.y + p.rad){
  358. dy = (p.Y - p.oldy) * 0.8;
  359. // Horizontal friction:
  360. if((dx < 0 ? -dx : dx) > 0) dx *= 0.5;
  361. else {
  362. dx = -(p.X - p.oldx) * 0.5;
  363. }
  364. }
  365. if(p.X > clipBounds.width - p.rad){
  366. dx = (p.X - p.oldx) * 0.8;
  367. }
  368. if(p.Y > clipBounds.height - p.rad){
  369. dy = (p.Y - p.oldy) * 0.8;
  370. // Horizontal friction:
  371. if((dx < 0 ? -dx : dx) > 0) dx *= 0.5;
  372. else {
  373. dx = -(p.X - p.oldx) * 0.5;
  374. }
  375. }
  376. var dpx:Number = clipBounds.x + p.rad, dpy:Number = clipBounds.y + p.rad;
  377. p.X = (p.X < dpx ? dpx : p.X);
  378. p.Y = (p.Y < dpy ? dpy : p.Y);
  379. dpx = clipBounds.width - p.rad, dpy = clipBounds.height - p.rad;
  380. p.X = (p.X > dpx ? dpx : p.X);
  381. p.Y = (p.Y > dpy ? dpy : p.Y);
  382. if((dx < 0 ? -dx : dx) > 0) p.oldx = p.X + dx;
  383. if((dy < 0 ? -dx : dx) > 0) p.oldy = p.Y + dy;
  384. }
  385. // Sim control:
  386. public function togglePause(pause:* = null) : void {
  387. active = (pause != null ? pause as Boolean : !active);
  388. }
  389. // Cllears the entire simulation:
  390. public function clearEverything() : void {
  391. while(parts.length > 0)
  392. removeParticle(parts[0]);
  393. while(cons.length > 0)
  394. removeConstraint(cons[0]);
  395. while(polys.length > 0)
  396. removePoly(polys[0]);
  397. while(rays.length > 0)
  398. removeRay(rays[0]);
  399. }
  400. // Misc:
  401. public function setOffset(X:Number = 0, Y:Number = 0) : void {
  402. offset.x = X;
  403. offset.y = Y;
  404. }
  405. // Trims a string
  406. public function trim(str:String) : String {
  407. var stripCharCodes:Object = {
  408. code_9 : true,
  409. code_10 : true,
  410. code_13 : true,
  411. code_32 : true
  412. };
  413. while(stripCharCodes["code_" + str.charCodeAt(0)] == true) {
  414. str = str.substring(1, str.length);
  415. }
  416. while(stripCharCodes["code_" + str.charCodeAt(str.length - 1)] == true) {
  417. str = str.substring(0, str.length - 1);
  418. }
  419. var strs:String = "";
  420. var a:Number;
  421. for(var i:int = 0; i < str.length; i++){
  422. a = str.charCodeAt(i);
  423. if(a != 9 && a != 10 && a != 13 && a != 32)
  424. strs += String.fromCharCode(str.charCodeAt(i));
  425. }
  426. return strs;
  427. }
  428. }
  429. }