/PortalGame/src/PortalTest/Portal.as
ActionScript | 528 lines | 429 code | 66 blank | 33 comment | 46 complexity | bcb506c06552c982b912f50b4c40677b MD5 | raw file
- /**
- * Created with IntelliJ IDEA.
- * User: $
- * Date: 18/05/13
- * Time: 18:41
- * To change this template use File | Settings | File Templates.
- */
- package PortalTest {
- import Box2D.Collision.Shapes.b2CircleShape;
- import Box2D.Collision.Shapes.b2PolygonShape;
- import Box2D.Collision.Shapes.b2Shape;
- import Box2D.Common.Math.b2Math;
- import Box2D.Common.Math.b2Vec2;
- import Box2D.Dynamics.b2Body;
- import Box2D.Dynamics.b2BodyDef;
- import Box2D.Dynamics.b2Fixture;
- import Box2D.Dynamics.b2FixtureDef;
- import Box2D.Dynamics.b2World;
- import Game2D.*;
- import Game2D.Functions.Lerp;
- import Game2D.Functions.LerpAngle;
- import Game2D.Functions.NormalizeAngle;
- import flash.display.BitmapData;
- import flash.display.Graphics;
- import flash.display.Sprite;
- import flash.geom.Matrix;
- import flash.geom.Point;
- import flash.utils.Dictionary;
- public class Portal extends PortalableWorldObject {
- private var _otherPortal:Portal = null;
- private var data:BitmapData;
- private var sprite:Sprite;
- private const edgeCapSize:Number = 0.1;
- private var sensorFixture:b2Fixture;
- private var world:b2World;
- public function Portal(width:Number, world:b2World, sprite:Sprite) {
- var bodyDef:b2BodyDef = new b2BodyDef();
- bodyDef.type = b2Body.b2_dynamicBody;
- super(world.CreateBody(bodyDef));
- this.scale = width;
- this.sprite = sprite;
- this.world = world;
- //var offset:Point2D = new Point2D(Game.physicsScale+edgeCapSize*Game.physicsScale, 0).Times(1);
- image = new Sprite();
- imageScale = new Point2D(1,1);
- imageOffset = new Point2D(0, 0);
- var imageSprite:Sprite = image as Sprite;
- imageSprite.graphics.lineStyle(1/Game.physicsScale,Color.Red);
- imageSprite.graphics.drawRect(-1-edgeCapSize*2*1, -edgeCapSize*1, edgeCapSize*2*1, edgeCapSize*2*1);
- imageSprite.graphics.drawRect(1, -edgeCapSize*1, edgeCapSize*2*1, edgeCapSize*2*1);
- var fixtureDef:b2FixtureDef = new b2FixtureDef();
- fixtureDef.density = 1.0;
- fixtureDef.isSensor = true;
- var shapeDef:b2PolygonShape = new b2PolygonShape();
- shapeDef.SetAsBox(width,0.05*width);
- fixtureDef.shape = shapeDef;
- sensorFixture = body.CreateFixture(fixtureDef);
- fixtureDef = new b2FixtureDef();
- fixtureDef.density = 1.0;
- shapeDef = new b2PolygonShape();
- shapeDef.SetAsOrientedBox(edgeCapSize*width,edgeCapSize*width,new b2Vec2(-(width+edgeCapSize*width),0));
- fixtureDef.shape = shapeDef;
- body.CreateFixture(fixtureDef);
- shapeDef.SetAsOrientedBox(edgeCapSize*width,edgeCapSize*width,new b2Vec2(width+edgeCapSize*width,0));
- body.CreateFixture(fixtureDef);
- data = new BitmapData(2000,2000,false,0xffffffff);
- //body.SetUserData(this);
- addEventListener(ContactEvent.BEGIN,onBeginContact);
- addEventListener(ContactEvent.END,onEndContact);
- }
- public function PortalPoint(p:Point2D):Point2D
- {
- if(otherPortal==null)
- return p.Clone();
- var localPoint:Point2D = p.Subtract(pos).Rotate(-rot);
- return localPoint.Rotate(otherPortal.rot).Times(-portalScale).Add(otherPortal.pos);
- }
- public override function render(graphics:Graphics, view:View):void
- {
- if(!otherPortal)
- return;
- var viewRect:Rect = view.rect.Scale(view.scale, true).Rotate(view.rotation);
- var offset:Point2D = new Point2D(scale, 0).Rotate(rot);
- var rightSide:Point2D = pos.Add(offset);
- var leftSide:Point2D = pos.Subtract(offset);
- //graphics.lineStyle(1, Color.Red, 1);
- //if(viewRect.contains(leftSide))
- // graphics.drawCircle(leftSide.x*Game.physicsScale, leftSide.y*Game.physicsScale,5);
- //graphics.lineStyle(1, Color.Green, 1);
- //if(viewRect.contains(rightSide))
- // graphics.drawCircle(rightSide.x*Game.physicsScale, rightSide.y*Game.physicsScale,5);
- var fwd:Point2D = new Point2D(0, 1.0).Rotate(rot);
- if (fwd.Dot(view.position.Subtract(pos).normalized) > 0&&(viewRect.contains(leftSide)||viewRect.contains(rightSide)||viewRect.IntersectLine(new Line(leftSide,rightSide))))
- {
- //graphics.lineStyle(1, Color.Black, 1);
- //viewRect.Draw(graphics, Game.physicsScale);
- data.fillRect(data.rect,0xffffffff);
- var cloneView:View = view.clone();
- cloneView.position = otherPortal.pos;//PortalPoint(view.position);
- cloneView.rotation = otherPortal.rot;//PortalAngle(view.rotation);
- cloneView.scale = view.scale;
- cloneView.UpdateMatrices();
- //PortalView(view, cloneView);
- cloneView.RenderInto(world, data, new Point2D(data.width/2, data.height/2));
- var matrix:Matrix = new Matrix();
- matrix.translate(-otherPortal.pos.x*Game.physicsScale,-otherPortal.pos.y*Game.physicsScale);
- matrix.rotate(-(otherPortal.rot));
- matrix.scale(1/view.scale,1/view.scale);
- //matrix.scale(1/portalScale,1/portalScale);
- matrix.translate(data.width/2,data.height/2);
- data.draw(sprite,matrix,null,null,null,false);
- DrawFov(graphics,view.position,viewRect,Game.physicsScale, view.scale);
- }
- }
- private function DrawFov(graphics:Graphics, fovPos:Point2D, rect:Rect, physicsScale:Number, viewScale:Number):void {
- var offset:Point2D = new Point2D(scale, 0).Rotate(rot);
- var rightSide:Point2D = pos.Add(offset);
- var leftSide:Point2D = pos.Subtract(offset);
- // graphics.lineStyle(1, Color.Blue, 1);
- // new Line(fovPos, rightSide).Draw(graphics, physicsScale);
- // graphics.lineStyle(1, Color.Green, 1);
- // new Line(fovPos, leftSide).Draw(graphics, physicsScale);
- var vectorToRight:Point2D = rightSide.Subtract(fovPos).normalized;
- var vectorToLeft:Point2D = leftSide.Subtract(fovPos).normalized;
- var rightProjection:Point2D = rightSide.Add(vectorToRight.Times(9999));
- var leftProjection:Point2D = leftSide.Add(vectorToLeft.Times(9999));
- graphics.lineStyle(1, Color.Black, 1);
- var out:Line = new Line();
- if (rect.IntersectLine(new Line(fovPos, rightProjection), out)) {
- rightProjection = out.b;
- }
- if (rect.IntersectLine(new Line(fovPos, leftProjection), out)) {
- leftProjection = out.b;
- }
- var shape:Vector.<Point2D> = new Vector.<Point2D>();
- {
- var topLeft:Point2D = new Point2D(rect.x, rect.y).Rotate(rect.rotation,rect.center);
- var topRight:Point2D = new Point2D(rect.right, rect.y).Rotate(rect.rotation,rect.center);
- var bottomLeft:Point2D = new Point2D(rect.x, rect.bottom).Rotate(rect.rotation,rect.center);
- var bottomRight:Point2D = new Point2D(rect.right, rect.bottom).Rotate(rect.rotation,rect.center);
- graphics.lineStyle(0, Color.Red, 1);
- var angleA:Number = leftProjection.Subtract(fovPos).angle;
- var angleB:Number = rightProjection.Subtract(fovPos).angle;
- {
- if(rect.contains(leftSide))
- {
- shape.push(leftSide);
- shape.push(leftProjection);
- }
- else
- {
- rect.IntersectLine(new Line(rightSide,leftSide),out);
- shape.push(out.b);
- }
- var trIndex:int = -1;
- var angleDiff:Number = NormalizeAngle(angleB-angleA);
- if(NormalizeAngle(topRight.Subtract(fovPos).angle-angleA)<angleDiff)
- {
- trIndex = shape.length;
- shape.push(topRight);
- }
- if(NormalizeAngle(bottomRight.Subtract(fovPos).angle-angleA)<angleDiff)
- {
- shape.push(bottomRight);
- }
- if(NormalizeAngle(bottomLeft.Subtract(fovPos).angle-angleA)<angleDiff)
- {
- shape.push(bottomLeft);
- }
- if(NormalizeAngle(topLeft.Subtract(fovPos).angle-angleA)<angleDiff)
- {
- if(trIndex==-1)
- shape.push(topLeft);
- else
- {
- shape.splice(trIndex,0,topLeft);
- }
- }
- if(rect.contains(rightSide))
- {
- shape.push(rightProjection);
- shape.push(rightSide);
- }
- else
- {
- rect.IntersectLine(new Line(leftSide,rightSide),out);
- shape.push(out.b);
- }
- }
- var matrix:Matrix = new Matrix();
- matrix.translate(-data.width/2,-data.height/2);
- // matrix.scale(1/portalScale,1/portalScale);
- // matrix.scale(view.scale,view.scale);
- matrix.scale(1/portalScale,1/portalScale);
- matrix.scale(viewScale,viewScale);
- matrix.rotate(rot+Math.PI);
- matrix.translate(pos.x*physicsScale,pos.y*physicsScale);
- graphics.beginBitmapFill(data,matrix,false,false);
- for(var i:uint=0;i<shape.length;i++)
- {
- var point:Point2D = shape[i].Times(physicsScale);
- if(i==0)
- graphics.moveTo(point.x, point.y);
- else
- graphics.lineTo(point.x, point.y);
- }
- graphics.endFill();
- }
- }
- public function get portalScale():Number {
- if(otherPortal)
- return otherPortal.scale/scale;
- return 1;
- }
- public function IsFacing(point:Point2D):Boolean {
- var fwd:Point2D = new Point2D(0, 1).Rotate(rot);
- return (fwd.Dot(point.Subtract(pos).normalized) > 0);
- }
- public function PortalAngle(angle:Number):Number {
- return angle+(otherPortal.rot+Math.PI-rot);
- }
- public function PortalVector(vec:Point2D, scale:Boolean = false):Point2D{
- if(otherPortal==null)
- {
- return vec.Clone();
- }
- var rotatedVector:Point2D = vec.Rotate(otherPortal.rot + Math.PI - rot);
- if(scale)
- return rotatedVector.Times(portalScale);
- else
- return rotatedVector;
- }
- private var bodiesInContact:Dictionary = new Dictionary();
- private var destroyQueue:Vector.<b2Body> = new Vector.<b2Body>();
- private function onBeginContact(event:ContactEvent):void {
- if(event.myFixture==sensorFixture)
- {
- var otherBody:b2Body = event.otherFixture.GetBody();
- if(bodiesInContact[otherBody]===undefined)
- {
- bodiesInContact[otherBody] = new CloneInfo(otherBody, otherPortal);
- bodiesInContact[otherBody].lastPos = body.GetLocalPoint(otherBody.GetPosition());
- var worldObject:PortalableWorldObject = otherBody.GetUserData() as PortalableWorldObject;
- if(worldObject)
- {
- worldObject.TouchingPortal(this,true);
- }
- trace("Beginning contact with body!");
- }
- else
- {
- var clone:CloneInfo = bodiesInContact[otherBody];
- clone.contactCount++;
- }
- //trace("Begin: "+bodies[otherBody]);
- }
- }
- public function GetClone(originalBody:b2Body):b2Body
- {
- if(bodiesInContact[originalBody]!==undefined)
- {
- return bodiesInContact[originalBody].cloneBody;
- }
- return null;
- }
- private function onEndContact(event:ContactEvent):void {
- if(event.myFixture==sensorFixture)
- {
- var otherBody:b2Body = event.otherFixture.GetBody();
- if(otherBody.GetUserData() as CloneInfo)
- return;
- if(bodiesInContact[otherBody]!==undefined)
- {
- var clone:CloneInfo = bodiesInContact[otherBody];
- if(clone.contactCount>1)
- {
- clone.contactCount--;
- }
- else
- {
- var bodyClone:BodyClone = otherBody.GetUserData() as BodyClone;
- if(bodyClone==null||bodyClone.portal!=this)
- {
- var originalBody:b2Body = clone.originalBody;
- var originalPos:b2Vec2 = body.GetLocalPoint(originalBody.GetPosition());
- var localVelocity:b2Vec2 = body.GetLocalVector(originalBody.GetLinearVelocity());
- if(clone.lastPos.y>0&&originalPos.y<0&&localVelocity.y<0)
- {
- if(clone.cloneBody!=null)
- clone.cloneBody.SetActive(false);
- //world.DestroyBody(clone.cloneBody);
- //clone.cloneBody = originalBody.Copy();
- ScaleBody(originalBody,portalScale);
- PortalBody(originalBody, originalBody);
- }
- clone.lastPos = originalPos.Copy();
- if(clone.cloneBody!=null)
- {
- clone.cloneBody.SetActive(false);
- destroyQueue.push(clone.cloneBody);
- }
- }
- delete bodiesInContact[otherBody];
- var worldObject:PortalableWorldObject = otherBody.GetUserData() as PortalableWorldObject;
- if(worldObject)
- {
- worldObject.TouchingPortal(this,false);
- }
- trace("Ending contact with body!");
- }
- }
- else
- {
- trace("Ending contact!!");
- }
- //trace("End: "+bodies[otherBody]);
- }
- }
- public override function update(deltaTime:Number):void {
- for(var i:* in bodiesInContact)
- {
- var originalBody:b2Body = i as b2Body;
- var clone:CloneInfo = bodiesInContact[i] as CloneInfo;
- var bodyClone:BodyClone = originalBody.GetUserData() as BodyClone;
- if(bodyClone==null||bodyClone.portal!=this)
- {
- if(clone.cloneBody==null)
- {
- clone.cloneBody = clone.originalBody.Copy();
- ScaleBody(clone.cloneBody, portalScale);
- PortalBody(originalBody, clone.cloneBody);
- }
- if(body.IsAwake()||otherPortal.body.IsAwake())
- {
- originalBody.SetAwake(true);
- clone.cloneBody.SetAwake(true);
- }
- PortalBody(originalBody, clone.cloneBody, 0.5);
- var originalPos:b2Vec2 = body.GetLocalPoint(originalBody.GetPosition());
- //var portaledPos:b2Vec2 = otherPortal.body.GetLocalPoint(clone.cloneBody.GetPosition())
- var combinedVelocity:Point2D =
- otherPortal.PortalVector(
- Point2D.FromVec(otherPortal.body.GetLinearVelocityFromWorldPoint(clone.cloneBody.GetPosition())))
- .Add(Point2D.FromVec(body.GetLinearVelocityFromLocalPoint(originalPos)));
- var localVelocity:b2Vec2 = body.GetLocalVector(b2Math.SubtractVV(combinedVelocity.vec,originalBody.GetLinearVelocity()));
- if(clone.lastPos.y>0&&originalPos.y<0&&localVelocity.y>0)
- {
- clone.cloneBody.SetActive(false);
- world.DestroyBody(clone.cloneBody);
- clone.cloneBody = originalBody.Copy();
- //clone.cloneBody.SetUserData(clone);
- ScaleBody(originalBody,portalScale);
- PortalBody(originalBody, originalBody);
- }
- clone.lastPos = originalPos.Copy();
- }
- }
- while(destroyQueue.length>0)
- {
- world.DestroyBody(destroyQueue.pop());
- }
- }
- public static function ScaleBody(body:b2Body, scaleMultiplier:Number):void {
- {
- var worldObject:WorldObject = body.GetUserData() as WorldObject;
- if(worldObject)
- worldObject.scale *= scaleMultiplier;
- for(var fixture:b2Fixture = body.GetFixtureList(); fixture; fixture=fixture.GetNext())
- {
- var shape:b2Shape = fixture.GetShape();
- if(shape as b2PolygonShape)
- {
- var polygonShape:b2PolygonShape = shape as b2PolygonShape;
- var vertices:Vector.<b2Vec2> = polygonShape.GetVertices();
- for(var j:uint = 0; j<vertices.length; j++)
- {
- //vertices[j] = b2Math.SubtractVV(vertices[j],localCenter);
- vertices[j].Multiply(scaleMultiplier);
- //vertices[j] = b2Math.AddVV(vertices[j],b2Math.MulFV(scaleMultiplier,localCenter));
- }
- }
- else if(shape as b2CircleShape)
- {
- var circleShape:b2CircleShape = shape as b2CircleShape;
- circleShape.SetLocalPosition(b2Math.MulFV(scaleMultiplier,circleShape.GetLocalPosition()));
- circleShape.SetRadius(circleShape.GetRadius()*scaleMultiplier);
- }
- }
- body.ResetMassData();
- }
- }
- public function PortalBody(src:b2Body, dest:b2Body, alpha:Number = 1):void {
- alpha = b2Math.Clamp(alpha,0,1);
- if(alpha==1)
- {
- if(dest.IsAwake()!=src.IsAwake())
- dest.SetAwake(src.IsAwake());
- dest.SetPosition(PortalPoint(Point2D.FromVec(src.GetPosition())).vec);
- dest.SetAngle(PortalAngle(src.GetAngle()));
- dest.SetGravityScale(src.GetGravityScale());
- dest.SetLinearDamping(src.GetLinearDamping());
- dest.SetTorque(src.GetTorque()*dest.GetInertia()/src.GetInertia());
- dest.SetForce(PortalVector(Point2D.FromVec(src.GetForce()).Times(dest.GetMass()/src.GetMass()),true).vec);
- dest.SetLinearVelocity(PortalVector(Point2D.FromVec(src.GetLinearVelocity()),true).vec);
- dest.SetAngularVelocity(src.GetAngularVelocity());
- }
- else
- {
- var destPosition:Point2D = PortalPoint(Point2D.FromVec(src.GetPosition()));
- var srcPosition:Point2D = otherPortal.PortalPoint(Point2D.FromVec(dest.GetPosition()));
- dest.SetPosition(Point2D.Lerp(Point2D.FromVec(dest.GetPosition()),destPosition,alpha).vec);
- src.SetPosition(Point2D.Lerp(Point2D.FromVec(src.GetPosition()),srcPosition,alpha).vec);
- var destAngle:Number = PortalAngle(src.GetAngle());
- var srcAngle:Number = otherPortal.PortalAngle(dest.GetAngle());
- dest.SetAngle(LerpAngle(dest.GetAngle(),destAngle,alpha));
- src.SetAngle(LerpAngle(src.GetAngle(),srcAngle, alpha));
- var destLinearVelocity:Point2D = PortalVector(Point2D.FromVec(src.GetLinearVelocity()),true);
- var srcLinearVelocity:Point2D = otherPortal.PortalVector(Point2D.FromVec(dest.GetLinearVelocity()),true);
- dest.SetLinearVelocity(Point2D.Lerp(Point2D.FromVec(dest.GetLinearVelocity()),destLinearVelocity,alpha).vec);
- src.SetLinearVelocity(Point2D.Lerp(Point2D.FromVec(src.GetLinearVelocity()),srcLinearVelocity,alpha).vec);
- var destAngularVelocity:Number = (src.GetAngularVelocity());
- var srcAngularVelocity:Number = (dest.GetAngularVelocity());
- dest.SetAngularVelocity(Lerp(dest.GetAngularVelocity(),destAngularVelocity,alpha));
- src.SetAngularVelocity(Lerp(src.GetAngularVelocity(),srcAngularVelocity, alpha));
- var destGravityScale:Number = src.GetGravityScale();
- var srcGravityScale:Number = dest.GetGravityScale();
- dest.SetGravityScale(Lerp(dest.GetGravityScale(),destGravityScale,alpha));
- src.SetGravityScale(Lerp(src.GetGravityScale(),srcGravityScale,alpha));
- var destLinearDamping:Number = src.GetLinearDamping();
- var srcLinearDamping:Number = dest.GetLinearDamping();
- dest.SetLinearDamping(Lerp(dest.GetLinearDamping(),destLinearDamping,alpha));
- src.SetLinearDamping(Lerp(src.GetLinearDamping(),srcLinearDamping,alpha));
- var destTorque:Number = src.GetTorque()*dest.GetInertia()/src.GetInertia();
- var srcTorque:Number = dest.GetTorque()*src.GetInertia()/dest.GetInertia();
- dest.SetTorque(Lerp(dest.GetTorque(),destTorque,alpha));
- src.SetTorque(Lerp(src.GetTorque(),srcTorque,alpha));
- var destForce:Point2D = PortalVector(Point2D.FromVec(src.GetForce()).Times(dest.GetMass()/src.GetMass()),true);
- var srcForce:Point2D = otherPortal.PortalVector(Point2D.FromVec(dest.GetForce()).Times(src.GetMass()/dest.GetMass()),true);
- dest.SetForce(Point2D.Lerp(Point2D.FromVec(dest.GetForce()),destForce,alpha).vec);
- src.SetForce(Point2D.Lerp(Point2D.FromVec(src.GetForce()),srcForce,alpha).vec);
- if(dest.IsAwake()!=src.IsAwake())
- dest.SetAwake(src.IsAwake());
- }
- var worldObject:PortalableWorldObject = dest.GetUserData() as PortalableWorldObject;
- if(worldObject)
- {
- worldObject.TouchingPortal(otherPortal,true);
- }
- }
- public function get otherPortal():Portal {
- if(_otherPortal==null||!_otherPortal.enabled)
- {
- _otherPortal = null;
- return this;
- }
- return _otherPortal;
- }
- public function set otherPortal(value:Portal):void {
- _otherPortal = value;
- }
- }
- }