PageRenderTime 82ms CodeModel.GetById 39ms RepoModel.GetById 0ms app.codeStats 0ms

/PortalGame/src/PortalTest/Portal.as

https://bitbucket.org/toxicFork/game2dflash
ActionScript | 528 lines | 429 code | 66 blank | 33 comment | 46 complexity | bcb506c06552c982b912f50b4c40677b MD5 | raw file
  1. /**
  2. * Created with IntelliJ IDEA.
  3. * User: $
  4. * Date: 18/05/13
  5. * Time: 18:41
  6. * To change this template use File | Settings | File Templates.
  7. */
  8. package PortalTest {
  9. import Box2D.Collision.Shapes.b2CircleShape;
  10. import Box2D.Collision.Shapes.b2PolygonShape;
  11. import Box2D.Collision.Shapes.b2Shape;
  12. import Box2D.Common.Math.b2Math;
  13. import Box2D.Common.Math.b2Vec2;
  14. import Box2D.Dynamics.b2Body;
  15. import Box2D.Dynamics.b2BodyDef;
  16. import Box2D.Dynamics.b2Fixture;
  17. import Box2D.Dynamics.b2FixtureDef;
  18. import Box2D.Dynamics.b2World;
  19. import Game2D.*;
  20. import Game2D.Functions.Lerp;
  21. import Game2D.Functions.LerpAngle;
  22. import Game2D.Functions.NormalizeAngle;
  23. import flash.display.BitmapData;
  24. import flash.display.Graphics;
  25. import flash.display.Sprite;
  26. import flash.geom.Matrix;
  27. import flash.geom.Point;
  28. import flash.utils.Dictionary;
  29. public class Portal extends PortalableWorldObject {
  30. private var _otherPortal:Portal = null;
  31. private var data:BitmapData;
  32. private var sprite:Sprite;
  33. private const edgeCapSize:Number = 0.1;
  34. private var sensorFixture:b2Fixture;
  35. private var world:b2World;
  36. public function Portal(width:Number, world:b2World, sprite:Sprite) {
  37. var bodyDef:b2BodyDef = new b2BodyDef();
  38. bodyDef.type = b2Body.b2_dynamicBody;
  39. super(world.CreateBody(bodyDef));
  40. this.scale = width;
  41. this.sprite = sprite;
  42. this.world = world;
  43. //var offset:Point2D = new Point2D(Game.physicsScale+edgeCapSize*Game.physicsScale, 0).Times(1);
  44. image = new Sprite();
  45. imageScale = new Point2D(1,1);
  46. imageOffset = new Point2D(0, 0);
  47. var imageSprite:Sprite = image as Sprite;
  48. imageSprite.graphics.lineStyle(1/Game.physicsScale,Color.Red);
  49. imageSprite.graphics.drawRect(-1-edgeCapSize*2*1, -edgeCapSize*1, edgeCapSize*2*1, edgeCapSize*2*1);
  50. imageSprite.graphics.drawRect(1, -edgeCapSize*1, edgeCapSize*2*1, edgeCapSize*2*1);
  51. var fixtureDef:b2FixtureDef = new b2FixtureDef();
  52. fixtureDef.density = 1.0;
  53. fixtureDef.isSensor = true;
  54. var shapeDef:b2PolygonShape = new b2PolygonShape();
  55. shapeDef.SetAsBox(width,0.05*width);
  56. fixtureDef.shape = shapeDef;
  57. sensorFixture = body.CreateFixture(fixtureDef);
  58. fixtureDef = new b2FixtureDef();
  59. fixtureDef.density = 1.0;
  60. shapeDef = new b2PolygonShape();
  61. shapeDef.SetAsOrientedBox(edgeCapSize*width,edgeCapSize*width,new b2Vec2(-(width+edgeCapSize*width),0));
  62. fixtureDef.shape = shapeDef;
  63. body.CreateFixture(fixtureDef);
  64. shapeDef.SetAsOrientedBox(edgeCapSize*width,edgeCapSize*width,new b2Vec2(width+edgeCapSize*width,0));
  65. body.CreateFixture(fixtureDef);
  66. data = new BitmapData(2000,2000,false,0xffffffff);
  67. //body.SetUserData(this);
  68. addEventListener(ContactEvent.BEGIN,onBeginContact);
  69. addEventListener(ContactEvent.END,onEndContact);
  70. }
  71. public function PortalPoint(p:Point2D):Point2D
  72. {
  73. if(otherPortal==null)
  74. return p.Clone();
  75. var localPoint:Point2D = p.Subtract(pos).Rotate(-rot);
  76. return localPoint.Rotate(otherPortal.rot).Times(-portalScale).Add(otherPortal.pos);
  77. }
  78. public override function render(graphics:Graphics, view:View):void
  79. {
  80. if(!otherPortal)
  81. return;
  82. var viewRect:Rect = view.rect.Scale(view.scale, true).Rotate(view.rotation);
  83. var offset:Point2D = new Point2D(scale, 0).Rotate(rot);
  84. var rightSide:Point2D = pos.Add(offset);
  85. var leftSide:Point2D = pos.Subtract(offset);
  86. //graphics.lineStyle(1, Color.Red, 1);
  87. //if(viewRect.contains(leftSide))
  88. // graphics.drawCircle(leftSide.x*Game.physicsScale, leftSide.y*Game.physicsScale,5);
  89. //graphics.lineStyle(1, Color.Green, 1);
  90. //if(viewRect.contains(rightSide))
  91. // graphics.drawCircle(rightSide.x*Game.physicsScale, rightSide.y*Game.physicsScale,5);
  92. var fwd:Point2D = new Point2D(0, 1.0).Rotate(rot);
  93. if (fwd.Dot(view.position.Subtract(pos).normalized) > 0&&(viewRect.contains(leftSide)||viewRect.contains(rightSide)||viewRect.IntersectLine(new Line(leftSide,rightSide))))
  94. {
  95. //graphics.lineStyle(1, Color.Black, 1);
  96. //viewRect.Draw(graphics, Game.physicsScale);
  97. data.fillRect(data.rect,0xffffffff);
  98. var cloneView:View = view.clone();
  99. cloneView.position = otherPortal.pos;//PortalPoint(view.position);
  100. cloneView.rotation = otherPortal.rot;//PortalAngle(view.rotation);
  101. cloneView.scale = view.scale;
  102. cloneView.UpdateMatrices();
  103. //PortalView(view, cloneView);
  104. cloneView.RenderInto(world, data, new Point2D(data.width/2, data.height/2));
  105. var matrix:Matrix = new Matrix();
  106. matrix.translate(-otherPortal.pos.x*Game.physicsScale,-otherPortal.pos.y*Game.physicsScale);
  107. matrix.rotate(-(otherPortal.rot));
  108. matrix.scale(1/view.scale,1/view.scale);
  109. //matrix.scale(1/portalScale,1/portalScale);
  110. matrix.translate(data.width/2,data.height/2);
  111. data.draw(sprite,matrix,null,null,null,false);
  112. DrawFov(graphics,view.position,viewRect,Game.physicsScale, view.scale);
  113. }
  114. }
  115. private function DrawFov(graphics:Graphics, fovPos:Point2D, rect:Rect, physicsScale:Number, viewScale:Number):void {
  116. var offset:Point2D = new Point2D(scale, 0).Rotate(rot);
  117. var rightSide:Point2D = pos.Add(offset);
  118. var leftSide:Point2D = pos.Subtract(offset);
  119. // graphics.lineStyle(1, Color.Blue, 1);
  120. // new Line(fovPos, rightSide).Draw(graphics, physicsScale);
  121. // graphics.lineStyle(1, Color.Green, 1);
  122. // new Line(fovPos, leftSide).Draw(graphics, physicsScale);
  123. var vectorToRight:Point2D = rightSide.Subtract(fovPos).normalized;
  124. var vectorToLeft:Point2D = leftSide.Subtract(fovPos).normalized;
  125. var rightProjection:Point2D = rightSide.Add(vectorToRight.Times(9999));
  126. var leftProjection:Point2D = leftSide.Add(vectorToLeft.Times(9999));
  127. graphics.lineStyle(1, Color.Black, 1);
  128. var out:Line = new Line();
  129. if (rect.IntersectLine(new Line(fovPos, rightProjection), out)) {
  130. rightProjection = out.b;
  131. }
  132. if (rect.IntersectLine(new Line(fovPos, leftProjection), out)) {
  133. leftProjection = out.b;
  134. }
  135. var shape:Vector.<Point2D> = new Vector.<Point2D>();
  136. {
  137. var topLeft:Point2D = new Point2D(rect.x, rect.y).Rotate(rect.rotation,rect.center);
  138. var topRight:Point2D = new Point2D(rect.right, rect.y).Rotate(rect.rotation,rect.center);
  139. var bottomLeft:Point2D = new Point2D(rect.x, rect.bottom).Rotate(rect.rotation,rect.center);
  140. var bottomRight:Point2D = new Point2D(rect.right, rect.bottom).Rotate(rect.rotation,rect.center);
  141. graphics.lineStyle(0, Color.Red, 1);
  142. var angleA:Number = leftProjection.Subtract(fovPos).angle;
  143. var angleB:Number = rightProjection.Subtract(fovPos).angle;
  144. {
  145. if(rect.contains(leftSide))
  146. {
  147. shape.push(leftSide);
  148. shape.push(leftProjection);
  149. }
  150. else
  151. {
  152. rect.IntersectLine(new Line(rightSide,leftSide),out);
  153. shape.push(out.b);
  154. }
  155. var trIndex:int = -1;
  156. var angleDiff:Number = NormalizeAngle(angleB-angleA);
  157. if(NormalizeAngle(topRight.Subtract(fovPos).angle-angleA)<angleDiff)
  158. {
  159. trIndex = shape.length;
  160. shape.push(topRight);
  161. }
  162. if(NormalizeAngle(bottomRight.Subtract(fovPos).angle-angleA)<angleDiff)
  163. {
  164. shape.push(bottomRight);
  165. }
  166. if(NormalizeAngle(bottomLeft.Subtract(fovPos).angle-angleA)<angleDiff)
  167. {
  168. shape.push(bottomLeft);
  169. }
  170. if(NormalizeAngle(topLeft.Subtract(fovPos).angle-angleA)<angleDiff)
  171. {
  172. if(trIndex==-1)
  173. shape.push(topLeft);
  174. else
  175. {
  176. shape.splice(trIndex,0,topLeft);
  177. }
  178. }
  179. if(rect.contains(rightSide))
  180. {
  181. shape.push(rightProjection);
  182. shape.push(rightSide);
  183. }
  184. else
  185. {
  186. rect.IntersectLine(new Line(leftSide,rightSide),out);
  187. shape.push(out.b);
  188. }
  189. }
  190. var matrix:Matrix = new Matrix();
  191. matrix.translate(-data.width/2,-data.height/2);
  192. // matrix.scale(1/portalScale,1/portalScale);
  193. // matrix.scale(view.scale,view.scale);
  194. matrix.scale(1/portalScale,1/portalScale);
  195. matrix.scale(viewScale,viewScale);
  196. matrix.rotate(rot+Math.PI);
  197. matrix.translate(pos.x*physicsScale,pos.y*physicsScale);
  198. graphics.beginBitmapFill(data,matrix,false,false);
  199. for(var i:uint=0;i<shape.length;i++)
  200. {
  201. var point:Point2D = shape[i].Times(physicsScale);
  202. if(i==0)
  203. graphics.moveTo(point.x, point.y);
  204. else
  205. graphics.lineTo(point.x, point.y);
  206. }
  207. graphics.endFill();
  208. }
  209. }
  210. public function get portalScale():Number {
  211. if(otherPortal)
  212. return otherPortal.scale/scale;
  213. return 1;
  214. }
  215. public function IsFacing(point:Point2D):Boolean {
  216. var fwd:Point2D = new Point2D(0, 1).Rotate(rot);
  217. return (fwd.Dot(point.Subtract(pos).normalized) > 0);
  218. }
  219. public function PortalAngle(angle:Number):Number {
  220. return angle+(otherPortal.rot+Math.PI-rot);
  221. }
  222. public function PortalVector(vec:Point2D, scale:Boolean = false):Point2D{
  223. if(otherPortal==null)
  224. {
  225. return vec.Clone();
  226. }
  227. var rotatedVector:Point2D = vec.Rotate(otherPortal.rot + Math.PI - rot);
  228. if(scale)
  229. return rotatedVector.Times(portalScale);
  230. else
  231. return rotatedVector;
  232. }
  233. private var bodiesInContact:Dictionary = new Dictionary();
  234. private var destroyQueue:Vector.<b2Body> = new Vector.<b2Body>();
  235. private function onBeginContact(event:ContactEvent):void {
  236. if(event.myFixture==sensorFixture)
  237. {
  238. var otherBody:b2Body = event.otherFixture.GetBody();
  239. if(bodiesInContact[otherBody]===undefined)
  240. {
  241. bodiesInContact[otherBody] = new CloneInfo(otherBody, otherPortal);
  242. bodiesInContact[otherBody].lastPos = body.GetLocalPoint(otherBody.GetPosition());
  243. var worldObject:PortalableWorldObject = otherBody.GetUserData() as PortalableWorldObject;
  244. if(worldObject)
  245. {
  246. worldObject.TouchingPortal(this,true);
  247. }
  248. trace("Beginning contact with body!");
  249. }
  250. else
  251. {
  252. var clone:CloneInfo = bodiesInContact[otherBody];
  253. clone.contactCount++;
  254. }
  255. //trace("Begin: "+bodies[otherBody]);
  256. }
  257. }
  258. public function GetClone(originalBody:b2Body):b2Body
  259. {
  260. if(bodiesInContact[originalBody]!==undefined)
  261. {
  262. return bodiesInContact[originalBody].cloneBody;
  263. }
  264. return null;
  265. }
  266. private function onEndContact(event:ContactEvent):void {
  267. if(event.myFixture==sensorFixture)
  268. {
  269. var otherBody:b2Body = event.otherFixture.GetBody();
  270. if(otherBody.GetUserData() as CloneInfo)
  271. return;
  272. if(bodiesInContact[otherBody]!==undefined)
  273. {
  274. var clone:CloneInfo = bodiesInContact[otherBody];
  275. if(clone.contactCount>1)
  276. {
  277. clone.contactCount--;
  278. }
  279. else
  280. {
  281. var bodyClone:BodyClone = otherBody.GetUserData() as BodyClone;
  282. if(bodyClone==null||bodyClone.portal!=this)
  283. {
  284. var originalBody:b2Body = clone.originalBody;
  285. var originalPos:b2Vec2 = body.GetLocalPoint(originalBody.GetPosition());
  286. var localVelocity:b2Vec2 = body.GetLocalVector(originalBody.GetLinearVelocity());
  287. if(clone.lastPos.y>0&&originalPos.y<0&&localVelocity.y<0)
  288. {
  289. if(clone.cloneBody!=null)
  290. clone.cloneBody.SetActive(false);
  291. //world.DestroyBody(clone.cloneBody);
  292. //clone.cloneBody = originalBody.Copy();
  293. ScaleBody(originalBody,portalScale);
  294. PortalBody(originalBody, originalBody);
  295. }
  296. clone.lastPos = originalPos.Copy();
  297. if(clone.cloneBody!=null)
  298. {
  299. clone.cloneBody.SetActive(false);
  300. destroyQueue.push(clone.cloneBody);
  301. }
  302. }
  303. delete bodiesInContact[otherBody];
  304. var worldObject:PortalableWorldObject = otherBody.GetUserData() as PortalableWorldObject;
  305. if(worldObject)
  306. {
  307. worldObject.TouchingPortal(this,false);
  308. }
  309. trace("Ending contact with body!");
  310. }
  311. }
  312. else
  313. {
  314. trace("Ending contact!!");
  315. }
  316. //trace("End: "+bodies[otherBody]);
  317. }
  318. }
  319. public override function update(deltaTime:Number):void {
  320. for(var i:* in bodiesInContact)
  321. {
  322. var originalBody:b2Body = i as b2Body;
  323. var clone:CloneInfo = bodiesInContact[i] as CloneInfo;
  324. var bodyClone:BodyClone = originalBody.GetUserData() as BodyClone;
  325. if(bodyClone==null||bodyClone.portal!=this)
  326. {
  327. if(clone.cloneBody==null)
  328. {
  329. clone.cloneBody = clone.originalBody.Copy();
  330. ScaleBody(clone.cloneBody, portalScale);
  331. PortalBody(originalBody, clone.cloneBody);
  332. }
  333. if(body.IsAwake()||otherPortal.body.IsAwake())
  334. {
  335. originalBody.SetAwake(true);
  336. clone.cloneBody.SetAwake(true);
  337. }
  338. PortalBody(originalBody, clone.cloneBody, 0.5);
  339. var originalPos:b2Vec2 = body.GetLocalPoint(originalBody.GetPosition());
  340. //var portaledPos:b2Vec2 = otherPortal.body.GetLocalPoint(clone.cloneBody.GetPosition())
  341. var combinedVelocity:Point2D =
  342. otherPortal.PortalVector(
  343. Point2D.FromVec(otherPortal.body.GetLinearVelocityFromWorldPoint(clone.cloneBody.GetPosition())))
  344. .Add(Point2D.FromVec(body.GetLinearVelocityFromLocalPoint(originalPos)));
  345. var localVelocity:b2Vec2 = body.GetLocalVector(b2Math.SubtractVV(combinedVelocity.vec,originalBody.GetLinearVelocity()));
  346. if(clone.lastPos.y>0&&originalPos.y<0&&localVelocity.y>0)
  347. {
  348. clone.cloneBody.SetActive(false);
  349. world.DestroyBody(clone.cloneBody);
  350. clone.cloneBody = originalBody.Copy();
  351. //clone.cloneBody.SetUserData(clone);
  352. ScaleBody(originalBody,portalScale);
  353. PortalBody(originalBody, originalBody);
  354. }
  355. clone.lastPos = originalPos.Copy();
  356. }
  357. }
  358. while(destroyQueue.length>0)
  359. {
  360. world.DestroyBody(destroyQueue.pop());
  361. }
  362. }
  363. public static function ScaleBody(body:b2Body, scaleMultiplier:Number):void {
  364. {
  365. var worldObject:WorldObject = body.GetUserData() as WorldObject;
  366. if(worldObject)
  367. worldObject.scale *= scaleMultiplier;
  368. for(var fixture:b2Fixture = body.GetFixtureList(); fixture; fixture=fixture.GetNext())
  369. {
  370. var shape:b2Shape = fixture.GetShape();
  371. if(shape as b2PolygonShape)
  372. {
  373. var polygonShape:b2PolygonShape = shape as b2PolygonShape;
  374. var vertices:Vector.<b2Vec2> = polygonShape.GetVertices();
  375. for(var j:uint = 0; j<vertices.length; j++)
  376. {
  377. //vertices[j] = b2Math.SubtractVV(vertices[j],localCenter);
  378. vertices[j].Multiply(scaleMultiplier);
  379. //vertices[j] = b2Math.AddVV(vertices[j],b2Math.MulFV(scaleMultiplier,localCenter));
  380. }
  381. }
  382. else if(shape as b2CircleShape)
  383. {
  384. var circleShape:b2CircleShape = shape as b2CircleShape;
  385. circleShape.SetLocalPosition(b2Math.MulFV(scaleMultiplier,circleShape.GetLocalPosition()));
  386. circleShape.SetRadius(circleShape.GetRadius()*scaleMultiplier);
  387. }
  388. }
  389. body.ResetMassData();
  390. }
  391. }
  392. public function PortalBody(src:b2Body, dest:b2Body, alpha:Number = 1):void {
  393. alpha = b2Math.Clamp(alpha,0,1);
  394. if(alpha==1)
  395. {
  396. if(dest.IsAwake()!=src.IsAwake())
  397. dest.SetAwake(src.IsAwake());
  398. dest.SetPosition(PortalPoint(Point2D.FromVec(src.GetPosition())).vec);
  399. dest.SetAngle(PortalAngle(src.GetAngle()));
  400. dest.SetGravityScale(src.GetGravityScale());
  401. dest.SetLinearDamping(src.GetLinearDamping());
  402. dest.SetTorque(src.GetTorque()*dest.GetInertia()/src.GetInertia());
  403. dest.SetForce(PortalVector(Point2D.FromVec(src.GetForce()).Times(dest.GetMass()/src.GetMass()),true).vec);
  404. dest.SetLinearVelocity(PortalVector(Point2D.FromVec(src.GetLinearVelocity()),true).vec);
  405. dest.SetAngularVelocity(src.GetAngularVelocity());
  406. }
  407. else
  408. {
  409. var destPosition:Point2D = PortalPoint(Point2D.FromVec(src.GetPosition()));
  410. var srcPosition:Point2D = otherPortal.PortalPoint(Point2D.FromVec(dest.GetPosition()));
  411. dest.SetPosition(Point2D.Lerp(Point2D.FromVec(dest.GetPosition()),destPosition,alpha).vec);
  412. src.SetPosition(Point2D.Lerp(Point2D.FromVec(src.GetPosition()),srcPosition,alpha).vec);
  413. var destAngle:Number = PortalAngle(src.GetAngle());
  414. var srcAngle:Number = otherPortal.PortalAngle(dest.GetAngle());
  415. dest.SetAngle(LerpAngle(dest.GetAngle(),destAngle,alpha));
  416. src.SetAngle(LerpAngle(src.GetAngle(),srcAngle, alpha));
  417. var destLinearVelocity:Point2D = PortalVector(Point2D.FromVec(src.GetLinearVelocity()),true);
  418. var srcLinearVelocity:Point2D = otherPortal.PortalVector(Point2D.FromVec(dest.GetLinearVelocity()),true);
  419. dest.SetLinearVelocity(Point2D.Lerp(Point2D.FromVec(dest.GetLinearVelocity()),destLinearVelocity,alpha).vec);
  420. src.SetLinearVelocity(Point2D.Lerp(Point2D.FromVec(src.GetLinearVelocity()),srcLinearVelocity,alpha).vec);
  421. var destAngularVelocity:Number = (src.GetAngularVelocity());
  422. var srcAngularVelocity:Number = (dest.GetAngularVelocity());
  423. dest.SetAngularVelocity(Lerp(dest.GetAngularVelocity(),destAngularVelocity,alpha));
  424. src.SetAngularVelocity(Lerp(src.GetAngularVelocity(),srcAngularVelocity, alpha));
  425. var destGravityScale:Number = src.GetGravityScale();
  426. var srcGravityScale:Number = dest.GetGravityScale();
  427. dest.SetGravityScale(Lerp(dest.GetGravityScale(),destGravityScale,alpha));
  428. src.SetGravityScale(Lerp(src.GetGravityScale(),srcGravityScale,alpha));
  429. var destLinearDamping:Number = src.GetLinearDamping();
  430. var srcLinearDamping:Number = dest.GetLinearDamping();
  431. dest.SetLinearDamping(Lerp(dest.GetLinearDamping(),destLinearDamping,alpha));
  432. src.SetLinearDamping(Lerp(src.GetLinearDamping(),srcLinearDamping,alpha));
  433. var destTorque:Number = src.GetTorque()*dest.GetInertia()/src.GetInertia();
  434. var srcTorque:Number = dest.GetTorque()*src.GetInertia()/dest.GetInertia();
  435. dest.SetTorque(Lerp(dest.GetTorque(),destTorque,alpha));
  436. src.SetTorque(Lerp(src.GetTorque(),srcTorque,alpha));
  437. var destForce:Point2D = PortalVector(Point2D.FromVec(src.GetForce()).Times(dest.GetMass()/src.GetMass()),true);
  438. var srcForce:Point2D = otherPortal.PortalVector(Point2D.FromVec(dest.GetForce()).Times(src.GetMass()/dest.GetMass()),true);
  439. dest.SetForce(Point2D.Lerp(Point2D.FromVec(dest.GetForce()),destForce,alpha).vec);
  440. src.SetForce(Point2D.Lerp(Point2D.FromVec(src.GetForce()),srcForce,alpha).vec);
  441. if(dest.IsAwake()!=src.IsAwake())
  442. dest.SetAwake(src.IsAwake());
  443. }
  444. var worldObject:PortalableWorldObject = dest.GetUserData() as PortalableWorldObject;
  445. if(worldObject)
  446. {
  447. worldObject.TouchingPortal(otherPortal,true);
  448. }
  449. }
  450. public function get otherPortal():Portal {
  451. if(_otherPortal==null||!_otherPortal.enabled)
  452. {
  453. _otherPortal = null;
  454. return this;
  455. }
  456. return _otherPortal;
  457. }
  458. public function set otherPortal(value:Portal):void {
  459. _otherPortal = value;
  460. }
  461. }
  462. }