Box2D — Физика движения авто своими руками

Приветствую всех читателей хабра. В этом топике я постараюсь показать вам как просто можно создать простую физику движения передне— и полноприводного автомобиля. Итак, поехали!

Вступление


Скажу сразу, что я еще не достаточно знаком со всеми понятиями физики, но понимаю что они из себя представляют, поэтому умных слов не ждите, все буду стараться описывать наиболее понятным и человеческим языком, извиняйте заранее.
Толчком для написания этой статьи является отсутствие рабочего аналога. На тот момент когда мне нужно было сделать подобное, я нагуглил лишь один более—менее нормальный пример, который, к сожалению, был мне не интересен по некоторым причинам:
  1. Полное отсутствие дрифта/скольжения
  2. Различная скорость при движении по осям X и Y (неизвестно, чем это вызвано, но мне такое не надо)


Подготовка


Итак, что мы знаем. А знаем мы то, что при движении на авто (а в нашем случае — на колёса) действуют некоторые силы. Для нашего простого проекта естесвенно, некоторыми из этих сил можно пренебречь (мы же не полноценный симулятор делаем).
Все параметры, которые мы будем использовать:
  1. Сила тяги (оно же у нас будет являться скоростью и ускорением)
  2. Продольное трение колесa
  3. Поперечное трение колеса

Все эти силы мы будем прикладывать непосредственно к объектам колёс.
При движении вперёд графически эти силы можно изобразить так (за переднюю часть авто на картинках принимать верх):
image
По оси X — поперечное трение колеса
По оси Y вниз — продольное трение колеса
По оси Y вверх — скорость и ускорение
Все вышеописанные оси всегда относительны центра каждого колеса и его угла поворота.

Пишем код


В качестве физического движка я выбрал Box2D. Для облегчения написания кода я все—таки решил использовать обертку QuickBox2D, потому как она существенно облегчает создание примитивов в Box2D.

Подключаем необходимые классы:
  1. import Box2D.Collision.Shapes.*;
  2. import Box2D.Common.Math.*;
  3. import Box2D.Dynamics.*;
  4. import Box2D.Dynamics.Joints.*;
  5. import Box2D.Collision.*;
  6. import Box2D.Common.*;
  7. import com.actionsnippet.qbox.*;

… и создаем наш мир:
  1. var world:QuickBox2D = new QuickBox2D(this,{debug:false, frim:true});
  2. world.gravity = new b2Vec2(0,0)//вектор гравитации
  3. world.start()//старт отрисовки и просчета физики
  4. world.createStageWalls()//фича от QuickBox'a - создает 4 стены по размерам stage
  5. world.mouseDrag()//и разрешаем перемещать все тела мышью


Прописываем необходимые переменные или константы:
  1. //константы и переменные:
  2. private const FWD=1//передний 
  3. private const AWD=2//полный
  4. private const RWD=3//задний
  5. private var _privod:Number//текущий привод авто, выбирается при создании
  6. private var _maxTurnAngle:Number// максимальный угол поворота колес
  7. private var _width:Number//длина авто
  8. private var _height:Number//ширина
  9. private var _axisOffset:Number//отступ колес по длине, относительно центра авто
  10. private const _angularDamping = 7//замедление кручения колеса
  11. private const _angularDampingReverse = 3//то же, но при заднем ходе
  12. private const _linearDamping = 0.25//замедление скольжения колеса, что-то вроде трения
  13. private const _linearDampingReverse = 0.5// и для заднего хода
  14.  
  15. public var _carBody:QuickObject;//объект автомобиля
  16.  
  17. private var _frontAxisBodyLeft:QuickObject;//и его колес
  18. private var _frontAxisBodyRight:QuickObject;
  19. private var _rearAxisBodyLeft:QuickObject;
  20. private var _rearAxisBodyRight:QuickObject;
  21.  
  22. private var _frontLeftJoint:QuickObject;//шарнирные соединения для передних колёс
  23. private var _frontRightJoint:QuickObject;
  24. private var _rearLeftJoint:QuickObject;//шарнирные соединения для задних колёс
  25. private var _rearRightJoint:QuickObject;
  26. protected var axisHeight:Number = 4;//ширина колеса
  27. protected var axisWidth:Number = 7;//длина
  28.  
  29. public var drive:int = 0;//переменные для управлления автомобилем
  30.         public var steer:int = 0;
  31. //drive = 1 - едем вперед
  32. //drive = 0 - отпускаем газ и катимся по инерции, либо просто стоим
  33. //drive = -1 - едем назад
  34. //
  35. //steer = -1 - рулим влево
  36. //steer = 0 - никуда не рулим
  37. //steer = 1 - рулим вправо
  38.  


