flipside双人旋转赛车物理原理解析

flipside双人旋转赛车物理原理解析

从源码看,flipside的物理技术由box2d开源物理引擎提供

image

 目前重点怀疑,游戏的赛车物理控制代码在以下包中

image

 怀疑com.nitrome.flipside.Car是赛车的类

public function getExtrapolatedPosition(param1:Number)

获得外推力位置

package com.nitrome.flipside
{
   import Box2D.Collision.*;
   import Box2D.Collision.Shapes.*;
   import Box2D.Common.Math.*;
   import Box2D.Dynamics.*;
   import Box2D.Dynamics.Contacts.*;
   import Box2D.Dynamics.Joints.*;
   import com.nitrome.game.Score;
   import com.nitrome.util.Global;
   import com.nitrome.util.Key;
   import flash.geom.ColorTransform;
   import flash.ui.Keyboard;
   
   public class Car extends ActiveObject
   {
      
      public static const DESTROYED_ANIM_DURATION:Number = 40;
      
      public static const RESTORED_ANIM_DURATION:Number = 40;
      
      public static const MAG_TIME:Number = 32;
      
      public var index:Number;
      
      public var wheel1:b2Body;
      
      public var wheel2:b2Body;
      
      public var axle:b2Body;
      
      public var pin1:b2RevoluteJoint;
      
      public var pin2:b2RevoluteJoint;
      
      public var lightTrail:LightTrail;
      
      public var lightTrail2:LightTrail;
      
      private const wheelRadius:Number = 0.515625;
      
      private const axleLength:Number = 1.90625;
      
      private const axleThickness:Number = 0.2;
      
      public var wheelSpin:Number = 0;
      
      public var playerTorque:Number = 0.15;
      
      public var playerMaxSpin:Number = 32;
      
      public var playerDownforceCutoff:Number = 12;
      
      public var boostTime:Number = 0;
      
      public var destroyedTime:Number = 0;
      
      public var restoreTime:Number = 0;
      
      public var touchPoint1:b2Vec2 = null;
      
      public var touchPoint2:b2Vec2 = null;
      
      public var touchBody1:b2Body = null;
      
      public var touchBody2:b2Body = null;
      
      public var touching1:Boolean = false;
      
      public var touching2:Boolean = false;
      
      public var touchTime1:Number = 0;
      
      public var touchTime2:Number = 0;
      
      public var tileTouchLastFrame:Number = 0;
      
      public var aiInstruction:String = "r";
      
      public var aiInstructionTime:Number = -1;
      
      public var aiRubberbandEnabled:Boolean = true;
      
      public var centerCellX:Number = -1;
      
      public var centerCellY:Number = -1;
      
      public var riderFlip:Boolean = false;
      
      public var riderFrame:Number = 1;
      
      public var riderAngle:Number = 0;
      
      public var riderAngleTarget:Number = 0;
      
      public var downforceDisabled:Number = 0;
      
      public var linearPosition:Number = 0;
      
      public var nextGate:Gate = null;
      
      public var lap:Number = 0;
      
      public var maxLap:Number = 0;
      
      public var rank:Number;
      
      public var finished:Boolean = false;
      
      public var finishFrameNumber:Number = 0;
      
      public var lastFrameNumber:Number = 0;
      
      public var ignoreUpKey:Boolean = false;
      
      public var instructionsVisibility:Number = 0;
      
      public function Car(param1:Number, param2:Number)
      {
         var _loc10_:Number = NaN;
         super();
         Controller.cars.push(this);
         index = Controller.cars.length - 1;
         var _loc3_:b2BodyDef = new b2BodyDef();
         _loc3_.userData = {
            "car":this,
            "activeObject":this,
            "contactMade":true,
            "contactHeld":true,
            "contactLost":true
         };
         var _loc4_:Number = (param1 + 0.5) * 64 / 32;
         var _loc5_:Number = param2 * 64 / 32;
         _loc5_ = _loc5_ + (2 - wheelRadius);
         _loc3_.position.Set(_loc4_ - 0.75,_loc5_);
         wheel1 = makeBody(_loc3_);
         _loc3_.position.Set(_loc4_ + 0.75,_loc5_);
         wheel2 = makeBody(_loc3_);
         _loc3_.position.Set(_loc4_,_loc5_);
         axle = makeBody(_loc3_);
         var _loc6_:b2CircleDef = new b2CircleDef();
         _loc6_.radius = wheelRadius;
         _loc6_.density = 1;
         _loc6_.friction = 1;
         _loc6_.restitution = 0.3;
         _loc6_.filter.categoryBits = 2;
         wheel1.CreateShape(_loc6_);
         wheel2.CreateShape(_loc6_);
         wheel1.SetMassFromShapes();
         wheel2.SetMassFromShapes();
         var _loc7_:b2PolygonDef = new b2PolygonDef();
         _loc7_.SetAsBox(axleLength / 2,axleThickness / 2);
         _loc7_.density = 1;
         _loc7_.friction = 0.8;
         _loc7_.restitution = 0.3;
         _loc7_.filter.categoryBits = 2;
         axle.CreateShape(_loc7_);
         axle.SetMassFromShapes();
         var _loc8_:b2RevoluteJointDef = new b2RevoluteJointDef();
         _loc8_.body1 = wheel1;
         _loc8_.body2 = axle;
         _loc8_.localAnchor1 = new b2Vec2(0,0);
         _loc8_.localAnchor2 = new b2Vec2(-axleLength / 2,0);
         _loc8_.collideConnected = false;
         pin1 = makeJoint(_loc8_) as b2RevoluteJoint;
         var _loc9_:b2RevoluteJointDef = new b2RevoluteJointDef();
         _loc9_.body1 = wheel2;
         _loc9_.body2 = axle;
         _loc9_.localAnchor1 = new b2Vec2(0,0);
         _loc9_.localAnchor2 = new b2Vec2(axleLength / 2,0);
         _loc9_.collideConnected = false;
         pin2 = makeJoint(_loc9_) as b2RevoluteJoint;
         Viewport.prerender("bike" + index + "Wheel");
         Viewport.prerender("bike" + index + "WheelLines");
         Viewport.prerender("bike" + index + "Rider");
         Viewport.prerender("bike" + index + "Chassis");
         Viewport.prerender("bike" + index + "ChassisNumbers");
         Viewport.prerender("bike" + index + "ChassisShine");
         Viewport.prerender("bikeArrows");
         nextGate = Controller.level.firstGate;
         lightTrail = new LightTrail();
         lightTrail2 = new LightTrail();
         switch(index)
         {
            case 0:
               _loc10_ = 65535;
               break;
            case 1:
               _loc10_ = 14869218;
               break;
            case 2:
               _loc10_ = 3407743;
               break;
            case 3:
               _loc10_ = 13526514;
         }
         lightTrail.setColor(_loc10_);
         lightTrail2.setColor(_loc10_);
      }
      
      override public function advance() : void
      {
         if(destroyedTime > 0)
         {
            beingDestroyed();
         }
         else if(restoreTime > 0)
         {
            beingRestored();
         }
         controlling();
         rubberbanding();
         gatetracking();
         motion();
         animation();
         lastFrameNumber = Controller.frameNumber;
      }
      
      public function beingDestroyed() : void
      {
         var _loc1_:b2Vec2 = null;
         var _loc2_:Number = NaN;
         var _loc3_:Number = NaN;
         var _loc4_:Car = null;
         var _loc5_:Number = NaN;
         var _loc6_:Number = NaN;
         var _loc7_:Number = NaN;
         axle.SetLinearVelocity(new b2Vec2(0,0));
         wheel1.SetLinearVelocity(new b2Vec2(0,0));
         wheel2.SetLinearVelocity(new b2Vec2(0,0));
         axle.SetAngularVelocity((Math.random() - 0.5) * 100);
         wheel1.SetAngularVelocity(0);
         wheel2.SetAngularVelocity(0);
         if(destroyedTime < 2)
         {
            _loc1_ = nextGate.lastGate.centerPoint;
            _loc2_ = (axleLength + wheelRadius) * 0.7;
            _loc3_ = 0;
            while(_loc3_ < Controller.cars.length)
            {
               _loc4_ = Controller.cars[_loc3_];
               if(_loc4_ != this)
               {
                  _loc5_ = _loc4_.getCenterX() - _loc1_.x;
                  _loc6_ = _loc4_.getCenterY() - _loc1_.y;
                  _loc7_ = _loc5_ * _loc5_ + _loc6_ * _loc6_;
                  if(_loc7_ < _loc2_ * _loc2_)
                  {
                     return;
                  }
               }
               _loc3_++;
            }
            destroyedTime = 0;
            axle.SetXForm(_loc1_.Copy(),0);
            wheel1.SetXForm(new b2Vec2(_loc1_.x - axleLength / 2,_loc1_.y),0);
            wheel2.SetXForm(new b2Vec2(_loc1_.x + axleLength / 2,_loc1_.y),0);
            axle.SetAngularVelocity(0);
         }
         else
         {
            --destroyedTime;
         }
      }
      
      public function beingRestored() : void
      {
         --restoreTime;
      }
      
      public function controlling() : void
      {
         var _loc5_:Number = NaN;
         var _loc6_:Number = NaN;
         var _loc7_:String = null;
         var _loc9_:Number = NaN;
         var _loc10_:ActiveObject = null;
         var _loc11_:b2Vec2 = null;
         var _loc1_:* = false;
         var _loc2_:* = false;
         var _loc3_:Boolean = false;
         if(index == 0 && !finished && !Controller.demoGame)
         {
            _loc1_ = Key.isDown(Keyboard.LEFT);
            _loc2_ = Key.isDown(Keyboard.RIGHT);
            _loc3_ = Key.isDown(Keyboard.UP);
            if(!Controller.multiplayerGame)
            {
               _loc1_ ||= Key.isDown("A".charCodeAt(0));
               _loc2_ ||= Key.isDown("D".charCodeAt(0));
               _loc3_ ||= Key.isDown("W".charCodeAt(0));
            }
         }
         else if(index == 1 && Controller.multiplayerGame && !finished && !Controller.demoGame)
         {
            _loc1_ = Key.isDown("A".charCodeAt(0));
            _loc2_ = Key.isDown("D".charCodeAt(0));
            _loc3_ = Key.isDown("W".charCodeAt(0));
         }
         else
         {
            _loc5_ = Math.floor(axle.GetPosition().x * 32 / 64);
            _loc6_ = Math.floor(axle.GetPosition().y * 32 / 64);
            if(_loc5_ != centerCellX || _loc6_ != centerCellY)
            {
               if(Controller.level.instructionGrid[_loc5_][_loc6_])
               {
                  var _loc8_:String = Controller.level.instructionGrid[_loc5_][_loc6_];
                  if(_loc8_ == "be" || null == "bd")
                  {
                     aiRubberbandEnabled = null == "be";
                  }
                  else if(null != aiInstruction)
                  {
                     aiInstruction = null;
                     aiInstructionTime = Controller.frameNumber;
                  }
               }
            }
            _loc7_ = aiInstruction;
            if(_loc7_.substr(0,1) == "i")
            {
               aiInstruction = "i r";
               _loc9_ = 0;
               while(_loc9_ < Controller.level.activeList.length)
               {
                  _loc10_ = Controller.level.activeList[_loc9_];
                  if(_loc10_.transmitsAI)
                  {
                     if(_loc10_.inheritedAI(this))
                     {
                        break;
                     }
                  }
                  _loc9_++;
               }
               _loc7_ = aiInstruction.substr(2);
            }
            if(_loc7_ == "r")
            {
               _loc1_ = false;
               _loc2_ = true;
               _loc3_ = false;
            }
            else if(_loc7_ == "l")
            {
               _loc1_ = true;
               _loc2_ = false;
               _loc3_ = false;
            }
            else if(_loc7_ == "rf")
            {
               _loc2_ = forwardSpeed() > playerDownforceCutoff / 2;
               _loc1_ = !_loc2_;
               _loc3_ = false;
            }
            else if(_loc7_ == "lf")
            {
               _loc1_ = forwardSpeed() < -playerDownforceCutoff / 2;
               _loc2_ = !_loc1_;
               _loc3_ = false;
            }
            else if(_loc7_ == "ls")
            {
               _loc1_ = wheelSpin > -8;
               _loc2_ = !_loc1_;
               _loc3_ = false;
            }
            else if(_loc7_ == "rs")
            {
               _loc2_ = wheelSpin < 8;
               _loc1_ = !_loc2_;
               _loc3_ = false;
            }
            else if(_loc7_ == "n")
            {
               _loc1_ = _loc2_ = _loc3_ = false;
            }
            else if(_loc7_ == "j")
            {
               _loc1_ = _loc2_ = false;
               _loc3_ = true;
            }
            else if(_loc7_ == "jl")
            {
               if(forwardSpeed() < 0)
               {
                  _loc3_ = true;
               }
               else
               {
                  _loc2_ = true;
               }
            }
            else if(_loc7_ == "jr")
            {
               if(forwardSpeed() > 0)
               {
                  _loc3_ = true;
               }
               else
               {
                  _loc1_ = true;
               }
            }
            else
            {
               trace("UNRECOGNISED INSTRUCTION: [" + aiInstruction + "]");
            }
         }
         if(Controller.introTime < Controller.INTRO_DURATION)
         {
            _loc1_ = _loc2_ = _loc3_ = false;
         }
         if(_loc3_ && !ignoreUpKey)
         {
            if(touchTime1 <= 2 && touchTime2 <= 2)
            {
               _loc11_ = axle.GetWorldVector(new b2Vec2(0,isInverted() ? 350 * 3 : -350 * 3));
               wheel1.ApplyForce(_loc11_,wheel1.GetWorldCenter());
               wheel2.ApplyForce(_loc11_,wheel2.GetWorldCenter());
               touchTime1 = MAG_TIME + 2;
               touchTime2 = MAG_TIME + 2;
               downforceDisabled = 20;
               ignoreUpKey = true;
            }
         }
         else if(!_loc3_)
         {
            ignoreUpKey = false;
         }
         if(boostTime > 0)
         {
            --boostTime;
         }
         var _loc4_:Number = 0;
         if(_loc2_)
         {
            _loc4_ = playerMaxSpin;
            wheelSpin = Math.max(wheelSpin,wheel1.m_angularVelocity);
         }
         else if(_loc1_)
         {
            _loc4_ = -playerMaxSpin;
            wheelSpin = Math.min(wheelSpin,wheel1.m_angularVelocity);
         }
         wheelSpin = Global.slide(wheelSpin,_loc4_,playerTorque);
         if(_loc4_ != 0)
         {
            wheel1.SetAngularVelocity(wheelSpin);
            wheel2.SetAngularVelocity(wheelSpin);
         }
         else
         {
            if(wheel1.IsSleeping() && wheel2.IsSleeping() && axle.IsSleeping())
            {
               return;
            }
            wheel1.m_angularVelocity = wheel2.m_angularVelocity = Global.slide(wheel1.m_angularVelocity,0,0.1);
         }
         wheel2.SetXForm(wheel2.GetPosition(),wheel1.GetAngle());
         axle.ApplyTorque(_loc4_ / 5);
      }
      
      public function rubberbanding() : void
      {
         var _loc1_:Number = NaN;
         linearPosition = nextGate.fromLast(axle.GetPosition());
         linearPosition = (linearPosition + nextGate.lastGate.index) / Controller.level.gates.length;
         linearPosition += lap - 1;
         playerTorque = 0.15;
         playerMaxSpin = 32;
         playerDownforceCutoff = 12;
         if(index != 0 && Controller.cars[0].rank && !Controller.multiplayerGame && aiRubberbandEnabled)
         {
            _loc1_ = linearPosition - Controller.cars[0].linearPosition;
            if(_loc1_ > 0.2)
            {
               if(_loc1_ > 1)
               {
                  _loc1_ = 1;
               }
               playerTorque = 0.15 - _loc1_ * 0.1;
               playerMaxSpin = 32 - _loc1_ * 10;
               playerDownforceCutoff = 12 + _loc1_ * 2;
            }
            else if(_loc1_ < -0.2)
            {
               if(_loc1_ < -1)
               {
                  _loc1_ = -1;
               }
               playerTorque = 0.15 + -_loc1_ * 0.15;
               playerMaxSpin = 32 + -_loc1_ * 10;
               playerDownforceCutoff = 12 - -_loc1_ * 4;
            }
         }
         if(boostTime > 0)
         {
            playerMaxSpin += 4;
            playerTorque += 0.05;
         }
      }
      
      public function gatetracking() : void
      {
         var _loc1_:b2Vec2 = null;
         var _loc2_:String = null;
         if(nextGate)
         {
            _loc1_ = axle.GetPosition();
            if(nextGate.after(_loc1_) && nextGate.aligned(_loc1_))
            {
               if(nextGate.isFirst && !finished && !Controller.demoGame)
               {
                  ++lap;
                  if(lap == Controller.level.totalLaps + 1)
                  {
                     if(index == 0)
                     {
                        Controller.overlay.doOverlay("finish");
                     }
                     else if(index == 1 && Controller.multiplayerGame)
                     {
                        Controller.overlay2.doOverlay("finish");
                     }
                     justFinished();
                  }
                  else if(lap == maxLap + 1 && lap > 1)
                  {
                     _loc2_ = "lap" + lap.toString();
                     if(lap == Controller.level.totalLaps)
                     {
                        _loc2_ = "finallap";
                     }
                     if(index == 0)
                     {
                        Controller.overlay.doOverlay(_loc2_);
                     }
                     else if(index == 1 && Controller.multiplayerGame)
                     {
                        Controller.overlay2.doOverlay(_loc2_);
                     }
                  }
                  if(lap > maxLap)
                  {
                     maxLap = lap;
                  }
               }
               nextGate = nextGate.nextGate;
            }
            if(!nextGate.lastGate.after(_loc1_) && nextGate.lastGate.aligned(_loc1_))
            {
               if(nextGate.lastGate.isFirst && !finished)
               {
                  --lap;
               }
               nextGate = nextGate.lastGate;
            }
         }
      }
      
      public function justFinished() : void
      {
         if(finished)
         {
            return;
         }
         finished = true;
         finishFrameNumber = Controller.frameNumber;
         if(Controller.multiplayerGame)
         {
            if(rank == 2)
            {
               if(index == 1)
               {
                  ++Controller.player1Score;
               }
               else
               {
                  ++Controller.player2Score;
               }
            }
         }
         else if(index == 0)
         {
            if(rank == 1)
            {
               Score.value += Controller.levelScore();
               NitromeGame.setLevelUnlocked(Controller.level.number + 1);
            }
         }
      }
      
      public function motion() : void
      {
         var _loc4_:b2Vec2 = null;
         var _loc5_:Array = null;
         var _loc6_:Number = NaN;
         var _loc7_:b2Body = null;
         var _loc8_:b2Vec2 = null;
         var _loc9_:b2Vec2 = null;
         if(touching1)
         {
            touchTime1 = 0;
         }
         else
         {
            ++touchTime1;
         }
         if(touching2)
         {
            touchTime2 = 0;
         }
         else
         {
            ++touchTime2;
         }
         if(wheel1.IsSleeping() && wheel2.IsSleeping() && axle.IsSleeping())
         {
            return;
         }
         var _loc1_:b2Vec2 = wheel2.GetWorldCenter().Copy();
         _loc1_.Subtract(wheel1.GetWorldCenter());
         _loc1_.Normalize();
         var _loc2_:b2Vec2 = axle.GetLinearVelocity();
         var _loc3_:Number = b2Math.b2Dot(_loc1_,_loc2_);
         --downforceDisabled;
         if(Math.abs(_loc3_) > playerDownforceCutoff && downforceDisabled < 0 && touchPoint1 && Boolean(touchPoint2))
         {
            _loc4_ = new b2Vec2(-_loc1_.y,_loc1_.x);
            if(b2Math.b2Dot(_loc4_,touchPoint1) < b2Math.b2Dot(_loc4_,wheel1.GetPosition()))
            {
               _loc4_.Multiply(-1);
            }
            _loc5_ = [wheel1,wheel2];
            _loc6_ = 33 * 0.5 / 32;
            for each(_loc7_ in _loc5_)
            {
               _loc8_ = _loc4_.Copy();
               _loc8_.Multiply(_loc6_ + 0.5);
               _loc8_.Add(_loc7_.GetPosition());
               if(surfaceAtPoint(_loc8_))
               {
                  _loc9_ = _loc4_.Copy();
                  _loc9_.Multiply(20);
                  applyGravity(_loc7_,_loc9_);
               }
            }
         }
         applyGravity(wheel1);
         applyGravity(wheel2);
         applyGravity(axle);
      }
      
      public function animation() : void
      {
         var _loc1_:Number = forwardSpeed();
         if(_loc1_ < playerDownforceCutoff || touchTime1 > MAG_TIME || touchTime2 > MAG_TIME)
         {
            if(Math.abs(axle.GetLinearVelocity().x) > 2 && Math.abs(_loc1_) > 2)
            {
               riderFlip = forwardSpeed() < 0;
            }
            if(isInverted())
            {
               riderAngleTarget = 180;
            }
            else
            {
               riderAngleTarget = 0;
            }
         }
         riderAngle = (riderAngle - riderAngleTarget) * 0.95 + riderAngleTarget;
         if(Controller.frameNumber != lastFrameNumber)
         {
            riderFrame = Global.slide(riderFrame,riderFlip ? 5 : 1,1);
         }
         var _loc2_:Boolean = isInverted();
         var _loc3_:b2Vec2 = (_loc1_ > 0 != _loc2_ ? wheel1 : wheel2).GetPosition().Copy();
         _loc3_.Add(axle.GetWorldVector(new b2Vec2(0,_loc2_ ? 0.2 : -0.2)));
         lightTrail.pushPosition(_loc3_,Math.abs(_loc1_ / 16));
         lightTrail.length = Global.slide(lightTrail.length,Math.abs(60 * _loc1_ / 16),2);
         _loc3_ = (_loc1_ > 0 != _loc2_ ? wheel1 : wheel2).GetPosition().Copy();
         _loc3_.Add(axle.GetWorldVector(new b2Vec2(0,_loc2_ ? -0.2 : 0.2)));
         lightTrail2.pushPosition(_loc3_,Math.abs(_loc1_ / 16));
         lightTrail2.length = Global.slide(lightTrail2.length,Math.abs(32 * _loc1_ / 16),2);
         if(Controller.introTime > 50 && Controller.introTime < 110 && index == 0 && !Controller.demoGame && !Controller.multiplayerGame)
         {
            instructionsVisibility = 2;
         }
         else if(instructionsVisibility > 0)
         {
            instructionsVisibility -= 0.02;
         }
      }
      
      public function surfaceAtPoint(param1:b2Vec2) : b2Shape
      {
         var _loc4_:b2Shape = null;
         var _loc2_:b2AABB = new b2AABB();
         _loc2_.lowerBound.Set(param1.x - 0.01,param1.y - 0.01);
         _loc2_.upperBound.Set(param1.x + 0.01,param1.y + 0.01);
         var _loc3_:Array = new Array();
         if(Controller.world.Query(_loc2_,_loc3_,1000) == 0)
         {
            return null;
         }
         for each(_loc4_ in _loc3_)
         {
            if(_loc4_.TestPoint(_loc4_.m_body.GetXForm(),param1))
            {
               return _loc4_;
            }
         }
         return null;
      }
      
      public function isInverted() : Boolean
      {
         if(!touchPoint1 || !touchPoint2)
         {
            return false;
         }
         var _loc1_:b2Vec2 = wheel2.GetPosition().Copy();
         _loc1_.Subtract(wheel1.GetPosition());
         _loc1_.Normalize();
         var _loc2_:b2Vec2 = touchPoint1.Copy();
         _loc2_.Add(touchPoint2);
         _loc2_.Multiply(0.5);
         var _loc3_:b2Vec2 = new b2Vec2(-_loc1_.y,_loc1_.x);
         return b2Math.b2Dot(_loc3_,wheel1.GetPosition()) > b2Math.b2Dot(_loc3_,_loc2_);
      }
      
      public function forwardSpeed() : Number
      {
         var _loc1_:b2Vec2 = wheel2.GetPosition().Copy();
         _loc1_.Subtract(wheel1.GetPosition());
         _loc1_.Normalize();
         var _loc2_:b2Vec2 = new b2Vec2(-_loc1_.y,_loc1_.x);
         var _loc3_:Boolean = touchPoint1 ? b2Math.b2Dot(_loc2_,wheel1.GetPosition()) > b2Math.b2Dot(_loc2_,touchPoint1) : false;
         var _loc4_:Number = b2Math.b2Dot(axle.GetLinearVelocity(),_loc1_);
         return isInverted() ? -_loc4_ : _loc4_;
      }
      
      public function getCenterX() : Number
      {
         return axle.GetWorldCenter().x;
      }
      
      public function getCenterY() : Number
      {
         return axle.GetWorldCenter().y;
      }
      
      public function getPosition() : b2Vec2
      {
         return axle.GetPosition();
      }
      
      public function getVelocity() : b2Vec2
      {
         return axle.GetLinearVelocity();
      }
      
      public function getNearbyCars(param1:Number) : Array
      {
         var _loc3_:Car = null;
         var _loc4_:b2Vec2 = null;
         var _loc2_:Array = [];
         for each(_loc3_ in Controller.cars)
         {
            if(_loc3_ != this)
            {
               _loc4_ = axle.GetPosition().Copy();
               _loc4_.Subtract(_loc3_.axle.GetPosition());
               if(_loc4_.LengthSquared() < param1 * param1)
               {
                  _loc2_.push(_loc3_);
               }
            }
         }
         return _loc2_;
      }
      
      public function getExtrapolatedPosition(param1:Number) : b2Vec2
      {
         var _loc2_:b2Vec2 = axle.GetPosition().Copy();
         var _loc3_:b2Vec2 = axle.GetLinearVelocity().Copy();
         _loc3_.Multiply(param1);
         _loc2_.Add(_loc3_);
         return _loc2_;
      }
      
      override public function contactMade(param1:b2ContactPoint) : void
      {
         var _loc2_:b2Shape = null;
         var _loc3_:b2Shape = null;
         var _loc4_:Car = null;
         if(param1.shape1.m_body == wheel1 || param1.shape1.m_body == wheel2)
         {
            _loc2_ = param1.shape1;
            _loc3_ = param1.shape2;
         }
         else
         {
            if(!(param1.shape2.m_body == wheel1 || param1.shape2.m_body == wheel2))
            {
               return;
            }
            _loc2_ = param1.shape2;
            _loc3_ = param1.shape1;
         }
         if(_loc2_.m_body == wheel1)
         {
            touchPoint1 = param1.position;
            touchBody1 = _loc3_.m_body;
            touching1 = true;
         }
         else
         {
            touchPoint2 = param1.position;
            touchBody2 = _loc3_.m_body;
            touching2 = true;
         }
         if(_loc3_.m_body.m_userData && Boolean(_loc3_.m_body.m_userData.tile))
         {
            tileTouchLastFrame = Controller.frameNumber;
         }
         if(_loc3_.m_body.m_userData && Boolean(_loc3_.m_body.m_userData.car))
         {
            _loc4_ = _loc3_.m_body.m_userData.car as Car;
            if(aiInstructionTime < _loc4_.aiInstructionTime)
            {
               aiInstruction = _loc4_.aiInstruction;
               aiInstructionTime = _loc4_.aiInstructionTime;
            }
            else
            {
               _loc4_.aiInstruction = aiInstruction;
               _loc4_.aiInstructionTime = aiInstructionTime;
            }
         }
      }
      
      override public function contactHeld(param1:b2ContactPoint) : void
      {
         var _loc2_:b2Shape = null;
         var _loc3_:b2Shape = null;
         if(param1.shape1.m_body == wheel1 || param1.shape1.m_body == wheel2)
         {
            _loc2_ = param1.shape1;
            _loc3_ = param1.shape2;
         }
         else
         {
            if(!(param1.shape2.m_body == wheel1 || param1.shape2.m_body == wheel2))
            {
               return;
            }
            _loc2_ = param1.shape2;
            _loc3_ = param1.shape1;
         }
         if(_loc2_.m_body == wheel1)
         {
            touchPoint1 = param1.position;
            touchBody1 = _loc3_.m_body;
            touching1 = true;
         }
         else
         {
            touchPoint2 = param1.position;
            touchBody2 = _loc3_.m_body;
            touching2 = true;
         }
         if(_loc3_.m_body.m_userData && Boolean(_loc3_.m_body.m_userData.tile))
         {
            tileTouchLastFrame = Controller.frameNumber;
         }
      }
      
      override public function contactLost(param1:b2ContactPoint) : void
      {
         var _loc2_:b2Shape = null;
         var _loc3_:b2Shape = null;
         if(param1.shape1.m_body == wheel1 || param1.shape1.m_body == wheel2)
         {
            _loc2_ = param1.shape1;
            _loc3_ = param1.shape2;
         }
         else
         {
            if(!(param1.shape2.m_body == wheel1 || param1.shape2.m_body == wheel2))
            {
               return;
            }
            _loc2_ = param1.shape2;
            _loc3_ = param1.shape1;
         }
         if(_loc2_.m_body == wheel1)
         {
            if(_loc3_.m_body == touchBody1)
            {
               touching1 = false;
            }
         }
         else if(_loc3_.m_body == touchBody2)
         {
            touching2 = false;
         }
      }
      
      public function hitLaser() : void
      {
         if(destroyedTime == 0)
         {
            destroyedTime = DESTROYED_ANIM_DURATION;
            restoreTime = RESTORED_ANIM_DURATION;
            if(Controller.onScreen(axle.GetPosition().x * 32,axle.GetPosition().y * 32))
            {
               NitromeGame.sound_manager.playSound("laser");
            }
         }
      }
      
      override public function render(param1:Viewport) : void
      {
         var _loc11_:b2Body = null;
         var _loc12_:b2Vec2 = null;
         var _loc13_:Number = NaN;
         var _loc14_:Number = NaN;
         var _loc2_:Number = Math.floor(axle.GetPosition().x * 32) - param1.scrollX;
         var _loc3_:Number = Math.floor(axle.GetPosition().y * 32) - param1.scrollY;
         if(_loc2_ < -100)
         {
            return;
         }
         if(_loc2_ > 650)
         {
            return;
         }
         if(_loc3_ < -100)
         {
            return;
         }
         if(_loc3_ > 500)
         {
            return;
         }
         var _loc4_:Number = axle.GetAngle();
         var _loc5_:ColorTransform = null;
         if(destroyedTime > 0)
         {
            if(destroyedTime == 1)
            {
               _loc5_ = Global.whiteOut(0);
            }
            else
            {
               _loc5_ = Global.whiteOut(destroyedTime / DESTROYED_ANIM_DURATION);
            }
         }
         else if(restoreTime > 0)
         {
            _loc5_ = Global.whiteOut(1 - restoreTime / RESTORED_ANIM_DURATION);
         }
         var _loc6_:Number = 0;
         while(_loc6_ < 2)
         {
            _loc11_ = _loc6_ == 0 ? wheel1 : wheel2;
            _loc12_ = axle.GetWorldPoint(new b2Vec2((_loc6_ == 0 ? 31 : -32) / 32,0));
            _loc13_ = Math.floor(_loc12_.x * 32) - param1.scrollX;
            _loc14_ = Math.floor(_loc12_.y * 32) - param1.scrollY;
            param1.drawRotated("bike" + index + "Wheel",_loc13_,_loc14_,0,_loc5_);
            param1.drawRotated("bike" + index + "WheelLines",_loc13_,_loc14_,_loc11_.GetAngle(),_loc5_);
            _loc6_++;
         }
         var _loc7_:Number = axle.GetAngle() % (Math.PI * 2);
         if(_loc7_ < -Math.PI)
         {
            _loc7_ += Math.PI * 2;
         }
         if(_loc7_ > Math.PI)
         {
            _loc7_ -= Math.PI * 2;
         }
         var _loc8_:Number = 1 - Math.abs(_loc7_ / Math.PI);
         var _loc9_:ColorTransform = new ColorTransform(1,1,1,_loc8_);
         if(_loc5_)
         {
            _loc9_.concat(_loc5_);
         }
         param1.drawRotated("bike" + index + "Chassis",_loc2_,_loc3_,_loc4_ + Math.PI,_loc5_);
         param1.drawRotated("bike" + index + "Chassis",_loc2_,_loc3_,_loc4_,_loc9_);
         param1.drawRotated("bike" + index + "ChassisNumbers",_loc2_,_loc3_,_loc4_,_loc5_);
         param1.drawRotated("bike" + index + "Rider-" + riderFrame.toString(),_loc2_,_loc3_,_loc4_ + riderAngle * Math.PI / 180,_loc5_);
         param1.drawRotated("bike" + index + "ChassisShine",_loc2_,_loc3_,0,_loc5_,"lighten");
         var _loc10_:Number = instructionsVisibility;
         if(_loc10_ > 1)
         {
            _loc10_ = 1;
         }
         if(_loc10_ > 0)
         {
            param1.drawRotated("bikeArrows",_loc2_,_loc3_,0,new ColorTransform(1,1,1,instructionsVisibility));
         }
      }
   }
}

 通过分析源码,可以思考得出,双人旋转赛车的赛车对象由3个部分组成,2个轮子(物理体)+一个轴(物理体)

关于旋转物理关节的实现

var _loc8_:b2RevoluteJointDef = new b2RevoluteJointDef();
_loc8_.body1 = wheel1;
_loc8_.body2 = axle;
_loc8_.localAnchor1 = new b2Vec2(0,0);
_loc8_.localAnchor2 = new b2Vec2(-axleLength / 2,0);
_loc8_.collideConnected = false;
pin1 = makeJoint(_loc8_) as b2RevoluteJoint;
var _loc9_:b2RevoluteJointDef = new b2RevoluteJointDef();
_loc9_.body1 = wheel2;
_loc9_.body2 = axle;
_loc9_.localAnchor1 = new b2Vec2(0,0);
_loc9_.localAnchor2 = new b2Vec2(axleLength / 2,0);
_loc9_.collideConnected = false;
pin2 = makeJoint(_loc9_) as b2RevoluteJoint;

 

posted on 2026-02-06 15:31  小沙盒工作室  阅读(5)  评论(0)    收藏  举报