everything i found in leaked code

This commit is contained in:
Tubix
2024-10-05 12:31:02 +01:00
parent 6679f44200
commit 28441faac3
2960 changed files with 394479 additions and 0 deletions

View File

@@ -0,0 +1,743 @@
package alternativa.physics {
import __AS3__.vec.Vector;
import alternativa.physics.collision.ICollisionDetector;
import alternativa.physics.collision.KdTreeCollisionDetector;
import alternativa.physics.constraints.Constraint;
import alternativa.physics.math.Matrix3;
import alternativa.physics.math.Vector3;
use namespace altphysics;
/**
* Класс реализует физическую симуляцию поведения твёрдых тел.
*/
public class World {
private static var lastBodyId:int;
// Максимальное количество контактов
altphysics const MAX_CONTACTS:int = 1000;
//////////////////////////////////////////////////////////////////
// Настроечные параметры симуляции. Могут быть изменены в любой
// момент времени без нарушения корректной работы симуляции.
//////////////////////////////////////////////////////////////////
// Количество шагов, за которое пересекающиеся тела должны разделиться
public var penResolutionSteps:int = 10;
// Величина допустимой глубины пересечения
public var allowedPenetration:Number = 0.1;
// Максимальная скорость, добавляемая с целью разделения тел
public var maxPenResolutionSpeed:Number = 0.5;
// Количество итераций для обработки упругих контактов
public var collisionIterations:int = 5;
// Количество итераций для обработки неупругих контактов
public var contactIterations:int = 5;
// Флаг использования предсказания состояний
public var usePrediction:Boolean = false;
public var freezeSteps:int = 10;
public var linSpeedFreezeLimit:Number = 1;
public var angSpeedFreezeLimit:Number = 0.01;
// Переменные для процедуры разделения тел путём непосредственного их перемещенеия.
// !!!!!!!!!!!!!!!!!!!!!!!!
// !!! Экспериментально !!!
// !!!!!!!!!!!!!!!!!!!!!!!!
public var staticSeparationIterations:int = 10;
public var staticSeparationSteps:int = 10;
public var maxAngleMove:Number = 10;
public var useStaticSeparation:Boolean = false;
// Вектор гравитации
public var _gravity:Vector3 = new Vector3(0, 0, -9.8);
// Модуль вектора гравитации
public var _gravityMagnitude:Number = 9.8;
// Использующийся детектор столкновений
public var collisionDetector:ICollisionDetector;
// Список тел, участвующих в симуляции
public var bodies:BodyList = new BodyList();
// Список контактов на текущем шаге симуляции
altphysics var contacts:Contact;
// Количество контактов на текущем шаге симуляции
// altphysics var contactsNum:int;
// Список ограничений
altphysics var constraints:Vector.<Constraint> = new Vector.<Constraint>();
// Количество ограничений
altphysics var constraintsNum:int;
// Временная метка. Число прошедших шагов с начала симуляции.
public var timeStamp:uint;
// Время с начала симуляции, мс
public var time:uint;
// Первый неиспользованный контакт на текущем шаге симуляции
private var borderContact:Contact;
// Временные переменные для избежания создания экземпляров
private var _r:Vector3 = new Vector3();
private var _t:Vector3 = new Vector3();
private var _v:Vector3 = new Vector3();
private var _v1:Vector3 = new Vector3();
private var _v2:Vector3 = new Vector3();
/**
*
*/
public function World() {
contacts = new Contact(0);
var contact:Contact = contacts;
for (var i:int = 1; i < MAX_CONTACTS; i++) {
contact.next = new Contact(i);
contact = contact.next;
}
collisionDetector = new KdTreeCollisionDetector();
}
/**
* Вектор гравитации.
*/
public function get gravity():Vector3 {
return _gravity.vClone();
}
/**
* @private
*/
public function set gravity(value:Vector3):void {
_gravity.vCopy(value);
_gravityMagnitude = _gravity.vLength();
}
/**
* Добавляет тело в симуляцию.
*
* @param body
*/
public function addBody(body:Body):void {
body.id = lastBodyId++;
body.world = this;
bodies.append(body);
}
/**
* Удаляет тело из симуляции.
* @param body
* @return
*/
public function removeBody(body:Body):void {
if (bodies.remove(body)) {
body.world = null;
}
}
/**
* Добавляет ограничение.
* @param c
*/
public function addConstraint(c:Constraint):void {
constraints[constraintsNum++] = c;
c.world = this;
}
/**
* Удаляет ограничение.
* @param c
*/
public function removeConstraint(c:Constraint):Boolean {
var idx:int = constraints.indexOf(c);
if (idx < 0) return false;
constraints.splice(idx, 1)
constraintsNum--;
c.world = null;
return true;
}
/**
* Применяет к телам действующте на них силы. Аккумуляторы сил и моментов тел очищаются после завершения шага
* симуляции, поэтому на момент вызова метода могут уже содержать некоторые значения.
*
* @param dt промежуток времени, в течении которого действуют силы
*/
private function applyForces(dt:Number):void {
var item:BodyListItem = bodies.head;
while (item != null) {
var body:Body = item.body;
body.beforePhysicsStep(dt);
body.calcAccelerations();
// Ускорение свободного падения применяется только к подвижным телам во избежание некорректного изменения
// фиктивной скорости неподвижных тел.
if (body.movable && !body.frozen) {
body.accel.x += _gravity.x;
body.accel.y += _gravity.y;
body.accel.z += _gravity.z;
}
item = item.next;
}
}
/**
* Определяет все столкновения на текущем шаге симуляции и заполняет список получившихся контактов.
*
* @param dt длительность шага симуляции
*/
private function detectCollisions(dt:Number):void {
var item:BodyListItem = bodies.head;
while (item != null) {
var body:Body = item.body;
if (!body.frozen) {
body.contactsNum = 0;
body.saveState();
// При включённом режиме предсказания состояние тел интегрируется на один шаг вперёд
if (usePrediction) {
body.integrateVelocity(dt);
body.integratePosition(dt);
}
body.calcDerivedData();
}
item = item.next;
}
borderContact = collisionDetector.getAllContacts(contacts);
// Расчёт относительных векторов точки контакта вынесен сюда из-за необходимости учитывать
// положение тел в предсказанном состоянии
var contact:Contact = contacts;
while (contact != borderContact) {
var b1:Body = contact.body1;
var b2:Body = contact.body2;
for (var j:int = 0; j < contact.pcount; j++) {
var cp:ContactPoint = contact.points[j];
var bPos:Vector3 = b1.state.pos;
cp.r1.x = cp.pos.x - bPos.x;
cp.r1.y = cp.pos.y - bPos.y;
cp.r1.z = cp.pos.z - bPos.z;
if (b2 != null) {
bPos = b2.state.pos;
cp.r2.x = cp.pos.x - bPos.x;
cp.r2.y = cp.pos.y - bPos.y;
cp.r2.z = cp.pos.z - bPos.z;
}
}
contact = contact.next;
}
// Восстановление состояния тел
if (usePrediction) {
item = bodies.head;
while (item != null) {
body = item.body;
if (!body.frozen) {
body.restoreState();
body.calcDerivedData();
}
item = item.next;
}
}
}
/**
* Подготваливает полученные из детектора столкновений контакты, расчитывая значения, не меняющиеся
* в ходе шага симуляции.
*/
private function preProcessContacts(dt:Number):void {
var contact:Contact = contacts;
while (contact != borderContact) {
var b1:Body = contact.body1;
var b2:Body = contact.body2;
// Столкнувшиеся тела размораживаются
if (b1.frozen) {
b1.frozen = false;
b1.freezeCounter = 0;
}
if (b2 != null && b2.frozen) {
b2.frozen = false;
b2.freezeCounter = 0;
}
contact.restitution = b1.material.restitution;
if (b2 != null && b2.material.restitution < contact.restitution) contact.restitution = b2.material.restitution;
contact.friction = b1.material.friction;
if (b2 != null && b2.material.friction < contact.friction) contact.friction = b2.material.friction;
for (var j:int = 0; j < contact.pcount; j++) {
var cp:ContactPoint = contact.points[j];
cp.accumImpulseN = 0;
// Расчитываем изменение нормальной скорости на единицу нормального импульса
// dV = b.invMass + ((invI * (r % n)) % r) * n
cp.velByUnitImpulseN = 0;
if (b1.movable) {
cp.angularInertia1 = _v.vCross2(cp.r1, contact.normal).vTransformBy3(b1.invInertiaWorld).vCross(cp.r1).vDot(contact.normal);
cp.velByUnitImpulseN += b1.invMass + cp.angularInertia1;
}
if (b2 != null && b2.movable) {
cp.angularInertia2 = _v.vCross2(cp.r2, contact.normal).vTransformBy3(b2.invInertiaWorld).vCross(cp.r2).vDot(contact.normal);
cp.velByUnitImpulseN += b2.invMass + cp.angularInertia2;
}
// Расчёт требуемой конечной скорости для упругого контакта
calcSepVelocity(b1, b2, cp, _v);
cp.normalVel = _v.vDot(contact.normal);
if (cp.normalVel < 0) cp.normalVel = - contact.restitution*cp.normalVel;
// Скорость разделения неупругого контакта
cp.minSepVel = cp.penetration > allowedPenetration ? (cp.penetration - allowedPenetration)/(penResolutionSteps*dt) : 0;
if (cp.minSepVel > maxPenResolutionSpeed) cp.minSepVel = maxPenResolutionSpeed;
}
contact = contact.next;
}
for (var i:int = 0; i < constraintsNum; i++) {
var constraint:Constraint = constraints[i];
constraint.preProcess(dt);
}
}
/**
*
* @param dt
* @param forceInelastic
*/
private function processContacts(dt:Number, forceInelastic:Boolean):void {
var iterNum:int = forceInelastic ? contactIterations : collisionIterations;
var i:int;
var forwardLoop:Boolean = false;
for (var iter:int = 0; iter < iterNum; iter++) {
forwardLoop = !forwardLoop;
var contact:Contact = contacts;
while (contact != borderContact) {
resolveContact(contact, forceInelastic, forwardLoop);
contact = contact.next;
}
// Ограничения
for (i = 0; i < constraintsNum; i++) {
var constraint:Constraint = constraints[i];
constraint.apply(dt);
}
}
// Разделение контактов путём непосредственного изменения координат и ориентации. Экспериментально.
// if (forceInelastic && useStaticSeparation) performStaticSeparation();
}
/**
*
*/
private function resolveContact(contactInfo:Contact, forceInelastic:Boolean, forwardLoop:Boolean):void {
var b1:Body = contactInfo.body1;
var b2:Body = contactInfo.body2;
var normal:Vector3 = contactInfo.normal;
var i:int;
if (forwardLoop) {
for (i = 0; i < contactInfo.pcount; i++) resolveContactPoint(i, b1, b2, contactInfo, normal, forceInelastic);
} else {
for (i = contactInfo.pcount - 1; i >= 0; i--) resolveContactPoint(i, b1, b2, contactInfo, normal, forceInelastic);
}
}
/**
*
* @param idx
* @param b1
* @param b2
* @param colInfo
* @param normal
* @param forceInelastic
*/
private function resolveContactPoint(idx:int, b1:Body, b2:Body, contact:Contact, normal:Vector3, forceInelastic:Boolean):void {
var cp:ContactPoint = contact.points[idx];
if (!forceInelastic) {
cp.satisfied = true;
}
var newVel:Number = 0;
calcSepVelocity(b1, b2, cp, _v);
var cnormal:Vector3 = contact.normal;
var sepVel:Number = _v.x*cnormal.x + _v.y*cnormal.y + _v.z*cnormal.z;
if (forceInelastic) {
var minSpeVel:Number = useStaticSeparation ? 0 : cp.minSepVel;
if (sepVel < minSpeVel) {
cp.satisfied = false;
} else if (cp.satisfied) return;
newVel = minSpeVel;
} else {
newVel = cp.normalVel;
}
var deltaVel:Number = newVel - sepVel;
var impulse:Number = deltaVel/cp.velByUnitImpulseN;
var accumImpulse:Number = cp.accumImpulseN + impulse;
if (accumImpulse < 0) {
accumImpulse = 0;
}
var deltaImpulse:Number = accumImpulse - cp.accumImpulseN;
cp.accumImpulseN = accumImpulse;
// Применяем импульс к телам
if (b1.movable) {
b1.applyRelPosWorldImpulse(cp.r1, normal, deltaImpulse);
}
if (b2 != null && b2.movable) {
b2.applyRelPosWorldImpulse(cp.r2, normal, -deltaImpulse);
}
// Учёт силы трения
calcSepVelocity(b1, b2, cp, _v);
// Расчитываем изменение касательной скорости на единицу касательного импульса
var tanSpeedByUnitImpulse:Number = 0;
// _v.vAddScaled(-_v.vDot(contact.normal), contact.normal);
var dot:Number = _v.x*cnormal.x + _v.y*cnormal.y + _v.z*cnormal.z;
_v.x -= dot*cnormal.x;
_v.y -= dot*cnormal.y;
_v.z -= dot*cnormal.z;
var tanSpeed:Number = _v.vLength();
if (tanSpeed < 0.001) return;
// _t.vCopy(_v).vNormalize().vReverse();
_t.x = -_v.x;
_t.y = -_v.y;
_t.z = -_v.z;
_t.vNormalize();
var r:Vector3;
var m:Matrix3;
var xx:Number;
var yy:Number;
var zz:Number;
// dV = b.invMass + ((invI * (r % t)) % r) * t
if (b1.movable) {
// _v.vCross2(cp.r1, _t).vTransformBy3(b1.invInertiaWorld).vCross(cp.r1);
r = cp.r1;
m = b1.invInertiaWorld;
_v.x = r.y*_t.z - r.z*_t.y;
_v.y = r.z*_t.x - r.x*_t.z;
_v.z = r.x*_t.y - r.y*_t.x;
xx = m.a*_v.x + m.b*_v.y + m.c*_v.z;
yy = m.e*_v.x + m.f*_v.y + m.g*_v.z;
zz = m.i*_v.x + m.j*_v.y + m.k*_v.z;
_v.x = yy*r.z - zz*r.y;
_v.y = zz*r.x - xx*r.z;
_v.z = xx*r.y - yy*r.x;
tanSpeedByUnitImpulse += b1.invMass + _v.x*_t.x + _v.y*_t.y + _v.z*_t.z;
}
if (b2 != null && b2.movable) {
// _v.vCross2(cp.r2, _t).vTransformBy3(b2.invInertiaWorld).vCross(cp.r2);
r = cp.r2;
m = b2.invInertiaWorld;
_v.x = r.y*_t.z - r.z*_t.y;
_v.y = r.z*_t.x - r.x*_t.z;
_v.z = r.x*_t.y - r.y*_t.x;
xx = m.a*_v.x + m.b*_v.y + m.c*_v.z;
yy = m.e*_v.x + m.f*_v.y + m.g*_v.z;
zz = m.i*_v.x + m.j*_v.y + m.k*_v.z;
_v.x = yy*r.z - zz*r.y;
_v.y = zz*r.x - xx*r.z;
_v.z = xx*r.y - yy*r.x;
tanSpeedByUnitImpulse += b2.invMass + _v.x*_t.x + _v.y*_t.y + _v.z*_t.z;
}
var tanImpulse:Number = tanSpeed/tanSpeedByUnitImpulse;
var max:Number = contact.friction*cp.accumImpulseN;
if (max < 0) {
if (tanImpulse < max) tanImpulse = max;
} else {
if (tanImpulse > max) tanImpulse = max;
}
// Применяем импульс к телам
if (b1.movable) {
b1.applyRelPosWorldImpulse(cp.r1, _t, tanImpulse);
}
if (b2 != null && b2.movable) {
b2.applyRelPosWorldImpulse(cp.r2, _t, -tanImpulse);
}
}
/**
*
* @param cp
* @param normal
* @return
*/
private function calcSepVelocity(body1:Body, body2:Body, cp:ContactPoint, result:Vector3):void {
// sepVel = (V1 - V2)*normal
// V1 = V1_c + w1%r1
// result.vCopy(body1.state.velocity).vAdd(_v1.vCross2(body1.state.rotation, cp.r1));
var rot:Vector3 = body1.state.rotation;
var v:Vector3 = cp.r1;
var x:Number = rot.y*v.z - rot.z*v.y;
var y:Number = rot.z*v.x - rot.x*v.z;
var z:Number = rot.x*v.y - rot.y*v.x;
v = body1.state.velocity;
result.x = v.x + x;
result.y = v.y + y;
result.z = v.z + z;
// V2 = V2_c + w2%r2
if (body2 != null) {
// result.vSubtract(body2.state.velocity).vSubtract(_v2.vCross2(body2.state.rotation, cp.r2));
rot = body2.state.rotation;
v = cp.r2;
x = rot.y*v.z - rot.z*v.y;
y = rot.z*v.x - rot.x*v.z;
z = rot.x*v.y - rot.y*v.x;
v = body2.state.velocity;
result.x -= v.x + x;
result.y -= v.y + y;
result.z -= v.z + z;
}
}
/**
*
* @param dt
*/
private function intergateVelocities(dt:Number):void {
var item:BodyListItem = bodies.head;
while (item != null) {
item.body.integrateVelocity(dt);
item = item.next;
}
}
/**
*
* @param dt
*/
private function integratePositions(dt:Number):void {
var item:BodyListItem = bodies.head;
while (item != null) {
var body:Body = item.body;
if (body.movable && !body.frozen) {
body.integratePosition(dt);
}
item = item.next;
}
}
/**
*
*/
private function performStaticSeparation():void {
var iterNum:int = staticSeparationIterations;
// iterNum = 100;
// 1. В начале каждой итерации для всех контактов сбрасывается флаг satisfied с одновременным поиском наихудшего контакта, т.е. имеющего наибольшую величину пересечения тел.
// 2. Если найденный контакт имеет величину пересечения меньше предельно допустимой процедура прерывается, т.к. разделение контактов не требуется.
// 3. Если процедура продолжается, то выполняется разделение найденного контакта и установка его флага satisfied в true, после чего запускается внутренний цикл, состоящий
// из contactsNum - 1 итераций. На каждой итерации ищется наихудший контакт среди оставшихся (satisfied == false). Если такой контакт найден, то выполняется его разделение
// и переход к следующей итерации внутреннего цикла, иначе внутренний цикл прерывается и выполняется переход к следующей итерации внешнего цикла (шаг 1.).
// for (var iter:int = 0; iter < iterNum; iter++) {
// // Ищем контакт с максимальной величиной пересечения тел, одновременно сбрасывая флаги satisfied в false
// var worstContact:Contact = contacts[0];
// var i:int;
// for (i = 1; i < contactsNum; i++) {
// var contact:Contact = contacts[i];
// contact.satisfied = false;
// if (contact.maxPenetration > worstContact.maxPenetration) worstContact = contact;
// }
// if (worstContact.maxPenetration <= allowedPenetration) return;
//
// resolveInterpenetration(worstContact);
// // Внутренний цикл по оставшимся контактам
// for (i = 1; i < contactsNum; i++) {
// worstContact = getWorstContact();
// if (worstContact == null) break;
// resolveInterpenetration(worstContact);
// }
// }
}
/**
*
*/
// private function getWorstContact():Contact {
// var maxPen:Number = 0;
// var worst:Contact = null;
// for (var i:int = 0; i < contactsNum; i++) {
// var c:Contact = contacts[i];
// if (!c.satisfied && c.maxPenetration > maxPen) {
// worst = c;
// maxPen = c.maxPenetration;
// }
// }
// return maxPen > allowedPenetration ? worst : null;
// }
/**
* Разделяет указанный контакт, выполняя staticSeparationSteps итераций по списку точек контакта.
* 1. В начале каждой итерации ищется точка с наибольшим пересечением, одновременно сбрасываются флаги satisfied у точек.
* 2. Для найденной точки выполняется процедура разделения.
* 3. После выполняется pcount - 1 итерация по списку точек, каждый раз ищется наихудшая среди имеющих satisfied == false, для которой выполняется процедура разделения.
* Если наихудшая точка не найдена, то выполнется переход к следующей итерации внешнего цикла (шаг 1).
*
* В конце процедуры разделения обновляются значения пересечений для остальных точек контакта, а также для всех прочих контактов, относящихся к телам текущего.
*
* @param contact контакт для разделения
*/
private function resolveInterpenetration(contact:Contact):void {
contact.satisfied = true;
for (var step:int = 0; step < staticSeparationSteps; step++) {
var worstCp:ContactPoint = contact.points[0];
var cp:ContactPoint;
var i:int;
for (i = 1; i < contact.pcount; i++) {
cp = contact.points[i];
cp.satisfied = false;
if (cp.penetration > worstCp.penetration) worstCp = cp;
}
if (worstCp.penetration <= allowedPenetration) break;
separateContactPoint(worstCp, contact);
// Разделяем оставшиеся точки
var maxPen:Number = 0;
for (i = 1; i < contact.pcount; i++) {
// Поиск наихудшей точки
for (var j:int = 0; j < contact.pcount; j++) {
cp = contact.points[j];
if (cp.satisfied) continue;
if (cp.penetration > maxPen) {
maxPen = cp.penetration;
worstCp = cp;
}
}
if (maxPen <= allowedPenetration) break;
separateContactPoint(worstCp, contact);
}
}
}
/**
*
* @param cp
* @param contact
*/
private function separateContactPoint(cp:ContactPoint, contact:Contact):void {
// cp.satisfied = true;
//
// var b1:Body = contact.body1;
// var b2:Body = contact.body2;
// var totalMove:Number = cp.penetration - allowedPenetration;
// var moveCoeff:Number = totalMove/cp.velByUnitImpulseN;
// var linMove1:Number;
// var angleMove1:Number;
// if (b1.movable) {
// linMove1 = b1.invMass*moveCoeff;
// angleMove1 = cp.angularInertia1*moveCoeff;
// if (angleMove1 > maxAngleMove) {
// linMove1 += angleMove1 - maxAngleMove;
// angleMove1 -= maxAngleMove;
// }
// b1.state.pos.vAddScaled(linMove1, contact.normal);
// _v1.vCross2(cp.r1, contact.normal).vTransformBy3(b1.invInertiaWorld).vScale(angleMove1);
// b1.state.orientation.addScaledVector(_v1, 1);
// }
// var linMove2:Number;
// var angleMove2:Number;
// if (b2 != null && b2.movable) {
// linMove2 = b2.invMass*moveCoeff;
// angleMove2 = cp.angularInertia2*moveCoeff;
// if (angleMove2 > maxAngleMove) {
// linMove2 += angleMove2 - maxAngleMove;
// angleMove2 -= maxAngleMove;
// }
// b2.state.pos.vAddScaled(-linMove2, contact.normal);
// _v2.vCross2(cp.r2, contact.normal).vTransformBy3(b2.invInertiaWorld).vScale(angleMove2);
// _v2.vReverse();
// b2.state.orientation.addScaledVector(_v2, 1);
// }
// cp.penetration = allowedPenetration;
// // Обновляем пересечения в других точках
// var i:int;
// for (i = 0; i < contact.pcount; i++) {
// var cp1:ContactPoint = contact.points[i];
// if (cp1 == cp) continue;
// var angularMove:Number;
// if (b1.movable) {
// angularMove = _v.vCross2(_v1, cp1.r1).vDot(contact.normal);
// cp1.penetration -= linMove1 + angularMove;
// }
// if (b2 != null && b2.movable) {
// angularMove = _v.vCross2(_v2, cp1.r2).vDot(contact.normal);
// cp1.penetration -= linMove2 - angularMove;
// }
// // Обновление максимального значения для контакта
// if (cp1.penetration > contact.maxPenetration) contact.maxPenetration = cp1.penetration;
// }
// // Обновляем пересечения для других контактов
// var c:Contact;
// var j:int;
// if (b1.movable) {
// for (i = 0; i < b1.contactsNum; i++) {
// c = b1.contacts[i];
// if (c == contact) continue;
// for (j = 0; j < c.pcount; j++) {
// cp1 = c.points[j];
// if (b1 == c.body1) cp1.penetration -= linMove1*contact.normal.vDot(c.normal) + _v.vCross2(_v1, cp1.r1).vDot(c.normal);
// else cp1.penetration += linMove1*contact.normal.vDot(c.normal) + _v.vCross2(_v1, cp1.r2).vDot(c.normal);
// if (c.maxPenetration < cp1.penetration) c.maxPenetration = cp1.penetration;
// }
// }
// }
// if (b2 != null && b2.movable) {
// for (i = 0; i < b2.contactsNum; i++) {
// c = b2.contacts[i];
// if (c == contact) continue;
// for (j = 0; j < c.pcount; j++) {
// cp1 = c.points[j];
// if (b2 == c.body1) cp1.penetration -= linMove2*contact.normal.vDot(c.normal) + _v.vCross2(_v2, cp1.r1).vDot(c.normal);
// else cp1.penetration += linMove2*contact.normal.vDot(c.normal) + _v.vCross2(_v2, cp1.r2).vDot(c.normal);
// if (c.maxPenetration < cp1.penetration) c.maxPenetration = cp1.penetration;
// }
// }
// }
}
/**
*
*/
private function postPhysics():void {
var item:BodyListItem = bodies.head;
while (item != null) {
var body:Body = item.body;
body.clearAccumulators();
body.calcDerivedData();
if (body.canFreeze) {
if (body.state.velocity.vLength() < linSpeedFreezeLimit && body.state.rotation.vLength() < angSpeedFreezeLimit) {
if (!body.frozen) {
body.freezeCounter++;
if (body.freezeCounter >= freezeSteps) body.frozen = true;
}
} else {
body.freezeCounter = 0;
body.frozen = false;
}
}
item = item.next;
}
}
/**
*
* @param delta
*/
public function runPhysics(delta:uint):void {
timeStamp++;
time += delta;
var dt:Number = 0.001*delta;
applyForces(dt);
detectCollisions(dt);
preProcessContacts(dt);
processContacts(dt, false);
intergateVelocities(dt);
processContacts(dt, true);
integratePositions(dt);
postPhysics();
}
}
}