Создаем авто с колёсами:
  1. //создаем авто
  2. _width = 76
  3. _height = 40
  4. _maxTurnAngle = 15 * Globals.DEG_TO_RAD//максимальный угол поворота передних колес
  5. _axisOffset:Number = (_width/4 - axisWidth)/ Globals.RATIO //отступ колес по длине
  6. _privod = FWD; // ну и наш привод, пока что функционируют передний и полный
  7.  
  8. _carBody = world.addBox({
  9.  width :this._width / 2 / Globals.RATIO,
  10.  height :this._height / 2 / Globals.RATIO,
  11.  x :(this.x + this._width / 2) / Globals.RATIO,
  12.  y :(this.y + this._height/ 2) /Globals.RATIO,
  13.  density: 0.48,
  14.  driction:0.3,
  15.  restitution:0.4,
  16.  linearDamping:this._linearDamping,
  17.  angularDamping:this._angularDamping,
  18.  groupIndex:-1,
  19.  isSleeping:true
  20. skin:null,
  21.  scaleSkin:true});
  22.  
  23. this._frontAxisBodyLeft = this.world.addBox({
  24. width :this.axisWidth / Globals.RATIO,
  25. height :(this.axisHeight) / Globals.RATIO,
  26. x :_carBody.body.GetWorldCenter().x + this._axisOffset,
  27. y :_carBody.body.GetWorldCenter().y - this._height/4/Globals.RATIO+1/Globals.RATIO,// + (this.axisHeight/2) / Globals.RATIO,
  28. density:0.48,
  29. friction:0.3,
  30. restitution:0.5,
  31. linearDamping:this._linearDamping,
  32. angularDamping:this._angularDamping,
  33. groupIndex:-1});
  34.  
  35. this._frontAxisBodyRight = this.world.addBox({
  36. width :this.axisWidth / Globals.RATIO,
  37. height :(this.axisHeight) / Globals.RATIO,
  38. x :_carBody.body.GetWorldCenter().x + this._axisOffset,
  39. y :_carBody.body.GetWorldCenter().y + this._height/4/Globals.RATIO-1/Globals.RATIO,// - (this.axisHeight) / Globals.RATIO,
  40. density:0.48,
  41. friction:0.3,
  42. restitution:0.5,
  43. linearDamping:this._linearDamping,
  44. angularDamping:this._angularDamping,
  45. groupIndex:-1});
  46.  
  47. this._frontLeftJoint = this.world.addJoint({
  48. type:QuickBox2D.REVOLUTE,
  49.     a:this._carBody.body,
  50. b:this._frontAxisBodyLeft.body,
  51. x1:this._frontAxisBodyLeft.body.GetWorldCenter().x,
  52. y1:this._frontAxisBodyLeft.body.GetWorldCenter().y,
  53. x2:this._frontAxisBodyLeft.body.GetWorldCenter().x,
  54. y2:this._frontAxisBodyLeft.body.GetWorldCenter().y,
  55. enableLimit:true,
  56. enableMotor:true,
  57. collideConnected:true,
  58. lowerAngle:-this._maxTurnAngle,
  59. upperAngle:this._maxTurnAngle
  60. });
  61.  
  62. this._frontRightJoint = this.world.addJoint({
  63. type:QuickBox2D.REVOLUTE,
  64.     a:this._carBody.body,
  65. b:this._frontAxisBodyRight.body,
  66. x1:this._frontAxisBodyRight.body.GetWorldCenter().x,
  67. y1:this._frontAxisBodyRight.body.GetWorldCenter().y,
  68. x2:this._frontAxisBodyRight.body.GetWorldCenter().x,
  69. y2:this._frontAxisBodyRight.body.GetWorldCenter().y,
  70. enableLimit:true,
  71. enableMotor:true,
  72. collideConnected:true,
  73. lowerAngle:-this._maxTurnAngle,
  74. upperAngle:this._maxTurnAngle
  75. });
  76.  
  77. this._rearAxisBodyLeft = this.world.addBox({
  78. width :this.axisWidth / Globals.RATIO,
  79. height :(this.axisHeight) / Globals.RATIO,
  80. x :_carBody.x - this._axisOffset,//-this.frontPivotOffset,
  81. y :_carBody.y - this._height/4/Globals.RATIO+1/Globals.RATIO,// + (this.axisHeight/2) / Globals.RATIO,
  82. density:0.48,
  83. friction:0.3,
  84. restitution:0.5,
  85. linearDamping:this._linearDamping,
  86. angularDamping:this._angularDamping,
  87. groupIndex:-1,
  88. isSleeping:true});
  89.  
  90. this._rearAxisBodyRight = this.world.addBox({
  91. width :this.axisWidth / Globals.RATIO,
  92. height :(this.axisHeight) / Globals.RATIO,
  93. x :_carBody.x - this._axisOffset,//-this.frontPivotOffset,
  94. y :_carBody.y + this._height/4/Globals.RATIO-1/Globals.RATIO,// - (this.axisHeight) / Globals.RATIO,
  95. density:0.48,
  96. friction:0.3,
  97. restitution:0.5,
  98. linearDamping:this._linearDamping,
  99. angularDamping:this._angularDamping,
  100. groupIndex:-1,
  101. isSleeping:true});
  102.  
  103.  
  104. this._rearLeftJoint = this.world.addJoint({
  105. type:QuickBox2D.REVOLUTE,
  106.     a:this._carBody.body,
  107. b:this._rearAxisBodyLeft.body,
  108. x1:this._rearAxisBodyLeft.x,
  109. y1:this._rearAxisBodyLeft.y,
  110. x2:this._rearAxisBodyLeft.x,
  111. y2:this._rearAxisBodyLeft.y,
  112. enableLimit:true,
  113. enableMotor:false,
  114. collideConnected:false,
  115. lowerAngle:0,
  116. upperAngle:0
  117. });
  118.  
  119. this._rearRightJoint = this.world.addJoint({
  120. type:QuickBox2D.REVOLUTE,
  121.     a:this._carBody.body,
  122. b:this._rearAxisBodyRight.body,
  123. x1:this._rearAxisBodyRight.x,
  124. y1:this._rearAxisBodyRight.y,
  125. x2:this._rearAxisBodyRight.x,
  126. y2:this._rearAxisBodyRight.y,
  127. enableLimit:true,
  128. enableMotor:false,
  129. lowerAngle:0,
  130. upperAngle:0
  131. });


Ну вот, мы создали наше авто. Вид его примерно как на картинке выше, но только оно будет повернуто на 90% по часовой.
Теперь перед нами стоит главная задача: научить наше авто ездить. Для достижения эффекта езды мы будем прикладывать ApplyForce(..) к нужным колесам (для переднего привода — передние колеса. для полного — все колеса)
Для просчета физики авто и управления им используем accelerate() и вызываем её при каждом обновлении мира:
  1. stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownList);
  2. stage.addEventListener(KeyboardEvent.KEY_UP, keyUpList);
  3. world.addEventListener(QuickBox2D.STEP,onStep);
  4. ...
  5. var bup:Boolean;
  6. var bdown:Boolean;
  7. var bleft:Boolean;
  8. var bright:Boolean;
  9.  
  10. function keyDownList(e:KeyboardEvent):void
  11. {
  12.   if (e.keyCode == Keyboard.UP){
  13.    bup = true;
  14.   }
  15.   if (e.keyCode == Keyboard.LEFT){
  16.    bleft = true;
  17.   }
  18.   if (e.keyCode == Keyboard.DOWN){
  19.    bdown = true;
  20.   }
  21.   if (e.keyCode == Keyboard.RIGHT){
  22.    bright = true;
  23.   }
  24. };
  25. function keyUpList(e:KeyboardEvent):void
  26. {
  27.   if (e.keyCode == Keyboard.UP){
  28.    bup = false;
  29.   };
  30.   if (e.keyCode == Keyboard.LEFT){
  31.    bleft = false;
  32.   };
  33.   if (e.keyCode == Keyboard.DOWN){
  34.    bdown = false;
  35.   };
  36.   if (e.keyCode == Keyboard.RIGHT){
  37.    bright = false;
  38.   };
  39. };
  40.  
  41. function onStep(evt:Event):void
  42. {
  43. car.accelerate();
  44. if (bup) {car.drive =1};
  45. if (bdown) {car.drive=-1};
  46. if (!bup && !bdown) (car.drive=0);
  47. if (bleft) {car.steer=-1};
  48. if (bright) {car.steer=1};
  49. if (!bleft && !bright) {car.steer=0};
  50. };


Ну и собственно сама процедура accelerate() (разбираем построчно, полный код процедуры будет позже):
1) Для начала мы разбудим наши тела
  1. this._carBody.body.WakeUp();
  2. this._frontAxisBodyLeft.body.WakeUp();
  3. this._frontAxisBodyRight.body.WakeUp();


2) Затем добавим необходимые силы трения(общую, по X, и по Y) чтобы авто ехало вперед, а не скользило при резком повороте, и при движении по инерции — замедлялось:
  1. if (this.drive > 0){ //едем вперёд
  2.  this._acceleration = this._accelerationForward;
  3.  this.setLinearDamping(this._linearDamping);
  4.  this.setAngularDamping(this._angularDamping);
  5. }
  6. else { //едем назад или стоим
  7.  this._acceleration = this._accelerationBackwards;
  8.  this.setLinearDamping(this._linearDamping);
  9.  this.setAngularDamping(this._angularDamping);
  10. }
  11. this.addFriction(this._rearAxisBodyLeft.body,0);
  12. this.addFriction(this._rearAxisBodyRight.body,0);
  13. this.addFriction(this._frontAxisBodyLeft.body,1);
  14. this.addFriction(this._frontAxisBodyRight.body,1);


3) setLinearDamping() и setAngularDamping()
  1. private function setLinearDamping(linDamp:Number) : void
  2. {
  3.  this._frontAxisBodyLeft.body.m_linearDamping = linDamp;
  4.  this._frontAxisBodyRight.body.m_linearDamping = linDamp;
  5.  this._rearAxisBodyLeft.body.m_linearDamping = linDamp;
  6.  this._rearAxisBodyRight.body.m_linearDamping = linDamp;
  7.  this._carBody.body.m_linearDamping = linDamp;
  8.  return;
  9. }
  10.  
  11. private function setAngularDamping(angDamp:Number) : void
  12. {
  13.  this._frontAxisBodyLeft.body.m_angularDamping = angDamp;
  14.  this._frontAxisBodyRight.body.m_angularDamping = angDamp;
  15.  this._rearAxisBodyLeft.body.m_angularDamping = angDamp;
  16.  this._rearAxisBodyRight.body.m_angularDamping = angDamp;
  17.  this._carBody.body.m_angularDamping = angDamp;
  18.  return;
  19. }


4) Ну и самая интересная на мой взгляд процедура addFriction(), реализацию которой я так долго искал и не нашел, и вот реализовал сам:
  1. function addFriction(targetBody:b2Body, isFront:Number)
  2. {
  3.   var spd,spd2:b2Vec2;
  4.   spd = targetBody.GetLinearVelocity();
  5.   spd2 = targetBody.GetLocalVector(spd);
  6.  
  7.   if (this._privod == FWD){//передний привод
  8.    if (isFront == 1){
  9.     spd2.y = spd2.y * 0.5;
  10.    }
  11.    else {
  12.     spd2.y = spd2.y>2.5? spd2.y * 0.45 : 0;
  13.     }
  14.    spd = targetBody.GetWorldVector(spd2);
  15.   targetBody.SetLinearVelocity(spd);
  16.   }
  17.  
  18.   if (this._privod == RWD){
  19.    if (isFront == 1){
  20.     spd2.y = 0;
  21.     spd2.x = spd2.x * .9;
  22.     spd = targetBody.GetWorldVector(spd2);
  23.     targetBody.SetLinearVelocity(spd);
  24.    }
  25.    else{
  26.     spd2.y = spd2.y>2.5? spd2.y * 0.25 : 0;
  27.     spd = targetBody.GetWorldVector(spd2);
  28.     targetBody.SetLinearVelocity(spd);
  29.    }
  30.   }
  31. }

Данная процедура раскладывает глобальный вектор скорости spd у каждого колеса на локальный spd2 и прикладывает трения по X и по Y. Единственные момент, который не укладывается в моей голове так это то, почему же все-таки оси повернуты на 90% по часовой? То есть чтобы отучить авто скользить и добавить трения по оси X которую я зарисовывал выше сейчас нам приходится добавлять трение на ось Y (оно же — поперечное трение колеса).

5) Продолжаем дополнять accelerate(), просчитываем углы по которым потом будем прикладывать силы скорости и ускорения (для передних колес):
  1. var carAngle:Number = this._carBody.body.GetAngle();
  2. if (this.steer !0){ // при езде вперед
  3.  this._steerAngle = this._steerAngle + this.steer * this._steeringAcceleration;
  4. }
  5.  
  6. if (this._steerAngle > carAngle + this._steeringRange){
  7.  this._steerAngle = carAngle + this._steeringRange;
  8. }
  9. else if (this._steerAngle < carAngle - this._steeringRange){
  10.  this._steerAngle = carAngle - this._steeringRange;
  11. }
  12.  
  13. if (this.drive < 0){//при езде назад
  14.  if (this.steer == 0){
  15.   this._steerAngle = carAngle;
  16.  }
  17.  else if (this.steer == -1){
  18.    this._steerAngle = carAngle - this._steeringRange;
  19.  }
  20.  else if (this.steer == 1){
  21.    this._steerAngle = carAngle + this._steeringRange;
  22.  }
  23. }
  24. if (this.steer == 0){
  25.  this._steerAngle = carAngle;
  26. }


6)Поворачиваем передние колёса:
  1. this._frontAxisBodyLeft.body.SetXForm(_frontAxisBodyLeft.body.GetXForm().positionthis._steerAngle);
  2. this._frontAxisBodyRight.body.SetXForm(_frontAxisBodyRight.body.GetXForm().positionthis._steerAngle);


7)Ну и в зависимости от привода прикладываем необходимые силы к нужным колёсам:
  1. var carspeedX, carspeedY, carRearX,carRearY:Number;
  2.  
  3. if (this._privod == FWD){ //передний привод
  4.   carspeedX = this.drive * Math.cos(this._steerAngle) * (this._acceleration);
  5.   carspeedY = this.drive * Math.sin(this._steerAngle) * (this._acceleration);
  6. }
  7. if (this._privod == AWD){
  8.   carspeedX = this.drive * Math.cos(this._steerAngle) * (this._acceleration);
  9.   carspeedY = this.drive * Math.sin(this._steerAngle) * (this._acceleration);
  10.   carRearX = this.drive * Math.cos(this._rearAxisBodyRight.angle) * (this._acceleration);
  11.   carRearY = this.drive * Math.sin(this._rearAxisBodyRight.angle) * (this._acceleration);      
  12. }
  13.  
  14. if (this.drive !0){
  15.   if (this._privod == FWD){//передний привод, едем (прикладываем скорости)
  16.     this._frontAxisBodyLeft.body.SetLinearVelocity(new b2Vec2(carspeedX, carspeedY));
  17.     this._frontAxisBodyRight.body.SetLinearVelocity(new b2Vec2(carspeedX, carspeedY));
  18.   }
  19.  
  20.   if (this._privod == AWD)//задний привод, едем (прикладываем скорости)
  21.   {
  22.     this._frontAxisBodyLeft.body.SetLinearVelocity(new b2Vec2(carspeedX, carspeedY));
  23.     this._frontAxisBodyRight.body.SetLinearVelocity(new b2Vec2(carspeedX, carspeedY));
  24.  
  25.     this._rearAxisBodyLeft.body.SetLinearVelocity(new b2Vec2(carRearX, carRearY));
  26.     this._rearAxisBodyRight.body.SetLinearVelocity(new b2Vec2(carRearX, carRearY));       
  27.   }       
  28.  
  29. }
  30. else{ //замедляемся
  31.   spd = this.speed;
  32.  
  33.   if (spd > this._friction)
  34.   {
  35.     spd = spd - this._friction/1.3;
  36.   }
  37.   else
  38.   {
  39.     spd = 0;
  40.   }
  41.   if (this._privod == FWD)//передний привод, замедляемся (прикладываем скорости)
  42.   {
  43.     carspeedX = Math.cos(this._steerAngle) * spd;
  44.       carspeedY = Math.sin(this._steerAngle) * spd;
  45.     this._frontAxisBodyLeft.body.SetLinearVelocity(new b2Vec2(carspeedX, carspeedY));
  46.     this._frontAxisBodyRight.body.SetLinearVelocity(new b2Vec2(carspeedX, carspeedY));         
  47.   }
  48.   if (this._privod == AWD){ //полный привод, замедляемся (прикладываем скорости)
  49.     carspeedX = Math.cos(this._steerAngle) * spd;
  50.       carspeedY = Math.sin(this._steerAngle) * spd;
  51.     this._frontAxisBodyLeft.body.SetLinearVelocity(new b2Vec2(carspeedX, carspeedY));
  52.     this._frontAxisBodyRight.body.SetLinearVelocity(new b2Vec2(carspeedX, carspeedY))
  53.  
  54.     carspeedX = Math.cos(this._carBody.angle) * spd;
  55.       carspeedY = Math.sin(this._carBody.angle) * spd;
  56.     this._rearAxisBodyLeft.body.SetLinearVelocity(new b2Vec2(carspeedX, carspeedY));
  57.     this._rearAxisBodyRight.body.SetLinearVelocity(new b2Vec2(carspeedX, carspeedY));
  58.   }
  59. }


8) Последний штрих:
  1. public function get speed() : Number{
  2.  return this._carBody.body.GetLinearVelocity().Length();
  3. }


Итого


В результате мы получаем примерно такое:
Демо-swf на народ.ру
Демка на megaswf.com(желательно в фуллскрине)

p.s. Полный код по некоторым причинам выложу немного позже.
Поделиться публикацией

Комментарии 64

    +7
    Огромная просьба минусующим — отписать о причине минуса. Я на хабре совсем недавно, это моя первая статья, и я нуждаюсь в объективной критике.
      +1
      Возможно, потому что слишком много кода, слишком мало объяснений. Тупо копипастить ведь неинтересно и не познавательно, хочется понять, как и что работает.
        +1
        Ну я же расписал немного, основные моменты — на блоки разделил, и тот кто разбирается — должен понять, т.к. вроде ничего сложного нет, но если причина кроется в этом — в ближайшие дни допилю модуль до дружелюбного вида, выложу, и построчно обьясню что и как.
        +3
        Я не минусовал, но может быть за подобное?
        > Сила тяги (оно же у нас будет являться скоростью и ускорением)

        Вы тут три физических величины смешали же. Дальше не читал пока.
          0
          Возможно, но не думаю что под «простой физикой движения» я подразумевал все физические величины действующие на авто.
            0
            Да я про то, что это безграмотность на уровне физики седьмого класса школы. Вот за это и минусуют, наверное.
        0
        Отлично, а где бы еще побольше почитать/посмотреть уроков по Box2D на actionscript?
        Кроме официальной документации, разумеется.
          +1
          По себе скажу — я читал офф.документацию, в т.ч. английскую оригинальную версию и оно мне показалось довольно кодоёмким, отчего решил все-таки поковыряться и освоиться с оболочкой для сего — с QuickBox2D, даже несмотря на то что оно использует не последнюю версию Box2D'a. По поводу ресурсов в QuickBox2D ничего сказать не могу, но то что кода получается меньше в отличие от Box2D — это факт. По крайней мере самые основные моменты — создание примитивов/джоинтов в мире.
            +2
            вот в этом блоге очень много и хорошо написано. и не только про box2d
            www.emanueleferonato.com/category/box2d/
              0
              спасибо! первый же пост сразу порадовал, да и остальные статьи интересные
              +1
              Вот что за менталитет такой — где бы почитать, но не официального. Почему? Зачем? Вам офф доков не хватает?
                0
                Менталитет тут не причем, официальная у меня есть, поэтому попросил интересные уроки от профессионалов. Энтузиасты пишут отличные уроки и снимают классные видеокасты, как например gotoandlearn.com
              +3
              Уберите срочно с дропбокса, через 15-20 минут вам паблик за такие нагрузки на сутки отключат :)
              +1
              Когда назад едешь машина не будет описывают такую окружность как в примере, будет почти вокруг задних колес крутиться.
              Что-то у тебя с расчетом трения не так.
              Так ведь должно быть статическое трение и динамическое. Динамические при скольжении колеса, а статическое пока скольжения нет.
              Из-за этого пока машину не сильно кидает в сторону она держится на колее из-за бОльшего статического трения, как только сила боковая превышает силу статического трения, ее срывает в занос и там уже динамическое трение учитывается.

              Хорошая статья:
              www.asawicki.info/Mirror/Car%20Physics%20for%20Games/Car%20Physics%20for%20Games.html
                0
                Хорошая, читал перевод на геймдев.ру, но не думаю что все эти тонкости нужны для 2D игры.
                  +2
                  С помощью вашей машинки, кажется, получится только игра «Езда по льда».
                    0
                    Почему это вы так считаете? «Езда по льда» можно спокойно сделать из моего примера, достаточно убрать трения колёс по осям. А сейчас мне очень кажется что вы вообще не посмотрели демку.
                    А если вы про инерцию имели ввиду — то так задумано, и это легко меняется (коэффициент на 35 строчке из п.7).
                      0
                      «Езда по льда» — смешное название вышло :)

                      Я поиграл в демку. И мне показалось что машинка как-то очень легко уж разворачивается на 180 градусов, возможно изменением бокового трения можно избавиться от того, что субъективно мне не очень нравится.
                        +1
                        гм, еще как вариант — добавить плавность поворота колёс, а не так как сейчас — либо макс.угол, либо 0. Тогда и повороты будут реалистичнее.
                0
                Не знаю причин минусующих, а машинка ездит забавно, спасибо за статью
                  0
                  Охренеть
                  В далеком 2004 году мне хватало около 30-ти строк и немного графики, чтобы сделать такую машинку.
                  Правда столкновения там было не сделать.
                    0
                    А заносы там може были?
                      0
                      Не знаю ответа автора, но предположу что реально могли бы быть и заносы, посмотрите на мою реализацию. Для реализации заноса достаточно преобразовать глобальный вектор движения колеса в локальный и приложить «боковое» трение. А управлять авто — просто прикладывать к текущему повороту колеса вектор скорости (в моем случае — speedX и speedY). Точнее сказать не прикладывать даже, а скорее даже направление — среднее между новым и предыдущим, а скорость (длина вектора) — выбирать наибольшее из двух(предыдущее и новое).
                        0
                        Не силён в физической части всех этих движков, это лишь мои предположения.
                          0
                          Я так понимаю, автор верхнего коммента писал без движков, на голом as.
                            –1
                            Но я технически тоже расписал голую физику, хотя вот в 30 строк наверное это конечно не уложится.
                        0
                        Да, можно было реализовать и заносы. И да, все на чистом ас, тогда еще не писали движков.
                        Кстати, помню, пробовал тогда поднять тему написания 2д движка на форуме флэшер.ру, но встретили меня без энтузиазма, если не сказать хуже.
                        –1
                        Примерно такая же история. Примерно тогда же делал машинки, гонки по столу между чашечками кофе, весь код был такого-же объема как в посте, но там были и столкновения с препятствиями, и отскоки, и смещение препятствий и всё-всё всё. И никакого движка не понадобилось.
                        +2
                        У вас как-то странно машина ездит в ролике. Я может не правильно пользуюсь, но у меня получается ее повернуть вокруг одного колеса.
                          0
                          Плюс, я не знаю надо ли оно вам или нет, но колеса автомобиля при повороте наклоняются, чтобы обеспечить большее соприкосновение с дорогой.
                          0
                          Теперь (дабы всё эт было нагляднее) можно сделать вот что:

                          — При боковом скольжении большем, чем определённое (экспериментально подобранное значение) — рисовать чёрный след (покрышка проскальзывает), пусть он через пару секунд исчезает.
                          — Сделать не 1 машинку, а выбор — тяга только на передних, только на задних, или на всех колёсах (будет заметно различное поведение передне-заднеприводных машин :)
                          — Чем больше скорость — тем меньше угол поворота передних колёс (в силу естесственных причин — центробежная сила будет компенсировать поворот колёс тем сильней, чем быстрее мы едем)
                            0
                            Машинка… похожа на машинку, и правда :)

                            Когда-то я тоже думал, что на гиковском хабре много кода в статье — это маст хэв. Но со временем заметил за собой, что чем больше кода в статье, тем менее интересно мне ее читать (хотя по профессии и разработчик). Базовые идеи лучше объяснять естественным языком, а не портянками плохо отформатированного кода. Код-то можно и приложить отдельно, кому надо — посмотрят.
                              0
                              Ммм… А какова необходимость ради эффекта заноса подключать физический движок и писать почти пол тысячи строк?
                              Мне кажется пролистав учебник по динамике/механике можно было бы значительно упростить задачу.
                                0
                                Более простая реализация игрового мира и столкновений в будущем. В планах было сделать игру, но из-за нехватки времени проект заморожен, отчего решил поделиться наработками со всеми.
                                0
                                Еще неплохо физика автомобилей сделана в QuickB2. Сам пользуюсь только Box2D Alchemy-порт, но демка в QuickB2 понравилась (пятая по счету).
                                  0
                                  Да кстати, тоже достаточно хорошая реализация, но вот у меня немного не хватило мозга чтобы понять как оно ездит. Да и дрифты там слишком уж… Возможно, трение контролируется. но демка не очень впечатлила. Хотя конечно, было поначалу желание разобраться и с этим.
                                  +1
                                  Следующей статьей ждем от вас готовый прототип годной игры. Спасибо за эту статью и за старания. Кто спрашивал про доп. информацию по Box2D во Flash, смотрите уроки Феронато www.emanueleferonato.com/ просто кладезь информациии не только по боксу.
                                    0
                                    Спасибо, учту все ваши пожелания и следующую статью оформлю годным образом и в нормальном законченном варианте.
                                    0
                                    Супер. Почему никто в флеш гонках не делает подобного? судя по статье — все не так уж и сложно.
                                    Не помню ни в одной флеш-игрушке дрифта, связанного с направлением колес.

                                    Автор молодец, детально продумывает мелочи.

                                    П.С. хотя код действительно малопонятный, особенно когда вместо описания действия стоит название метода.

                                    П.С. 2 мне показалось, что если сделать замедление\ускорение чуть меньше, игра станет немного реалистичней.
                                      0
                                      В данном варианте ускорения как такового вообще нету. Сразу прикладываем к телу максимальную скорость. Собственно отсутствие нормальной подобной статьи заставило меня сделать своё.
                                        0
                                        Флешу не нужна реалистичность, казуал рулит. Убедился в этом продав первую игру. Делал для себя, а надо было делать для народа. На миллион хомячков находится всего пару человек действительно заинтересованных реализмом. Поэтому, на продажу делаешь то, что требует народ, а в свободное время делаешь для души.
                                          +1
                                          Вы так скоро разочаруете меня в людях, дайте мне верить, что нормальных людей больше.
                                            0
                                            Самому не хочется, но в процессе тестирования был удивлен. Я из поколения взрощенного на NES(Dendy) и Spectrum. Нам никто не объяснял куда и как нажимать. А при тестировании игры получил множество вопросов об управлении, хотя казалось бы, стрелочки и пробел потыкай, наугад хотя бы.
                                          –1
                                          Возможно, потому что математика во флеше довольно медленная, если считать физику для 10-ти машинок и попутно рендерить красивые картинки, будет тормозить.
                                          0
                                          Мне кажется, вы стреляете из пушки по воробьям.
                                          Тут отлично показано как можно сделать все гораздо проще (как по мне). Заносы и столкновения можно добавить без проблем. Постараюсь найти исходники игры, которая делалась по этому уроку полтора года назад, там довольно простая реализация получилась, с примерно равным этому результатом. Хотя, если это развивать в игру, то с бокс2д будет гораздо приятнее работать со столкновениями нескольких объектов, и т. п. Тут не поспоришь.

                                          А вообще — статья хорошая, спасибо!
                                            +2
                                            «Мне кажется, вы стреляете из пушки по воробьям.
                                            Тут отлично показано как можно сделать все гораздо проще (как по мне).»

                                            Гм. Я вроде выше отписал о моих предпочтениях относительно Box2D. Зачем нам делать свой физический движок если есть хороший готовый?

                                            «Заносы и столкновения можно добавить без проблем»
                                            Так где же вы были когда я ковырял тот пример с xitri.com? Да, я понимаю вас, всё знаете, профи и всё такое. Но почему же я тогда не нашел достойной реализации в момент разработки этого? Да и собсно в топике я расписал примитивную систему реализации заносов для 2D. И да, если говорите о простом создании заносов, то вы скорее всего по-быстрому нашли эту статью, в которой вся реализация заносов сводится к тому что физический движок за тебя все считает, т.к. по сути там (в 3D движке) ничего не стоит сделать круглое тело (оно же — колесо), добавить ему массы и трения, и просто крутить его, благодаря чему имеем практически готовую физику движения. В Box2D из-за того что это 2D движок мы имеем не круги, а прямоугольники, которые можем условно принять за кубы, но покрутить как круги мы их не можем, поэтому приходится просто «толкать» их вперёд и добавлять нужные трения по осям для достижения эффекта езды и одновременно дрифта (без такого трения получим эффект езды по льду).
                                              0
                                              простите, опечатался в «которые можем условно принять за колёса»
                                                +3
                                                >И да, если говорите о простом создании заносов, то вы скорее всего по-быстрому нашли эту статью...

                                                А-а-а, мои глаза!!!

                                                ВНИМАНИЕ! WARNING! ACHTUNG!

                                                Количество баннеров по ссылке из предыдущего комментария превышеает предельно допустимую норму в 20 раз! Настоятельно советую экологически чистый аналог (откуда и был, собственно, взят материал).
                                                  +1
                                                  > Да, я понимаю вас, всё знаете, профи и всё такое.
                                                  Извините, если чем-то вас обидел. Я не ожидал что мой комментарий вас так сильно заденет.

                                                  Чтобы расставить точки над i — я не хотел показаться умнее, или потешить самолюбие, просто выразил свое мнение по поводу реализации похожей задачи. На вопрос где я был — не знаю. Сейчас я есть тут. Если интересно — можем попробовать совместно сделать такую же машинку без использования бокс2д, кто знает, может получится статья?
                                                    0
                                                    Извините за то что сорвался, но «Заносы и столкновения можно добавить без проблем» дано не для всех, как и множество других задач без готовых решений(движков/модулей/etc..), вопрос/проблема тут скорее в моем уровне знания флеша, из-за этого и выбрал готовый физ.движок для реализации таких вещей.

                                                    «Если интересно — можем попробовать совместно сделать такую же машинку без использования бокс2д, кто знает, может получится статья?»
                                                    Спасибо. Не думаю что это потянет на полноценную статью, хотя с удовольствием бы посмотрел на это даже сейчас, имея в распоряжении хорошую реализацию на Box2D.
                                                      +1
                                                      У вас все хорошо получается, при желании заходите и пишите на flashgameblogs.ru/
                                                        0
                                                        как бы на него инвайт получить?
                                                          0
                                                          Извините, ответ на ваш коментарий ниже
                                                0
                                                Через какое-то время адекватного общения на flashgamedev.ru/ вы можете без проблем попросить инвайт. Для этого даже есть отдельная ветка.
                                                  +2
                                                  Сам некоторое время возился с 2д-рейсинг игрой, но пока забросил. Самое интересно как раз таки была физика колес, а точнее шин.
                                                  www.racer.nl/reference/pacejka.htm
                                                  Вот как надо ТРУ делать :)
                                                    0
                                                    В ТРУ-симуляторах эта формула считается самой примитивной и годной лишь для начинающих :)
                                                      0
                                                      зато этот пример в комменте от Dulea — самое ТРУ для начинающих, т.к. с открытым кодом.
                                                    0
                                                    Попробуйте в дрифте «вниз» нажать. Полагаю, что это следствие отсутствия проверки на нулевую скорость при переключении вниз.
                                                    Другими словами — чтобы с передней на заднюю включить (и наоборот) — неплохо было бы проверить, а не равняется ли скорость нулю :)
                                                      0
                                                      нет, это следствие того что
                                                      1) проверка нажатия «назад» идет ПОСЛЕ проверки нажатия вперёд, и
                                                      2) как я уже говорил выше — нет никакого ускорения, а сразу придает телу максимально возможную силу.

                                                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                    Самое читаемое