mirror of
https://github.com/MapMakersAndProgrammers/alternativaphysics-archive.git
synced 2025-10-26 01:49:13 -07:00
everything i found in leaked code
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.DS_Store
|
||||
28
0.0.0.18/pom.xml
Normal file
28
0.0.0.18/pom.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>platform.clients.fp9.libraries</groupId>
|
||||
<artifactId>AlternativaPhysics</artifactId>
|
||||
<packaging>swc</packaging>
|
||||
<version>0.0.0.18</version>
|
||||
<parent>
|
||||
<groupId>platform.tools.maven</groupId>
|
||||
<artifactId>FlashBasePom</artifactId>
|
||||
<version>1.0</version>
|
||||
</parent>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>platform.clients.fp9.libraries</groupId>
|
||||
<artifactId>AlternativaTypes</artifactId>
|
||||
<version>[1.1.0.1,2.0.0.0)</version>
|
||||
<type>swc</type>
|
||||
<scope>external</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>platform.clients.fp9.libraries</groupId>
|
||||
<artifactId>AlternativaUtils</artifactId>
|
||||
<version>[1.2.0.0,2.0.0.0)</version>
|
||||
<type>swc</type>
|
||||
<scope>external</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
5
0.0.0.18/src/.svn/all-wcprops
Normal file
5
0.0.0.18/src/.svn/all-wcprops
Normal file
@@ -0,0 +1,5 @@
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 74
|
||||
/!svn/ver/5193/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src
|
||||
END
|
||||
31
0.0.0.18/src/.svn/entries
Normal file
31
0.0.0.18/src/.svn/entries
Normal file
@@ -0,0 +1,31 @@
|
||||
8
|
||||
|
||||
dir
|
||||
46043
|
||||
http://svndev.alternativaplatform.com/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src
|
||||
http://svndev.alternativaplatform.com
|
||||
|
||||
|
||||
|
||||
2008-12-17T11:38:42.040147Z
|
||||
5193
|
||||
mike
|
||||
|
||||
|
||||
svn:special svn:externals svn:needs-lock
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
d9e2387a-1f3e-40e2-b57f-9df5970a2fa5
|
||||
|
||||
alternativa
|
||||
dir
|
||||
|
||||
1
0.0.0.18/src/.svn/format
Normal file
1
0.0.0.18/src/.svn/format
Normal file
@@ -0,0 +1 @@
|
||||
8
|
||||
5
0.0.0.18/src/alternativa/.svn/all-wcprops
Normal file
5
0.0.0.18/src/alternativa/.svn/all-wcprops
Normal file
@@ -0,0 +1,5 @@
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 86
|
||||
/!svn/ver/5193/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa
|
||||
END
|
||||
31
0.0.0.18/src/alternativa/.svn/entries
Normal file
31
0.0.0.18/src/alternativa/.svn/entries
Normal file
@@ -0,0 +1,31 @@
|
||||
8
|
||||
|
||||
dir
|
||||
46043
|
||||
http://svndev.alternativaplatform.com/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa
|
||||
http://svndev.alternativaplatform.com
|
||||
|
||||
|
||||
|
||||
2008-12-17T11:38:42.040147Z
|
||||
5193
|
||||
mike
|
||||
|
||||
|
||||
svn:special svn:externals svn:needs-lock
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
d9e2387a-1f3e-40e2-b57f-9df5970a2fa5
|
||||
|
||||
physics
|
||||
dir
|
||||
|
||||
1
0.0.0.18/src/alternativa/.svn/format
Normal file
1
0.0.0.18/src/alternativa/.svn/format
Normal file
@@ -0,0 +1 @@
|
||||
8
|
||||
11
0.0.0.18/src/alternativa/physics/.svn/all-wcprops
Normal file
11
0.0.0.18/src/alternativa/physics/.svn/all-wcprops
Normal file
@@ -0,0 +1,11 @@
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 94
|
||||
/!svn/ver/5193/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics
|
||||
END
|
||||
altphysics.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 108
|
||||
/!svn/ver/4196/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/altphysics.as
|
||||
END
|
||||
55
0.0.0.18/src/alternativa/physics/.svn/entries
Normal file
55
0.0.0.18/src/alternativa/physics/.svn/entries
Normal file
@@ -0,0 +1,55 @@
|
||||
8
|
||||
|
||||
dir
|
||||
46043
|
||||
http://svndev.alternativaplatform.com/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics
|
||||
http://svndev.alternativaplatform.com
|
||||
|
||||
|
||||
|
||||
2008-12-17T11:38:42.040147Z
|
||||
5193
|
||||
mike
|
||||
|
||||
|
||||
svn:special svn:externals svn:needs-lock
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
d9e2387a-1f3e-40e2-b57f-9df5970a2fa5
|
||||
|
||||
particle
|
||||
dir
|
||||
|
||||
altphysics.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
44fa0a3979af103ba658ab05e4428212
|
||||
2008-11-24T06:53:44.272574Z
|
||||
4196
|
||||
mike
|
||||
|
||||
registry
|
||||
dir
|
||||
|
||||
collision
|
||||
dir
|
||||
|
||||
force
|
||||
dir
|
||||
|
||||
rigid
|
||||
dir
|
||||
|
||||
1
0.0.0.18/src/alternativa/physics/.svn/format
Normal file
1
0.0.0.18/src/alternativa/physics/.svn/format
Normal file
@@ -0,0 +1 @@
|
||||
8
|
||||
@@ -0,0 +1,3 @@
|
||||
package alternativa.physics {
|
||||
public namespace altphysics = "http://alternativaplatform.com/en/altphysics";
|
||||
}
|
||||
3
0.0.0.18/src/alternativa/physics/altphysics.as
Normal file
3
0.0.0.18/src/alternativa/physics/altphysics.as
Normal file
@@ -0,0 +1,3 @@
|
||||
package alternativa.physics {
|
||||
public namespace altphysics = "http://alternativaplatform.com/en/altphysics";
|
||||
}
|
||||
29
0.0.0.18/src/alternativa/physics/collision/.svn/all-wcprops
Normal file
29
0.0.0.18/src/alternativa/physics/collision/.svn/all-wcprops
Normal file
@@ -0,0 +1,29 @@
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 104
|
||||
/!svn/ver/4398/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/collision
|
||||
END
|
||||
CollisionBox.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 120
|
||||
/!svn/ver/4196/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/collision/CollisionBox.as
|
||||
END
|
||||
CollisionPrimitive.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 126
|
||||
/!svn/ver/4375/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/collision/CollisionPrimitive.as
|
||||
END
|
||||
CollisionData.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 121
|
||||
/!svn/ver/4196/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/collision/CollisionData.as
|
||||
END
|
||||
CollisionDetector.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 125
|
||||
/!svn/ver/4398/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/collision/CollisionDetector.as
|
||||
END
|
||||
76
0.0.0.18/src/alternativa/physics/collision/.svn/entries
Normal file
76
0.0.0.18/src/alternativa/physics/collision/.svn/entries
Normal file
@@ -0,0 +1,76 @@
|
||||
8
|
||||
|
||||
dir
|
||||
46043
|
||||
http://svndev.alternativaplatform.com/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/collision
|
||||
http://svndev.alternativaplatform.com
|
||||
|
||||
|
||||
|
||||
2008-11-26T15:04:50.319495Z
|
||||
4398
|
||||
mike
|
||||
|
||||
|
||||
svn:special svn:externals svn:needs-lock
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
d9e2387a-1f3e-40e2-b57f-9df5970a2fa5
|
||||
|
||||
CollisionBox.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
777502bd075948da11606f32afba6679
|
||||
2008-11-24T06:53:44.272574Z
|
||||
4196
|
||||
mike
|
||||
|
||||
CollisionPrimitive.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
1e73f056a418e5c664977b4fafad70e5
|
||||
2008-11-26T12:04:03.108808Z
|
||||
4375
|
||||
mike
|
||||
|
||||
CollisionData.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
a8943fcaceb0836d59e7f4c2b2d3f4df
|
||||
2008-11-24T06:53:44.272574Z
|
||||
4196
|
||||
mike
|
||||
|
||||
CollisionDetector.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
ca727662c3fe996a487323977c4a67bb
|
||||
2008-11-26T15:04:50.319495Z
|
||||
4398
|
||||
mike
|
||||
|
||||
1
0.0.0.18/src/alternativa/physics/collision/.svn/format
Normal file
1
0.0.0.18/src/alternativa/physics/collision/.svn/format
Normal file
@@ -0,0 +1 @@
|
||||
8
|
||||
@@ -0,0 +1,15 @@
|
||||
package alternativa.physics.collision {
|
||||
import alternativa.physics.rigid.RigidBody;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
public class CollisionBox extends CollisionPrimitive {
|
||||
|
||||
public var halfSize:Point3D = new Point3D();
|
||||
|
||||
public function CollisionBox(body:RigidBody, halfSize:Point3D) {
|
||||
super(body);
|
||||
this.halfSize.copy(halfSize);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package alternativa.physics.collision {
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
public class CollisionData {
|
||||
|
||||
public var primitive1:CollisionPrimitive;
|
||||
public var primitive2:CollisionPrimitive;
|
||||
|
||||
public var collisionNormal:Point3D = new Point3D();
|
||||
public var collisionPoint:Point3D = new Point3D();
|
||||
public var penetration:Number;
|
||||
|
||||
public var pointAxisCode1:int;
|
||||
public var pointAxisCode2:int;
|
||||
|
||||
public var timeStamp:int;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,342 @@
|
||||
package alternativa.physics.collision {
|
||||
import alternativa.physics.altphysics;
|
||||
import alternativa.types.Matrix3D;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
use namespace altphysics;
|
||||
|
||||
public class CollisionDetector {
|
||||
|
||||
private var epsilon:Number;
|
||||
|
||||
private var bestAxisIndex:int;
|
||||
private var minOverlap:Number;
|
||||
|
||||
private var vectorToBox1:Point3D = new Point3D();
|
||||
private var axis:Point3D = new Point3D();
|
||||
private var axis10:Point3D = new Point3D();
|
||||
private var axis11:Point3D = new Point3D();
|
||||
private var axis12:Point3D = new Point3D();
|
||||
private var axis20:Point3D = new Point3D();
|
||||
private var axis21:Point3D = new Point3D();
|
||||
private var axis22:Point3D = new Point3D();
|
||||
private var collisionAxis:Point3D = new Point3D();
|
||||
private var tmpAxis:Point3D = new Point3D();
|
||||
private var point1:Point3D = new Point3D();
|
||||
private var point2:Point3D = new Point3D();
|
||||
private var vector:Point3D = new Point3D();
|
||||
|
||||
public function CollisionDetector(epsilon:Number = 0.01) {
|
||||
this.epsilon = epsilon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет столкновение двух боксов, используя теорему о разделяющих плоскостях.
|
||||
*
|
||||
* @param box1
|
||||
* @param box2
|
||||
* @param collisionData
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public function boxToBoxCollision(box1:CollisionBox, box2:CollisionBox, collisionData:CollisionData):Boolean {
|
||||
if (box1.body.inverseMass == 0 && box2.body.inverseMass == 0) {
|
||||
// Нет необходимости проверять столкновения между неподвижными объектами
|
||||
return false;
|
||||
}
|
||||
minOverlap = Number.MAX_VALUE;
|
||||
// Вектор из центра второго бокса в центр первого
|
||||
vectorToBox1.difference(box1.position, box2.position);
|
||||
|
||||
// Проверка пересечения по основным осям
|
||||
box1.transform.getAxis(0, axis10);
|
||||
if (!testAxis(box1, box2, axis10, 0, vectorToBox1)) return false;
|
||||
box1.transform.getAxis(1, axis11);
|
||||
if (!testAxis(box1, box2, axis11, 1, vectorToBox1)) return false;
|
||||
box1.transform.getAxis(2, axis12);
|
||||
if (!testAxis(box1, box2, axis12, 2, vectorToBox1)) return false;
|
||||
|
||||
box2.transform.getAxis(0, axis20);
|
||||
if (!testAxis(box1, box2, axis20, 3, vectorToBox1)) return false;
|
||||
box2.transform.getAxis(1, axis21);
|
||||
if (!testAxis(box1, box2, axis21, 4, vectorToBox1)) return false;
|
||||
box2.transform.getAxis(2, axis22);
|
||||
if (!testAxis(box1, box2, axis22, 5, vectorToBox1)) return false;
|
||||
|
||||
// Сохраняем ось с наименьшим перекрытием на случай обнаружения контакта ребро-грань
|
||||
var bestMainAxis:int = bestAxisIndex;
|
||||
|
||||
// Проверка производных осей
|
||||
axis.cross2(axis10, axis20);
|
||||
if (!testAxis(box1, box2, axis, 6, vectorToBox1)) return false;
|
||||
axis.cross2(axis10, axis21);
|
||||
if (!testAxis(box1, box2, axis, 7, vectorToBox1)) return false;
|
||||
axis.cross2(axis10, axis22);
|
||||
if (!testAxis(box1, box2, axis, 8, vectorToBox1)) return false;
|
||||
|
||||
axis.cross2(axis11, axis20);
|
||||
if (!testAxis(box1, box2, axis, 9, vectorToBox1)) return false;
|
||||
axis.cross2(axis11, axis21);
|
||||
if (!testAxis(box1, box2, axis, 10, vectorToBox1)) return false;
|
||||
axis.cross2(axis11, axis22);
|
||||
if (!testAxis(box1, box2, axis, 11, vectorToBox1)) return false;
|
||||
|
||||
axis.cross2(axis12, axis20);
|
||||
if (!testAxis(box1, box2, axis, 12, vectorToBox1)) return false;
|
||||
axis.cross2(axis12, axis21);
|
||||
if (!testAxis(box1, box2, axis, 13, vectorToBox1)) return false;
|
||||
axis.cross2(axis12, axis22);
|
||||
if (!testAxis(box1, box2, axis, 14, vectorToBox1)) return false;
|
||||
|
||||
if (bestAxisIndex < 3) {
|
||||
// Пересечение вершины второго бокса с гранью первого
|
||||
fillPointBoxPenetrationData(box1, box2, vectorToBox1, bestAxisIndex, minOverlap, collisionData);
|
||||
collisionData.primitive1 = box1;
|
||||
collisionData.primitive2 = box2;
|
||||
return true;
|
||||
} else if (bestAxisIndex < 6) {
|
||||
// Пересечение вершины первого бокса с гранью второго
|
||||
vectorToBox1.invert();
|
||||
fillPointBoxPenetrationData(box2, box1, vectorToBox1, bestAxisIndex - 3, minOverlap, collisionData);
|
||||
collisionData.primitive1 = box1;
|
||||
collisionData.primitive2 = box2;
|
||||
collisionData.collisionNormal.invert();
|
||||
var tmp:Number = collisionData.pointAxisCode1;
|
||||
collisionData.pointAxisCode1 = collisionData.pointAxisCode2;
|
||||
collisionData.pointAxisCode2 = tmp;
|
||||
return true;
|
||||
} else {
|
||||
// Пересечение рёбер
|
||||
bestAxisIndex -= 6;
|
||||
var axisIndex1:int = int(bestAxisIndex/3);
|
||||
var axisIndex2:int = bestAxisIndex%3;
|
||||
|
||||
box1.transform.getAxis(axisIndex1, axis10);
|
||||
box2.transform.getAxis(axisIndex2, axis20);
|
||||
collisionAxis.cross2(axis10, axis20);
|
||||
collisionAxis.normalize();
|
||||
// Разворот оси в сторону первого бокса
|
||||
if (collisionAxis.dot(vectorToBox1) < 0) {
|
||||
collisionAxis.invert();
|
||||
}
|
||||
|
||||
var edgeHalfLength1:Number;
|
||||
var edgeHalfLength2:Number;
|
||||
var pointEdgeCode1:int;
|
||||
var pointEdgeCode2:int;
|
||||
|
||||
point1.copy(box1.halfSize);
|
||||
point2.copy(box2.halfSize);
|
||||
// x
|
||||
if (axisIndex1 == 0) {
|
||||
point1.x = 0;
|
||||
edgeHalfLength1 = box1.halfSize.x;
|
||||
pointEdgeCode1 |= 1;
|
||||
} else {
|
||||
box1.transform.getAxis(0, tmpAxis);
|
||||
if (tmpAxis.dot(collisionAxis) > 0) {
|
||||
point1.x = -point1.x;
|
||||
pointEdgeCode1 |= 1;
|
||||
}
|
||||
}
|
||||
if (axisIndex2 == 0) {
|
||||
point2.x = 0;
|
||||
edgeHalfLength2 = box2.halfSize.x;
|
||||
pointEdgeCode2 |= 1;
|
||||
} else {
|
||||
box2.transform.getAxis(0, tmpAxis);
|
||||
if (tmpAxis.dot(collisionAxis) < 0) {
|
||||
point2.x = -point2.x;
|
||||
pointEdgeCode2 |= 1;
|
||||
}
|
||||
}
|
||||
// y
|
||||
if (axisIndex1 == 1) {
|
||||
point1.y = 0;
|
||||
edgeHalfLength1 = box1.halfSize.y;
|
||||
pointEdgeCode1 |= 2;
|
||||
} else {
|
||||
box1.transform.getAxis(1, tmpAxis);
|
||||
if (tmpAxis.dot(collisionAxis) > 0) {
|
||||
point1.y = -point1.y;
|
||||
pointEdgeCode1 |= 2;
|
||||
}
|
||||
}
|
||||
if (axisIndex2 == 1) {
|
||||
point2.y = 0;
|
||||
edgeHalfLength2 = box2.halfSize.y;
|
||||
pointEdgeCode2 |= 2;
|
||||
} else {
|
||||
box2.transform.getAxis(1, tmpAxis);
|
||||
if (tmpAxis.dot(collisionAxis) < 0) {
|
||||
point2.y = -point2.y;
|
||||
pointEdgeCode2 |= 2;
|
||||
}
|
||||
}
|
||||
// z
|
||||
if (axisIndex1 == 2) {
|
||||
point1.z = 0;
|
||||
edgeHalfLength1 = box1.halfSize.z;
|
||||
pointEdgeCode1 |= 4;
|
||||
} else {
|
||||
box1.transform.getAxis(2, tmpAxis);
|
||||
if (tmpAxis.dot(collisionAxis) > 0) {
|
||||
point1.z = -point1.z;
|
||||
pointEdgeCode1 |= 4;
|
||||
}
|
||||
}
|
||||
if (axisIndex2 == 2) {
|
||||
point2.z = 0;
|
||||
edgeHalfLength2 = box2.halfSize.z;
|
||||
pointEdgeCode2 |= 4;
|
||||
} else {
|
||||
box2.transform.getAxis(2, tmpAxis);
|
||||
if (tmpAxis.dot(collisionAxis) < 0) {
|
||||
point2.z = -point2.z;
|
||||
pointEdgeCode2 |= 4;
|
||||
}
|
||||
}
|
||||
|
||||
point1.transform(box1.transform);
|
||||
point2.transform(box2.transform);
|
||||
|
||||
// Находим точку пересечения рёбер
|
||||
var k:Number = axis10.dot(axis20);
|
||||
var det:Number = k*k - 1;
|
||||
if (det > -0.0001 && det < 0.0001) {
|
||||
vector.copy(bestMainAxis > 2 ? point1 : point2);
|
||||
} else {
|
||||
vector.difference(point2, point1);
|
||||
var c1:Number = axis10.dot(vector);
|
||||
var c2:Number = axis20.dot(vector);
|
||||
var t1:Number = (c2*k - c1)/det;
|
||||
if (t1 < -edgeHalfLength1 || t1 > edgeHalfLength1) {
|
||||
vector.copy(bestMainAxis > 2 ? point1 : point2);
|
||||
} else {
|
||||
var t2:Number = (c2 - c1*k)/det;
|
||||
if (t2 < -edgeHalfLength2 || t2 > edgeHalfLength2) {
|
||||
vector.copy(bestMainAxis > 2 ? point1 : point2);
|
||||
} else {
|
||||
vector.x = 0.5*(point1.x + point2.x + axis10.x*t1 + axis20.x*t2);
|
||||
vector.y = 0.5*(point1.y + point2.y + axis10.y*t1 + axis20.y*t2);
|
||||
vector.z = 0.5*(point1.z + point2.z + axis10.z*t1 + axis20.z*t2);
|
||||
}
|
||||
}
|
||||
}
|
||||
collisionData.primitive1 = box1;
|
||||
collisionData.primitive2 = box2;
|
||||
collisionData.penetration = minOverlap;
|
||||
collisionData.collisionPoint.copy(vector);
|
||||
collisionData.collisionNormal.copy(collisionAxis);
|
||||
collisionData.pointAxisCode1 = pointEdgeCode1 | (axisIndex1 << 3) | 32;
|
||||
collisionData.pointAxisCode2 = pointEdgeCode2 | (axisIndex2 << 3) | 32;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param box1
|
||||
* @param box2
|
||||
* @param axis
|
||||
* @param axisIndex
|
||||
* @param vectorToBox1
|
||||
* @param bestAxis
|
||||
* @return
|
||||
*
|
||||
*/
|
||||
private function testAxis(box1:CollisionBox, box2:CollisionBox, axis:Point3D, axisIndex:int, vectorToBox1:Point3D):Boolean {
|
||||
if (axis.lengthSqr < 0.0001) {
|
||||
return true;
|
||||
}
|
||||
axis.normalize();
|
||||
|
||||
var overlap:Number = overlapOnAxis(box1, box2, axis, vectorToBox1);
|
||||
if (overlap <= 0) {
|
||||
return false;
|
||||
}
|
||||
if (overlap < minOverlap) {
|
||||
minOverlap = overlap;
|
||||
bestAxisIndex = axisIndex;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param box1
|
||||
* @param box2
|
||||
* @param axis
|
||||
* @param vectorToBox1
|
||||
* @return
|
||||
*
|
||||
*/
|
||||
public function overlapOnAxis(box1:CollisionBox, box2:CollisionBox, axis:Point3D, vectorToBox1:Point3D):Number {
|
||||
var m:Matrix3D = box1.transform;
|
||||
var d:Number = (m.a*axis.x + m.e*axis.y + m.i*axis.z)*box1.halfSize.x;
|
||||
var projection:Number = d < 0 ? -d : d;
|
||||
d = (m.b*axis.x + m.f*axis.y + m.j*axis.z)*box1.halfSize.y;
|
||||
projection += d < 0 ? -d : d;
|
||||
d = (m.c*axis.x + m.g*axis.y + m.k*axis.z)*box1.halfSize.z;
|
||||
projection += d < 0 ? -d : d;
|
||||
|
||||
m = box2.transform;
|
||||
d = (m.a*axis.x + m.e*axis.y + m.i*axis.z)*box2.halfSize.x;
|
||||
projection += d < 0 ? -d : d;
|
||||
d = (m.b*axis.x + m.f*axis.y + m.j*axis.z)*box2.halfSize.y;
|
||||
projection += d < 0 ? -d : d;
|
||||
d = (m.c*axis.x + m.g*axis.y + m.k*axis.z)*box2.halfSize.z;
|
||||
projection += d < 0 ? -d : d;
|
||||
|
||||
d = vectorToBox1.x*axis.x + vectorToBox1.y*axis.y + vectorToBox1.z*axis.z;
|
||||
if (d < 0) {
|
||||
d = -d;
|
||||
}
|
||||
|
||||
return projection - d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Заполняет данные о контакте грани первого бокса с вершиной второго.
|
||||
*
|
||||
* @param box1
|
||||
* @param box2
|
||||
* @param vectorToBox1
|
||||
* @param axisIndex
|
||||
* @param overlap
|
||||
* @param collisionData
|
||||
* @param swapBoxes поменять примитивы местами при записи данных
|
||||
*/
|
||||
private function fillPointBoxPenetrationData(box1:CollisionBox, box2:CollisionBox, vectorToBox1:Point3D, axisIndex:int, overlap:Number, collisionData:CollisionData):void {
|
||||
box1.transform.getAxis(axisIndex, collisionData.collisionNormal);
|
||||
if (collisionData.collisionNormal.dot(vectorToBox1) < 0) {
|
||||
collisionData.collisionNormal.invert();
|
||||
}
|
||||
|
||||
var pointCode:int;
|
||||
axis10.copy(box2.halfSize);
|
||||
box2.transform.getAxis(0, axis20);
|
||||
if (axis20.dot(collisionData.collisionNormal) < 0) {
|
||||
axis10.x = -axis10.x;
|
||||
pointCode |= 1;
|
||||
}
|
||||
box2.transform.getAxis(1, axis20);
|
||||
if (axis20.dot(collisionData.collisionNormal) < 0) {
|
||||
axis10.y = -axis10.y;
|
||||
pointCode |= 2;
|
||||
}
|
||||
box2.transform.getAxis(2, axis20);
|
||||
if (axis20.dot(collisionData.collisionNormal) < 0) {
|
||||
axis10.z = -axis10.z;
|
||||
pointCode |= 4;
|
||||
}
|
||||
axis10.transform(box2.transform);
|
||||
|
||||
collisionData.collisionPoint.copy(axis10);
|
||||
collisionData.penetration = overlap;
|
||||
collisionData.pointAxisCode1 = (axisIndex << 3) | 32;
|
||||
collisionData.pointAxisCode2 = pointCode;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package alternativa.physics.collision {
|
||||
|
||||
import alternativa.physics.altphysics;
|
||||
import alternativa.physics.rigid.RigidBody;
|
||||
import alternativa.types.Matrix3D;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
use namespace altphysics;
|
||||
|
||||
public class CollisionPrimitive {
|
||||
|
||||
public var position:Point3D = new Point3D();
|
||||
public var transform:Matrix3D = new Matrix3D();
|
||||
public var body:RigidBody;
|
||||
|
||||
public function CollisionPrimitive(body:RigidBody) {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public function updateTransform():void {
|
||||
transform.copy(body.transformMatrix);
|
||||
position.x = body.position.x;
|
||||
position.y = body.position.y;
|
||||
position.z = body.position.z;
|
||||
transform.d = position.x;
|
||||
transform.h = position.y;
|
||||
transform.l = position.z;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
15
0.0.0.18/src/alternativa/physics/collision/CollisionBox.as
Normal file
15
0.0.0.18/src/alternativa/physics/collision/CollisionBox.as
Normal file
@@ -0,0 +1,15 @@
|
||||
package alternativa.physics.collision {
|
||||
import alternativa.physics.rigid.RigidBody;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
public class CollisionBox extends CollisionPrimitive {
|
||||
|
||||
public var halfSize:Point3D = new Point3D();
|
||||
|
||||
public function CollisionBox(body:RigidBody, halfSize:Point3D) {
|
||||
super(body);
|
||||
this.halfSize.copy(halfSize);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
18
0.0.0.18/src/alternativa/physics/collision/CollisionData.as
Normal file
18
0.0.0.18/src/alternativa/physics/collision/CollisionData.as
Normal file
@@ -0,0 +1,18 @@
|
||||
package alternativa.physics.collision {
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
public class CollisionData {
|
||||
|
||||
public var primitive1:CollisionPrimitive;
|
||||
public var primitive2:CollisionPrimitive;
|
||||
|
||||
public var collisionNormal:Point3D = new Point3D();
|
||||
public var collisionPoint:Point3D = new Point3D();
|
||||
public var penetration:Number;
|
||||
|
||||
public var pointAxisCode1:int;
|
||||
public var pointAxisCode2:int;
|
||||
|
||||
public var timeStamp:int;
|
||||
}
|
||||
}
|
||||
342
0.0.0.18/src/alternativa/physics/collision/CollisionDetector.as
Normal file
342
0.0.0.18/src/alternativa/physics/collision/CollisionDetector.as
Normal file
@@ -0,0 +1,342 @@
|
||||
package alternativa.physics.collision {
|
||||
import alternativa.physics.altphysics;
|
||||
import alternativa.types.Matrix3D;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
use namespace altphysics;
|
||||
|
||||
public class CollisionDetector {
|
||||
|
||||
private var epsilon:Number;
|
||||
|
||||
private var bestAxisIndex:int;
|
||||
private var minOverlap:Number;
|
||||
|
||||
private var vectorToBox1:Point3D = new Point3D();
|
||||
private var axis:Point3D = new Point3D();
|
||||
private var axis10:Point3D = new Point3D();
|
||||
private var axis11:Point3D = new Point3D();
|
||||
private var axis12:Point3D = new Point3D();
|
||||
private var axis20:Point3D = new Point3D();
|
||||
private var axis21:Point3D = new Point3D();
|
||||
private var axis22:Point3D = new Point3D();
|
||||
private var collisionAxis:Point3D = new Point3D();
|
||||
private var tmpAxis:Point3D = new Point3D();
|
||||
private var point1:Point3D = new Point3D();
|
||||
private var point2:Point3D = new Point3D();
|
||||
private var vector:Point3D = new Point3D();
|
||||
|
||||
public function CollisionDetector(epsilon:Number = 0.01) {
|
||||
this.epsilon = epsilon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет столкновение двух боксов, используя теорему о разделяющих плоскостях.
|
||||
*
|
||||
* @param box1
|
||||
* @param box2
|
||||
* @param collisionData
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public function boxToBoxCollision(box1:CollisionBox, box2:CollisionBox, collisionData:CollisionData):Boolean {
|
||||
if (box1.body.inverseMass == 0 && box2.body.inverseMass == 0) {
|
||||
// Нет необходимости проверять столкновения между неподвижными объектами
|
||||
return false;
|
||||
}
|
||||
minOverlap = Number.MAX_VALUE;
|
||||
// Вектор из центра второго бокса в центр первого
|
||||
vectorToBox1.difference(box1.position, box2.position);
|
||||
|
||||
// Проверка пересечения по основным осям
|
||||
box1.transform.getAxis(0, axis10);
|
||||
if (!testAxis(box1, box2, axis10, 0, vectorToBox1)) return false;
|
||||
box1.transform.getAxis(1, axis11);
|
||||
if (!testAxis(box1, box2, axis11, 1, vectorToBox1)) return false;
|
||||
box1.transform.getAxis(2, axis12);
|
||||
if (!testAxis(box1, box2, axis12, 2, vectorToBox1)) return false;
|
||||
|
||||
box2.transform.getAxis(0, axis20);
|
||||
if (!testAxis(box1, box2, axis20, 3, vectorToBox1)) return false;
|
||||
box2.transform.getAxis(1, axis21);
|
||||
if (!testAxis(box1, box2, axis21, 4, vectorToBox1)) return false;
|
||||
box2.transform.getAxis(2, axis22);
|
||||
if (!testAxis(box1, box2, axis22, 5, vectorToBox1)) return false;
|
||||
|
||||
// Сохраняем ось с наименьшим перекрытием на случай обнаружения контакта ребро-грань
|
||||
var bestMainAxis:int = bestAxisIndex;
|
||||
|
||||
// Проверка производных осей
|
||||
axis.cross2(axis10, axis20);
|
||||
if (!testAxis(box1, box2, axis, 6, vectorToBox1)) return false;
|
||||
axis.cross2(axis10, axis21);
|
||||
if (!testAxis(box1, box2, axis, 7, vectorToBox1)) return false;
|
||||
axis.cross2(axis10, axis22);
|
||||
if (!testAxis(box1, box2, axis, 8, vectorToBox1)) return false;
|
||||
|
||||
axis.cross2(axis11, axis20);
|
||||
if (!testAxis(box1, box2, axis, 9, vectorToBox1)) return false;
|
||||
axis.cross2(axis11, axis21);
|
||||
if (!testAxis(box1, box2, axis, 10, vectorToBox1)) return false;
|
||||
axis.cross2(axis11, axis22);
|
||||
if (!testAxis(box1, box2, axis, 11, vectorToBox1)) return false;
|
||||
|
||||
axis.cross2(axis12, axis20);
|
||||
if (!testAxis(box1, box2, axis, 12, vectorToBox1)) return false;
|
||||
axis.cross2(axis12, axis21);
|
||||
if (!testAxis(box1, box2, axis, 13, vectorToBox1)) return false;
|
||||
axis.cross2(axis12, axis22);
|
||||
if (!testAxis(box1, box2, axis, 14, vectorToBox1)) return false;
|
||||
|
||||
if (bestAxisIndex < 3) {
|
||||
// Пересечение вершины второго бокса с гранью первого
|
||||
fillPointBoxPenetrationData(box1, box2, vectorToBox1, bestAxisIndex, minOverlap, collisionData);
|
||||
collisionData.primitive1 = box1;
|
||||
collisionData.primitive2 = box2;
|
||||
return true;
|
||||
} else if (bestAxisIndex < 6) {
|
||||
// Пересечение вершины первого бокса с гранью второго
|
||||
vectorToBox1.invert();
|
||||
fillPointBoxPenetrationData(box2, box1, vectorToBox1, bestAxisIndex - 3, minOverlap, collisionData);
|
||||
collisionData.primitive1 = box1;
|
||||
collisionData.primitive2 = box2;
|
||||
collisionData.collisionNormal.invert();
|
||||
var tmp:Number = collisionData.pointAxisCode1;
|
||||
collisionData.pointAxisCode1 = collisionData.pointAxisCode2;
|
||||
collisionData.pointAxisCode2 = tmp;
|
||||
return true;
|
||||
} else {
|
||||
// Пересечение рёбер
|
||||
bestAxisIndex -= 6;
|
||||
var axisIndex1:int = int(bestAxisIndex/3);
|
||||
var axisIndex2:int = bestAxisIndex%3;
|
||||
|
||||
box1.transform.getAxis(axisIndex1, axis10);
|
||||
box2.transform.getAxis(axisIndex2, axis20);
|
||||
collisionAxis.cross2(axis10, axis20);
|
||||
collisionAxis.normalize();
|
||||
// Разворот оси в сторону первого бокса
|
||||
if (collisionAxis.dot(vectorToBox1) < 0) {
|
||||
collisionAxis.invert();
|
||||
}
|
||||
|
||||
var edgeHalfLength1:Number;
|
||||
var edgeHalfLength2:Number;
|
||||
var pointEdgeCode1:int;
|
||||
var pointEdgeCode2:int;
|
||||
|
||||
point1.copy(box1.halfSize);
|
||||
point2.copy(box2.halfSize);
|
||||
// x
|
||||
if (axisIndex1 == 0) {
|
||||
point1.x = 0;
|
||||
edgeHalfLength1 = box1.halfSize.x;
|
||||
pointEdgeCode1 |= 1;
|
||||
} else {
|
||||
box1.transform.getAxis(0, tmpAxis);
|
||||
if (tmpAxis.dot(collisionAxis) > 0) {
|
||||
point1.x = -point1.x;
|
||||
pointEdgeCode1 |= 1;
|
||||
}
|
||||
}
|
||||
if (axisIndex2 == 0) {
|
||||
point2.x = 0;
|
||||
edgeHalfLength2 = box2.halfSize.x;
|
||||
pointEdgeCode2 |= 1;
|
||||
} else {
|
||||
box2.transform.getAxis(0, tmpAxis);
|
||||
if (tmpAxis.dot(collisionAxis) < 0) {
|
||||
point2.x = -point2.x;
|
||||
pointEdgeCode2 |= 1;
|
||||
}
|
||||
}
|
||||
// y
|
||||
if (axisIndex1 == 1) {
|
||||
point1.y = 0;
|
||||
edgeHalfLength1 = box1.halfSize.y;
|
||||
pointEdgeCode1 |= 2;
|
||||
} else {
|
||||
box1.transform.getAxis(1, tmpAxis);
|
||||
if (tmpAxis.dot(collisionAxis) > 0) {
|
||||
point1.y = -point1.y;
|
||||
pointEdgeCode1 |= 2;
|
||||
}
|
||||
}
|
||||
if (axisIndex2 == 1) {
|
||||
point2.y = 0;
|
||||
edgeHalfLength2 = box2.halfSize.y;
|
||||
pointEdgeCode2 |= 2;
|
||||
} else {
|
||||
box2.transform.getAxis(1, tmpAxis);
|
||||
if (tmpAxis.dot(collisionAxis) < 0) {
|
||||
point2.y = -point2.y;
|
||||
pointEdgeCode2 |= 2;
|
||||
}
|
||||
}
|
||||
// z
|
||||
if (axisIndex1 == 2) {
|
||||
point1.z = 0;
|
||||
edgeHalfLength1 = box1.halfSize.z;
|
||||
pointEdgeCode1 |= 4;
|
||||
} else {
|
||||
box1.transform.getAxis(2, tmpAxis);
|
||||
if (tmpAxis.dot(collisionAxis) > 0) {
|
||||
point1.z = -point1.z;
|
||||
pointEdgeCode1 |= 4;
|
||||
}
|
||||
}
|
||||
if (axisIndex2 == 2) {
|
||||
point2.z = 0;
|
||||
edgeHalfLength2 = box2.halfSize.z;
|
||||
pointEdgeCode2 |= 4;
|
||||
} else {
|
||||
box2.transform.getAxis(2, tmpAxis);
|
||||
if (tmpAxis.dot(collisionAxis) < 0) {
|
||||
point2.z = -point2.z;
|
||||
pointEdgeCode2 |= 4;
|
||||
}
|
||||
}
|
||||
|
||||
point1.transform(box1.transform);
|
||||
point2.transform(box2.transform);
|
||||
|
||||
// Находим точку пересечения рёбер
|
||||
var k:Number = axis10.dot(axis20);
|
||||
var det:Number = k*k - 1;
|
||||
if (det > -0.0001 && det < 0.0001) {
|
||||
vector.copy(bestMainAxis > 2 ? point1 : point2);
|
||||
} else {
|
||||
vector.difference(point2, point1);
|
||||
var c1:Number = axis10.dot(vector);
|
||||
var c2:Number = axis20.dot(vector);
|
||||
var t1:Number = (c2*k - c1)/det;
|
||||
if (t1 < -edgeHalfLength1 || t1 > edgeHalfLength1) {
|
||||
vector.copy(bestMainAxis > 2 ? point1 : point2);
|
||||
} else {
|
||||
var t2:Number = (c2 - c1*k)/det;
|
||||
if (t2 < -edgeHalfLength2 || t2 > edgeHalfLength2) {
|
||||
vector.copy(bestMainAxis > 2 ? point1 : point2);
|
||||
} else {
|
||||
vector.x = 0.5*(point1.x + point2.x + axis10.x*t1 + axis20.x*t2);
|
||||
vector.y = 0.5*(point1.y + point2.y + axis10.y*t1 + axis20.y*t2);
|
||||
vector.z = 0.5*(point1.z + point2.z + axis10.z*t1 + axis20.z*t2);
|
||||
}
|
||||
}
|
||||
}
|
||||
collisionData.primitive1 = box1;
|
||||
collisionData.primitive2 = box2;
|
||||
collisionData.penetration = minOverlap;
|
||||
collisionData.collisionPoint.copy(vector);
|
||||
collisionData.collisionNormal.copy(collisionAxis);
|
||||
collisionData.pointAxisCode1 = pointEdgeCode1 | (axisIndex1 << 3) | 32;
|
||||
collisionData.pointAxisCode2 = pointEdgeCode2 | (axisIndex2 << 3) | 32;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param box1
|
||||
* @param box2
|
||||
* @param axis
|
||||
* @param axisIndex
|
||||
* @param vectorToBox1
|
||||
* @param bestAxis
|
||||
* @return
|
||||
*
|
||||
*/
|
||||
private function testAxis(box1:CollisionBox, box2:CollisionBox, axis:Point3D, axisIndex:int, vectorToBox1:Point3D):Boolean {
|
||||
if (axis.lengthSqr < 0.0001) {
|
||||
return true;
|
||||
}
|
||||
axis.normalize();
|
||||
|
||||
var overlap:Number = overlapOnAxis(box1, box2, axis, vectorToBox1);
|
||||
if (overlap <= 0) {
|
||||
return false;
|
||||
}
|
||||
if (overlap < minOverlap) {
|
||||
minOverlap = overlap;
|
||||
bestAxisIndex = axisIndex;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param box1
|
||||
* @param box2
|
||||
* @param axis
|
||||
* @param vectorToBox1
|
||||
* @return
|
||||
*
|
||||
*/
|
||||
public function overlapOnAxis(box1:CollisionBox, box2:CollisionBox, axis:Point3D, vectorToBox1:Point3D):Number {
|
||||
var m:Matrix3D = box1.transform;
|
||||
var d:Number = (m.a*axis.x + m.e*axis.y + m.i*axis.z)*box1.halfSize.x;
|
||||
var projection:Number = d < 0 ? -d : d;
|
||||
d = (m.b*axis.x + m.f*axis.y + m.j*axis.z)*box1.halfSize.y;
|
||||
projection += d < 0 ? -d : d;
|
||||
d = (m.c*axis.x + m.g*axis.y + m.k*axis.z)*box1.halfSize.z;
|
||||
projection += d < 0 ? -d : d;
|
||||
|
||||
m = box2.transform;
|
||||
d = (m.a*axis.x + m.e*axis.y + m.i*axis.z)*box2.halfSize.x;
|
||||
projection += d < 0 ? -d : d;
|
||||
d = (m.b*axis.x + m.f*axis.y + m.j*axis.z)*box2.halfSize.y;
|
||||
projection += d < 0 ? -d : d;
|
||||
d = (m.c*axis.x + m.g*axis.y + m.k*axis.z)*box2.halfSize.z;
|
||||
projection += d < 0 ? -d : d;
|
||||
|
||||
d = vectorToBox1.x*axis.x + vectorToBox1.y*axis.y + vectorToBox1.z*axis.z;
|
||||
if (d < 0) {
|
||||
d = -d;
|
||||
}
|
||||
|
||||
return projection - d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Заполняет данные о контакте грани первого бокса с вершиной второго.
|
||||
*
|
||||
* @param box1
|
||||
* @param box2
|
||||
* @param vectorToBox1
|
||||
* @param axisIndex
|
||||
* @param overlap
|
||||
* @param collisionData
|
||||
* @param swapBoxes поменять примитивы местами при записи данных
|
||||
*/
|
||||
private function fillPointBoxPenetrationData(box1:CollisionBox, box2:CollisionBox, vectorToBox1:Point3D, axisIndex:int, overlap:Number, collisionData:CollisionData):void {
|
||||
box1.transform.getAxis(axisIndex, collisionData.collisionNormal);
|
||||
if (collisionData.collisionNormal.dot(vectorToBox1) < 0) {
|
||||
collisionData.collisionNormal.invert();
|
||||
}
|
||||
|
||||
var pointCode:int;
|
||||
axis10.copy(box2.halfSize);
|
||||
box2.transform.getAxis(0, axis20);
|
||||
if (axis20.dot(collisionData.collisionNormal) < 0) {
|
||||
axis10.x = -axis10.x;
|
||||
pointCode |= 1;
|
||||
}
|
||||
box2.transform.getAxis(1, axis20);
|
||||
if (axis20.dot(collisionData.collisionNormal) < 0) {
|
||||
axis10.y = -axis10.y;
|
||||
pointCode |= 2;
|
||||
}
|
||||
box2.transform.getAxis(2, axis20);
|
||||
if (axis20.dot(collisionData.collisionNormal) < 0) {
|
||||
axis10.z = -axis10.z;
|
||||
pointCode |= 4;
|
||||
}
|
||||
axis10.transform(box2.transform);
|
||||
|
||||
collisionData.collisionPoint.copy(axis10);
|
||||
collisionData.penetration = overlap;
|
||||
collisionData.pointAxisCode1 = (axisIndex << 3) | 32;
|
||||
collisionData.pointAxisCode2 = pointCode;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package alternativa.physics.collision {
|
||||
|
||||
import alternativa.physics.altphysics;
|
||||
import alternativa.physics.rigid.RigidBody;
|
||||
import alternativa.types.Matrix3D;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
use namespace altphysics;
|
||||
|
||||
public class CollisionPrimitive {
|
||||
|
||||
public var position:Point3D = new Point3D();
|
||||
public var transform:Matrix3D = new Matrix3D();
|
||||
public var body:RigidBody;
|
||||
|
||||
public function CollisionPrimitive(body:RigidBody) {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public function updateTransform():void {
|
||||
transform.copy(body.transformMatrix);
|
||||
position.x = body.position.x;
|
||||
position.y = body.position.y;
|
||||
position.z = body.position.z;
|
||||
transform.d = position.x;
|
||||
transform.h = position.y;
|
||||
transform.l = position.z;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
77
0.0.0.18/src/alternativa/physics/force/.svn/all-wcprops
Normal file
77
0.0.0.18/src/alternativa/physics/force/.svn/all-wcprops
Normal file
@@ -0,0 +1,77 @@
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 100
|
||||
/!svn/ver/4732/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/force
|
||||
END
|
||||
ParticleAnchoredBungee.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 126
|
||||
/!svn/ver/4196/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/force/ParticleAnchoredBungee.as
|
||||
END
|
||||
ParticleBuoyancy.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 120
|
||||
/!svn/ver/4196/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/force/ParticleBuoyancy.as
|
||||
END
|
||||
RigidBodySpring.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 119
|
||||
/!svn/ver/4196/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/force/RigidBodySpring.as
|
||||
END
|
||||
ParticleDrag.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 116
|
||||
/!svn/ver/4196/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/force/ParticleDrag.as
|
||||
END
|
||||
IParticelForceGenerator.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 127
|
||||
/!svn/ver/4196/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/force/IParticelForceGenerator.as
|
||||
END
|
||||
RigidBodyGravity.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 120
|
||||
/!svn/ver/4196/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/force/RigidBodyGravity.as
|
||||
END
|
||||
ParticleSpring.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 118
|
||||
/!svn/ver/4196/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/force/ParticleSpring.as
|
||||
END
|
||||
RigidBodyAnchoredBungee.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 127
|
||||
/!svn/ver/4732/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/force/RigidBodyAnchoredBungee.as
|
||||
END
|
||||
ParticleBungee.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 118
|
||||
/!svn/ver/4196/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/force/ParticleBungee.as
|
||||
END
|
||||
ParticleGravity.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 119
|
||||
/!svn/ver/4196/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/force/ParticleGravity.as
|
||||
END
|
||||
ParticleAnchoredSpring.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 126
|
||||
/!svn/ver/4196/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/force/ParticleAnchoredSpring.as
|
||||
END
|
||||
IRigidBodyForceGenerator.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 128
|
||||
/!svn/ver/4196/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/force/IRigidBodyForceGenerator.as
|
||||
END
|
||||
172
0.0.0.18/src/alternativa/physics/force/.svn/entries
Normal file
172
0.0.0.18/src/alternativa/physics/force/.svn/entries
Normal file
@@ -0,0 +1,172 @@
|
||||
8
|
||||
|
||||
dir
|
||||
46043
|
||||
http://svndev.alternativaplatform.com/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/force
|
||||
http://svndev.alternativaplatform.com
|
||||
|
||||
|
||||
|
||||
2008-12-03T05:15:16.843707Z
|
||||
4732
|
||||
mike
|
||||
|
||||
|
||||
svn:special svn:externals svn:needs-lock
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
d9e2387a-1f3e-40e2-b57f-9df5970a2fa5
|
||||
|
||||
ParticleAnchoredBungee.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
ed65cd81f1a99df1cc3c04e061cc15fd
|
||||
2008-11-24T06:53:44.272574Z
|
||||
4196
|
||||
mike
|
||||
|
||||
ParticleBuoyancy.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
4479f6ebbce6c7326410485e5c62b9a9
|
||||
2008-11-24T06:53:44.272574Z
|
||||
4196
|
||||
mike
|
||||
|
||||
RigidBodySpring.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
3f0de100aebf0d3250e608872e6f3863
|
||||
2008-11-24T06:53:44.272574Z
|
||||
4196
|
||||
mike
|
||||
|
||||
ParticleDrag.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
1a8e8b326a47d4771d157259e43deb53
|
||||
2008-11-24T06:53:44.272574Z
|
||||
4196
|
||||
mike
|
||||
|
||||
IParticelForceGenerator.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
645a997b618f0708a8311054767340a7
|
||||
2008-11-24T06:53:44.272574Z
|
||||
4196
|
||||
mike
|
||||
|
||||
RigidBodyGravity.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
b206b142e125e9fe4a1775f8c4768b17
|
||||
2008-11-24T06:53:44.272574Z
|
||||
4196
|
||||
mike
|
||||
|
||||
ParticleSpring.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
fb5cb524f90e27812074bc2668c548d1
|
||||
2008-11-24T06:53:44.272574Z
|
||||
4196
|
||||
mike
|
||||
|
||||
RigidBodyAnchoredBungee.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
a64b67f4f850a73a3ffc226ab8fb0774
|
||||
2008-12-03T05:15:16.843707Z
|
||||
4732
|
||||
mike
|
||||
|
||||
ParticleBungee.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
d79408ff66b4c9d92f9a2be73417ba3b
|
||||
2008-11-24T06:53:44.272574Z
|
||||
4196
|
||||
mike
|
||||
|
||||
ParticleGravity.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
3b0d1310430d785b3ec7ffebf8ea7ea9
|
||||
2008-11-24T06:53:44.272574Z
|
||||
4196
|
||||
mike
|
||||
|
||||
ParticleAnchoredSpring.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
2a0eee0933c8973ec42bb28a8b0b7160
|
||||
2008-11-24T06:53:44.272574Z
|
||||
4196
|
||||
mike
|
||||
|
||||
IRigidBodyForceGenerator.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
824ea9b7a68dda215974882d6f32f892
|
||||
2008-11-24T06:53:44.272574Z
|
||||
4196
|
||||
mike
|
||||
|
||||
1
0.0.0.18/src/alternativa/physics/force/.svn/format
Normal file
1
0.0.0.18/src/alternativa/physics/force/.svn/format
Normal file
@@ -0,0 +1 @@
|
||||
8
|
||||
@@ -0,0 +1,7 @@
|
||||
package alternativa.physics.force {
|
||||
import alternativa.physics.particle.Particle;
|
||||
|
||||
public interface IParticelForceGenerator {
|
||||
function updateForce(particle:Particle, time:Number):void;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package alternativa.physics.force {
|
||||
import alternativa.physics.rigid.RigidBody;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public interface IRigidBodyForceGenerator {
|
||||
function updateForce(body:RigidBody, time:Number):void;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package alternativa.physics.force {
|
||||
import alternativa.physics.particle.Particle;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
public class ParticleAnchoredBungee implements IParticelForceGenerator {
|
||||
|
||||
private var force:Point3D = new Point3D();
|
||||
|
||||
private var anchor:Point3D;
|
||||
private var springCoeff:Number;
|
||||
private var restLength:Number;
|
||||
public var relaxed:Boolean;
|
||||
|
||||
public function ParticleAnchoredBungee(anchor:Point3D, springCoeff:Number, restLength:Number) {
|
||||
this.anchor = anchor;
|
||||
this.springCoeff = springCoeff;
|
||||
this.restLength = restLength;
|
||||
}
|
||||
|
||||
public function updateForce(particle:Particle, time:Number):void {
|
||||
force.x = particle.position.x - anchor.x;
|
||||
force.y = particle.position.y - anchor.y;
|
||||
force.z = particle.position.z - anchor.z;
|
||||
var len:Number = force.length;
|
||||
if (len < restLength) {
|
||||
relaxed = true;
|
||||
return;
|
||||
}
|
||||
relaxed = false;
|
||||
var k:Number = (restLength - len)*springCoeff/len;
|
||||
force.x *= k;
|
||||
force.y *= k;
|
||||
force.z *= k;
|
||||
particle.addForce(force);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package alternativa.physics.force {
|
||||
import alternativa.physics.particle.Particle;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
public class ParticleAnchoredSpring implements IParticelForceGenerator {
|
||||
|
||||
private var force:Point3D = new Point3D();
|
||||
|
||||
private var anchor:Point3D;
|
||||
private var springCoeff:Number;
|
||||
private var restLength:Number;
|
||||
|
||||
public function ParticleAnchoredSpring(anchor:Point3D, springCoeff:Number, restLength:Number) {
|
||||
this.anchor = anchor;
|
||||
this.springCoeff = springCoeff;
|
||||
this.restLength = restLength;
|
||||
}
|
||||
|
||||
public function updateForce(particle:Particle, time:Number):void {
|
||||
force.x = particle.position.x - anchor.x;
|
||||
force.y = particle.position.y - anchor.y;
|
||||
force.z = particle.position.z - anchor.z;
|
||||
var len:Number = force.length;
|
||||
var k:Number = (restLength - len)*springCoeff/len;
|
||||
force.x *= k;
|
||||
force.y *= k;
|
||||
force.z *= k;
|
||||
particle.addForce(force);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package alternativa.physics.force {
|
||||
import alternativa.physics.particle.Particle;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
public class ParticleBungee implements IParticelForceGenerator {
|
||||
|
||||
private var force:Point3D = new Point3D();
|
||||
|
||||
private var otherParticle:Particle;
|
||||
private var springCoeff:Number;
|
||||
private var restLength:Number;
|
||||
|
||||
public var relaxed:Boolean;
|
||||
|
||||
public function ParticleBungee(otherParticle:Particle, springCoeff:Number, restLength:Number) {
|
||||
this.otherParticle = otherParticle;
|
||||
this.springCoeff = springCoeff;
|
||||
this.restLength = restLength;
|
||||
}
|
||||
|
||||
public function updateForce(particle:Particle, time:Number):void {
|
||||
force.x = particle.position.x - otherParticle.position.x;
|
||||
force.y = particle.position.y - otherParticle.position.y;
|
||||
force.z = particle.position.z - otherParticle.position.z;
|
||||
var len:Number = force.length;
|
||||
if (len < restLength) {
|
||||
relaxed = true;
|
||||
return;
|
||||
}
|
||||
relaxed = false;
|
||||
var k:Number = (restLength - len)*springCoeff/len;
|
||||
force.x *= k;
|
||||
force.y *= k;
|
||||
force.z *= k;
|
||||
particle.addForce(force);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package alternativa.physics.force {
|
||||
import alternativa.physics.particle.Particle;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
public class ParticleBuoyancy implements IParticelForceGenerator {
|
||||
|
||||
private var force:Point3D = new Point3D();
|
||||
|
||||
private var maxDepth:Number;
|
||||
private var waterHeight:Number;
|
||||
private var volume:Number;
|
||||
private var liquidDensity:Number;
|
||||
|
||||
public function ParticleBuoyancy(maxDepth:Number, waterHeight:Number, volume:Number, liquidDensity:Number = 1000) {
|
||||
this.maxDepth = maxDepth;
|
||||
this.waterHeight = waterHeight;
|
||||
this.volume = volume;
|
||||
this.liquidDensity = liquidDensity;
|
||||
}
|
||||
|
||||
public function updateForce(particle:Particle, time:Number):void {
|
||||
var depth:Number = particle.position.y;
|
||||
if (depth > waterHeight + maxDepth) {
|
||||
return;
|
||||
}
|
||||
|
||||
force.x = 0;
|
||||
force.y = 0;
|
||||
if (depth <= waterHeight - maxDepth) {
|
||||
force.z = liquidDensity*volume;
|
||||
} else {
|
||||
force.z = liquidDensity*volume*(waterHeight + maxDepth - depth)/maxDepth*0.5;
|
||||
}
|
||||
particle.addForce(force);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package alternativa.physics.force {
|
||||
import alternativa.physics.particle.Particle;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
public class ParticleDrag implements IParticelForceGenerator {
|
||||
private var force:Point3D = new Point3D();
|
||||
|
||||
private var k1:Number;
|
||||
private var k2:Number;
|
||||
|
||||
public function ParticleDrag(k1:Number, k2:Number) {
|
||||
this.k1 = k1;
|
||||
this.k2 = k2;
|
||||
}
|
||||
|
||||
public function updateForce(particle:Particle, time:Number):void {
|
||||
force.x = particle.velocity.x;
|
||||
force.y = particle.velocity.y;
|
||||
force.z = particle.velocity.z;
|
||||
var len:Number = force.length;
|
||||
var coeff:Number = len;
|
||||
coeff = -(k1*coeff + k2*coeff*coeff)/len;
|
||||
force.x *= coeff;
|
||||
force.y *= coeff;
|
||||
force.z *= coeff;
|
||||
particle.addForce(force);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package alternativa.physics.force {
|
||||
import alternativa.physics.particle.Particle;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
public class ParticleGravity implements IParticelForceGenerator {
|
||||
private var force:Point3D = new Point3D();
|
||||
|
||||
private var _gravity:Point3D;
|
||||
|
||||
public function ParticleGravity(gravity:Point3D) {
|
||||
_gravity = gravity.clone();
|
||||
}
|
||||
|
||||
public function updateForce(particle:Particle, time:Number):void {
|
||||
if (!particle.hasFiniteMass()) {
|
||||
return;
|
||||
}
|
||||
force.x = _gravity.x*particle.mass;
|
||||
force.y = _gravity.y*particle.mass;
|
||||
force.z = _gravity.z*particle.mass;
|
||||
particle.addForce(force);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package alternativa.physics.force {
|
||||
import alternativa.physics.particle.Particle;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
public class ParticleSpring implements IParticelForceGenerator {
|
||||
|
||||
private var force:Point3D = new Point3D();
|
||||
|
||||
private var otherParticle:Particle;
|
||||
private var springCoeff:Number;
|
||||
private var restLength:Number;
|
||||
|
||||
public function ParticleSpring(otherParticle:Particle, springCoeff:Number, restLength:Number) {
|
||||
this.otherParticle = otherParticle;
|
||||
this.springCoeff = springCoeff;
|
||||
this.restLength = restLength;
|
||||
}
|
||||
|
||||
public function updateForce(particle:Particle, time:Number):void {
|
||||
force.x = particle.position.x - otherParticle.position.x;
|
||||
force.y = particle.position.y - otherParticle.position.y;
|
||||
force.z = particle.position.z - otherParticle.position.z;
|
||||
var len:Number = force.length;
|
||||
var k:Number = (restLength - len)*springCoeff/len;
|
||||
force.x *= k;
|
||||
force.y *= k;
|
||||
force.z *= k;
|
||||
particle.addForce(force);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package alternativa.physics.force {
|
||||
import alternativa.physics.*;
|
||||
import alternativa.physics.rigid.RigidBody;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
use namespace altphysics;
|
||||
|
||||
public class RigidBodyAnchoredBungee implements IRigidBodyForceGenerator {
|
||||
|
||||
private var vector1:Point3D = new Point3D();
|
||||
private var vector2:Point3D = new Point3D();
|
||||
|
||||
private var _connectionPoint:Point3D = new Point3D();
|
||||
private var _anchorPoint:Point3D = new Point3D();
|
||||
private var _springConstant:Number;
|
||||
private var _restLength:Number;
|
||||
|
||||
public function RigidBodyAnchoredBungee(connectionPoint:Point3D, anchorPoint:Point3D, springConstant:Number, restLength:Number) {
|
||||
_connectionPoint.copy(connectionPoint);
|
||||
_anchorPoint.copy(anchorPoint);
|
||||
_springConstant = springConstant;
|
||||
_restLength = restLength;
|
||||
}
|
||||
|
||||
public function updateForce(body:RigidBody, time:Number):void {
|
||||
// TODO: Оптимизировать!!!
|
||||
vector1.copy(_connectionPoint);
|
||||
vector1.transform(body.transformMatrix);
|
||||
vector2.copy(_anchorPoint);
|
||||
vector2.subtract(vector1);
|
||||
var len:Number = vector2.length;
|
||||
var magnitude:Number = len - _restLength;
|
||||
if (magnitude > 0) {
|
||||
magnitude *= _springConstant;
|
||||
vector2.multiply(magnitude/len);
|
||||
body.addForceAtPoint(vector2, vector1);
|
||||
}
|
||||
}
|
||||
|
||||
public function set anchorPoint(value:Point3D):void {
|
||||
_anchorPoint.copy(value);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package alternativa.physics.force {
|
||||
import alternativa.physics.*;
|
||||
import alternativa.physics.rigid.RigidBody;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
use namespace altphysics;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class RigidBodyGravity implements IRigidBodyForceGenerator {
|
||||
|
||||
private var _gravity:Point3D = new Point3D();
|
||||
|
||||
public function RigidBodyGravity(g:Point3D) {
|
||||
_gravity.copy(g);
|
||||
}
|
||||
|
||||
public function updateForce(body:RigidBody, time:Number):void {
|
||||
if (body.inverseMass == 0) {
|
||||
return;
|
||||
}
|
||||
body.addForceComponents(_gravity.x*body.mass, _gravity.y*body.mass, _gravity.z*body.mass);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package alternativa.physics.force {
|
||||
import alternativa.physics.*;
|
||||
import alternativa.physics.rigid.RigidBody;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
use namespace altphysics;
|
||||
|
||||
public class RigidBodySpring implements IRigidBodyForceGenerator {
|
||||
|
||||
private var vector1:Point3D = new Point3D();
|
||||
private var vector2:Point3D = new Point3D();
|
||||
|
||||
private var _connectionPoint:Point3D = new Point3D();
|
||||
private var _otherConnectionPoint:Point3D = new Point3D();
|
||||
private var _springConstant:Number;
|
||||
private var _restLength:Number;
|
||||
private var _otherBody:RigidBody;
|
||||
|
||||
public function RigidBodySpring(connectionPoint:Point3D, otherBody:RigidBody, otherConnectionPoint:Point3D, springConstant:Number, restLength:Number) {
|
||||
_connectionPoint.copy(connectionPoint);
|
||||
_otherConnectionPoint = otherConnectionPoint;
|
||||
_otherBody = otherBody;
|
||||
_springConstant = springConstant;
|
||||
_restLength = restLength;
|
||||
}
|
||||
|
||||
public function updateForce(body:RigidBody, time:Number):void {
|
||||
// TODO: Оптимизировать!!!
|
||||
vector1.copy(_connectionPoint);
|
||||
vector1.transform(body.transformMatrix);
|
||||
vector2.copy(_otherConnectionPoint);
|
||||
vector2.transform(_otherBody.transformMatrix);
|
||||
vector2.subtract(vector1);
|
||||
var len:Number = vector2.length;
|
||||
if (len == 0) {
|
||||
trace("[RigidBodySpring::updateForce] spring length is zero");
|
||||
}
|
||||
var magnitude:Number = len - _restLength;
|
||||
magnitude *= _springConstant;
|
||||
vector2.multiply(magnitude/len);
|
||||
body.addForceAtPoint(vector2, vector1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package alternativa.physics.force {
|
||||
import alternativa.physics.particle.Particle;
|
||||
|
||||
public interface IParticelForceGenerator {
|
||||
function updateForce(particle:Particle, time:Number):void;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package alternativa.physics.force {
|
||||
import alternativa.physics.rigid.RigidBody;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public interface IRigidBodyForceGenerator {
|
||||
function updateForce(body:RigidBody, time:Number):void;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package alternativa.physics.force {
|
||||
import alternativa.physics.particle.Particle;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
public class ParticleAnchoredBungee implements IParticelForceGenerator {
|
||||
|
||||
private var force:Point3D = new Point3D();
|
||||
|
||||
private var anchor:Point3D;
|
||||
private var springCoeff:Number;
|
||||
private var restLength:Number;
|
||||
public var relaxed:Boolean;
|
||||
|
||||
public function ParticleAnchoredBungee(anchor:Point3D, springCoeff:Number, restLength:Number) {
|
||||
this.anchor = anchor;
|
||||
this.springCoeff = springCoeff;
|
||||
this.restLength = restLength;
|
||||
}
|
||||
|
||||
public function updateForce(particle:Particle, time:Number):void {
|
||||
force.x = particle.position.x - anchor.x;
|
||||
force.y = particle.position.y - anchor.y;
|
||||
force.z = particle.position.z - anchor.z;
|
||||
var len:Number = force.length;
|
||||
if (len < restLength) {
|
||||
relaxed = true;
|
||||
return;
|
||||
}
|
||||
relaxed = false;
|
||||
var k:Number = (restLength - len)*springCoeff/len;
|
||||
force.x *= k;
|
||||
force.y *= k;
|
||||
force.z *= k;
|
||||
particle.addForce(force);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package alternativa.physics.force {
|
||||
import alternativa.physics.particle.Particle;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
public class ParticleAnchoredSpring implements IParticelForceGenerator {
|
||||
|
||||
private var force:Point3D = new Point3D();
|
||||
|
||||
private var anchor:Point3D;
|
||||
private var springCoeff:Number;
|
||||
private var restLength:Number;
|
||||
|
||||
public function ParticleAnchoredSpring(anchor:Point3D, springCoeff:Number, restLength:Number) {
|
||||
this.anchor = anchor;
|
||||
this.springCoeff = springCoeff;
|
||||
this.restLength = restLength;
|
||||
}
|
||||
|
||||
public function updateForce(particle:Particle, time:Number):void {
|
||||
force.x = particle.position.x - anchor.x;
|
||||
force.y = particle.position.y - anchor.y;
|
||||
force.z = particle.position.z - anchor.z;
|
||||
var len:Number = force.length;
|
||||
var k:Number = (restLength - len)*springCoeff/len;
|
||||
force.x *= k;
|
||||
force.y *= k;
|
||||
force.z *= k;
|
||||
particle.addForce(force);
|
||||
}
|
||||
}
|
||||
}
|
||||
38
0.0.0.18/src/alternativa/physics/force/ParticleBungee.as
Normal file
38
0.0.0.18/src/alternativa/physics/force/ParticleBungee.as
Normal file
@@ -0,0 +1,38 @@
|
||||
package alternativa.physics.force {
|
||||
import alternativa.physics.particle.Particle;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
public class ParticleBungee implements IParticelForceGenerator {
|
||||
|
||||
private var force:Point3D = new Point3D();
|
||||
|
||||
private var otherParticle:Particle;
|
||||
private var springCoeff:Number;
|
||||
private var restLength:Number;
|
||||
|
||||
public var relaxed:Boolean;
|
||||
|
||||
public function ParticleBungee(otherParticle:Particle, springCoeff:Number, restLength:Number) {
|
||||
this.otherParticle = otherParticle;
|
||||
this.springCoeff = springCoeff;
|
||||
this.restLength = restLength;
|
||||
}
|
||||
|
||||
public function updateForce(particle:Particle, time:Number):void {
|
||||
force.x = particle.position.x - otherParticle.position.x;
|
||||
force.y = particle.position.y - otherParticle.position.y;
|
||||
force.z = particle.position.z - otherParticle.position.z;
|
||||
var len:Number = force.length;
|
||||
if (len < restLength) {
|
||||
relaxed = true;
|
||||
return;
|
||||
}
|
||||
relaxed = false;
|
||||
var k:Number = (restLength - len)*springCoeff/len;
|
||||
force.x *= k;
|
||||
force.y *= k;
|
||||
force.z *= k;
|
||||
particle.addForce(force);
|
||||
}
|
||||
}
|
||||
}
|
||||
37
0.0.0.18/src/alternativa/physics/force/ParticleBuoyancy.as
Normal file
37
0.0.0.18/src/alternativa/physics/force/ParticleBuoyancy.as
Normal file
@@ -0,0 +1,37 @@
|
||||
package alternativa.physics.force {
|
||||
import alternativa.physics.particle.Particle;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
public class ParticleBuoyancy implements IParticelForceGenerator {
|
||||
|
||||
private var force:Point3D = new Point3D();
|
||||
|
||||
private var maxDepth:Number;
|
||||
private var waterHeight:Number;
|
||||
private var volume:Number;
|
||||
private var liquidDensity:Number;
|
||||
|
||||
public function ParticleBuoyancy(maxDepth:Number, waterHeight:Number, volume:Number, liquidDensity:Number = 1000) {
|
||||
this.maxDepth = maxDepth;
|
||||
this.waterHeight = waterHeight;
|
||||
this.volume = volume;
|
||||
this.liquidDensity = liquidDensity;
|
||||
}
|
||||
|
||||
public function updateForce(particle:Particle, time:Number):void {
|
||||
var depth:Number = particle.position.y;
|
||||
if (depth > waterHeight + maxDepth) {
|
||||
return;
|
||||
}
|
||||
|
||||
force.x = 0;
|
||||
force.y = 0;
|
||||
if (depth <= waterHeight - maxDepth) {
|
||||
force.z = liquidDensity*volume;
|
||||
} else {
|
||||
force.z = liquidDensity*volume*(waterHeight + maxDepth - depth)/maxDepth*0.5;
|
||||
}
|
||||
particle.addForce(force);
|
||||
}
|
||||
}
|
||||
}
|
||||
29
0.0.0.18/src/alternativa/physics/force/ParticleDrag.as
Normal file
29
0.0.0.18/src/alternativa/physics/force/ParticleDrag.as
Normal file
@@ -0,0 +1,29 @@
|
||||
package alternativa.physics.force {
|
||||
import alternativa.physics.particle.Particle;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
public class ParticleDrag implements IParticelForceGenerator {
|
||||
private var force:Point3D = new Point3D();
|
||||
|
||||
private var k1:Number;
|
||||
private var k2:Number;
|
||||
|
||||
public function ParticleDrag(k1:Number, k2:Number) {
|
||||
this.k1 = k1;
|
||||
this.k2 = k2;
|
||||
}
|
||||
|
||||
public function updateForce(particle:Particle, time:Number):void {
|
||||
force.x = particle.velocity.x;
|
||||
force.y = particle.velocity.y;
|
||||
force.z = particle.velocity.z;
|
||||
var len:Number = force.length;
|
||||
var coeff:Number = len;
|
||||
coeff = -(k1*coeff + k2*coeff*coeff)/len;
|
||||
force.x *= coeff;
|
||||
force.y *= coeff;
|
||||
force.z *= coeff;
|
||||
particle.addForce(force);
|
||||
}
|
||||
}
|
||||
}
|
||||
24
0.0.0.18/src/alternativa/physics/force/ParticleGravity.as
Normal file
24
0.0.0.18/src/alternativa/physics/force/ParticleGravity.as
Normal file
@@ -0,0 +1,24 @@
|
||||
package alternativa.physics.force {
|
||||
import alternativa.physics.particle.Particle;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
public class ParticleGravity implements IParticelForceGenerator {
|
||||
private var force:Point3D = new Point3D();
|
||||
|
||||
private var _gravity:Point3D;
|
||||
|
||||
public function ParticleGravity(gravity:Point3D) {
|
||||
_gravity = gravity.clone();
|
||||
}
|
||||
|
||||
public function updateForce(particle:Particle, time:Number):void {
|
||||
if (!particle.hasFiniteMass()) {
|
||||
return;
|
||||
}
|
||||
force.x = _gravity.x*particle.mass;
|
||||
force.y = _gravity.y*particle.mass;
|
||||
force.z = _gravity.z*particle.mass;
|
||||
particle.addForce(force);
|
||||
}
|
||||
}
|
||||
}
|
||||
31
0.0.0.18/src/alternativa/physics/force/ParticleSpring.as
Normal file
31
0.0.0.18/src/alternativa/physics/force/ParticleSpring.as
Normal file
@@ -0,0 +1,31 @@
|
||||
package alternativa.physics.force {
|
||||
import alternativa.physics.particle.Particle;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
public class ParticleSpring implements IParticelForceGenerator {
|
||||
|
||||
private var force:Point3D = new Point3D();
|
||||
|
||||
private var otherParticle:Particle;
|
||||
private var springCoeff:Number;
|
||||
private var restLength:Number;
|
||||
|
||||
public function ParticleSpring(otherParticle:Particle, springCoeff:Number, restLength:Number) {
|
||||
this.otherParticle = otherParticle;
|
||||
this.springCoeff = springCoeff;
|
||||
this.restLength = restLength;
|
||||
}
|
||||
|
||||
public function updateForce(particle:Particle, time:Number):void {
|
||||
force.x = particle.position.x - otherParticle.position.x;
|
||||
force.y = particle.position.y - otherParticle.position.y;
|
||||
force.z = particle.position.z - otherParticle.position.z;
|
||||
var len:Number = force.length;
|
||||
var k:Number = (restLength - len)*springCoeff/len;
|
||||
force.x *= k;
|
||||
force.y *= k;
|
||||
force.z *= k;
|
||||
particle.addForce(force);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package alternativa.physics.force {
|
||||
import alternativa.physics.*;
|
||||
import alternativa.physics.rigid.RigidBody;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
use namespace altphysics;
|
||||
|
||||
public class RigidBodyAnchoredBungee implements IRigidBodyForceGenerator {
|
||||
|
||||
private var vector1:Point3D = new Point3D();
|
||||
private var vector2:Point3D = new Point3D();
|
||||
|
||||
private var _connectionPoint:Point3D = new Point3D();
|
||||
private var _anchorPoint:Point3D = new Point3D();
|
||||
private var _springConstant:Number;
|
||||
private var _restLength:Number;
|
||||
|
||||
public function RigidBodyAnchoredBungee(connectionPoint:Point3D, anchorPoint:Point3D, springConstant:Number, restLength:Number) {
|
||||
_connectionPoint.copy(connectionPoint);
|
||||
_anchorPoint.copy(anchorPoint);
|
||||
_springConstant = springConstant;
|
||||
_restLength = restLength;
|
||||
}
|
||||
|
||||
public function updateForce(body:RigidBody, time:Number):void {
|
||||
// TODO: Оптимизировать!!!
|
||||
vector1.copy(_connectionPoint);
|
||||
vector1.transform(body.transformMatrix);
|
||||
vector2.copy(_anchorPoint);
|
||||
vector2.subtract(vector1);
|
||||
var len:Number = vector2.length;
|
||||
var magnitude:Number = len - _restLength;
|
||||
if (magnitude > 0) {
|
||||
magnitude *= _springConstant;
|
||||
vector2.multiply(magnitude/len);
|
||||
body.addForceAtPoint(vector2, vector1);
|
||||
}
|
||||
}
|
||||
|
||||
public function set anchorPoint(value:Point3D):void {
|
||||
_anchorPoint.copy(value);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
27
0.0.0.18/src/alternativa/physics/force/RigidBodyGravity.as
Normal file
27
0.0.0.18/src/alternativa/physics/force/RigidBodyGravity.as
Normal file
@@ -0,0 +1,27 @@
|
||||
package alternativa.physics.force {
|
||||
import alternativa.physics.*;
|
||||
import alternativa.physics.rigid.RigidBody;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
use namespace altphysics;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class RigidBodyGravity implements IRigidBodyForceGenerator {
|
||||
|
||||
private var _gravity:Point3D = new Point3D();
|
||||
|
||||
public function RigidBodyGravity(g:Point3D) {
|
||||
_gravity.copy(g);
|
||||
}
|
||||
|
||||
public function updateForce(body:RigidBody, time:Number):void {
|
||||
if (body.inverseMass == 0) {
|
||||
return;
|
||||
}
|
||||
body.addForceComponents(_gravity.x*body.mass, _gravity.y*body.mass, _gravity.z*body.mass);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
45
0.0.0.18/src/alternativa/physics/force/RigidBodySpring.as
Normal file
45
0.0.0.18/src/alternativa/physics/force/RigidBodySpring.as
Normal file
@@ -0,0 +1,45 @@
|
||||
package alternativa.physics.force {
|
||||
import alternativa.physics.*;
|
||||
import alternativa.physics.rigid.RigidBody;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
use namespace altphysics;
|
||||
|
||||
public class RigidBodySpring implements IRigidBodyForceGenerator {
|
||||
|
||||
private var vector1:Point3D = new Point3D();
|
||||
private var vector2:Point3D = new Point3D();
|
||||
|
||||
private var _connectionPoint:Point3D = new Point3D();
|
||||
private var _otherConnectionPoint:Point3D = new Point3D();
|
||||
private var _springConstant:Number;
|
||||
private var _restLength:Number;
|
||||
private var _otherBody:RigidBody;
|
||||
|
||||
public function RigidBodySpring(connectionPoint:Point3D, otherBody:RigidBody, otherConnectionPoint:Point3D, springConstant:Number, restLength:Number) {
|
||||
_connectionPoint.copy(connectionPoint);
|
||||
_otherConnectionPoint = otherConnectionPoint;
|
||||
_otherBody = otherBody;
|
||||
_springConstant = springConstant;
|
||||
_restLength = restLength;
|
||||
}
|
||||
|
||||
public function updateForce(body:RigidBody, time:Number):void {
|
||||
// TODO: Оптимизировать!!!
|
||||
vector1.copy(_connectionPoint);
|
||||
vector1.transform(body.transformMatrix);
|
||||
vector2.copy(_otherConnectionPoint);
|
||||
vector2.transform(_otherBody.transformMatrix);
|
||||
vector2.subtract(vector1);
|
||||
var len:Number = vector2.length;
|
||||
if (len == 0) {
|
||||
trace("[RigidBodySpring::updateForce] spring length is zero");
|
||||
}
|
||||
var magnitude:Number = len - _restLength;
|
||||
magnitude *= _springConstant;
|
||||
vector2.multiply(magnitude/len);
|
||||
body.addForceAtPoint(vector2, vector1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
53
0.0.0.18/src/alternativa/physics/particle/.svn/all-wcprops
Normal file
53
0.0.0.18/src/alternativa/physics/particle/.svn/all-wcprops
Normal file
@@ -0,0 +1,53 @@
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 103
|
||||
/!svn/ver/4378/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/particle
|
||||
END
|
||||
ParticleContact.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 122
|
||||
/!svn/ver/4196/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/particle/ParticleContact.as
|
||||
END
|
||||
ParticleContactResolver.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 130
|
||||
/!svn/ver/4196/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/particle/ParticleContactResolver.as
|
||||
END
|
||||
ParticleLink.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 119
|
||||
/!svn/ver/4196/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/particle/ParticleLink.as
|
||||
END
|
||||
Particle.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 115
|
||||
/!svn/ver/4196/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/particle/Particle.as
|
||||
END
|
||||
ParticleContactGenerator.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 131
|
||||
/!svn/ver/4196/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/particle/ParticleContactGenerator.as
|
||||
END
|
||||
ParticleRod.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 118
|
||||
/!svn/ver/4196/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/particle/ParticleRod.as
|
||||
END
|
||||
ParticleCable.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 120
|
||||
/!svn/ver/4196/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/particle/ParticleCable.as
|
||||
END
|
||||
ParticleWorld.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 120
|
||||
/!svn/ver/4378/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/particle/ParticleWorld.as
|
||||
END
|
||||
124
0.0.0.18/src/alternativa/physics/particle/.svn/entries
Normal file
124
0.0.0.18/src/alternativa/physics/particle/.svn/entries
Normal file
@@ -0,0 +1,124 @@
|
||||
8
|
||||
|
||||
dir
|
||||
46043
|
||||
http://svndev.alternativaplatform.com/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/particle
|
||||
http://svndev.alternativaplatform.com
|
||||
|
||||
|
||||
|
||||
2008-11-26T12:12:57.063201Z
|
||||
4378
|
||||
mike
|
||||
|
||||
|
||||
svn:special svn:externals svn:needs-lock
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
d9e2387a-1f3e-40e2-b57f-9df5970a2fa5
|
||||
|
||||
ParticleContact.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
af51b49cb3918bc31be32dca4a9ddff2
|
||||
2008-11-24T06:53:44.272574Z
|
||||
4196
|
||||
mike
|
||||
|
||||
ParticleContactResolver.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
09a37756afe614b640d36b5e474ae709
|
||||
2008-11-24T06:53:44.272574Z
|
||||
4196
|
||||
mike
|
||||
|
||||
ParticleLink.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
6313230f57ccdba2b80c3ab4306d9d02
|
||||
2008-11-24T06:53:44.272574Z
|
||||
4196
|
||||
mike
|
||||
|
||||
Particle.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
36a3a8de3fce54e29395a591388b0fd9
|
||||
2008-11-24T06:53:44.272574Z
|
||||
4196
|
||||
mike
|
||||
|
||||
ParticleContactGenerator.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
1d585c4b2678e36ed0d44403ed35bbac
|
||||
2008-11-24T06:53:44.272574Z
|
||||
4196
|
||||
mike
|
||||
|
||||
ParticleRod.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
a95a229bcce5f16576e8aa3bbee4d4b9
|
||||
2008-11-24T06:53:44.272574Z
|
||||
4196
|
||||
mike
|
||||
|
||||
ParticleCable.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
b289fc57f98c5170eb964493250a309d
|
||||
2008-11-24T06:53:44.272574Z
|
||||
4196
|
||||
mike
|
||||
|
||||
ParticleWorld.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
29ebff641b6d9cc9def3022dd679889f
|
||||
2008-11-26T12:12:57.063201Z
|
||||
4378
|
||||
mike
|
||||
|
||||
1
0.0.0.18/src/alternativa/physics/particle/.svn/format
Normal file
1
0.0.0.18/src/alternativa/physics/particle/.svn/format
Normal file
@@ -0,0 +1 @@
|
||||
8
|
||||
@@ -0,0 +1,78 @@
|
||||
package alternativa.physics.particle {
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
public class Particle {
|
||||
|
||||
private static var resultingAcceleration:Point3D = new Point3D();
|
||||
|
||||
public var position:Point3D = new Point3D();
|
||||
public var velocity:Point3D = new Point3D();
|
||||
public var acceleration:Point3D = new Point3D();
|
||||
public var accumulatedForce:Point3D = new Point3D();
|
||||
public var mass:Number;
|
||||
public var inverseMass:Number;
|
||||
public var damping:Number = 0.995;
|
||||
|
||||
public var next:Particle;
|
||||
|
||||
/**
|
||||
* @param mass масса частицы. Значение меньшее или равное нулю означает бесконечную массу.
|
||||
*/
|
||||
public function Particle(mass:Number = 0) {
|
||||
if (mass <= 0) {
|
||||
this.mass = 0;
|
||||
inverseMass = 0;
|
||||
} else {
|
||||
this.mass = mass;
|
||||
inverseMass = 1/mass;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param time время в секундах
|
||||
*/
|
||||
public function integrate(time:Number):void {
|
||||
if (time <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
position.x += velocity.x*time;
|
||||
position.y += velocity.y*time;
|
||||
position.z += velocity.z*time;
|
||||
|
||||
resultingAcceleration.x = acceleration.x + inverseMass*accumulatedForce.x;
|
||||
resultingAcceleration.y = acceleration.y + inverseMass*accumulatedForce.y;
|
||||
resultingAcceleration.z = acceleration.z + inverseMass*accumulatedForce.z;
|
||||
|
||||
velocity.x += resultingAcceleration.x*time;
|
||||
velocity.y += resultingAcceleration.y*time;
|
||||
velocity.z += resultingAcceleration.z*time;
|
||||
|
||||
var d:Number = Math.pow(damping, time);
|
||||
velocity.x *= d;
|
||||
velocity.y *= d;
|
||||
velocity.z *= d;
|
||||
|
||||
accumulatedForce.x = 0;
|
||||
accumulatedForce.y = 0;
|
||||
accumulatedForce.z = 0;
|
||||
}
|
||||
|
||||
public function clearForce():void {
|
||||
accumulatedForce.x = 0;
|
||||
accumulatedForce.y = 0;
|
||||
accumulatedForce.z = 0;
|
||||
}
|
||||
|
||||
public function addForce(force:Point3D):void {
|
||||
accumulatedForce.x += force.x;
|
||||
accumulatedForce.y += force.y;
|
||||
accumulatedForce.z += force.z;
|
||||
}
|
||||
|
||||
public function hasFiniteMass():Boolean {
|
||||
return inverseMass > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package alternativa.physics.particle {
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
public class ParticleCable extends ParticleLink {
|
||||
|
||||
private static var vector:Point3D = new Point3D();
|
||||
|
||||
public var maxLength:Number;
|
||||
public var restitution:Number;
|
||||
|
||||
public function ParticleCable(particle1:Particle, particle2:Particle, maxLength:Number, restitution:Number) {
|
||||
super(particle1, particle2);
|
||||
this.maxLength = maxLength;
|
||||
this.restitution = restitution;
|
||||
}
|
||||
|
||||
override protected function getCurrentLength():Number {
|
||||
var x:Number = particle1.position.x - particle2.position.x;
|
||||
var y:Number = particle1.position.y - particle2.position.y;
|
||||
var z:Number = particle1.position.z - particle2.position.z;
|
||||
return Math.sqrt(x*x + y*y + z*z);
|
||||
}
|
||||
|
||||
override public function fillContact(contact:ParticleContact):Boolean {
|
||||
// Для кабеля нормаль контакта направлена в сторону второй частицы
|
||||
vector.x = particle2.position.x - particle1.position.x;
|
||||
vector.y = particle2.position.y - particle1.position.y;
|
||||
vector.z = particle2.position.z - particle1.position.z;
|
||||
var len:Number = Math.sqrt(vector.x*vector.x + vector.y*vector.y + vector.z*vector.z);
|
||||
|
||||
if (len < maxLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
contact.particle1 = particle1;
|
||||
contact.particle2 = particle2;
|
||||
contact.contactNormal.x = vector.x;
|
||||
contact.contactNormal.y = vector.y;
|
||||
contact.contactNormal.z = vector.z;
|
||||
contact.penetration = len - maxLength;
|
||||
contact.restitution = restitution;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
package alternativa.physics.particle {
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
public class ParticleContact {
|
||||
|
||||
private static var vector:Point3D = new Point3D();
|
||||
|
||||
public var particle1:Particle;
|
||||
public var particle2:Particle;
|
||||
public var restitution:Number;
|
||||
public var penetration:Number;
|
||||
public var contactNormal:Point3D = new Point3D();
|
||||
public var isCollision:Boolean;
|
||||
public var frictionCoeff:Number = 0;
|
||||
|
||||
public var next:ParticleContact;
|
||||
public var index:int;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param particle1
|
||||
* @param particle2
|
||||
* @param restitution
|
||||
* @param contactNormal
|
||||
*/
|
||||
public function ParticleContact(index:int, particle1:Particle = null, particle2:Particle = null, contactNormal:Point3D = null, penetration:Number = 0, restitution:Number = 0) {
|
||||
this.index = index;
|
||||
this.particle1 = particle1;
|
||||
this.particle2 = particle2;
|
||||
if (contactNormal != null) {
|
||||
this.contactNormal.x = contactNormal.x;
|
||||
this.contactNormal.y = contactNormal.y;
|
||||
this.contactNormal.z = contactNormal.z;
|
||||
}
|
||||
this.penetration = penetration;
|
||||
this.restitution = restitution;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param time
|
||||
*/
|
||||
public function resolve(time:Number):void {
|
||||
resolveVelocity(time);
|
||||
resolveInterpenetration(time);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public function calculateSeparatingVelocity():Number {
|
||||
vector.x = particle1.velocity.x;
|
||||
vector.y = particle1.velocity.y;
|
||||
vector.z = particle1.velocity.z;
|
||||
if (particle2 != null) {
|
||||
vector.x -= particle2.velocity.x;
|
||||
vector.y -= particle2.velocity.y;
|
||||
vector.z -= particle2.velocity.z;
|
||||
}
|
||||
return vector.x*contactNormal.x + vector.y*contactNormal.y + vector.z*contactNormal.z;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param time
|
||||
*/
|
||||
private function resolveVelocity(time:Number):void {
|
||||
var separatingVelocity:Number = calculateSeparatingVelocity();
|
||||
if (separatingVelocity > 0) {
|
||||
return;
|
||||
}
|
||||
var newSeparatingVelocity:Number = -restitution*separatingVelocity;
|
||||
|
||||
var totalInverseMass:Number = particle1.inverseMass;
|
||||
if (particle2 != null) {
|
||||
totalInverseMass += particle2.inverseMass;
|
||||
}
|
||||
if (totalInverseMass <= 0) {
|
||||
// Пропускаем, т.к. обе частицы бесконечной массы
|
||||
return;
|
||||
}
|
||||
|
||||
// Обработка покоящихся контактов
|
||||
// Проверяем, не была ли относительная скорость приобретена только в течении одного кадра
|
||||
if (particle2 != null) {
|
||||
vector.x = particle1.acceleration.x - particle2.acceleration.x;
|
||||
vector.y = particle1.acceleration.y - particle2.acceleration.y;
|
||||
vector.z = particle1.acceleration.z - particle2.acceleration.z;
|
||||
} else {
|
||||
vector.x = particle1.acceleration.x;
|
||||
vector.y = particle1.acceleration.y;
|
||||
vector.z = particle1.acceleration.z;
|
||||
}
|
||||
var accCausedSepVelocity:Number = (vector.x*contactNormal.x + vector.y*contactNormal.y + vector.z*contactNormal.z)*time;
|
||||
|
||||
if (accCausedSepVelocity < 0) {
|
||||
// Вычтем скорость сближения, полученную под действием сил во время последнего кадра, из скорости разделения контакта
|
||||
newSeparatingVelocity += restitution*accCausedSepVelocity;
|
||||
if (newSeparatingVelocity < 0) {
|
||||
// Скорость разделения не может быть отрицательной
|
||||
newSeparatingVelocity = 0;
|
||||
}
|
||||
}
|
||||
|
||||
var impulse:Number = (newSeparatingVelocity - separatingVelocity)/totalInverseMass;
|
||||
vector.x = impulse*contactNormal.x;
|
||||
vector.y = impulse*contactNormal.y;
|
||||
vector.z = impulse*contactNormal.z;
|
||||
|
||||
particle1.velocity.x += vector.x*particle1.inverseMass;
|
||||
particle1.velocity.y += vector.y*particle1.inverseMass;
|
||||
particle1.velocity.z += vector.z*particle1.inverseMass;
|
||||
|
||||
if (particle2 != null) {
|
||||
particle2.velocity.x -= vector.x*particle2.inverseMass;
|
||||
particle2.velocity.y -= vector.y*particle2.inverseMass;
|
||||
particle2.velocity.z -= vector.z*particle2.inverseMass;
|
||||
}
|
||||
|
||||
// if (isCollision) {
|
||||
// var tangentSpeed:Number = particle1.velocity.length;
|
||||
// var deltaSpeed:Number = frictionCoeff*particle1.inverseMass*impulse;
|
||||
// if (tangentSpeed < deltaSpeed) {
|
||||
// particle1.velocity.x = 0;
|
||||
// particle1.velocity.y = 0;
|
||||
// particle1.velocity.z = 0;
|
||||
// } else {
|
||||
// var k:Number = (tangentSpeed - deltaSpeed)/tangentSpeed;
|
||||
// particle1.velocity.x *= k;
|
||||
// particle1.velocity.y *= k;
|
||||
// particle1.velocity.z *= k;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param time
|
||||
*/
|
||||
private function resolveInterpenetration(time:Number):void {
|
||||
if (penetration <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var totalInverseMass:Number = particle1.inverseMass;
|
||||
if (particle2 != null) {
|
||||
totalInverseMass += particle2.inverseMass;
|
||||
}
|
||||
if (totalInverseMass <= 0) {
|
||||
// Пропускаем, т.к. обе частицы бесконечной массы
|
||||
return;
|
||||
}
|
||||
|
||||
var k:Number = penetration/totalInverseMass;
|
||||
|
||||
vector.x = k*contactNormal.x;
|
||||
vector.y = k*contactNormal.y;
|
||||
vector.z = k*contactNormal.z;
|
||||
|
||||
// trace("\nparticle1.position", particle1.position.z, particle1.velocity.z);
|
||||
particle1.position.x += vector.x*particle1.inverseMass;
|
||||
particle1.position.y += vector.y*particle1.inverseMass;
|
||||
particle1.position.z += vector.z*particle1.inverseMass;
|
||||
// trace("particle1.position", particle1.position.z, particle1.velocity.z);
|
||||
|
||||
if (particle2 != null) {
|
||||
particle2.position.x -= vector.x*particle2.inverseMass;
|
||||
particle2.position.y -= vector.y*particle2.inverseMass;
|
||||
particle2.position.z -= vector.z*particle2.inverseMass;
|
||||
}
|
||||
penetration = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package alternativa.physics.particle {
|
||||
|
||||
/**
|
||||
* Базовй класс для генераторов контактов. Реализует поддержку однонаправленного списока генераторов.
|
||||
*/
|
||||
public class ParticleContactGenerator {
|
||||
|
||||
/**
|
||||
* Следующий генератор в списке.
|
||||
*/
|
||||
public var next:ParticleContactGenerator;
|
||||
|
||||
/**
|
||||
* Метод создаёт информацию о контактах.
|
||||
*
|
||||
* @param contact первый свободный для записи контакт в списке контактов мира
|
||||
*
|
||||
* @return следующий свободный для записи контакт после того, как генератор записал свою информацию. Если возвращено значение null,
|
||||
* то значит список доступных контактов исчерпан.
|
||||
*/
|
||||
public function addContacts(contact:ParticleContact):ParticleContact {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package alternativa.physics.particle {
|
||||
public class ParticleContactResolver {
|
||||
|
||||
private var iterations:int;
|
||||
private var iterationsUsed:int;
|
||||
|
||||
public function ParticleContactResolver(iterations:int) {
|
||||
this.iterations = iterations;
|
||||
}
|
||||
|
||||
public function setIterations(value:int):void {
|
||||
iterations = value;
|
||||
}
|
||||
|
||||
public function resolveContacts(contacts:ParticleContact, contactsUsed:int, time:Number):void {
|
||||
resolveAllContacts(contacts, contactsUsed, time);
|
||||
// resolveCollisionContacts(contacts, contactsUsed, time);
|
||||
// resolveNonCollisionContacts(contacts, contactsUsed, time);
|
||||
}
|
||||
|
||||
private function resolveAllContacts(contacts:ParticleContact, contactsUsed:int, time:Number):void {
|
||||
iterationsUsed = 0;
|
||||
iterations = 5;
|
||||
while (iterationsUsed < iterations) {
|
||||
var maxSepVelocity:Number = 0;
|
||||
var maxPenetration:Number = 0;
|
||||
var mostSevereContact:ParticleContact = null;
|
||||
var contact:ParticleContact = contacts;
|
||||
while (contact.index < contactsUsed) {
|
||||
var sepVelocity:Number = contact.calculateSeparatingVelocity();
|
||||
if (sepVelocity < maxSepVelocity) {
|
||||
maxSepVelocity = sepVelocity;
|
||||
mostSevereContact = contact;
|
||||
}
|
||||
contact = contact.next;
|
||||
}
|
||||
if (mostSevereContact != null) {
|
||||
mostSevereContact.resolve(time);
|
||||
}
|
||||
iterationsUsed++;
|
||||
}
|
||||
}
|
||||
|
||||
private function resolveNonCollisionContacts(contacts:ParticleContact, contactsUsed:int, time:Number):void {
|
||||
iterationsUsed = 0;
|
||||
while (iterationsUsed < iterations) {
|
||||
var maxSepVelocity:Number = 0;
|
||||
var maxPenetration:Number = 0;
|
||||
var mostSevereContact:ParticleContact = null;
|
||||
var contact:ParticleContact = contacts;
|
||||
while (contact.index < contactsUsed) {
|
||||
if (!contact.isCollision) {
|
||||
var sepVelocity:Number = contact.calculateSeparatingVelocity();
|
||||
if (sepVelocity < maxSepVelocity) {
|
||||
maxSepVelocity = sepVelocity;
|
||||
mostSevereContact = contact;
|
||||
}
|
||||
}
|
||||
contact = contact.next;
|
||||
}
|
||||
if (mostSevereContact != null) {
|
||||
mostSevereContact.resolve(time);
|
||||
}
|
||||
iterationsUsed++;
|
||||
}
|
||||
}
|
||||
|
||||
private function resolveCollisionContacts(contacts:ParticleContact, contactsUsed:int, time:Number):void {
|
||||
var maxPenetration:Number = 0;
|
||||
var mostSevereContact:ParticleContact = null;
|
||||
var contact:ParticleContact = contacts;
|
||||
while (contact.index < contactsUsed) {
|
||||
if (contact.isCollision && contact.penetration > maxPenetration) {
|
||||
maxPenetration = contact.penetration;
|
||||
mostSevereContact = contact;
|
||||
}
|
||||
contact = contact.next;
|
||||
}
|
||||
if (mostSevereContact != null) {
|
||||
if (mostSevereContact.calculateSeparatingVelocity() < 0) {
|
||||
mostSevereContact.resolve(time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package alternativa.physics.particle {
|
||||
|
||||
public class ParticleLink {
|
||||
|
||||
public var particle1:Particle;
|
||||
public var particle2:Particle;
|
||||
|
||||
public function ParticleLink(particle1:Particle, particle2:Particle) {
|
||||
this.particle1 = particle1;
|
||||
this.particle2 = particle2;
|
||||
}
|
||||
|
||||
protected function getCurrentLength():Number {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function fillContact(contact:ParticleContact):Boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package alternativa.physics.particle {
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
public class ParticleRod extends ParticleLink {
|
||||
|
||||
private static var vector:Point3D = new Point3D();
|
||||
|
||||
public var length:Number;
|
||||
|
||||
public function ParticleRod(particle1:Particle, particle2:Particle, length:Number = 0) {
|
||||
super(particle1, particle2);
|
||||
if (length <= 0) {
|
||||
this.length = Point3D.difference(particle1.position, particle2.position).length;
|
||||
} else {
|
||||
this.length = length;
|
||||
}
|
||||
}
|
||||
|
||||
override protected function getCurrentLength():Number {
|
||||
var x:Number = particle1.position.x - particle2.position.x;
|
||||
var y:Number = particle1.position.y - particle2.position.y;
|
||||
var z:Number = particle1.position.z - particle2.position.z;
|
||||
return Math.sqrt(x*x + y*y + z*z);
|
||||
}
|
||||
|
||||
override public function fillContact(contact:ParticleContact):Boolean {
|
||||
vector.x = particle1.position.x - particle2.position.x;
|
||||
vector.y = particle1.position.y - particle2.position.y;
|
||||
vector.z = particle1.position.z - particle2.position.z;
|
||||
var len:Number = Math.sqrt(vector.x*vector.x + vector.y*vector.y + vector.z*vector.z);
|
||||
|
||||
if (len == length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var penetration:Number;
|
||||
if (len > length) {
|
||||
vector.x = -vector.x;
|
||||
vector.y = -vector.y;
|
||||
vector.z = -vector.z;
|
||||
penetration = len - length;
|
||||
} else {
|
||||
penetration = length - len;
|
||||
}
|
||||
|
||||
contact.particle1 = particle1;
|
||||
contact.particle2 = particle2;
|
||||
contact.contactNormal.x = vector.x/len;
|
||||
contact.contactNormal.y = vector.y/len;
|
||||
contact.contactNormal.z = vector.z/len;
|
||||
contact.penetration = penetration;
|
||||
contact.restitution = 0;
|
||||
contact.isCollision = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package alternativa.physics.particle {
|
||||
import alternativa.physics.particle.Particle;
|
||||
import alternativa.physics.particle.ParticleContact;
|
||||
import alternativa.physics.particle.ParticleContactGenerator;
|
||||
import alternativa.physics.particle.ParticleContactResolver;
|
||||
import alternativa.physics.registry.ParticleForceRegistry;
|
||||
|
||||
public class ParticleWorld {
|
||||
|
||||
public var particles:Particle;
|
||||
public var last:Particle;
|
||||
|
||||
public var contacts:ParticleContact;
|
||||
public var contactGenerators:ParticleContactGenerator;
|
||||
public var forceRegistry:ParticleForceRegistry;
|
||||
|
||||
public var resolver:ParticleContactResolver;
|
||||
|
||||
public var maxContacts:int;
|
||||
public var iterations:int;
|
||||
|
||||
public function ParticleWorld(maxContacts:int, iterations:int = 0) {
|
||||
this.maxContacts = maxContacts;
|
||||
this.iterations = iterations;
|
||||
|
||||
// Создаём контакты
|
||||
contacts = new ParticleContact(0);
|
||||
var contact:ParticleContact = contacts;
|
||||
for (var i:int = 1; i < maxContacts; i++) {
|
||||
contact = contact.next = new ParticleContact(i);
|
||||
}
|
||||
|
||||
resolver = new ParticleContactResolver(0);
|
||||
forceRegistry = new ParticleForceRegistry();
|
||||
}
|
||||
|
||||
public function addParticle(particle:Particle):void {
|
||||
if (particles == null) {
|
||||
last = particles = particle;
|
||||
} else {
|
||||
last.next = particle;
|
||||
last = particle;
|
||||
}
|
||||
}
|
||||
|
||||
public function addContactGenerator(generator:ParticleContactGenerator):void {
|
||||
if (contactGenerators == null) {
|
||||
contactGenerators = generator;
|
||||
} else {
|
||||
var gen:ParticleContactGenerator = contactGenerators;
|
||||
while (gen.next != null) {
|
||||
gen = gen.next;
|
||||
}
|
||||
gen.next = generator;
|
||||
}
|
||||
}
|
||||
|
||||
public function startFrame():void {
|
||||
var particle:Particle = particles;
|
||||
while (particle != null) {
|
||||
particle.clearForce();
|
||||
particle = particle.next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Последоавтельно запускает все зарегистрированные генераторы контактов.
|
||||
*
|
||||
* @return количество использованных контактов
|
||||
*/
|
||||
public function generateContacts():int {
|
||||
var contact:ParticleContact = contacts;
|
||||
var generator:ParticleContactGenerator = contactGenerators;
|
||||
while (generator != null) {
|
||||
contact = generator.addContacts(contact);
|
||||
if (contact == null) {
|
||||
// Доступные контакты исчерпаны
|
||||
return maxContacts;
|
||||
}
|
||||
generator = generator.next;
|
||||
}
|
||||
return contact.index;
|
||||
}
|
||||
|
||||
public function intergrate(time:Number):void {
|
||||
var particle:Particle = particles;
|
||||
while (particle != null) {
|
||||
particle.integrate(time);
|
||||
particle = particle.next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Запускает физическую симуляцию.
|
||||
*
|
||||
* @param time
|
||||
*/
|
||||
public function runPhysics(time:Number):void {
|
||||
// Применение генераторов сил
|
||||
forceRegistry.updateForces(time);
|
||||
// Запуск интеграторов для всех частиц
|
||||
intergrate(time);
|
||||
// Создание контактов
|
||||
var contactsUsed:int = generateContacts();
|
||||
// Обработка полученных контактов
|
||||
if (iterations == 0) {
|
||||
resolver.setIterations(3*contactsUsed);
|
||||
}
|
||||
resolver.resolveContacts(contacts, contactsUsed, time);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
78
0.0.0.18/src/alternativa/physics/particle/Particle.as
Normal file
78
0.0.0.18/src/alternativa/physics/particle/Particle.as
Normal file
@@ -0,0 +1,78 @@
|
||||
package alternativa.physics.particle {
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
public class Particle {
|
||||
|
||||
private static var resultingAcceleration:Point3D = new Point3D();
|
||||
|
||||
public var position:Point3D = new Point3D();
|
||||
public var velocity:Point3D = new Point3D();
|
||||
public var acceleration:Point3D = new Point3D();
|
||||
public var accumulatedForce:Point3D = new Point3D();
|
||||
public var mass:Number;
|
||||
public var inverseMass:Number;
|
||||
public var damping:Number = 0.995;
|
||||
|
||||
public var next:Particle;
|
||||
|
||||
/**
|
||||
* @param mass масса частицы. Значение меньшее или равное нулю означает бесконечную массу.
|
||||
*/
|
||||
public function Particle(mass:Number = 0) {
|
||||
if (mass <= 0) {
|
||||
this.mass = 0;
|
||||
inverseMass = 0;
|
||||
} else {
|
||||
this.mass = mass;
|
||||
inverseMass = 1/mass;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param time время в секундах
|
||||
*/
|
||||
public function integrate(time:Number):void {
|
||||
if (time <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
position.x += velocity.x*time;
|
||||
position.y += velocity.y*time;
|
||||
position.z += velocity.z*time;
|
||||
|
||||
resultingAcceleration.x = acceleration.x + inverseMass*accumulatedForce.x;
|
||||
resultingAcceleration.y = acceleration.y + inverseMass*accumulatedForce.y;
|
||||
resultingAcceleration.z = acceleration.z + inverseMass*accumulatedForce.z;
|
||||
|
||||
velocity.x += resultingAcceleration.x*time;
|
||||
velocity.y += resultingAcceleration.y*time;
|
||||
velocity.z += resultingAcceleration.z*time;
|
||||
|
||||
var d:Number = Math.pow(damping, time);
|
||||
velocity.x *= d;
|
||||
velocity.y *= d;
|
||||
velocity.z *= d;
|
||||
|
||||
accumulatedForce.x = 0;
|
||||
accumulatedForce.y = 0;
|
||||
accumulatedForce.z = 0;
|
||||
}
|
||||
|
||||
public function clearForce():void {
|
||||
accumulatedForce.x = 0;
|
||||
accumulatedForce.y = 0;
|
||||
accumulatedForce.z = 0;
|
||||
}
|
||||
|
||||
public function addForce(force:Point3D):void {
|
||||
accumulatedForce.x += force.x;
|
||||
accumulatedForce.y += force.y;
|
||||
accumulatedForce.z += force.z;
|
||||
}
|
||||
|
||||
public function hasFiniteMass():Boolean {
|
||||
return inverseMass > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
46
0.0.0.18/src/alternativa/physics/particle/ParticleCable.as
Normal file
46
0.0.0.18/src/alternativa/physics/particle/ParticleCable.as
Normal file
@@ -0,0 +1,46 @@
|
||||
package alternativa.physics.particle {
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
public class ParticleCable extends ParticleLink {
|
||||
|
||||
private static var vector:Point3D = new Point3D();
|
||||
|
||||
public var maxLength:Number;
|
||||
public var restitution:Number;
|
||||
|
||||
public function ParticleCable(particle1:Particle, particle2:Particle, maxLength:Number, restitution:Number) {
|
||||
super(particle1, particle2);
|
||||
this.maxLength = maxLength;
|
||||
this.restitution = restitution;
|
||||
}
|
||||
|
||||
override protected function getCurrentLength():Number {
|
||||
var x:Number = particle1.position.x - particle2.position.x;
|
||||
var y:Number = particle1.position.y - particle2.position.y;
|
||||
var z:Number = particle1.position.z - particle2.position.z;
|
||||
return Math.sqrt(x*x + y*y + z*z);
|
||||
}
|
||||
|
||||
override public function fillContact(contact:ParticleContact):Boolean {
|
||||
// Для кабеля нормаль контакта направлена в сторону второй частицы
|
||||
vector.x = particle2.position.x - particle1.position.x;
|
||||
vector.y = particle2.position.y - particle1.position.y;
|
||||
vector.z = particle2.position.z - particle1.position.z;
|
||||
var len:Number = Math.sqrt(vector.x*vector.x + vector.y*vector.y + vector.z*vector.z);
|
||||
|
||||
if (len < maxLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
contact.particle1 = particle1;
|
||||
contact.particle2 = particle2;
|
||||
contact.contactNormal.x = vector.x;
|
||||
contact.contactNormal.y = vector.y;
|
||||
contact.contactNormal.z = vector.z;
|
||||
contact.penetration = len - maxLength;
|
||||
contact.restitution = restitution;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
175
0.0.0.18/src/alternativa/physics/particle/ParticleContact.as
Normal file
175
0.0.0.18/src/alternativa/physics/particle/ParticleContact.as
Normal file
@@ -0,0 +1,175 @@
|
||||
package alternativa.physics.particle {
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
public class ParticleContact {
|
||||
|
||||
private static var vector:Point3D = new Point3D();
|
||||
|
||||
public var particle1:Particle;
|
||||
public var particle2:Particle;
|
||||
public var restitution:Number;
|
||||
public var penetration:Number;
|
||||
public var contactNormal:Point3D = new Point3D();
|
||||
public var isCollision:Boolean;
|
||||
public var frictionCoeff:Number = 0;
|
||||
|
||||
public var next:ParticleContact;
|
||||
public var index:int;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param particle1
|
||||
* @param particle2
|
||||
* @param restitution
|
||||
* @param contactNormal
|
||||
*/
|
||||
public function ParticleContact(index:int, particle1:Particle = null, particle2:Particle = null, contactNormal:Point3D = null, penetration:Number = 0, restitution:Number = 0) {
|
||||
this.index = index;
|
||||
this.particle1 = particle1;
|
||||
this.particle2 = particle2;
|
||||
if (contactNormal != null) {
|
||||
this.contactNormal.x = contactNormal.x;
|
||||
this.contactNormal.y = contactNormal.y;
|
||||
this.contactNormal.z = contactNormal.z;
|
||||
}
|
||||
this.penetration = penetration;
|
||||
this.restitution = restitution;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param time
|
||||
*/
|
||||
public function resolve(time:Number):void {
|
||||
resolveVelocity(time);
|
||||
resolveInterpenetration(time);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public function calculateSeparatingVelocity():Number {
|
||||
vector.x = particle1.velocity.x;
|
||||
vector.y = particle1.velocity.y;
|
||||
vector.z = particle1.velocity.z;
|
||||
if (particle2 != null) {
|
||||
vector.x -= particle2.velocity.x;
|
||||
vector.y -= particle2.velocity.y;
|
||||
vector.z -= particle2.velocity.z;
|
||||
}
|
||||
return vector.x*contactNormal.x + vector.y*contactNormal.y + vector.z*contactNormal.z;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param time
|
||||
*/
|
||||
private function resolveVelocity(time:Number):void {
|
||||
var separatingVelocity:Number = calculateSeparatingVelocity();
|
||||
if (separatingVelocity > 0) {
|
||||
return;
|
||||
}
|
||||
var newSeparatingVelocity:Number = -restitution*separatingVelocity;
|
||||
|
||||
var totalInverseMass:Number = particle1.inverseMass;
|
||||
if (particle2 != null) {
|
||||
totalInverseMass += particle2.inverseMass;
|
||||
}
|
||||
if (totalInverseMass <= 0) {
|
||||
// Пропускаем, т.к. обе частицы бесконечной массы
|
||||
return;
|
||||
}
|
||||
|
||||
// Обработка покоящихся контактов
|
||||
// Проверяем, не была ли относительная скорость приобретена только в течении одного кадра
|
||||
if (particle2 != null) {
|
||||
vector.x = particle1.acceleration.x - particle2.acceleration.x;
|
||||
vector.y = particle1.acceleration.y - particle2.acceleration.y;
|
||||
vector.z = particle1.acceleration.z - particle2.acceleration.z;
|
||||
} else {
|
||||
vector.x = particle1.acceleration.x;
|
||||
vector.y = particle1.acceleration.y;
|
||||
vector.z = particle1.acceleration.z;
|
||||
}
|
||||
var accCausedSepVelocity:Number = (vector.x*contactNormal.x + vector.y*contactNormal.y + vector.z*contactNormal.z)*time;
|
||||
|
||||
if (accCausedSepVelocity < 0) {
|
||||
// Вычтем скорость сближения, полученную под действием сил во время последнего кадра, из скорости разделения контакта
|
||||
newSeparatingVelocity += restitution*accCausedSepVelocity;
|
||||
if (newSeparatingVelocity < 0) {
|
||||
// Скорость разделения не может быть отрицательной
|
||||
newSeparatingVelocity = 0;
|
||||
}
|
||||
}
|
||||
|
||||
var impulse:Number = (newSeparatingVelocity - separatingVelocity)/totalInverseMass;
|
||||
vector.x = impulse*contactNormal.x;
|
||||
vector.y = impulse*contactNormal.y;
|
||||
vector.z = impulse*contactNormal.z;
|
||||
|
||||
particle1.velocity.x += vector.x*particle1.inverseMass;
|
||||
particle1.velocity.y += vector.y*particle1.inverseMass;
|
||||
particle1.velocity.z += vector.z*particle1.inverseMass;
|
||||
|
||||
if (particle2 != null) {
|
||||
particle2.velocity.x -= vector.x*particle2.inverseMass;
|
||||
particle2.velocity.y -= vector.y*particle2.inverseMass;
|
||||
particle2.velocity.z -= vector.z*particle2.inverseMass;
|
||||
}
|
||||
|
||||
// if (isCollision) {
|
||||
// var tangentSpeed:Number = particle1.velocity.length;
|
||||
// var deltaSpeed:Number = frictionCoeff*particle1.inverseMass*impulse;
|
||||
// if (tangentSpeed < deltaSpeed) {
|
||||
// particle1.velocity.x = 0;
|
||||
// particle1.velocity.y = 0;
|
||||
// particle1.velocity.z = 0;
|
||||
// } else {
|
||||
// var k:Number = (tangentSpeed - deltaSpeed)/tangentSpeed;
|
||||
// particle1.velocity.x *= k;
|
||||
// particle1.velocity.y *= k;
|
||||
// particle1.velocity.z *= k;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param time
|
||||
*/
|
||||
private function resolveInterpenetration(time:Number):void {
|
||||
if (penetration <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var totalInverseMass:Number = particle1.inverseMass;
|
||||
if (particle2 != null) {
|
||||
totalInverseMass += particle2.inverseMass;
|
||||
}
|
||||
if (totalInverseMass <= 0) {
|
||||
// Пропускаем, т.к. обе частицы бесконечной массы
|
||||
return;
|
||||
}
|
||||
|
||||
var k:Number = penetration/totalInverseMass;
|
||||
|
||||
vector.x = k*contactNormal.x;
|
||||
vector.y = k*contactNormal.y;
|
||||
vector.z = k*contactNormal.z;
|
||||
|
||||
// trace("\nparticle1.position", particle1.position.z, particle1.velocity.z);
|
||||
particle1.position.x += vector.x*particle1.inverseMass;
|
||||
particle1.position.y += vector.y*particle1.inverseMass;
|
||||
particle1.position.z += vector.z*particle1.inverseMass;
|
||||
// trace("particle1.position", particle1.position.z, particle1.velocity.z);
|
||||
|
||||
if (particle2 != null) {
|
||||
particle2.position.x -= vector.x*particle2.inverseMass;
|
||||
particle2.position.y -= vector.y*particle2.inverseMass;
|
||||
particle2.position.z -= vector.z*particle2.inverseMass;
|
||||
}
|
||||
penetration = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package alternativa.physics.particle {
|
||||
|
||||
/**
|
||||
* Базовй класс для генераторов контактов. Реализует поддержку однонаправленного списока генераторов.
|
||||
*/
|
||||
public class ParticleContactGenerator {
|
||||
|
||||
/**
|
||||
* Следующий генератор в списке.
|
||||
*/
|
||||
public var next:ParticleContactGenerator;
|
||||
|
||||
/**
|
||||
* Метод создаёт информацию о контактах.
|
||||
*
|
||||
* @param contact первый свободный для записи контакт в списке контактов мира
|
||||
*
|
||||
* @return следующий свободный для записи контакт после того, как генератор записал свою информацию. Если возвращено значение null,
|
||||
* то значит список доступных контактов исчерпан.
|
||||
*/
|
||||
public function addContacts(contact:ParticleContact):ParticleContact {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package alternativa.physics.particle {
|
||||
public class ParticleContactResolver {
|
||||
|
||||
private var iterations:int;
|
||||
private var iterationsUsed:int;
|
||||
|
||||
public function ParticleContactResolver(iterations:int) {
|
||||
this.iterations = iterations;
|
||||
}
|
||||
|
||||
public function setIterations(value:int):void {
|
||||
iterations = value;
|
||||
}
|
||||
|
||||
public function resolveContacts(contacts:ParticleContact, contactsUsed:int, time:Number):void {
|
||||
resolveAllContacts(contacts, contactsUsed, time);
|
||||
// resolveCollisionContacts(contacts, contactsUsed, time);
|
||||
// resolveNonCollisionContacts(contacts, contactsUsed, time);
|
||||
}
|
||||
|
||||
private function resolveAllContacts(contacts:ParticleContact, contactsUsed:int, time:Number):void {
|
||||
iterationsUsed = 0;
|
||||
iterations = 5;
|
||||
while (iterationsUsed < iterations) {
|
||||
var maxSepVelocity:Number = 0;
|
||||
var maxPenetration:Number = 0;
|
||||
var mostSevereContact:ParticleContact = null;
|
||||
var contact:ParticleContact = contacts;
|
||||
while (contact.index < contactsUsed) {
|
||||
var sepVelocity:Number = contact.calculateSeparatingVelocity();
|
||||
if (sepVelocity < maxSepVelocity) {
|
||||
maxSepVelocity = sepVelocity;
|
||||
mostSevereContact = contact;
|
||||
}
|
||||
contact = contact.next;
|
||||
}
|
||||
if (mostSevereContact != null) {
|
||||
mostSevereContact.resolve(time);
|
||||
}
|
||||
iterationsUsed++;
|
||||
}
|
||||
}
|
||||
|
||||
private function resolveNonCollisionContacts(contacts:ParticleContact, contactsUsed:int, time:Number):void {
|
||||
iterationsUsed = 0;
|
||||
while (iterationsUsed < iterations) {
|
||||
var maxSepVelocity:Number = 0;
|
||||
var maxPenetration:Number = 0;
|
||||
var mostSevereContact:ParticleContact = null;
|
||||
var contact:ParticleContact = contacts;
|
||||
while (contact.index < contactsUsed) {
|
||||
if (!contact.isCollision) {
|
||||
var sepVelocity:Number = contact.calculateSeparatingVelocity();
|
||||
if (sepVelocity < maxSepVelocity) {
|
||||
maxSepVelocity = sepVelocity;
|
||||
mostSevereContact = contact;
|
||||
}
|
||||
}
|
||||
contact = contact.next;
|
||||
}
|
||||
if (mostSevereContact != null) {
|
||||
mostSevereContact.resolve(time);
|
||||
}
|
||||
iterationsUsed++;
|
||||
}
|
||||
}
|
||||
|
||||
private function resolveCollisionContacts(contacts:ParticleContact, contactsUsed:int, time:Number):void {
|
||||
var maxPenetration:Number = 0;
|
||||
var mostSevereContact:ParticleContact = null;
|
||||
var contact:ParticleContact = contacts;
|
||||
while (contact.index < contactsUsed) {
|
||||
if (contact.isCollision && contact.penetration > maxPenetration) {
|
||||
maxPenetration = contact.penetration;
|
||||
mostSevereContact = contact;
|
||||
}
|
||||
contact = contact.next;
|
||||
}
|
||||
if (mostSevereContact != null) {
|
||||
if (mostSevereContact.calculateSeparatingVelocity() < 0) {
|
||||
mostSevereContact.resolve(time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
21
0.0.0.18/src/alternativa/physics/particle/ParticleLink.as
Normal file
21
0.0.0.18/src/alternativa/physics/particle/ParticleLink.as
Normal file
@@ -0,0 +1,21 @@
|
||||
package alternativa.physics.particle {
|
||||
|
||||
public class ParticleLink {
|
||||
|
||||
public var particle1:Particle;
|
||||
public var particle2:Particle;
|
||||
|
||||
public function ParticleLink(particle1:Particle, particle2:Particle) {
|
||||
this.particle1 = particle1;
|
||||
this.particle2 = particle2;
|
||||
}
|
||||
|
||||
protected function getCurrentLength():Number {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function fillContact(contact:ParticleContact):Boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
58
0.0.0.18/src/alternativa/physics/particle/ParticleRod.as
Normal file
58
0.0.0.18/src/alternativa/physics/particle/ParticleRod.as
Normal file
@@ -0,0 +1,58 @@
|
||||
package alternativa.physics.particle {
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
public class ParticleRod extends ParticleLink {
|
||||
|
||||
private static var vector:Point3D = new Point3D();
|
||||
|
||||
public var length:Number;
|
||||
|
||||
public function ParticleRod(particle1:Particle, particle2:Particle, length:Number = 0) {
|
||||
super(particle1, particle2);
|
||||
if (length <= 0) {
|
||||
this.length = Point3D.difference(particle1.position, particle2.position).length;
|
||||
} else {
|
||||
this.length = length;
|
||||
}
|
||||
}
|
||||
|
||||
override protected function getCurrentLength():Number {
|
||||
var x:Number = particle1.position.x - particle2.position.x;
|
||||
var y:Number = particle1.position.y - particle2.position.y;
|
||||
var z:Number = particle1.position.z - particle2.position.z;
|
||||
return Math.sqrt(x*x + y*y + z*z);
|
||||
}
|
||||
|
||||
override public function fillContact(contact:ParticleContact):Boolean {
|
||||
vector.x = particle1.position.x - particle2.position.x;
|
||||
vector.y = particle1.position.y - particle2.position.y;
|
||||
vector.z = particle1.position.z - particle2.position.z;
|
||||
var len:Number = Math.sqrt(vector.x*vector.x + vector.y*vector.y + vector.z*vector.z);
|
||||
|
||||
if (len == length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var penetration:Number;
|
||||
if (len > length) {
|
||||
vector.x = -vector.x;
|
||||
vector.y = -vector.y;
|
||||
vector.z = -vector.z;
|
||||
penetration = len - length;
|
||||
} else {
|
||||
penetration = length - len;
|
||||
}
|
||||
|
||||
contact.particle1 = particle1;
|
||||
contact.particle2 = particle2;
|
||||
contact.contactNormal.x = vector.x/len;
|
||||
contact.contactNormal.y = vector.y/len;
|
||||
contact.contactNormal.z = vector.z/len;
|
||||
contact.penetration = penetration;
|
||||
contact.restitution = 0;
|
||||
contact.isCollision = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
113
0.0.0.18/src/alternativa/physics/particle/ParticleWorld.as
Normal file
113
0.0.0.18/src/alternativa/physics/particle/ParticleWorld.as
Normal file
@@ -0,0 +1,113 @@
|
||||
package alternativa.physics.particle {
|
||||
import alternativa.physics.particle.Particle;
|
||||
import alternativa.physics.particle.ParticleContact;
|
||||
import alternativa.physics.particle.ParticleContactGenerator;
|
||||
import alternativa.physics.particle.ParticleContactResolver;
|
||||
import alternativa.physics.registry.ParticleForceRegistry;
|
||||
|
||||
public class ParticleWorld {
|
||||
|
||||
public var particles:Particle;
|
||||
public var last:Particle;
|
||||
|
||||
public var contacts:ParticleContact;
|
||||
public var contactGenerators:ParticleContactGenerator;
|
||||
public var forceRegistry:ParticleForceRegistry;
|
||||
|
||||
public var resolver:ParticleContactResolver;
|
||||
|
||||
public var maxContacts:int;
|
||||
public var iterations:int;
|
||||
|
||||
public function ParticleWorld(maxContacts:int, iterations:int = 0) {
|
||||
this.maxContacts = maxContacts;
|
||||
this.iterations = iterations;
|
||||
|
||||
// Создаём контакты
|
||||
contacts = new ParticleContact(0);
|
||||
var contact:ParticleContact = contacts;
|
||||
for (var i:int = 1; i < maxContacts; i++) {
|
||||
contact = contact.next = new ParticleContact(i);
|
||||
}
|
||||
|
||||
resolver = new ParticleContactResolver(0);
|
||||
forceRegistry = new ParticleForceRegistry();
|
||||
}
|
||||
|
||||
public function addParticle(particle:Particle):void {
|
||||
if (particles == null) {
|
||||
last = particles = particle;
|
||||
} else {
|
||||
last.next = particle;
|
||||
last = particle;
|
||||
}
|
||||
}
|
||||
|
||||
public function addContactGenerator(generator:ParticleContactGenerator):void {
|
||||
if (contactGenerators == null) {
|
||||
contactGenerators = generator;
|
||||
} else {
|
||||
var gen:ParticleContactGenerator = contactGenerators;
|
||||
while (gen.next != null) {
|
||||
gen = gen.next;
|
||||
}
|
||||
gen.next = generator;
|
||||
}
|
||||
}
|
||||
|
||||
public function startFrame():void {
|
||||
var particle:Particle = particles;
|
||||
while (particle != null) {
|
||||
particle.clearForce();
|
||||
particle = particle.next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Последоавтельно запускает все зарегистрированные генераторы контактов.
|
||||
*
|
||||
* @return количество использованных контактов
|
||||
*/
|
||||
public function generateContacts():int {
|
||||
var contact:ParticleContact = contacts;
|
||||
var generator:ParticleContactGenerator = contactGenerators;
|
||||
while (generator != null) {
|
||||
contact = generator.addContacts(contact);
|
||||
if (contact == null) {
|
||||
// Доступные контакты исчерпаны
|
||||
return maxContacts;
|
||||
}
|
||||
generator = generator.next;
|
||||
}
|
||||
return contact.index;
|
||||
}
|
||||
|
||||
public function intergrate(time:Number):void {
|
||||
var particle:Particle = particles;
|
||||
while (particle != null) {
|
||||
particle.integrate(time);
|
||||
particle = particle.next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Запускает физическую симуляцию.
|
||||
*
|
||||
* @param time
|
||||
*/
|
||||
public function runPhysics(time:Number):void {
|
||||
// Применение генераторов сил
|
||||
forceRegistry.updateForces(time);
|
||||
// Запуск интеграторов для всех частиц
|
||||
intergrate(time);
|
||||
// Создание контактов
|
||||
var contactsUsed:int = generateContacts();
|
||||
// Обработка полученных контактов
|
||||
if (iterations == 0) {
|
||||
resolver.setIterations(3*contactsUsed);
|
||||
}
|
||||
resolver.resolveContacts(contacts, contactsUsed, time);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
29
0.0.0.18/src/alternativa/physics/registry/.svn/all-wcprops
Normal file
29
0.0.0.18/src/alternativa/physics/registry/.svn/all-wcprops
Normal file
@@ -0,0 +1,29 @@
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 103
|
||||
/!svn/ver/4196/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/registry
|
||||
END
|
||||
ParticleForceRegistration.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 132
|
||||
/!svn/ver/4196/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/registry/ParticleForceRegistration.as
|
||||
END
|
||||
BodyForceRegistry.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 124
|
||||
/!svn/ver/4196/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/registry/BodyForceRegistry.as
|
||||
END
|
||||
BodyForceRegistration.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 128
|
||||
/!svn/ver/4196/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/registry/BodyForceRegistration.as
|
||||
END
|
||||
ParticleForceRegistry.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 128
|
||||
/!svn/ver/4196/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/registry/ParticleForceRegistry.as
|
||||
END
|
||||
76
0.0.0.18/src/alternativa/physics/registry/.svn/entries
Normal file
76
0.0.0.18/src/alternativa/physics/registry/.svn/entries
Normal file
@@ -0,0 +1,76 @@
|
||||
8
|
||||
|
||||
dir
|
||||
46043
|
||||
http://svndev.alternativaplatform.com/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/registry
|
||||
http://svndev.alternativaplatform.com
|
||||
|
||||
|
||||
|
||||
2008-11-24T06:53:44.272574Z
|
||||
4196
|
||||
mike
|
||||
|
||||
|
||||
svn:special svn:externals svn:needs-lock
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
d9e2387a-1f3e-40e2-b57f-9df5970a2fa5
|
||||
|
||||
ParticleForceRegistration.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
eacf3bd4d8f93fcaf786f50cccdc2be2
|
||||
2008-11-24T06:53:44.272574Z
|
||||
4196
|
||||
mike
|
||||
|
||||
BodyForceRegistry.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
bc7c7f17acaa538a68392942fe5b4ddf
|
||||
2008-11-24T06:53:44.272574Z
|
||||
4196
|
||||
mike
|
||||
|
||||
BodyForceRegistration.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
8b67908405c7eebf4c91e715ff7e26fd
|
||||
2008-11-24T06:53:44.272574Z
|
||||
4196
|
||||
mike
|
||||
|
||||
ParticleForceRegistry.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
ed017f73d079580385616a6cf0724645
|
||||
2008-11-24T06:53:44.272574Z
|
||||
4196
|
||||
mike
|
||||
|
||||
1
0.0.0.18/src/alternativa/physics/registry/.svn/format
Normal file
1
0.0.0.18/src/alternativa/physics/registry/.svn/format
Normal file
@@ -0,0 +1 @@
|
||||
8
|
||||
@@ -0,0 +1,16 @@
|
||||
package alternativa.physics.registry {
|
||||
import alternativa.physics.force.IRigidBodyForceGenerator;
|
||||
import alternativa.physics.rigid.RigidBody;
|
||||
|
||||
public class BodyForceRegistration {
|
||||
public var body:RigidBody;
|
||||
public var forceGenerator:IRigidBodyForceGenerator;
|
||||
|
||||
public var next:BodyForceRegistration;
|
||||
|
||||
public function BodyForceRegistration(body:RigidBody, forceGenerator:IRigidBodyForceGenerator) {
|
||||
this.body = body;
|
||||
this.forceGenerator = forceGenerator;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package alternativa.physics.registry {
|
||||
import alternativa.physics.force.IRigidBodyForceGenerator;
|
||||
import alternativa.physics.rigid.RigidBody;
|
||||
|
||||
public class BodyForceRegistry {
|
||||
|
||||
protected var registrations:BodyForceRegistration;
|
||||
|
||||
public function BodyForceRegistry() {
|
||||
}
|
||||
|
||||
public function add(body:RigidBody, fg:IRigidBodyForceGenerator):void {
|
||||
var registration:BodyForceRegistration = new BodyForceRegistration(body, fg);
|
||||
registration.next = registrations;
|
||||
registrations = registration;
|
||||
}
|
||||
|
||||
public function remove(body:RigidBody, fg:IRigidBodyForceGenerator):void {
|
||||
var current:BodyForceRegistration = registrations;
|
||||
var prev:BodyForceRegistration = null;
|
||||
while (current != null) {
|
||||
if (current.body == body && current.forceGenerator == fg) {
|
||||
if (current == registrations) {
|
||||
registrations = current.next;
|
||||
} else {
|
||||
prev.next = current.next;
|
||||
}
|
||||
break;
|
||||
}
|
||||
prev = current;
|
||||
current = current.next;
|
||||
}
|
||||
}
|
||||
|
||||
public function clear():void {
|
||||
registrations = null;
|
||||
}
|
||||
|
||||
public function updateForces(time:Number):void {
|
||||
var current:BodyForceRegistration = registrations;
|
||||
while (current != null) {
|
||||
current.forceGenerator.updateForce(current.body, time);
|
||||
current = current.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package alternativa.physics.registry {
|
||||
import alternativa.physics.force.IParticelForceGenerator;
|
||||
import alternativa.physics.particle.Particle;
|
||||
|
||||
public class ParticleForceRegistration {
|
||||
public var particle:Particle;
|
||||
public var forceGenerator:IParticelForceGenerator;
|
||||
|
||||
public var next:ParticleForceRegistration;
|
||||
|
||||
public function ParticleForceRegistration(particle:Particle, forceGenerator:IParticelForceGenerator) {
|
||||
this.particle = particle;
|
||||
this.forceGenerator = forceGenerator;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package alternativa.physics.registry {
|
||||
import alternativa.physics.force.IParticelForceGenerator;
|
||||
import alternativa.physics.particle.Particle;
|
||||
|
||||
public class ParticleForceRegistry {
|
||||
|
||||
protected var registrations:ParticleForceRegistration;
|
||||
|
||||
public function ParticleForceRegistry() {
|
||||
}
|
||||
|
||||
public function add(particle:Particle, fg:IParticelForceGenerator):void {
|
||||
var registration:ParticleForceRegistration = new ParticleForceRegistration(particle, fg);
|
||||
registration.next = registrations;
|
||||
registrations = registration;
|
||||
}
|
||||
|
||||
public function remove(particle:Particle, fg:IParticelForceGenerator):void {
|
||||
var current:ParticleForceRegistration = registrations;
|
||||
var prev:ParticleForceRegistration = null;
|
||||
while (current != null) {
|
||||
if (current.particle == particle && current.forceGenerator == fg) {
|
||||
if (current == registrations) {
|
||||
registrations = current.next;
|
||||
} else {
|
||||
prev.next = current.next;
|
||||
}
|
||||
break;
|
||||
}
|
||||
prev = current;
|
||||
current = current.next;
|
||||
}
|
||||
}
|
||||
|
||||
public function clear():void {
|
||||
registrations = null;
|
||||
}
|
||||
|
||||
public function updateForces(time:Number):void {
|
||||
var current:ParticleForceRegistration = registrations;
|
||||
while (current != null) {
|
||||
current.forceGenerator.updateForce(current.particle, time);
|
||||
current = current.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package alternativa.physics.registry {
|
||||
import alternativa.physics.force.IRigidBodyForceGenerator;
|
||||
import alternativa.physics.rigid.RigidBody;
|
||||
|
||||
public class BodyForceRegistration {
|
||||
public var body:RigidBody;
|
||||
public var forceGenerator:IRigidBodyForceGenerator;
|
||||
|
||||
public var next:BodyForceRegistration;
|
||||
|
||||
public function BodyForceRegistration(body:RigidBody, forceGenerator:IRigidBodyForceGenerator) {
|
||||
this.body = body;
|
||||
this.forceGenerator = forceGenerator;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package alternativa.physics.registry {
|
||||
import alternativa.physics.force.IRigidBodyForceGenerator;
|
||||
import alternativa.physics.rigid.RigidBody;
|
||||
|
||||
public class BodyForceRegistry {
|
||||
|
||||
protected var registrations:BodyForceRegistration;
|
||||
|
||||
public function BodyForceRegistry() {
|
||||
}
|
||||
|
||||
public function add(body:RigidBody, fg:IRigidBodyForceGenerator):void {
|
||||
var registration:BodyForceRegistration = new BodyForceRegistration(body, fg);
|
||||
registration.next = registrations;
|
||||
registrations = registration;
|
||||
}
|
||||
|
||||
public function remove(body:RigidBody, fg:IRigidBodyForceGenerator):void {
|
||||
var current:BodyForceRegistration = registrations;
|
||||
var prev:BodyForceRegistration = null;
|
||||
while (current != null) {
|
||||
if (current.body == body && current.forceGenerator == fg) {
|
||||
if (current == registrations) {
|
||||
registrations = current.next;
|
||||
} else {
|
||||
prev.next = current.next;
|
||||
}
|
||||
break;
|
||||
}
|
||||
prev = current;
|
||||
current = current.next;
|
||||
}
|
||||
}
|
||||
|
||||
public function clear():void {
|
||||
registrations = null;
|
||||
}
|
||||
|
||||
public function updateForces(time:Number):void {
|
||||
var current:BodyForceRegistration = registrations;
|
||||
while (current != null) {
|
||||
current.forceGenerator.updateForce(current.body, time);
|
||||
current = current.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package alternativa.physics.registry {
|
||||
import alternativa.physics.force.IParticelForceGenerator;
|
||||
import alternativa.physics.particle.Particle;
|
||||
|
||||
public class ParticleForceRegistration {
|
||||
public var particle:Particle;
|
||||
public var forceGenerator:IParticelForceGenerator;
|
||||
|
||||
public var next:ParticleForceRegistration;
|
||||
|
||||
public function ParticleForceRegistration(particle:Particle, forceGenerator:IParticelForceGenerator) {
|
||||
this.particle = particle;
|
||||
this.forceGenerator = forceGenerator;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package alternativa.physics.registry {
|
||||
import alternativa.physics.force.IParticelForceGenerator;
|
||||
import alternativa.physics.particle.Particle;
|
||||
|
||||
public class ParticleForceRegistry {
|
||||
|
||||
protected var registrations:ParticleForceRegistration;
|
||||
|
||||
public function ParticleForceRegistry() {
|
||||
}
|
||||
|
||||
public function add(particle:Particle, fg:IParticelForceGenerator):void {
|
||||
var registration:ParticleForceRegistration = new ParticleForceRegistration(particle, fg);
|
||||
registration.next = registrations;
|
||||
registrations = registration;
|
||||
}
|
||||
|
||||
public function remove(particle:Particle, fg:IParticelForceGenerator):void {
|
||||
var current:ParticleForceRegistration = registrations;
|
||||
var prev:ParticleForceRegistration = null;
|
||||
while (current != null) {
|
||||
if (current.particle == particle && current.forceGenerator == fg) {
|
||||
if (current == registrations) {
|
||||
registrations = current.next;
|
||||
} else {
|
||||
prev.next = current.next;
|
||||
}
|
||||
break;
|
||||
}
|
||||
prev = current;
|
||||
current = current.next;
|
||||
}
|
||||
}
|
||||
|
||||
public function clear():void {
|
||||
registrations = null;
|
||||
}
|
||||
|
||||
public function updateForces(time:Number):void {
|
||||
var current:ParticleForceRegistration = registrations;
|
||||
while (current != null) {
|
||||
current.forceGenerator.updateForce(current.particle, time);
|
||||
current = current.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
47
0.0.0.18/src/alternativa/physics/rigid/.svn/all-wcprops
Normal file
47
0.0.0.18/src/alternativa/physics/rigid/.svn/all-wcprops
Normal file
@@ -0,0 +1,47 @@
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 100
|
||||
/!svn/ver/5193/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/rigid
|
||||
END
|
||||
RigidBodyContactGenerator.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 129
|
||||
/!svn/ver/4732/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/rigid/RigidBodyContactGenerator.as
|
||||
END
|
||||
BodyForceRegistry.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 121
|
||||
/!svn/ver/4375/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/rigid/BodyForceRegistry.as
|
||||
END
|
||||
RigidWorld.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 114
|
||||
/!svn/ver/4741/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/rigid/RigidWorld.as
|
||||
END
|
||||
BodyForceRegistration.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 125
|
||||
/!svn/ver/4375/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/rigid/BodyForceRegistration.as
|
||||
END
|
||||
RigidBodyContact.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 120
|
||||
/!svn/ver/4813/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/rigid/RigidBodyContact.as
|
||||
END
|
||||
RigidBodyContactResolver.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 128
|
||||
/!svn/ver/4270/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/rigid/RigidBodyContactResolver.as
|
||||
END
|
||||
RigidBody.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 113
|
||||
/!svn/ver/5193/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/rigid/RigidBody.as
|
||||
END
|
||||
115
0.0.0.18/src/alternativa/physics/rigid/.svn/entries
Normal file
115
0.0.0.18/src/alternativa/physics/rigid/.svn/entries
Normal file
@@ -0,0 +1,115 @@
|
||||
8
|
||||
|
||||
dir
|
||||
46043
|
||||
http://svndev.alternativaplatform.com/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/rigid
|
||||
http://svndev.alternativaplatform.com
|
||||
|
||||
|
||||
|
||||
2008-12-17T11:38:42.040147Z
|
||||
5193
|
||||
mike
|
||||
|
||||
|
||||
svn:special svn:externals svn:needs-lock
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
d9e2387a-1f3e-40e2-b57f-9df5970a2fa5
|
||||
|
||||
RigidBodyContactGenerator.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
577dac0a54d7d990734d27170ddf1f14
|
||||
2008-12-03T05:15:16.843707Z
|
||||
4732
|
||||
mike
|
||||
|
||||
BodyForceRegistry.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
e2125f3fa80a45e6e3a304c33e5cbd47
|
||||
2008-11-26T12:04:03.108808Z
|
||||
4375
|
||||
mike
|
||||
|
||||
RigidWorld.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
0031086a4c4b3f39f81a0f224ad8560a
|
||||
2008-12-03T08:31:09.097064Z
|
||||
4741
|
||||
mike
|
||||
|
||||
generators
|
||||
dir
|
||||
|
||||
BodyForceRegistration.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
bed2d6357d27f7311216db6acd156c4e
|
||||
2008-11-26T12:04:03.108808Z
|
||||
4375
|
||||
mike
|
||||
|
||||
RigidBodyContact.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
473e71d1b8a62f4f9bcd94c2e38d26d6
|
||||
2008-12-10T13:18:05.069708Z
|
||||
4813
|
||||
mike
|
||||
|
||||
RigidBodyContactResolver.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
ad30ebb588f523d3255ce0a768a39b40
|
||||
2008-11-25T04:51:53.783696Z
|
||||
4270
|
||||
mike
|
||||
|
||||
RigidBody.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
8f0e9d6652c8f023b9c0b7a78135030d
|
||||
2008-12-17T11:38:42.040147Z
|
||||
5193
|
||||
mike
|
||||
|
||||
1
0.0.0.18/src/alternativa/physics/rigid/.svn/format
Normal file
1
0.0.0.18/src/alternativa/physics/rigid/.svn/format
Normal file
@@ -0,0 +1 @@
|
||||
8
|
||||
@@ -0,0 +1,16 @@
|
||||
package alternativa.physics.rigid {
|
||||
import alternativa.physics.force.IRigidBodyForceGenerator;
|
||||
import alternativa.physics.rigid.RigidBody;
|
||||
|
||||
public class BodyForceRegistration {
|
||||
public var body:RigidBody;
|
||||
public var forceGenerator:IRigidBodyForceGenerator;
|
||||
|
||||
public var next:BodyForceRegistration;
|
||||
|
||||
public function BodyForceRegistration(body:RigidBody, forceGenerator:IRigidBodyForceGenerator) {
|
||||
this.body = body;
|
||||
this.forceGenerator = forceGenerator;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package alternativa.physics.rigid {
|
||||
import alternativa.physics.force.IRigidBodyForceGenerator;
|
||||
import alternativa.physics.rigid.RigidBody;
|
||||
|
||||
public class BodyForceRegistry {
|
||||
|
||||
protected var registrations:BodyForceRegistration;
|
||||
|
||||
public function BodyForceRegistry() {
|
||||
}
|
||||
|
||||
public function add(body:RigidBody, fg:IRigidBodyForceGenerator):void {
|
||||
var registration:BodyForceRegistration = new BodyForceRegistration(body, fg);
|
||||
registration.next = registrations;
|
||||
registrations = registration;
|
||||
}
|
||||
|
||||
public function remove(body:RigidBody, fg:IRigidBodyForceGenerator):void {
|
||||
var current:BodyForceRegistration = registrations;
|
||||
var prev:BodyForceRegistration = null;
|
||||
while (current != null) {
|
||||
if (current.body == body && current.forceGenerator == fg) {
|
||||
if (current == registrations) {
|
||||
registrations = current.next;
|
||||
} else {
|
||||
prev.next = current.next;
|
||||
}
|
||||
break;
|
||||
}
|
||||
prev = current;
|
||||
current = current.next;
|
||||
}
|
||||
}
|
||||
|
||||
public function clear():void {
|
||||
registrations = null;
|
||||
}
|
||||
|
||||
public function updateForces(time:Number):void {
|
||||
var current:BodyForceRegistration = registrations;
|
||||
while (current != null) {
|
||||
current.forceGenerator.updateForce(current.body, time);
|
||||
current = current.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,707 @@
|
||||
package alternativa.physics.rigid {
|
||||
|
||||
import alternativa.physics.altphysics;
|
||||
import alternativa.types.Matrix3D;
|
||||
import alternativa.types.Point3D;
|
||||
import alternativa.types.Quaternion;
|
||||
|
||||
use namespace altphysics;
|
||||
|
||||
/**
|
||||
* Класс представляет твёрдое тело.
|
||||
*/
|
||||
public class RigidBody {
|
||||
|
||||
private var angularAcceleration:Point3D = new Point3D();
|
||||
private var motionThreshold:Number = 0.1;
|
||||
private var motionThreshold2:Number = 2*motionThreshold;
|
||||
private var baseBias:Number = 0.8;
|
||||
private var name:String;
|
||||
|
||||
public var next:RigidBody;
|
||||
public var prev:RigidBody;
|
||||
|
||||
altphysics var mass:Number;
|
||||
altphysics var inverseMass:Number;
|
||||
altphysics var inverseInertiaTensor:Matrix3D = new Matrix3D();
|
||||
|
||||
altphysics var linearDamping:Number = 0.95;
|
||||
altphysics var angularDamping:Number = 0.95;
|
||||
altphysics var awake:Boolean = true;
|
||||
altphysics var canSleep:Boolean = true;
|
||||
|
||||
altphysics var acceleration:Point3D = new Point3D();
|
||||
altphysics var angularVelocity:Point3D = new Point3D();
|
||||
|
||||
altphysics var position:Point3D = new Point3D();
|
||||
altphysics var orientation:Quaternion = new Quaternion(1, 0, 0, 0);
|
||||
altphysics var velocity:Point3D = new Point3D();
|
||||
altphysics var rotation:Point3D = new Point3D();
|
||||
altphysics var lastFrameAcceleration:Point3D = new Point3D();
|
||||
|
||||
altphysics var transformMatrix:Matrix3D = new Matrix3D();
|
||||
altphysics var inverseInertiaTensorWorld:Matrix3D = new Matrix3D();
|
||||
|
||||
altphysics var forceAccum:Point3D = new Point3D();
|
||||
altphysics var torqueAccum:Point3D = new Point3D();
|
||||
altphysics var motion:Number = 10;
|
||||
|
||||
/**
|
||||
* Создаёт новый экзепляр твёрдого тела.
|
||||
*
|
||||
* @param inverseMass величина, обратная массе тела. Значение 0 указывает, что тело имеет имеет бесконечную массу и момент инерции.
|
||||
* @param inverseInertiaTensor обратный тензор момента инерции тела. Значение <code>null</code> указывает, что тело имеет бесконечную массу и момент инерции.
|
||||
*/
|
||||
public function RigidBody(inverseMass:Number = 1, inverseInertiaTensor:Matrix3D = null) {
|
||||
if (inverseMass == 0 || inverseInertiaTensor == null) {
|
||||
setInfinteMass();
|
||||
} else {
|
||||
this.inverseMass = inverseMass;
|
||||
this.mass = 1/inverseMass;
|
||||
this.inverseInertiaTensor.copy(inverseInertiaTensor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return имя тела
|
||||
*/
|
||||
public function getName():String {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Устанавливает имя тела.
|
||||
*
|
||||
* @param value имя тела
|
||||
*/
|
||||
public function setName(value:String):void {
|
||||
name = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Предельное количество движения, ниже которого тело усыпляеся.
|
||||
*/
|
||||
public function getMotionThreshold():Number {
|
||||
return motionThreshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function setMotionThreshold(value:Number):void {
|
||||
motionThreshold = value;
|
||||
motionThreshold2 = value*2;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public function setBaseBias(value:Number):void {
|
||||
baseBias = value;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public function getBaseBias():Number {
|
||||
return baseBias;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function getMass():Number {
|
||||
return mass;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function setMass(value:Number):void {
|
||||
if (value <= 0) {
|
||||
inverseMass = 0;
|
||||
mass = 0;
|
||||
} else {
|
||||
mass = value;
|
||||
inverseMass = 1/value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function getInverseMass():Number {
|
||||
return inverseMass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function setInverseMass(value:Number):void {
|
||||
if (value > 0) {
|
||||
inverseMass = value;
|
||||
mass = 1/value;
|
||||
} else {
|
||||
inverseMass = 0;
|
||||
mass = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param m
|
||||
*/
|
||||
public function setIntertiaTensor(intertiaTensor:Matrix3D):void {
|
||||
inverseInertiaTensor.copy(intertiaTensor);
|
||||
inverseInertiaTensor.invert();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param intertiaTensor
|
||||
*/
|
||||
public function getIntertiaTensor(intertiaTensor:Matrix3D):void {
|
||||
intertiaTensor.copy(inverseInertiaTensor);
|
||||
intertiaTensor.invert();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param inverseInertiaTensor
|
||||
*/
|
||||
public function setInverseIntertiaTensor(inverseInertiaTensor:Matrix3D):void {
|
||||
this.inverseInertiaTensor.copy(inverseInertiaTensor);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param inverseInertiaTensor
|
||||
*/
|
||||
public function getInverseIntertiaTensor(inverseInertiaTensor:Matrix3D):void {
|
||||
inverseInertiaTensor.copy(this.inverseInertiaTensor);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function setInfinteMass():void {
|
||||
inverseMass = 0;
|
||||
mass = 0;
|
||||
inverseInertiaTensor.toIdentity();
|
||||
inverseInertiaTensor.a = inverseInertiaTensor.f = inverseInertiaTensor.k = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param linearDamping
|
||||
* @param angularDamping
|
||||
*/
|
||||
public function setDamping(linearDamping:Number, angularDamping:Number):void {
|
||||
this.linearDamping = linearDamping;
|
||||
this.angularDamping = angularDamping;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public function setLinearDamping(value:Number):void {
|
||||
linearDamping = value;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public function getLinearDamping():Number {
|
||||
return linearDamping;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public function setAngularDamping(value:Number):void {
|
||||
angularDamping = value;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public function getAngularDamping():Number {
|
||||
return angularDamping;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param position
|
||||
*/
|
||||
public function setPosition(position:Point3D):void {
|
||||
this.position.x = position.x;
|
||||
this.position.y = position.y;
|
||||
this.position.z = position.z;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
*/
|
||||
public function setPositionComponents(x:Number, y:Number, z:Number):void {
|
||||
position.x = x;
|
||||
position.y = y;
|
||||
position.z = z;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param position
|
||||
*/
|
||||
public function getPosition(position:Point3D):void {
|
||||
position.x = this.position.x;
|
||||
position.y = this.position.y;
|
||||
position.z = this.position.z;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param orientation
|
||||
*/
|
||||
public function setOrientation(orientation:Quaternion):void {
|
||||
this.orientation.copy(orientation);
|
||||
this.orientation.normalize();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param r
|
||||
* @param i
|
||||
* @param j
|
||||
* @param k
|
||||
*/
|
||||
public function setOrientationComponents(w:Number, x:Number, y:Number, z:Number):void {
|
||||
orientation.reset(w, x, y, z);
|
||||
orientation.normalize();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param orientation
|
||||
*/
|
||||
public function getOrientation(orientation:Quaternion):void {
|
||||
orientation.copy(this.orientation);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param matrix
|
||||
*/
|
||||
public function getTransformMatrix(matrix:Matrix3D):void {
|
||||
matrix.copy(transformMatrix);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param velocity
|
||||
*/
|
||||
public function setVelocity(velocity:Point3D):void {
|
||||
this.velocity.copy(velocity);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
*/
|
||||
public function setVelocityComponents(x:Number, y:Number, z:Number):void {
|
||||
velocity.reset(x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param velocity
|
||||
*/
|
||||
public function getVelocity(velocity:Point3D):void {
|
||||
velocity.copy(this.velocity);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param acceleration
|
||||
*
|
||||
*/
|
||||
public function setAcceleration(acceleration:Point3D):void {
|
||||
this.acceleration.copy(acceleration);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
*
|
||||
*/
|
||||
public function setAccelerationComponents(x:Number, y:Number, z:Number):void {
|
||||
acceleration.reset(x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param acceleration
|
||||
*
|
||||
*/
|
||||
public function getAcceleration(acceleration:Point3D):void {
|
||||
acceleration.copy(this.acceleration);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param rotation
|
||||
*
|
||||
*/
|
||||
public function setRotation(rotation:Point3D):void {
|
||||
this.rotation.copy(rotation);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
*
|
||||
*/
|
||||
public function setRotationComponents(x:Number, y:Number, z:Number):void {
|
||||
rotation.reset(x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param rotation
|
||||
*
|
||||
*/
|
||||
public function addRotation(deltaRotation:Point3D):void {
|
||||
rotation.add(deltaRotation);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param rotation
|
||||
*
|
||||
*/
|
||||
public function getRotation(rotation:Point3D):void {
|
||||
rotation.copy(this.rotation);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param angularVelocity
|
||||
*/
|
||||
public function setAngularVelocity(angularVelocity:Point3D):void {
|
||||
this.angularVelocity.x = angularVelocity.x;
|
||||
this.angularVelocity.y = angularVelocity.y;
|
||||
this.angularVelocity.z = angularVelocity.z;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
*/
|
||||
public function setAngularVelocityComponents(x:Number, y:Number, z:Number):void {
|
||||
angularVelocity.x = x;
|
||||
angularVelocity.y = y;
|
||||
angularVelocity.z = z;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param awake
|
||||
*/
|
||||
public function setAwake(awake:Boolean = true):void {
|
||||
this.awake = awake;
|
||||
if (awake) {
|
||||
motion = motionThreshold2;
|
||||
} else {
|
||||
velocity.x = 0;
|
||||
velocity.y = 0;
|
||||
velocity.z = 0;
|
||||
|
||||
rotation.x = 0;
|
||||
rotation.y = 0;
|
||||
rotation.z = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public function isAwake():Boolean {
|
||||
return awake;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param canSleep
|
||||
*/
|
||||
public function setCanSleep(canSleep:Boolean = true):void {
|
||||
this.canSleep = canSleep;
|
||||
if (!canSleep && !awake) {
|
||||
setAwake();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public function isCanSleep():Boolean {
|
||||
return canSleep;
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавляет глобальную силу, приложенную к центру масс тела.
|
||||
*
|
||||
* @param force вектор силы в глобальной системе координат
|
||||
*/
|
||||
public function addForce(force:Point3D):void {
|
||||
forceAccum.x += force.x;
|
||||
forceAccum.y += force.y;
|
||||
forceAccum.z += force.z;
|
||||
setAwake();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param force
|
||||
*/
|
||||
public function addForceComponents(x:Number, y:Number, z:Number):void {
|
||||
forceAccum.x += x;
|
||||
forceAccum.y += y;
|
||||
forceAccum.z += z;
|
||||
setAwake();
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавляет глобальную силу, приложенную к заданной локальной точке тела.
|
||||
*
|
||||
* @param force вектор силы в глобальной системе координат
|
||||
* @param localPoint локальные координаты точки приложения силы
|
||||
*/
|
||||
public function addForceAtLocalPoint(force:Point3D, localPoint:Point3D):void {
|
||||
forceAccum.x += force.x;
|
||||
forceAccum.y += force.y;
|
||||
forceAccum.z += force.z;
|
||||
// Трансформация локальных координат в глобальные
|
||||
var x:Number = transformMatrix.a*localPoint.x + transformMatrix.b*localPoint.y + transformMatrix.c*localPoint.z;
|
||||
var y:Number = transformMatrix.e*localPoint.x + transformMatrix.f*localPoint.y + transformMatrix.g*localPoint.z;
|
||||
var z:Number = transformMatrix.i*localPoint.x + transformMatrix.j*localPoint.y + transformMatrix.k*localPoint.z;
|
||||
torqueAccum.x += y*force.z - z*force.y;
|
||||
torqueAccum.y += z*force.x - x*force.z;
|
||||
torqueAccum.z += x*force.y - y*force.x;
|
||||
setAwake();
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавляет глобальную силу, приложенную к заданной точке тела, выраженной в глобальных координатах.
|
||||
*
|
||||
* @param force вектор силы в глобальной системе координат
|
||||
* @param point глобальные координаты точки приложения силы
|
||||
*/
|
||||
public function addForceAtPoint(force:Point3D, point:Point3D):void {
|
||||
forceAccum.x += force.x;
|
||||
forceAccum.y += force.y;
|
||||
forceAccum.z += force.z;
|
||||
var x:Number = point.x - position.x;
|
||||
var y:Number = point.y - position.y;
|
||||
var z:Number = point.z - position.z;
|
||||
torqueAccum.x += y*force.z - z*force.y;
|
||||
torqueAccum.y += z*force.x - x*force.z;
|
||||
torqueAccum.z += x*force.y - y*force.x;
|
||||
setAwake();
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавляет локальную силу, приложенную в заданной локальной точке тела.
|
||||
*
|
||||
* @param localForce вектор локальной силы
|
||||
* @param localPoint локальные координаты точки приложения силы
|
||||
*/
|
||||
public function addLocalForce(localForce:Point3D, localPoint:Point3D):void {
|
||||
// Трансформация локального вектора силы в глобальный
|
||||
var globalForceX:Number = transformMatrix.a*localForce.x + transformMatrix.b*localForce.y + transformMatrix.c*localForce.z;
|
||||
var globalForceY:Number = transformMatrix.e*localForce.x + transformMatrix.f*localForce.y + transformMatrix.g*localForce.z;
|
||||
var globalForceZ:Number = transformMatrix.i*localForce.x + transformMatrix.j*localForce.y + transformMatrix.k*localForce.z;
|
||||
forceAccum.x += globalForceX;
|
||||
forceAccum.y += globalForceY;
|
||||
forceAccum.z += globalForceZ;
|
||||
// Получение глобального вектора плеча силы
|
||||
var globalPointX:Number = transformMatrix.a*localPoint.x + transformMatrix.b*localPoint.y + transformMatrix.c*localPoint.z;
|
||||
var globalPointY:Number = transformMatrix.e*localPoint.x + transformMatrix.f*localPoint.y + transformMatrix.g*localPoint.z;
|
||||
var globalPointZ:Number = transformMatrix.i*localPoint.x + transformMatrix.j*localPoint.y + transformMatrix.k*localPoint.z;
|
||||
// Приращение момента силы
|
||||
torqueAccum.x += globalPointY*globalForceZ - globalPointZ*globalForceY;
|
||||
torqueAccum.y += globalPointZ*globalForceX - globalPointX*globalForceZ;
|
||||
torqueAccum.z += globalPointX*globalForceY - globalPointY*globalForceX;
|
||||
setAwake();
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавляет момент силы.
|
||||
*
|
||||
* @param torque вектор момента силы
|
||||
*/
|
||||
public function addTorque(torque:Point3D):void {
|
||||
torqueAccum.x += torque.x;
|
||||
torqueAccum.y += torque.y;
|
||||
torqueAccum.z += torque.z;
|
||||
setAwake();
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавляет момент силы, заданный покомпонентно.
|
||||
*/
|
||||
public function addTorqueComponents(x:Number, y:Number, z:Number):void {
|
||||
torqueAccum.x += x;
|
||||
torqueAccum.y += y;
|
||||
torqueAccum.z += z;
|
||||
setAwake();
|
||||
}
|
||||
|
||||
/**
|
||||
* Вычисляет векторные параметры тела в глобальной системе координат.
|
||||
*/
|
||||
public function calculateDerivedData():void {
|
||||
// inlined position.normalize()
|
||||
var d:Number = orientation.w*orientation.w + orientation.x*orientation.x + orientation.y*orientation.y + orientation.z*orientation.z;
|
||||
if (d == 0) {
|
||||
orientation.w = 1;
|
||||
} else {
|
||||
d = 1/Math.sqrt(d);
|
||||
orientation.w *= d;
|
||||
orientation.x *= d;
|
||||
orientation.y *= d;
|
||||
orientation.z *= d;
|
||||
}
|
||||
// Вычисление глобальной матрицы трансформации
|
||||
orientation.toMatrix3D(transformMatrix);
|
||||
transformMatrix.d = position.x;
|
||||
transformMatrix.h = position.y;
|
||||
transformMatrix.l = position.z;
|
||||
// Расчёт обратного тензора инерции в мировых координатах
|
||||
var a:Number = transformMatrix.a*inverseInertiaTensor.a + transformMatrix.b*inverseInertiaTensor.e + transformMatrix.c*inverseInertiaTensor.i;
|
||||
var b:Number = transformMatrix.a*inverseInertiaTensor.b + transformMatrix.b*inverseInertiaTensor.f + transformMatrix.c*inverseInertiaTensor.j;
|
||||
var c:Number = transformMatrix.a*inverseInertiaTensor.c + transformMatrix.b*inverseInertiaTensor.g + transformMatrix.c*inverseInertiaTensor.k;
|
||||
var e:Number = transformMatrix.e*inverseInertiaTensor.a + transformMatrix.f*inverseInertiaTensor.e + transformMatrix.g*inverseInertiaTensor.i;
|
||||
var f:Number = transformMatrix.e*inverseInertiaTensor.b + transformMatrix.f*inverseInertiaTensor.f + transformMatrix.g*inverseInertiaTensor.j;
|
||||
var g:Number = transformMatrix.e*inverseInertiaTensor.c + transformMatrix.f*inverseInertiaTensor.g + transformMatrix.g*inverseInertiaTensor.k;
|
||||
var i:Number = transformMatrix.i*inverseInertiaTensor.a + transformMatrix.j*inverseInertiaTensor.e + transformMatrix.k*inverseInertiaTensor.i;
|
||||
var j:Number = transformMatrix.i*inverseInertiaTensor.b + transformMatrix.j*inverseInertiaTensor.f + transformMatrix.k*inverseInertiaTensor.j;
|
||||
var k:Number = transformMatrix.i*inverseInertiaTensor.c + transformMatrix.j*inverseInertiaTensor.g + transformMatrix.k*inverseInertiaTensor.k;
|
||||
// Здесь подразумевается, что матрица трансформации тела не содержит масштабирования
|
||||
// Произведение [transformMatrix*inverseInertiaTensor]*transpose(transformMatrix)
|
||||
inverseInertiaTensorWorld.a = a*transformMatrix.a + b*transformMatrix.b + c*transformMatrix.c;
|
||||
inverseInertiaTensorWorld.b = a*transformMatrix.e + b*transformMatrix.f + c*transformMatrix.g;
|
||||
inverseInertiaTensorWorld.c = a*transformMatrix.i + b*transformMatrix.j + c*transformMatrix.k;
|
||||
inverseInertiaTensorWorld.e = e*transformMatrix.a + f*transformMatrix.b + g*transformMatrix.c;
|
||||
inverseInertiaTensorWorld.f = e*transformMatrix.e + f*transformMatrix.f + g*transformMatrix.g;
|
||||
inverseInertiaTensorWorld.g = e*transformMatrix.i + f*transformMatrix.j + g*transformMatrix.k;
|
||||
inverseInertiaTensorWorld.i = i*transformMatrix.a + j*transformMatrix.b + k*transformMatrix.c;
|
||||
inverseInertiaTensorWorld.j = i*transformMatrix.e + j*transformMatrix.f + k*transformMatrix.g;
|
||||
inverseInertiaTensorWorld.k = i*transformMatrix.i + j*transformMatrix.j + k*transformMatrix.k;
|
||||
}
|
||||
|
||||
/**
|
||||
* Интегрирует динамические характеристики и обновляет параметры состояния тела.
|
||||
*
|
||||
* @param time временной шаг интегрирования
|
||||
*/
|
||||
public function integrate(time:Number):void {
|
||||
if (!awake) {
|
||||
return;
|
||||
}
|
||||
|
||||
lastFrameAcceleration.x = acceleration.x + forceAccum.x*inverseMass;
|
||||
lastFrameAcceleration.y = acceleration.y + forceAccum.y*inverseMass;
|
||||
lastFrameAcceleration.z = acceleration.z + forceAccum.z*inverseMass;
|
||||
// angularAcceleration = inverseInertiaTensorWorld*torqueAccum
|
||||
angularAcceleration.x = inverseInertiaTensorWorld.a*torqueAccum.x + inverseInertiaTensorWorld.b*torqueAccum.y + inverseInertiaTensorWorld.c*torqueAccum.z;
|
||||
angularAcceleration.y = inverseInertiaTensorWorld.e*torqueAccum.x + inverseInertiaTensorWorld.f*torqueAccum.y + inverseInertiaTensorWorld.g*torqueAccum.z;
|
||||
angularAcceleration.z = inverseInertiaTensorWorld.i*torqueAccum.x + inverseInertiaTensorWorld.j*torqueAccum.y + inverseInertiaTensorWorld.k*torqueAccum.z;
|
||||
|
||||
var d:Number = Math.pow(linearDamping, time);
|
||||
var dtime:Number = d*time;
|
||||
|
||||
velocity.x += lastFrameAcceleration.x*dtime;
|
||||
velocity.y += lastFrameAcceleration.y*dtime;
|
||||
velocity.z += lastFrameAcceleration.z*dtime;
|
||||
|
||||
rotation.x += angularAcceleration.x*dtime;
|
||||
rotation.y += angularAcceleration.y*dtime;
|
||||
rotation.z += angularAcceleration.z*dtime;
|
||||
|
||||
rotation.x += angularVelocity.x*time;
|
||||
rotation.y += angularVelocity.y*time;
|
||||
rotation.z += angularVelocity.z*time;
|
||||
|
||||
position.x += velocity.x*time;
|
||||
position.y += velocity.y*time;
|
||||
position.z += velocity.z*time;
|
||||
|
||||
orientation.addScaledVector(rotation, time);
|
||||
|
||||
// TODO: Нужно ли двойное уменьшение скоростей?
|
||||
velocity.x *= d;
|
||||
velocity.y *= d;
|
||||
velocity.z *= d;
|
||||
|
||||
rotation.x *= d;
|
||||
rotation.y *= d;
|
||||
rotation.z *= d;
|
||||
|
||||
calculateDerivedData();
|
||||
// inlined clearAccumulators()
|
||||
forceAccum.x = 0;
|
||||
forceAccum.y = 0;
|
||||
forceAccum.z = 0;
|
||||
torqueAccum.x = 0;
|
||||
torqueAccum.y = 0;
|
||||
torqueAccum.z = 0;
|
||||
|
||||
// Усыпление тела при необходимости
|
||||
if (canSleep) {
|
||||
var currentMotion:Number = velocity.x*velocity.x + velocity.y*velocity.y + velocity.z*velocity.z +
|
||||
rotation.x*rotation.x + rotation.y*rotation.y + rotation.z*rotation.z;
|
||||
var bias:Number = Math.pow(baseBias, time);
|
||||
motion = bias*motion + (1 - bias)*currentMotion;
|
||||
// trace("[RigidBody::integrate]", name, "motion", motion, "motionEpsilon", motionEpsilon);
|
||||
if (motion < motionThreshold) {
|
||||
setAwake(false);
|
||||
} else {
|
||||
if (motion > motionThreshold2) {
|
||||
motion = motionThreshold2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function clearAccumulators():void {
|
||||
forceAccum.x = 0;
|
||||
forceAccum.y = 0;
|
||||
forceAccum.z = 0;
|
||||
torqueAccum.x = 0;
|
||||
torqueAccum.y = 0;
|
||||
torqueAccum.z = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,550 @@
|
||||
package alternativa.physics.rigid {
|
||||
|
||||
import alternativa.physics.*;
|
||||
import alternativa.types.Matrix3D;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
use namespace altphysics;
|
||||
|
||||
/**
|
||||
* Класс описывает контакт между телами. Контакты могут составлять двунаправленный список.
|
||||
*/
|
||||
public class RigidBodyContact {
|
||||
|
||||
private var tmpVelocityVector:Point3D = new Point3D();
|
||||
private var impulse:Point3D = new Point3D();
|
||||
|
||||
public static var velocityLimit:Number = 1;
|
||||
|
||||
/**
|
||||
* Ссылка на следующий контакт в списке.
|
||||
*/
|
||||
public var next:RigidBodyContact;
|
||||
/**
|
||||
* Ссылка на предыдущий контакт в списке.
|
||||
*/
|
||||
public var prev:RigidBodyContact;
|
||||
/**
|
||||
* Индекс контакта в списке.
|
||||
*/
|
||||
public var index:int;
|
||||
|
||||
/**
|
||||
* Первое тело, к которому относится контакт.
|
||||
*/
|
||||
public var body1:RigidBody;
|
||||
/**
|
||||
* Первое тело, к которому относится контакт (может быть null).
|
||||
*/
|
||||
public var body2:RigidBody;
|
||||
/**
|
||||
* Точка контакта.
|
||||
*/
|
||||
public var contactPoint:Point3D = new Point3D();
|
||||
/**
|
||||
* Нормаль контакта. Нормаль направлена от второго тела к первому. В локальной системе координат контакта
|
||||
* нормаль является базисным вектором, задающим направление оси X.
|
||||
*/
|
||||
public var contactNormal:Point3D = new Point3D();
|
||||
/**
|
||||
* Коэффициент взаимного трения в точке контакта.
|
||||
*/
|
||||
public var friction:Number = 0;
|
||||
/**
|
||||
* Коэффициент упругости удара.
|
||||
*/
|
||||
public var restitution:Number = 0;
|
||||
/**
|
||||
* Глубина взаимного проникновения тел в точке контакта.
|
||||
*/
|
||||
public var penetration:Number;
|
||||
|
||||
public var timeStamp:int;
|
||||
|
||||
/**
|
||||
* Матрица перехода из локальной системы координат контакта в мировую систему координат без компонентов параллельного переноса.
|
||||
* Матрица задаёт базис локальной системы координат контакта.
|
||||
*/
|
||||
altphysics var contactToWorld:Matrix3D = new Matrix3D();
|
||||
/**
|
||||
* Относительная скорость в точке контакта. Вычисляется в методе calculateInternals().
|
||||
*/
|
||||
altphysics var contactVelocity:Point3D = new Point3D();
|
||||
/**
|
||||
* Приращение скорости в точке контакта по направлению нормали, необходимое для прекращения сближения. Вычисляется в методе calculateInternals().
|
||||
*/
|
||||
altphysics var desiredDeltaVelocity:Number;
|
||||
/**
|
||||
* Координаты точки контакта относительныо первого тела. Вычисляется в методе calculateInternals().
|
||||
*/
|
||||
altphysics var relativeContactPosition1:Point3D = new Point3D();
|
||||
/**
|
||||
* Координаты точки контакта относительныо второго тела. Вычисляется в методе calculateInternals().
|
||||
*/
|
||||
altphysics var relativeContactPosition2:Point3D = new Point3D();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index
|
||||
*/
|
||||
public function RigidBodyContact(index:int) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param body1
|
||||
* @param body2
|
||||
* @param friction
|
||||
* @param restitution
|
||||
*/
|
||||
public function setBodyData(body1:RigidBody, body2:RigidBody, friction:Number, restitution:Number):void {
|
||||
this.body1 = body1;
|
||||
this.body2 = body2;
|
||||
this.friction = friction;
|
||||
this.restitution = restitution;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function matchAwakeState():void {
|
||||
if (body2 == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (body1.awake != body2.awake) {
|
||||
if (body1.awake) {
|
||||
body2.setAwake();
|
||||
} else {
|
||||
body1.setAwake();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Вычисляет и сохраняет базис локальной системы координат контакта.
|
||||
*/
|
||||
public function calculateContactBasis():void {
|
||||
// Нормаль является ортом X локальной системы координат
|
||||
contactToWorld.a = contactNormal.x;
|
||||
contactToWorld.e = contactNormal.y;
|
||||
contactToWorld.i = contactNormal.z;
|
||||
var nx:Number = contactNormal.x > 0 ? contactNormal.x : -contactNormal.x;
|
||||
var ny:Number = contactNormal.y > 0 ? contactNormal.y : -contactNormal.y;
|
||||
var s:Number;
|
||||
if (nx > ny) {
|
||||
// Нормаль ближе к глобальной оси X, используем ось Y для вычислений. Локальный орт Y находится как результат векторного произведения globalY x contactNormal.
|
||||
s = 1/Math.sqrt(nx*nx + contactNormal.z*contactNormal.z);
|
||||
contactToWorld.b = contactNormal.z*s;
|
||||
contactToWorld.f = 0;
|
||||
contactToWorld.j = -contactNormal.x*s;
|
||||
// Локальный орт Z находится как результат векторного произведения contactNormal x localY.
|
||||
contactToWorld.c = contactNormal.y*contactToWorld.j;
|
||||
contactToWorld.g = contactNormal.z*contactToWorld.b - contactNormal.x*contactToWorld.j;
|
||||
contactToWorld.k = -contactNormal.y*contactToWorld.b;
|
||||
} else {
|
||||
// Нормаль ближе к глобальной оси Y, используем ось X для вычислений. Локальный орт Y находится как результат векторного произведения globalX x contactNormal.
|
||||
s = 1/Math.sqrt(ny*ny + contactNormal.z*contactNormal.z);
|
||||
contactToWorld.b = 0;
|
||||
contactToWorld.f = -contactNormal.z*s;
|
||||
contactToWorld.j = contactNormal.y*s;
|
||||
// Локальный орт Z находится как результат векторного произведения contactNormal x localY.
|
||||
contactToWorld.c = contactNormal.y*contactToWorld.j - contactNormal.z*contactToWorld.f;
|
||||
contactToWorld.g = -contactNormal.x*contactToWorld.j;
|
||||
contactToWorld.k = contactNormal.x*contactToWorld.f;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Вычисляет скорость точки заданного тела в точке контакта в его локальной системе координат.
|
||||
*
|
||||
* @param body тело, для которого выполняются вычисления
|
||||
* @param relativeContactPosition положение точки контакта относительно тела
|
||||
* @param time временной шаг
|
||||
* @param result в эту переменную записывается результат
|
||||
*/
|
||||
public function calculateLocalVelocity(body:RigidBody, relativeContactPosition:Point3D, time:Number, result:Point3D):void {
|
||||
// Расчёт прироста скорости за последний кадр от действующих сил
|
||||
var x:Number = body.lastFrameAcceleration.x*time;
|
||||
var y:Number = body.lastFrameAcceleration.y*time;
|
||||
var z:Number = body.lastFrameAcceleration.z*time;
|
||||
// Прирост скорости в системе координат контакта
|
||||
// Убираем прирост скорости в направлении контакта
|
||||
var accVelocityY:Number = contactToWorld.b*x + contactToWorld.f*y + contactToWorld.j*z;
|
||||
var accVelocityZ:Number = contactToWorld.c*x + contactToWorld.g*y + contactToWorld.k*z;
|
||||
|
||||
// Скорость точки контакта в мировой системе координат
|
||||
// Скорость за счёт вращения тела
|
||||
var rotation:Point3D = body.rotation;
|
||||
x = rotation.y*relativeContactPosition.z - rotation.z*relativeContactPosition.y + body.velocity.x;
|
||||
y = rotation.z*relativeContactPosition.x - rotation.x*relativeContactPosition.z + body.velocity.y;
|
||||
z = rotation.x*relativeContactPosition.y - rotation.y*relativeContactPosition.x + body.velocity.z;
|
||||
// Скорость точки контакта в системе координат контакта
|
||||
// Касательные компоненты прироста скорости добавляются к скорости точки контакта. В дальнейшем они либо уберутся силой трения,
|
||||
// либо уменьшатся ею.
|
||||
result.x = contactToWorld.a*x + contactToWorld.e*y + contactToWorld.i*z;
|
||||
result.y = contactToWorld.b*x + contactToWorld.f*y + contactToWorld.j*z + accVelocityY;
|
||||
result.z = contactToWorld.c*x + contactToWorld.g*y + contactToWorld.k*z + accVelocityZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Вычисляет и устанавливает внутреннее значение для требуемого изменения относительной скорости вдоль нормали контакта.
|
||||
* С реакциями опоры разбираемся путём вычитания из скорости сближения прироста скорости, полученного во время последнего кадра.
|
||||
*
|
||||
* @param time
|
||||
*/
|
||||
public function calculateDesiredVelocity(time:Number):void {
|
||||
// Вычисляем проекцию прироста скорости за текущий кадр на нормаль контакта. Для относительного прироста скорости, вызывающего
|
||||
// сближение объектов, значение будет отрицательным.
|
||||
var velocityFromAcc:Number = 0;
|
||||
if (body1.awake) {
|
||||
velocityFromAcc = (body1.lastFrameAcceleration.x*contactNormal.x + body1.lastFrameAcceleration.y*contactNormal.y + body1.lastFrameAcceleration.z*contactNormal.z)*time;
|
||||
}
|
||||
if (body2 != null && body2.awake) {
|
||||
velocityFromAcc -= (body2.lastFrameAcceleration.x*contactNormal.x + body2.lastFrameAcceleration.y*contactNormal.y + body2.lastFrameAcceleration.z*contactNormal.z)*time;
|
||||
}
|
||||
// Если относительная скорость вдоль нормали контакта слишком мала, игнорируем её
|
||||
var thisRestitution:Number = restitution;
|
||||
if (contactVelocity.x > -velocityLimit && contactVelocity.x < velocityLimit) {
|
||||
thisRestitution = 0;
|
||||
}
|
||||
// Вычисляем дельту для скорости отскока, убрав влияние прироста скорости за последний кадр
|
||||
desiredDeltaVelocity = -contactVelocity.x - thisRestitution*(contactVelocity.x - velocityFromAcc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Расчитывает внутренние данные о контакта на основе данных о его состоянии. Вызывается до того, как будет запущен
|
||||
* алгоритм разрешения контактов. Эта функция в нормальных условиях никогда не должна вызываться вручную.
|
||||
*
|
||||
* @param time
|
||||
*/
|
||||
public function calculateInternals(time:Number):void {
|
||||
// Расчёт базиса системы координат контакта
|
||||
// === inlined calculateContactBasis();
|
||||
contactToWorld.a = contactNormal.x;
|
||||
contactToWorld.e = contactNormal.y;
|
||||
contactToWorld.i = contactNormal.z;
|
||||
var nx:Number = contactNormal.x > 0 ? contactNormal.x : -contactNormal.x;
|
||||
var ny:Number = contactNormal.y > 0 ? contactNormal.y : -contactNormal.y;
|
||||
var s:Number;
|
||||
if (nx > ny) {
|
||||
// Нормаль ближе к глобальной оси X, используем ось Y для вычислений. Локальный орт Y находится как результат векторного произведения globalY x contactNormal.
|
||||
s = 1/Math.sqrt(nx*nx + contactNormal.z*contactNormal.z);
|
||||
contactToWorld.b = contactNormal.z*s;
|
||||
contactToWorld.f = 0;
|
||||
contactToWorld.j = -contactNormal.x*s;
|
||||
// Локальный орт Z находится как результат векторного произведения contactNormal x localY.
|
||||
contactToWorld.c = contactNormal.y*contactToWorld.j;
|
||||
contactToWorld.g = contactNormal.z*contactToWorld.b - contactNormal.x*contactToWorld.j;
|
||||
contactToWorld.k = -contactNormal.y*contactToWorld.b;
|
||||
} else {
|
||||
// Нормаль ближе к глобальной оси Y, используем ось X для вычислений. Локальный орт Y находится как результат векторного произведения globalX x contactNormal.
|
||||
s = 1/Math.sqrt(ny*ny + contactNormal.z*contactNormal.z);
|
||||
contactToWorld.b = 0;
|
||||
contactToWorld.f = -contactNormal.z*s;
|
||||
contactToWorld.j = contactNormal.y*s;
|
||||
// Локальный орт Z находится как результат векторного произведения contactNormal x localY.
|
||||
contactToWorld.c = contactNormal.y*contactToWorld.j - contactNormal.z*contactToWorld.f;
|
||||
contactToWorld.g = -contactNormal.x*contactToWorld.j;
|
||||
contactToWorld.k = contactNormal.x*contactToWorld.f;
|
||||
}
|
||||
// === end inlined
|
||||
|
||||
// Расчёт локальной скорости в точке контакта для первого тела
|
||||
relativeContactPosition1.x = contactPoint.x - body1.position.x;
|
||||
relativeContactPosition1.y = contactPoint.y - body1.position.y;
|
||||
relativeContactPosition1.z = contactPoint.z - body1.position.z;
|
||||
calculateLocalVelocity(body1, relativeContactPosition1, time, contactVelocity);
|
||||
// Расчёт локальной скорости в точке контакта для второго тела
|
||||
if (body2 != null) {
|
||||
relativeContactPosition2.x = contactPoint.x - body2.position.x;
|
||||
relativeContactPosition2.y = contactPoint.y - body2.position.y;
|
||||
relativeContactPosition2.z = contactPoint.z - body2.position.z;
|
||||
calculateLocalVelocity(body2, relativeContactPosition2, time, tmpVelocityVector);
|
||||
// Расчёт относительной скорости в точке контакта
|
||||
contactVelocity.x -= tmpVelocityVector.x;
|
||||
contactVelocity.y -= tmpVelocityVector.y;
|
||||
contactVelocity.z -= tmpVelocityVector.z;
|
||||
}
|
||||
// Расчёт вектора изменения скорости, требуемого для разрешения контакта
|
||||
calculateDesiredVelocity(time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Выполняет разделение контакта посредством импульса, пропорционально инерции тел.
|
||||
*/
|
||||
public function applyVelocityChange(velocityChange1:Point3D, velocityChange2:Point3D, rotationChange1:Point3D, rotationChange2:Point3D):void {
|
||||
var inverseInertiaTensor1:Matrix3D = body1.inverseInertiaTensorWorld;
|
||||
var inverseInertiaTensor2:Matrix3D;
|
||||
if (body2 != null) {
|
||||
inverseInertiaTensor2 = body2.inverseInertiaTensorWorld;
|
||||
}
|
||||
|
||||
if (friction == 0) {
|
||||
calculateFrictionlessImpulse(inverseInertiaTensor1, inverseInertiaTensor2, impulse);
|
||||
} else {
|
||||
calculateFrictionImpulse(inverseInertiaTensor1, inverseInertiaTensor2, impulse);
|
||||
}
|
||||
|
||||
// Переведём импульс в мировые координаты
|
||||
var x:Number = impulse.x;
|
||||
var y:Number = impulse.y;
|
||||
var z:Number = impulse.z;
|
||||
impulse.x = contactToWorld.a*x + contactToWorld.b*y + contactToWorld.c*z;
|
||||
impulse.y = contactToWorld.e*x + contactToWorld.f*y + contactToWorld.g*z;
|
||||
impulse.z = contactToWorld.i*x + contactToWorld.j*y + contactToWorld.k*z;
|
||||
|
||||
// Разделим импульс на вращательную и линейную часть
|
||||
x = relativeContactPosition1.y*impulse.z - relativeContactPosition1.z*impulse.y;
|
||||
y = relativeContactPosition1.z*impulse.x - relativeContactPosition1.x*impulse.z;
|
||||
z = relativeContactPosition1.x*impulse.y - relativeContactPosition1.y*impulse.x;
|
||||
rotationChange1.x = inverseInertiaTensor1.a*x + inverseInertiaTensor1.b*y + inverseInertiaTensor1.c*z;
|
||||
rotationChange1.y = inverseInertiaTensor1.e*x + inverseInertiaTensor1.f*y + inverseInertiaTensor1.g*z;
|
||||
rotationChange1.z = inverseInertiaTensor1.i*x + inverseInertiaTensor1.j*y + inverseInertiaTensor1.k*z;
|
||||
|
||||
velocityChange1.x = impulse.x*body1.inverseMass;
|
||||
velocityChange1.y = impulse.y*body1.inverseMass;
|
||||
velocityChange1.z = impulse.z*body1.inverseMass;
|
||||
|
||||
body1.velocity.x += velocityChange1.x;
|
||||
body1.velocity.y += velocityChange1.y;
|
||||
body1.velocity.z += velocityChange1.z;
|
||||
|
||||
body1.rotation.x += rotationChange1.x;
|
||||
body1.rotation.y += rotationChange1.y;
|
||||
body1.rotation.z += rotationChange1.z;
|
||||
|
||||
if (body2 != null) {
|
||||
x = relativeContactPosition2.z*impulse.y - relativeContactPosition2.y*impulse.z;
|
||||
y = relativeContactPosition2.x*impulse.z - relativeContactPosition2.z*impulse.x;
|
||||
z = relativeContactPosition2.y*impulse.x - relativeContactPosition2.x*impulse.y;
|
||||
rotationChange2.x = inverseInertiaTensor2.a*x + inverseInertiaTensor2.b*y + inverseInertiaTensor2.c*z;
|
||||
rotationChange2.y = inverseInertiaTensor2.e*x + inverseInertiaTensor2.f*y + inverseInertiaTensor2.g*z;
|
||||
rotationChange2.z = inverseInertiaTensor2.i*x + inverseInertiaTensor2.j*y + inverseInertiaTensor2.k*z;
|
||||
|
||||
velocityChange2.x = -impulse.x*body2.inverseMass;
|
||||
velocityChange2.y = -impulse.y*body2.inverseMass;
|
||||
velocityChange2.z = -impulse.z*body2.inverseMass;
|
||||
|
||||
body2.velocity.x += velocityChange2.x;
|
||||
body2.velocity.y += velocityChange2.y;
|
||||
body2.velocity.z += velocityChange2.z;
|
||||
|
||||
body2.rotation.x += rotationChange2.x;
|
||||
body2.rotation.y += rotationChange2.y;
|
||||
body2.rotation.z += rotationChange2.z;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Вычисляет импульс, необходимый для коррекции скоростей в точке контакта в отсутствие сил трения.
|
||||
*/
|
||||
public function calculateFrictionlessImpulse(inverseInertiaTensor1:Matrix3D, inverseInertiaTensor2:Matrix3D, result:Point3D):void {
|
||||
tmpVelocityVector.x = relativeContactPosition1.y*contactNormal.z - relativeContactPosition1.z*contactNormal.y;
|
||||
tmpVelocityVector.y = relativeContactPosition1.z*contactNormal.x - relativeContactPosition1.x*contactNormal.z;
|
||||
tmpVelocityVector.z = relativeContactPosition1.x*contactNormal.y - relativeContactPosition1.y*contactNormal.x;
|
||||
|
||||
var x:Number = inverseInertiaTensor1.a*tmpVelocityVector.x + inverseInertiaTensor1.b*tmpVelocityVector.y + inverseInertiaTensor1.c*tmpVelocityVector.z;
|
||||
var y:Number = inverseInertiaTensor1.e*tmpVelocityVector.x + inverseInertiaTensor1.f*tmpVelocityVector.y + inverseInertiaTensor1.g*tmpVelocityVector.z;
|
||||
var z:Number = inverseInertiaTensor1.i*tmpVelocityVector.x + inverseInertiaTensor1.j*tmpVelocityVector.y + inverseInertiaTensor1.k*tmpVelocityVector.z;
|
||||
|
||||
tmpVelocityVector.x = y*relativeContactPosition1.z - z*relativeContactPosition1.y;
|
||||
tmpVelocityVector.y = z*relativeContactPosition1.x - x*relativeContactPosition1.z;
|
||||
tmpVelocityVector.z = x*relativeContactPosition1.y - y*relativeContactPosition1.x;
|
||||
|
||||
var deltaVelocity:Number = tmpVelocityVector.x*contactNormal.x + tmpVelocityVector.y*contactNormal.y + tmpVelocityVector.z*contactNormal.z + body1.inverseMass;
|
||||
|
||||
if (body2 != null) {
|
||||
tmpVelocityVector.x = relativeContactPosition2.y*contactNormal.z - relativeContactPosition2.z*contactNormal.y;
|
||||
tmpVelocityVector.y = relativeContactPosition2.z*contactNormal.x - relativeContactPosition2.x*contactNormal.z;
|
||||
tmpVelocityVector.z = relativeContactPosition2.x*contactNormal.y - relativeContactPosition2.y*contactNormal.x;
|
||||
|
||||
x = inverseInertiaTensor2.a*tmpVelocityVector.x + inverseInertiaTensor2.b*tmpVelocityVector.y + inverseInertiaTensor2.c*tmpVelocityVector.z;
|
||||
y = inverseInertiaTensor2.e*tmpVelocityVector.x + inverseInertiaTensor2.f*tmpVelocityVector.y + inverseInertiaTensor2.g*tmpVelocityVector.z;
|
||||
z = inverseInertiaTensor2.i*tmpVelocityVector.x + inverseInertiaTensor2.j*tmpVelocityVector.y + inverseInertiaTensor2.k*tmpVelocityVector.z;
|
||||
|
||||
tmpVelocityVector.x = y*relativeContactPosition2.z - z*relativeContactPosition2.y;
|
||||
tmpVelocityVector.y = z*relativeContactPosition2.x - x*relativeContactPosition2.z;
|
||||
tmpVelocityVector.z = x*relativeContactPosition2.y - y*relativeContactPosition2.x;
|
||||
|
||||
deltaVelocity += tmpVelocityVector.x*contactNormal.x + tmpVelocityVector.y*contactNormal.y + tmpVelocityVector.z*contactNormal.z + body2.inverseMass;
|
||||
}
|
||||
|
||||
result.x = desiredDeltaVelocity/deltaVelocity;
|
||||
result.y = 0;
|
||||
result.z = 0;
|
||||
}
|
||||
|
||||
private var impulseToTorque:Matrix3D = new Matrix3D();
|
||||
private var deltaVelWorldMatrix:Matrix3D = new Matrix3D();
|
||||
private var deltaVelWorldMatrix2:Matrix3D = new Matrix3D();
|
||||
/**
|
||||
* Вычисляет импульс, необходимый для коррекции скоростей в точке контакта при наличии сил трения.
|
||||
*/
|
||||
public function calculateFrictionImpulse(inverseInertiaTensor1:Matrix3D, inverseInertiaTensor2:Matrix3D, result:Point3D):void {
|
||||
var inverseMass:Number = body1.inverseMass;
|
||||
|
||||
relativeContactPosition1.createSkewSymmetricMatrix(impulseToTorque);
|
||||
|
||||
deltaVelWorldMatrix.copy(impulseToTorque);
|
||||
deltaVelWorldMatrix.inverseCombine(inverseInertiaTensor1);
|
||||
deltaVelWorldMatrix.inverseCombine(impulseToTorque);
|
||||
deltaVelWorldMatrix.multByScalar(-1);
|
||||
|
||||
if (body2 != null) {
|
||||
relativeContactPosition2.createSkewSymmetricMatrix(impulseToTorque);
|
||||
deltaVelWorldMatrix2.copy(impulseToTorque);
|
||||
deltaVelWorldMatrix2.inverseCombine(inverseInertiaTensor2);
|
||||
deltaVelWorldMatrix2.inverseCombine(impulseToTorque);
|
||||
deltaVelWorldMatrix2.multByScalar(-1);
|
||||
|
||||
deltaVelWorldMatrix.add(deltaVelWorldMatrix2);
|
||||
inverseMass += body2.inverseMass;
|
||||
}
|
||||
|
||||
deltaVelWorldMatrix2.copy(contactToWorld);
|
||||
deltaVelWorldMatrix2.transpose();
|
||||
deltaVelWorldMatrix2.inverseCombine(deltaVelWorldMatrix);
|
||||
deltaVelWorldMatrix2.inverseCombine(contactToWorld);
|
||||
deltaVelWorldMatrix2.a += inverseMass;
|
||||
deltaVelWorldMatrix2.f += inverseMass;
|
||||
deltaVelWorldMatrix2.k += inverseMass;
|
||||
|
||||
deltaVelWorldMatrix.copy(deltaVelWorldMatrix2);
|
||||
deltaVelWorldMatrix.invert();
|
||||
|
||||
result.reset(desiredDeltaVelocity, -contactVelocity.y, -contactVelocity.z);
|
||||
result.transform(deltaVelWorldMatrix);
|
||||
|
||||
var planarImpulse:Number = Math.sqrt(result.y*result.y + result.z*result.z);
|
||||
if (planarImpulse > result.x*friction) {
|
||||
result.y /= planarImpulse;
|
||||
result.z /= planarImpulse;
|
||||
result.x = desiredDeltaVelocity/(deltaVelWorldMatrix2.a + deltaVelWorldMatrix2.b*friction*result.y + deltaVelWorldMatrix2.c*friction*result.z);
|
||||
result.y *= friction*result.x;
|
||||
result.z *= friction*result.x;
|
||||
}
|
||||
}
|
||||
|
||||
private var angularInertiaWorld:Point3D = new Point3D();
|
||||
/**
|
||||
* Выполняет разделение контакта с учётом инертности тел.
|
||||
*/
|
||||
public function applyPositionChange(linearChange1:Point3D, linearChange2:Point3D, angularChange1:Point3D, angularChange2:Point3D, penetration:Number):void {
|
||||
var totalInertia:Number = 0;
|
||||
var angularInertia1:Number;
|
||||
var angularInertia2:Number;
|
||||
var linearInertia1:Number;
|
||||
var linearInertia2:Number;
|
||||
|
||||
// body1
|
||||
angularInertiaWorld.x = relativeContactPosition1.y*contactNormal.z - relativeContactPosition1.z*contactNormal.y;
|
||||
angularInertiaWorld.y = relativeContactPosition1.z*contactNormal.x - relativeContactPosition1.x*contactNormal.z;
|
||||
angularInertiaWorld.z = relativeContactPosition1.x*contactNormal.y - relativeContactPosition1.y*contactNormal.x;
|
||||
var m:Matrix3D = body1.inverseInertiaTensorWorld;
|
||||
var x:Number = m.a*angularInertiaWorld.x + m.b*angularInertiaWorld.y + m.c*angularInertiaWorld.z;
|
||||
var y:Number = m.e*angularInertiaWorld.x + m.f*angularInertiaWorld.y + m.g*angularInertiaWorld.z;
|
||||
var z:Number = m.i*angularInertiaWorld.x + m.j*angularInertiaWorld.y + m.k*angularInertiaWorld.z;
|
||||
angularInertiaWorld.x = y*relativeContactPosition1.z - z*relativeContactPosition1.y;
|
||||
angularInertiaWorld.y = z*relativeContactPosition1.x - x*relativeContactPosition1.z;
|
||||
angularInertiaWorld.z = x*relativeContactPosition1.y - y*relativeContactPosition1.x;
|
||||
|
||||
angularInertia1 = angularInertiaWorld.x*contactNormal.x + angularInertiaWorld.y*contactNormal.y + angularInertiaWorld.z*contactNormal.z;
|
||||
linearInertia1 = body1.inverseMass;
|
||||
|
||||
totalInertia = linearInertia1 + angularInertia1;
|
||||
|
||||
if (body2 != null) {
|
||||
angularInertiaWorld.x = relativeContactPosition2.y*contactNormal.z - relativeContactPosition2.z*contactNormal.y;
|
||||
angularInertiaWorld.y = relativeContactPosition2.z*contactNormal.x - relativeContactPosition2.x*contactNormal.z;
|
||||
angularInertiaWorld.z = relativeContactPosition2.x*contactNormal.y - relativeContactPosition2.y*contactNormal.x;
|
||||
m = body2.inverseInertiaTensorWorld;
|
||||
x = m.a*angularInertiaWorld.x + m.b*angularInertiaWorld.y + m.c*angularInertiaWorld.z;
|
||||
y = m.e*angularInertiaWorld.x + m.f*angularInertiaWorld.y + m.g*angularInertiaWorld.z;
|
||||
z = m.i*angularInertiaWorld.x + m.j*angularInertiaWorld.y + m.k*angularInertiaWorld.z;
|
||||
angularInertiaWorld.x = y*relativeContactPosition2.z - z*relativeContactPosition2.y;
|
||||
angularInertiaWorld.y = z*relativeContactPosition2.x - x*relativeContactPosition2.z;
|
||||
angularInertiaWorld.z = x*relativeContactPosition2.y - y*relativeContactPosition2.x;
|
||||
|
||||
angularInertia2 = angularInertiaWorld.x*contactNormal.x + angularInertiaWorld.y*contactNormal.y + angularInertiaWorld.z*contactNormal.z;
|
||||
linearInertia2 = body2.inverseMass;
|
||||
|
||||
totalInertia += linearInertia2 + angularInertia2;
|
||||
}
|
||||
|
||||
// body1
|
||||
applyPostionChangeToBody(body1, relativeContactPosition1, angularInertia1, linearInertia1, totalInertia, 1, angularChange1, linearChange1);
|
||||
|
||||
if (body2 != null) {
|
||||
applyPostionChangeToBody(body2, relativeContactPosition2, angularInertia2, linearInertia2, totalInertia, -1, angularChange2, linearChange2);
|
||||
}
|
||||
}
|
||||
|
||||
private var projection:Point3D = new Point3D();
|
||||
/**
|
||||
*
|
||||
* @param body
|
||||
* @param relativeContactPosition
|
||||
* @param angularInertia
|
||||
* @param linearInertia
|
||||
* @param totalInertia
|
||||
* @param sign
|
||||
* @param angularChange
|
||||
* @param linearChange
|
||||
*/
|
||||
private function applyPostionChangeToBody(body:RigidBody, relativeContactPosition:Point3D, angularInertia:Number, linearInertia:Number, totalInertia:Number, sign:Number, angularChange:Point3D, linearChange:Point3D):void {
|
||||
var angularLimit:Number = 0.2;
|
||||
var angularMove:Number = sign*penetration*angularInertia/totalInertia;
|
||||
var linearMove:Number = sign*penetration*linearInertia/totalInertia;
|
||||
|
||||
projection.copy(contactNormal);
|
||||
projection.multiply(-relativeContactPosition.dot(contactNormal));
|
||||
projection.add(relativeContactPosition);
|
||||
|
||||
var maxMagnitude:Number = angularLimit*projection.length;
|
||||
|
||||
var totalMove:Number;
|
||||
if (angularMove < -maxMagnitude) {
|
||||
totalMove = angularMove + linearMove;
|
||||
angularMove = -maxMagnitude;
|
||||
linearMove = totalMove - angularMove;
|
||||
} else if (angularMove > maxMagnitude) {
|
||||
totalMove = angularMove + linearMove;
|
||||
angularMove = maxMagnitude;
|
||||
linearMove = totalMove - angularMove;
|
||||
}
|
||||
|
||||
if (angularMove == 0) {
|
||||
angularChange.reset();
|
||||
} else {
|
||||
angularChange.copy(relativeContactPosition);
|
||||
angularChange.cross(contactNormal);
|
||||
angularChange.transform(body.inverseInertiaTensorWorld);
|
||||
angularChange.multiply(angularMove/angularInertia);
|
||||
}
|
||||
|
||||
linearChange.copy(contactNormal);
|
||||
linearChange.multiply(linearMove);
|
||||
|
||||
body.position.add(linearChange);
|
||||
body.orientation.addScaledVector(angularChange, 1);
|
||||
if (!body.awake) {
|
||||
body.calculateDerivedData();
|
||||
}
|
||||
}
|
||||
|
||||
public function toString():String {
|
||||
return "RigidBodyContact" +
|
||||
"\n timeStamp: " + timeStamp +
|
||||
"\n body1: " + body1.getName() +
|
||||
"\n body2: " + (body2 == null ? "" : body2.getName()) +
|
||||
"\n contactPoint: " + contactPoint +
|
||||
"\n contactNormal: " + contactNormal +
|
||||
"\n restitution: " + restitution +
|
||||
"\n penetration: " + penetration +
|
||||
"\n friction: " + friction;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package alternativa.physics.rigid {
|
||||
|
||||
/**
|
||||
* Генератор контактов для твёрдых тел.
|
||||
*/
|
||||
public class RigidBodyContactGenerator {
|
||||
/**
|
||||
* Следующий генератор в списке.
|
||||
*/
|
||||
public var next:RigidBodyContactGenerator;
|
||||
|
||||
/**
|
||||
* Метод создаёт контакты.
|
||||
*
|
||||
* @param contact первый свободный для записи контакт в списке контактов мира
|
||||
* @return следующий свободный для записи контакт после окончания работы метода. Значение null означает, что доступные контакты исчерпаны.
|
||||
*/
|
||||
public function addContacts(contact:RigidBodyContact):RigidBodyContact {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
package alternativa.physics.rigid {
|
||||
|
||||
import alternativa.physics.*;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
use namespace altphysics;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class RigidBodyContactResolver {
|
||||
|
||||
private var velocityIterations:int;
|
||||
private var positionIterations:int;
|
||||
private var velocityEpsilon:Number;
|
||||
private var positionEpsilon:Number;
|
||||
|
||||
private var velocityIterationsUsed:int;
|
||||
private var positionIterationsUsed:int;
|
||||
|
||||
private var linearChange1:Point3D = new Point3D();
|
||||
private var linearChange2:Point3D = new Point3D();
|
||||
private var angularChange1:Point3D = new Point3D();
|
||||
private var angularChange2:Point3D = new Point3D();
|
||||
|
||||
private var velocityChange1:Point3D = new Point3D();
|
||||
private var velocityChange2:Point3D = new Point3D();
|
||||
private var rotationChange1:Point3D = new Point3D();
|
||||
private var rotationChange2:Point3D = new Point3D();
|
||||
|
||||
private var deltaVector:Point3D = new Point3D();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param velocityIterations
|
||||
* @param positionIterations
|
||||
* @param velocityEpsilon
|
||||
* @param positionEpsilon
|
||||
*/
|
||||
public function RigidBodyContactResolver(velocityIterations:int, positionIterations:int, velocityEpsilon:Number = 0.001, positionEpsilon:Number = 0.001) {
|
||||
this.velocityIterations = velocityIterations;
|
||||
this.positionIterations = positionIterations;
|
||||
this.velocityEpsilon = velocityEpsilon;
|
||||
this.positionEpsilon = positionEpsilon;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param velocityIterations
|
||||
* @param positionEpsilon
|
||||
*/
|
||||
public function setIterations(velocityIterations:int, positionIterations:int):void {
|
||||
this.velocityIterations = velocityIterations;
|
||||
this.positionIterations = positionIterations;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private function isValid():Boolean {
|
||||
return (positionIterations > 0) && (velocityIterations > 0) && (positionEpsilon >= 0) && (velocityEpsilon >= 0);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param firstContact
|
||||
* @param numContacts
|
||||
* @param time
|
||||
*/
|
||||
public function resolveContacts(firstContact:RigidBodyContact, numContacts:int, time:Number):void {
|
||||
if (numContacts == 0 || !isValid()) {
|
||||
return;
|
||||
}
|
||||
// Подготовка контактов к обработке
|
||||
prepareContacts(firstContact, numContacts, time);
|
||||
// Разделение взаимно проникающих контактов
|
||||
adjustPositions(firstContact, numContacts, time);
|
||||
// Коррекция скорости для контактов
|
||||
adjustVelocities(firstContact, numContacts, time);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param firstContact
|
||||
* @param numContacts
|
||||
* @param time
|
||||
*/
|
||||
public function prepareContacts(firstContact:RigidBodyContact, numContacts:int, time:Number):void {
|
||||
var contact:RigidBodyContact = firstContact;
|
||||
while (contact.index < numContacts) {
|
||||
// Вычисление внутренних данных контакта, необходимых для дальнейшей работы
|
||||
contact.calculateInternals(time);
|
||||
contact = contact.next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param firstContact
|
||||
* @param numContacts
|
||||
* @param time
|
||||
*/
|
||||
public function adjustPositions(firstContact:RigidBodyContact, numContacts:int, time:Number):void {
|
||||
positionIterationsUsed = 0;
|
||||
// Итерационное устранение взаимного проникновения тел в точках контактов в порядке наибольшего пересечения тел
|
||||
while (positionIterationsUsed < positionIterations) {
|
||||
var max:Number = positionEpsilon;
|
||||
var mostSevereContact:RigidBodyContact = null;
|
||||
// Поиск контакта с наибольшим пересечением
|
||||
var contact:RigidBodyContact = firstContact;
|
||||
while (contact.index < numContacts) {
|
||||
if (contact.penetration > max) {
|
||||
max = contact.penetration;
|
||||
mostSevereContact = contact;
|
||||
}
|
||||
contact = contact.next;
|
||||
}
|
||||
if (mostSevereContact == null) {
|
||||
// Алгоритм прерывается, если не осталось пересечений
|
||||
return;
|
||||
}
|
||||
// Будим спящего
|
||||
mostSevereContact.matchAwakeState();
|
||||
|
||||
// Разделяем контакт
|
||||
mostSevereContact.applyPositionChange(linearChange1, linearChange2, angularChange1, angularChange2, max);
|
||||
// Обновляем величину проникновения в каждом контакте, содержащем обработанные объекты
|
||||
contact = firstContact;
|
||||
while (contact.index < numContacts) {
|
||||
if (contact.body1 == mostSevereContact.body1) {
|
||||
deltaVector.copy(angularChange1);
|
||||
deltaVector.cross(contact.relativeContactPosition1);
|
||||
deltaVector.add(linearChange1);
|
||||
contact.penetration -= deltaVector.dot(contact.contactNormal);
|
||||
}
|
||||
if (contact.body1 == mostSevereContact.body2) {
|
||||
deltaVector.copy(angularChange2);
|
||||
deltaVector.cross(contact.relativeContactPosition1);
|
||||
deltaVector.add(linearChange2);
|
||||
contact.penetration -= deltaVector.dot(contact.contactNormal);
|
||||
}
|
||||
if (contact.body2 != null) {
|
||||
if (contact.body2 == mostSevereContact.body1) {
|
||||
deltaVector.copy(angularChange1);
|
||||
deltaVector.cross(contact.relativeContactPosition2);
|
||||
deltaVector.add(linearChange1);
|
||||
contact.penetration += deltaVector.dot(contact.contactNormal);
|
||||
}
|
||||
if (contact.body2 == mostSevereContact.body2) {
|
||||
deltaVector.copy(angularChange2);
|
||||
deltaVector.cross(contact.relativeContactPosition2);
|
||||
deltaVector.add(linearChange2);
|
||||
contact.penetration += deltaVector.dot(contact.contactNormal);
|
||||
}
|
||||
}
|
||||
contact = contact.next;
|
||||
}
|
||||
positionIterationsUsed++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param firstContact
|
||||
* @param numContacts
|
||||
* @param time
|
||||
*/
|
||||
public function adjustVelocities(firstContact:RigidBodyContact, numContacts:int, time:Number):void {
|
||||
velocityIterationsUsed = 0;
|
||||
while (velocityIterationsUsed < velocityIterations) {
|
||||
var max:Number = velocityEpsilon;
|
||||
var mostSevereContact:RigidBodyContact = null;
|
||||
var contact:RigidBodyContact = firstContact;
|
||||
while (contact.index < numContacts) {
|
||||
if (contact.desiredDeltaVelocity > max) {
|
||||
max = contact.desiredDeltaVelocity;
|
||||
mostSevereContact = contact;
|
||||
}
|
||||
contact = contact.next;
|
||||
}
|
||||
if (mostSevereContact == null) {
|
||||
return;
|
||||
}
|
||||
// Будим спящих
|
||||
mostSevereContact.matchAwakeState();
|
||||
// Корректируем скорости
|
||||
mostSevereContact.applyVelocityChange(velocityChange1, velocityChange2, rotationChange1, rotationChange2);
|
||||
// Обновляем скорости сближения для каждого контакта, содержащего обработанные объекты
|
||||
contact = firstContact;
|
||||
var needRecalculation:Boolean = false;
|
||||
while (contact.index < numContacts) {
|
||||
if (contact.body1 == mostSevereContact.body1) {
|
||||
deltaVector.copy(rotationChange1);
|
||||
deltaVector.cross(contact.relativeContactPosition1);
|
||||
deltaVector.add(velocityChange1);
|
||||
deltaVector.transformTranspose(contact.contactToWorld);
|
||||
contact.contactVelocity.add(deltaVector);
|
||||
needRecalculation = true;
|
||||
}
|
||||
if (contact.body1 == mostSevereContact.body2) {
|
||||
deltaVector.copy(rotationChange2);
|
||||
deltaVector.cross(contact.relativeContactPosition1);
|
||||
deltaVector.add(velocityChange2);
|
||||
deltaVector.transformTranspose(contact.contactToWorld);
|
||||
contact.contactVelocity.add(deltaVector);
|
||||
needRecalculation = true;
|
||||
}
|
||||
if (contact.body2 != null) {
|
||||
if (contact.body2 == mostSevereContact.body1) {
|
||||
deltaVector.copy(rotationChange1);
|
||||
deltaVector.cross(contact.relativeContactPosition2);
|
||||
deltaVector.add(velocityChange1);
|
||||
deltaVector.transformTranspose(contact.contactToWorld);
|
||||
contact.contactVelocity.subtract(deltaVector);
|
||||
needRecalculation = true;
|
||||
}
|
||||
if (contact.body2 == mostSevereContact.body2) {
|
||||
deltaVector.copy(rotationChange2);
|
||||
deltaVector.cross(contact.relativeContactPosition2);
|
||||
deltaVector.add(velocityChange2);
|
||||
deltaVector.transformTranspose(contact.contactToWorld);
|
||||
contact.contactVelocity.subtract(deltaVector);
|
||||
needRecalculation = true;
|
||||
}
|
||||
}
|
||||
if (needRecalculation) {
|
||||
contact.calculateDesiredVelocity(time);
|
||||
}
|
||||
contact = contact.next;
|
||||
}
|
||||
velocityIterationsUsed++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package alternativa.physics.rigid {
|
||||
|
||||
public class RigidWorld {
|
||||
|
||||
private var firstBody:RigidBody;
|
||||
private var lastBody:RigidBody;
|
||||
private var contactGenerators:RigidBodyContactGenerator;
|
||||
private var lastContactGenerator:RigidBodyContactGenerator;
|
||||
|
||||
public var contacts:RigidBodyContact;
|
||||
private var maxContacts:int;
|
||||
private var resolver:RigidBodyContactResolver;
|
||||
|
||||
public var forceRegistry:BodyForceRegistry = new BodyForceRegistry();
|
||||
public var calculateIterations:Boolean;
|
||||
|
||||
public var numContacts:int;
|
||||
|
||||
public function RigidWorld(maxContacts:int, iterations:int) {
|
||||
this.maxContacts = maxContacts;
|
||||
resolver = new RigidBodyContactResolver(iterations, iterations);
|
||||
createContactList(maxContacts);
|
||||
}
|
||||
|
||||
private function createContactList(numContacts:int):void {
|
||||
if (numContacts > 0) {
|
||||
var contact:RigidBodyContact = contacts = new RigidBodyContact(0);
|
||||
for (var i:int = 1; i < numContacts; i++) {
|
||||
contact.next = new RigidBodyContact(i);
|
||||
contact = contact.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function addBody(body:RigidBody):void {
|
||||
if (firstBody == null) {
|
||||
firstBody = body;
|
||||
} else {
|
||||
lastBody.next = body;
|
||||
}
|
||||
lastBody = body;
|
||||
while (lastBody.next != null) {
|
||||
lastBody = lastBody.next;
|
||||
}
|
||||
}
|
||||
|
||||
public function removeBody(body:RigidBody):void {
|
||||
if (body == firstBody) {
|
||||
firstBody = firstBody.next;
|
||||
body.next = null;
|
||||
} else {
|
||||
var current:RigidBody = firstBody;
|
||||
var prev:RigidBody = null;
|
||||
while (current != body && current != null) {
|
||||
prev = current;
|
||||
current = current.next;
|
||||
}
|
||||
if (current != null) {
|
||||
if (lastBody == body) {
|
||||
lastBody = prev;
|
||||
}
|
||||
prev.next = current.next;
|
||||
current.next = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function addContactGenerator(gen:RigidBodyContactGenerator):void {
|
||||
if (contactGenerators == null) {
|
||||
contactGenerators = gen;
|
||||
} else {
|
||||
lastContactGenerator.next = gen;
|
||||
}
|
||||
lastContactGenerator = gen;
|
||||
while (lastContactGenerator.next != null) {
|
||||
lastContactGenerator = lastContactGenerator.next;
|
||||
}
|
||||
}
|
||||
|
||||
public function removeContactGenerator(gen:RigidBodyContactGenerator):void {
|
||||
if (gen == contactGenerators) {
|
||||
contactGenerators = gen.next;
|
||||
gen.next = null;
|
||||
} else {
|
||||
var prev:RigidBodyContactGenerator = contactGenerators;
|
||||
var curr:RigidBodyContactGenerator = contactGenerators.next;
|
||||
while (curr != gen && curr != null) {
|
||||
prev = curr;
|
||||
curr = curr.next;
|
||||
}
|
||||
if (curr == gen) {
|
||||
if (lastContactGenerator == gen) {
|
||||
lastContactGenerator = prev;
|
||||
}
|
||||
prev.next = curr.next;
|
||||
curr.next = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function startFrame():void {
|
||||
var body:RigidBody = firstBody;
|
||||
while (body != null) {
|
||||
body.clearAccumulators();
|
||||
body.calculateDerivedData();
|
||||
body = body.next;
|
||||
}
|
||||
}
|
||||
|
||||
private function generateContacts():int {
|
||||
var contact:RigidBodyContact = contacts;
|
||||
var gen:RigidBodyContactGenerator = contactGenerators;
|
||||
while (gen != null && contact != null) {
|
||||
contact = gen.addContacts(contact);
|
||||
gen = gen.next;
|
||||
}
|
||||
return contact == null ? maxContacts : contact.index;
|
||||
}
|
||||
|
||||
public function runPhysics(time:Number):void {
|
||||
forceRegistry.updateForces(time);
|
||||
var body:RigidBody = firstBody;
|
||||
while (body != null) {
|
||||
body.integrate(time);
|
||||
body = body.next;
|
||||
}
|
||||
numContacts = generateContacts();
|
||||
// trace("[RigidWorld.runPhysics] numContacts", numContacts);
|
||||
if (calculateIterations) {
|
||||
resolver.setIterations(4*numContacts, 4*numContacts);
|
||||
}
|
||||
resolver.resolveContacts(contacts, numContacts, time);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package alternativa.physics.rigid {
|
||||
import alternativa.physics.force.IRigidBodyForceGenerator;
|
||||
import alternativa.physics.rigid.RigidBody;
|
||||
|
||||
public class BodyForceRegistration {
|
||||
public var body:RigidBody;
|
||||
public var forceGenerator:IRigidBodyForceGenerator;
|
||||
|
||||
public var next:BodyForceRegistration;
|
||||
|
||||
public function BodyForceRegistration(body:RigidBody, forceGenerator:IRigidBodyForceGenerator) {
|
||||
this.body = body;
|
||||
this.forceGenerator = forceGenerator;
|
||||
}
|
||||
}
|
||||
}
|
||||
47
0.0.0.18/src/alternativa/physics/rigid/BodyForceRegistry.as
Normal file
47
0.0.0.18/src/alternativa/physics/rigid/BodyForceRegistry.as
Normal file
@@ -0,0 +1,47 @@
|
||||
package alternativa.physics.rigid {
|
||||
import alternativa.physics.force.IRigidBodyForceGenerator;
|
||||
import alternativa.physics.rigid.RigidBody;
|
||||
|
||||
public class BodyForceRegistry {
|
||||
|
||||
protected var registrations:BodyForceRegistration;
|
||||
|
||||
public function BodyForceRegistry() {
|
||||
}
|
||||
|
||||
public function add(body:RigidBody, fg:IRigidBodyForceGenerator):void {
|
||||
var registration:BodyForceRegistration = new BodyForceRegistration(body, fg);
|
||||
registration.next = registrations;
|
||||
registrations = registration;
|
||||
}
|
||||
|
||||
public function remove(body:RigidBody, fg:IRigidBodyForceGenerator):void {
|
||||
var current:BodyForceRegistration = registrations;
|
||||
var prev:BodyForceRegistration = null;
|
||||
while (current != null) {
|
||||
if (current.body == body && current.forceGenerator == fg) {
|
||||
if (current == registrations) {
|
||||
registrations = current.next;
|
||||
} else {
|
||||
prev.next = current.next;
|
||||
}
|
||||
break;
|
||||
}
|
||||
prev = current;
|
||||
current = current.next;
|
||||
}
|
||||
}
|
||||
|
||||
public function clear():void {
|
||||
registrations = null;
|
||||
}
|
||||
|
||||
public function updateForces(time:Number):void {
|
||||
var current:BodyForceRegistration = registrations;
|
||||
while (current != null) {
|
||||
current.forceGenerator.updateForce(current.body, time);
|
||||
current = current.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
707
0.0.0.18/src/alternativa/physics/rigid/RigidBody.as
Normal file
707
0.0.0.18/src/alternativa/physics/rigid/RigidBody.as
Normal file
@@ -0,0 +1,707 @@
|
||||
package alternativa.physics.rigid {
|
||||
|
||||
import alternativa.physics.altphysics;
|
||||
import alternativa.types.Matrix3D;
|
||||
import alternativa.types.Point3D;
|
||||
import alternativa.types.Quaternion;
|
||||
|
||||
use namespace altphysics;
|
||||
|
||||
/**
|
||||
* Класс представляет твёрдое тело.
|
||||
*/
|
||||
public class RigidBody {
|
||||
|
||||
private var angularAcceleration:Point3D = new Point3D();
|
||||
private var motionThreshold:Number = 0.1;
|
||||
private var motionThreshold2:Number = 2*motionThreshold;
|
||||
private var baseBias:Number = 0.8;
|
||||
private var name:String;
|
||||
|
||||
public var next:RigidBody;
|
||||
public var prev:RigidBody;
|
||||
|
||||
altphysics var mass:Number;
|
||||
altphysics var inverseMass:Number;
|
||||
altphysics var inverseInertiaTensor:Matrix3D = new Matrix3D();
|
||||
|
||||
altphysics var linearDamping:Number = 0.95;
|
||||
altphysics var angularDamping:Number = 0.95;
|
||||
altphysics var awake:Boolean = true;
|
||||
altphysics var canSleep:Boolean = true;
|
||||
|
||||
altphysics var acceleration:Point3D = new Point3D();
|
||||
altphysics var angularVelocity:Point3D = new Point3D();
|
||||
|
||||
altphysics var position:Point3D = new Point3D();
|
||||
altphysics var orientation:Quaternion = new Quaternion(1, 0, 0, 0);
|
||||
altphysics var velocity:Point3D = new Point3D();
|
||||
altphysics var rotation:Point3D = new Point3D();
|
||||
altphysics var lastFrameAcceleration:Point3D = new Point3D();
|
||||
|
||||
altphysics var transformMatrix:Matrix3D = new Matrix3D();
|
||||
altphysics var inverseInertiaTensorWorld:Matrix3D = new Matrix3D();
|
||||
|
||||
altphysics var forceAccum:Point3D = new Point3D();
|
||||
altphysics var torqueAccum:Point3D = new Point3D();
|
||||
altphysics var motion:Number = 10;
|
||||
|
||||
/**
|
||||
* Создаёт новый экзепляр твёрдого тела.
|
||||
*
|
||||
* @param inverseMass величина, обратная массе тела. Значение 0 указывает, что тело имеет имеет бесконечную массу и момент инерции.
|
||||
* @param inverseInertiaTensor обратный тензор момента инерции тела. Значение <code>null</code> указывает, что тело имеет бесконечную массу и момент инерции.
|
||||
*/
|
||||
public function RigidBody(inverseMass:Number = 1, inverseInertiaTensor:Matrix3D = null) {
|
||||
if (inverseMass == 0 || inverseInertiaTensor == null) {
|
||||
setInfinteMass();
|
||||
} else {
|
||||
this.inverseMass = inverseMass;
|
||||
this.mass = 1/inverseMass;
|
||||
this.inverseInertiaTensor.copy(inverseInertiaTensor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return имя тела
|
||||
*/
|
||||
public function getName():String {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Устанавливает имя тела.
|
||||
*
|
||||
* @param value имя тела
|
||||
*/
|
||||
public function setName(value:String):void {
|
||||
name = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Предельное количество движения, ниже которого тело усыпляеся.
|
||||
*/
|
||||
public function getMotionThreshold():Number {
|
||||
return motionThreshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function setMotionThreshold(value:Number):void {
|
||||
motionThreshold = value;
|
||||
motionThreshold2 = value*2;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public function setBaseBias(value:Number):void {
|
||||
baseBias = value;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public function getBaseBias():Number {
|
||||
return baseBias;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function getMass():Number {
|
||||
return mass;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function setMass(value:Number):void {
|
||||
if (value <= 0) {
|
||||
inverseMass = 0;
|
||||
mass = 0;
|
||||
} else {
|
||||
mass = value;
|
||||
inverseMass = 1/value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function getInverseMass():Number {
|
||||
return inverseMass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function setInverseMass(value:Number):void {
|
||||
if (value > 0) {
|
||||
inverseMass = value;
|
||||
mass = 1/value;
|
||||
} else {
|
||||
inverseMass = 0;
|
||||
mass = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param m
|
||||
*/
|
||||
public function setIntertiaTensor(intertiaTensor:Matrix3D):void {
|
||||
inverseInertiaTensor.copy(intertiaTensor);
|
||||
inverseInertiaTensor.invert();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param intertiaTensor
|
||||
*/
|
||||
public function getIntertiaTensor(intertiaTensor:Matrix3D):void {
|
||||
intertiaTensor.copy(inverseInertiaTensor);
|
||||
intertiaTensor.invert();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param inverseInertiaTensor
|
||||
*/
|
||||
public function setInverseIntertiaTensor(inverseInertiaTensor:Matrix3D):void {
|
||||
this.inverseInertiaTensor.copy(inverseInertiaTensor);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param inverseInertiaTensor
|
||||
*/
|
||||
public function getInverseIntertiaTensor(inverseInertiaTensor:Matrix3D):void {
|
||||
inverseInertiaTensor.copy(this.inverseInertiaTensor);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function setInfinteMass():void {
|
||||
inverseMass = 0;
|
||||
mass = 0;
|
||||
inverseInertiaTensor.toIdentity();
|
||||
inverseInertiaTensor.a = inverseInertiaTensor.f = inverseInertiaTensor.k = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param linearDamping
|
||||
* @param angularDamping
|
||||
*/
|
||||
public function setDamping(linearDamping:Number, angularDamping:Number):void {
|
||||
this.linearDamping = linearDamping;
|
||||
this.angularDamping = angularDamping;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public function setLinearDamping(value:Number):void {
|
||||
linearDamping = value;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public function getLinearDamping():Number {
|
||||
return linearDamping;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public function setAngularDamping(value:Number):void {
|
||||
angularDamping = value;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public function getAngularDamping():Number {
|
||||
return angularDamping;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param position
|
||||
*/
|
||||
public function setPosition(position:Point3D):void {
|
||||
this.position.x = position.x;
|
||||
this.position.y = position.y;
|
||||
this.position.z = position.z;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
*/
|
||||
public function setPositionComponents(x:Number, y:Number, z:Number):void {
|
||||
position.x = x;
|
||||
position.y = y;
|
||||
position.z = z;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param position
|
||||
*/
|
||||
public function getPosition(position:Point3D):void {
|
||||
position.x = this.position.x;
|
||||
position.y = this.position.y;
|
||||
position.z = this.position.z;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param orientation
|
||||
*/
|
||||
public function setOrientation(orientation:Quaternion):void {
|
||||
this.orientation.copy(orientation);
|
||||
this.orientation.normalize();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param r
|
||||
* @param i
|
||||
* @param j
|
||||
* @param k
|
||||
*/
|
||||
public function setOrientationComponents(w:Number, x:Number, y:Number, z:Number):void {
|
||||
orientation.reset(w, x, y, z);
|
||||
orientation.normalize();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param orientation
|
||||
*/
|
||||
public function getOrientation(orientation:Quaternion):void {
|
||||
orientation.copy(this.orientation);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param matrix
|
||||
*/
|
||||
public function getTransformMatrix(matrix:Matrix3D):void {
|
||||
matrix.copy(transformMatrix);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param velocity
|
||||
*/
|
||||
public function setVelocity(velocity:Point3D):void {
|
||||
this.velocity.copy(velocity);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
*/
|
||||
public function setVelocityComponents(x:Number, y:Number, z:Number):void {
|
||||
velocity.reset(x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param velocity
|
||||
*/
|
||||
public function getVelocity(velocity:Point3D):void {
|
||||
velocity.copy(this.velocity);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param acceleration
|
||||
*
|
||||
*/
|
||||
public function setAcceleration(acceleration:Point3D):void {
|
||||
this.acceleration.copy(acceleration);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
*
|
||||
*/
|
||||
public function setAccelerationComponents(x:Number, y:Number, z:Number):void {
|
||||
acceleration.reset(x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param acceleration
|
||||
*
|
||||
*/
|
||||
public function getAcceleration(acceleration:Point3D):void {
|
||||
acceleration.copy(this.acceleration);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param rotation
|
||||
*
|
||||
*/
|
||||
public function setRotation(rotation:Point3D):void {
|
||||
this.rotation.copy(rotation);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
*
|
||||
*/
|
||||
public function setRotationComponents(x:Number, y:Number, z:Number):void {
|
||||
rotation.reset(x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param rotation
|
||||
*
|
||||
*/
|
||||
public function addRotation(deltaRotation:Point3D):void {
|
||||
rotation.add(deltaRotation);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param rotation
|
||||
*
|
||||
*/
|
||||
public function getRotation(rotation:Point3D):void {
|
||||
rotation.copy(this.rotation);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param angularVelocity
|
||||
*/
|
||||
public function setAngularVelocity(angularVelocity:Point3D):void {
|
||||
this.angularVelocity.x = angularVelocity.x;
|
||||
this.angularVelocity.y = angularVelocity.y;
|
||||
this.angularVelocity.z = angularVelocity.z;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
*/
|
||||
public function setAngularVelocityComponents(x:Number, y:Number, z:Number):void {
|
||||
angularVelocity.x = x;
|
||||
angularVelocity.y = y;
|
||||
angularVelocity.z = z;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param awake
|
||||
*/
|
||||
public function setAwake(awake:Boolean = true):void {
|
||||
this.awake = awake;
|
||||
if (awake) {
|
||||
motion = motionThreshold2;
|
||||
} else {
|
||||
velocity.x = 0;
|
||||
velocity.y = 0;
|
||||
velocity.z = 0;
|
||||
|
||||
rotation.x = 0;
|
||||
rotation.y = 0;
|
||||
rotation.z = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public function isAwake():Boolean {
|
||||
return awake;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param canSleep
|
||||
*/
|
||||
public function setCanSleep(canSleep:Boolean = true):void {
|
||||
this.canSleep = canSleep;
|
||||
if (!canSleep && !awake) {
|
||||
setAwake();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public function isCanSleep():Boolean {
|
||||
return canSleep;
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавляет глобальную силу, приложенную к центру масс тела.
|
||||
*
|
||||
* @param force вектор силы в глобальной системе координат
|
||||
*/
|
||||
public function addForce(force:Point3D):void {
|
||||
forceAccum.x += force.x;
|
||||
forceAccum.y += force.y;
|
||||
forceAccum.z += force.z;
|
||||
setAwake();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param force
|
||||
*/
|
||||
public function addForceComponents(x:Number, y:Number, z:Number):void {
|
||||
forceAccum.x += x;
|
||||
forceAccum.y += y;
|
||||
forceAccum.z += z;
|
||||
setAwake();
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавляет глобальную силу, приложенную к заданной локальной точке тела.
|
||||
*
|
||||
* @param force вектор силы в глобальной системе координат
|
||||
* @param localPoint локальные координаты точки приложения силы
|
||||
*/
|
||||
public function addForceAtLocalPoint(force:Point3D, localPoint:Point3D):void {
|
||||
forceAccum.x += force.x;
|
||||
forceAccum.y += force.y;
|
||||
forceAccum.z += force.z;
|
||||
// Трансформация локальных координат в глобальные
|
||||
var x:Number = transformMatrix.a*localPoint.x + transformMatrix.b*localPoint.y + transformMatrix.c*localPoint.z;
|
||||
var y:Number = transformMatrix.e*localPoint.x + transformMatrix.f*localPoint.y + transformMatrix.g*localPoint.z;
|
||||
var z:Number = transformMatrix.i*localPoint.x + transformMatrix.j*localPoint.y + transformMatrix.k*localPoint.z;
|
||||
torqueAccum.x += y*force.z - z*force.y;
|
||||
torqueAccum.y += z*force.x - x*force.z;
|
||||
torqueAccum.z += x*force.y - y*force.x;
|
||||
setAwake();
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавляет глобальную силу, приложенную к заданной точке тела, выраженной в глобальных координатах.
|
||||
*
|
||||
* @param force вектор силы в глобальной системе координат
|
||||
* @param point глобальные координаты точки приложения силы
|
||||
*/
|
||||
public function addForceAtPoint(force:Point3D, point:Point3D):void {
|
||||
forceAccum.x += force.x;
|
||||
forceAccum.y += force.y;
|
||||
forceAccum.z += force.z;
|
||||
var x:Number = point.x - position.x;
|
||||
var y:Number = point.y - position.y;
|
||||
var z:Number = point.z - position.z;
|
||||
torqueAccum.x += y*force.z - z*force.y;
|
||||
torqueAccum.y += z*force.x - x*force.z;
|
||||
torqueAccum.z += x*force.y - y*force.x;
|
||||
setAwake();
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавляет локальную силу, приложенную в заданной локальной точке тела.
|
||||
*
|
||||
* @param localForce вектор локальной силы
|
||||
* @param localPoint локальные координаты точки приложения силы
|
||||
*/
|
||||
public function addLocalForce(localForce:Point3D, localPoint:Point3D):void {
|
||||
// Трансформация локального вектора силы в глобальный
|
||||
var globalForceX:Number = transformMatrix.a*localForce.x + transformMatrix.b*localForce.y + transformMatrix.c*localForce.z;
|
||||
var globalForceY:Number = transformMatrix.e*localForce.x + transformMatrix.f*localForce.y + transformMatrix.g*localForce.z;
|
||||
var globalForceZ:Number = transformMatrix.i*localForce.x + transformMatrix.j*localForce.y + transformMatrix.k*localForce.z;
|
||||
forceAccum.x += globalForceX;
|
||||
forceAccum.y += globalForceY;
|
||||
forceAccum.z += globalForceZ;
|
||||
// Получение глобального вектора плеча силы
|
||||
var globalPointX:Number = transformMatrix.a*localPoint.x + transformMatrix.b*localPoint.y + transformMatrix.c*localPoint.z;
|
||||
var globalPointY:Number = transformMatrix.e*localPoint.x + transformMatrix.f*localPoint.y + transformMatrix.g*localPoint.z;
|
||||
var globalPointZ:Number = transformMatrix.i*localPoint.x + transformMatrix.j*localPoint.y + transformMatrix.k*localPoint.z;
|
||||
// Приращение момента силы
|
||||
torqueAccum.x += globalPointY*globalForceZ - globalPointZ*globalForceY;
|
||||
torqueAccum.y += globalPointZ*globalForceX - globalPointX*globalForceZ;
|
||||
torqueAccum.z += globalPointX*globalForceY - globalPointY*globalForceX;
|
||||
setAwake();
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавляет момент силы.
|
||||
*
|
||||
* @param torque вектор момента силы
|
||||
*/
|
||||
public function addTorque(torque:Point3D):void {
|
||||
torqueAccum.x += torque.x;
|
||||
torqueAccum.y += torque.y;
|
||||
torqueAccum.z += torque.z;
|
||||
setAwake();
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавляет момент силы, заданный покомпонентно.
|
||||
*/
|
||||
public function addTorqueComponents(x:Number, y:Number, z:Number):void {
|
||||
torqueAccum.x += x;
|
||||
torqueAccum.y += y;
|
||||
torqueAccum.z += z;
|
||||
setAwake();
|
||||
}
|
||||
|
||||
/**
|
||||
* Вычисляет векторные параметры тела в глобальной системе координат.
|
||||
*/
|
||||
public function calculateDerivedData():void {
|
||||
// inlined position.normalize()
|
||||
var d:Number = orientation.w*orientation.w + orientation.x*orientation.x + orientation.y*orientation.y + orientation.z*orientation.z;
|
||||
if (d == 0) {
|
||||
orientation.w = 1;
|
||||
} else {
|
||||
d = 1/Math.sqrt(d);
|
||||
orientation.w *= d;
|
||||
orientation.x *= d;
|
||||
orientation.y *= d;
|
||||
orientation.z *= d;
|
||||
}
|
||||
// Вычисление глобальной матрицы трансформации
|
||||
orientation.toMatrix3D(transformMatrix);
|
||||
transformMatrix.d = position.x;
|
||||
transformMatrix.h = position.y;
|
||||
transformMatrix.l = position.z;
|
||||
// Расчёт обратного тензора инерции в мировых координатах
|
||||
var a:Number = transformMatrix.a*inverseInertiaTensor.a + transformMatrix.b*inverseInertiaTensor.e + transformMatrix.c*inverseInertiaTensor.i;
|
||||
var b:Number = transformMatrix.a*inverseInertiaTensor.b + transformMatrix.b*inverseInertiaTensor.f + transformMatrix.c*inverseInertiaTensor.j;
|
||||
var c:Number = transformMatrix.a*inverseInertiaTensor.c + transformMatrix.b*inverseInertiaTensor.g + transformMatrix.c*inverseInertiaTensor.k;
|
||||
var e:Number = transformMatrix.e*inverseInertiaTensor.a + transformMatrix.f*inverseInertiaTensor.e + transformMatrix.g*inverseInertiaTensor.i;
|
||||
var f:Number = transformMatrix.e*inverseInertiaTensor.b + transformMatrix.f*inverseInertiaTensor.f + transformMatrix.g*inverseInertiaTensor.j;
|
||||
var g:Number = transformMatrix.e*inverseInertiaTensor.c + transformMatrix.f*inverseInertiaTensor.g + transformMatrix.g*inverseInertiaTensor.k;
|
||||
var i:Number = transformMatrix.i*inverseInertiaTensor.a + transformMatrix.j*inverseInertiaTensor.e + transformMatrix.k*inverseInertiaTensor.i;
|
||||
var j:Number = transformMatrix.i*inverseInertiaTensor.b + transformMatrix.j*inverseInertiaTensor.f + transformMatrix.k*inverseInertiaTensor.j;
|
||||
var k:Number = transformMatrix.i*inverseInertiaTensor.c + transformMatrix.j*inverseInertiaTensor.g + transformMatrix.k*inverseInertiaTensor.k;
|
||||
// Здесь подразумевается, что матрица трансформации тела не содержит масштабирования
|
||||
// Произведение [transformMatrix*inverseInertiaTensor]*transpose(transformMatrix)
|
||||
inverseInertiaTensorWorld.a = a*transformMatrix.a + b*transformMatrix.b + c*transformMatrix.c;
|
||||
inverseInertiaTensorWorld.b = a*transformMatrix.e + b*transformMatrix.f + c*transformMatrix.g;
|
||||
inverseInertiaTensorWorld.c = a*transformMatrix.i + b*transformMatrix.j + c*transformMatrix.k;
|
||||
inverseInertiaTensorWorld.e = e*transformMatrix.a + f*transformMatrix.b + g*transformMatrix.c;
|
||||
inverseInertiaTensorWorld.f = e*transformMatrix.e + f*transformMatrix.f + g*transformMatrix.g;
|
||||
inverseInertiaTensorWorld.g = e*transformMatrix.i + f*transformMatrix.j + g*transformMatrix.k;
|
||||
inverseInertiaTensorWorld.i = i*transformMatrix.a + j*transformMatrix.b + k*transformMatrix.c;
|
||||
inverseInertiaTensorWorld.j = i*transformMatrix.e + j*transformMatrix.f + k*transformMatrix.g;
|
||||
inverseInertiaTensorWorld.k = i*transformMatrix.i + j*transformMatrix.j + k*transformMatrix.k;
|
||||
}
|
||||
|
||||
/**
|
||||
* Интегрирует динамические характеристики и обновляет параметры состояния тела.
|
||||
*
|
||||
* @param time временной шаг интегрирования
|
||||
*/
|
||||
public function integrate(time:Number):void {
|
||||
if (!awake) {
|
||||
return;
|
||||
}
|
||||
|
||||
lastFrameAcceleration.x = acceleration.x + forceAccum.x*inverseMass;
|
||||
lastFrameAcceleration.y = acceleration.y + forceAccum.y*inverseMass;
|
||||
lastFrameAcceleration.z = acceleration.z + forceAccum.z*inverseMass;
|
||||
// angularAcceleration = inverseInertiaTensorWorld*torqueAccum
|
||||
angularAcceleration.x = inverseInertiaTensorWorld.a*torqueAccum.x + inverseInertiaTensorWorld.b*torqueAccum.y + inverseInertiaTensorWorld.c*torqueAccum.z;
|
||||
angularAcceleration.y = inverseInertiaTensorWorld.e*torqueAccum.x + inverseInertiaTensorWorld.f*torqueAccum.y + inverseInertiaTensorWorld.g*torqueAccum.z;
|
||||
angularAcceleration.z = inverseInertiaTensorWorld.i*torqueAccum.x + inverseInertiaTensorWorld.j*torqueAccum.y + inverseInertiaTensorWorld.k*torqueAccum.z;
|
||||
|
||||
var d:Number = Math.pow(linearDamping, time);
|
||||
var dtime:Number = d*time;
|
||||
|
||||
velocity.x += lastFrameAcceleration.x*dtime;
|
||||
velocity.y += lastFrameAcceleration.y*dtime;
|
||||
velocity.z += lastFrameAcceleration.z*dtime;
|
||||
|
||||
rotation.x += angularAcceleration.x*dtime;
|
||||
rotation.y += angularAcceleration.y*dtime;
|
||||
rotation.z += angularAcceleration.z*dtime;
|
||||
|
||||
rotation.x += angularVelocity.x*time;
|
||||
rotation.y += angularVelocity.y*time;
|
||||
rotation.z += angularVelocity.z*time;
|
||||
|
||||
position.x += velocity.x*time;
|
||||
position.y += velocity.y*time;
|
||||
position.z += velocity.z*time;
|
||||
|
||||
orientation.addScaledVector(rotation, time);
|
||||
|
||||
// TODO: Нужно ли двойное уменьшение скоростей?
|
||||
velocity.x *= d;
|
||||
velocity.y *= d;
|
||||
velocity.z *= d;
|
||||
|
||||
rotation.x *= d;
|
||||
rotation.y *= d;
|
||||
rotation.z *= d;
|
||||
|
||||
calculateDerivedData();
|
||||
// inlined clearAccumulators()
|
||||
forceAccum.x = 0;
|
||||
forceAccum.y = 0;
|
||||
forceAccum.z = 0;
|
||||
torqueAccum.x = 0;
|
||||
torqueAccum.y = 0;
|
||||
torqueAccum.z = 0;
|
||||
|
||||
// Усыпление тела при необходимости
|
||||
if (canSleep) {
|
||||
var currentMotion:Number = velocity.x*velocity.x + velocity.y*velocity.y + velocity.z*velocity.z +
|
||||
rotation.x*rotation.x + rotation.y*rotation.y + rotation.z*rotation.z;
|
||||
var bias:Number = Math.pow(baseBias, time);
|
||||
motion = bias*motion + (1 - bias)*currentMotion;
|
||||
// trace("[RigidBody::integrate]", name, "motion", motion, "motionEpsilon", motionEpsilon);
|
||||
if (motion < motionThreshold) {
|
||||
setAwake(false);
|
||||
} else {
|
||||
if (motion > motionThreshold2) {
|
||||
motion = motionThreshold2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function clearAccumulators():void {
|
||||
forceAccum.x = 0;
|
||||
forceAccum.y = 0;
|
||||
forceAccum.z = 0;
|
||||
torqueAccum.x = 0;
|
||||
torqueAccum.y = 0;
|
||||
torqueAccum.z = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
550
0.0.0.18/src/alternativa/physics/rigid/RigidBodyContact.as
Normal file
550
0.0.0.18/src/alternativa/physics/rigid/RigidBodyContact.as
Normal file
@@ -0,0 +1,550 @@
|
||||
package alternativa.physics.rigid {
|
||||
|
||||
import alternativa.physics.*;
|
||||
import alternativa.types.Matrix3D;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
use namespace altphysics;
|
||||
|
||||
/**
|
||||
* Класс описывает контакт между телами. Контакты могут составлять двунаправленный список.
|
||||
*/
|
||||
public class RigidBodyContact {
|
||||
|
||||
private var tmpVelocityVector:Point3D = new Point3D();
|
||||
private var impulse:Point3D = new Point3D();
|
||||
|
||||
public static var velocityLimit:Number = 1;
|
||||
|
||||
/**
|
||||
* Ссылка на следующий контакт в списке.
|
||||
*/
|
||||
public var next:RigidBodyContact;
|
||||
/**
|
||||
* Ссылка на предыдущий контакт в списке.
|
||||
*/
|
||||
public var prev:RigidBodyContact;
|
||||
/**
|
||||
* Индекс контакта в списке.
|
||||
*/
|
||||
public var index:int;
|
||||
|
||||
/**
|
||||
* Первое тело, к которому относится контакт.
|
||||
*/
|
||||
public var body1:RigidBody;
|
||||
/**
|
||||
* Первое тело, к которому относится контакт (может быть null).
|
||||
*/
|
||||
public var body2:RigidBody;
|
||||
/**
|
||||
* Точка контакта.
|
||||
*/
|
||||
public var contactPoint:Point3D = new Point3D();
|
||||
/**
|
||||
* Нормаль контакта. Нормаль направлена от второго тела к первому. В локальной системе координат контакта
|
||||
* нормаль является базисным вектором, задающим направление оси X.
|
||||
*/
|
||||
public var contactNormal:Point3D = new Point3D();
|
||||
/**
|
||||
* Коэффициент взаимного трения в точке контакта.
|
||||
*/
|
||||
public var friction:Number = 0;
|
||||
/**
|
||||
* Коэффициент упругости удара.
|
||||
*/
|
||||
public var restitution:Number = 0;
|
||||
/**
|
||||
* Глубина взаимного проникновения тел в точке контакта.
|
||||
*/
|
||||
public var penetration:Number;
|
||||
|
||||
public var timeStamp:int;
|
||||
|
||||
/**
|
||||
* Матрица перехода из локальной системы координат контакта в мировую систему координат без компонентов параллельного переноса.
|
||||
* Матрица задаёт базис локальной системы координат контакта.
|
||||
*/
|
||||
altphysics var contactToWorld:Matrix3D = new Matrix3D();
|
||||
/**
|
||||
* Относительная скорость в точке контакта. Вычисляется в методе calculateInternals().
|
||||
*/
|
||||
altphysics var contactVelocity:Point3D = new Point3D();
|
||||
/**
|
||||
* Приращение скорости в точке контакта по направлению нормали, необходимое для прекращения сближения. Вычисляется в методе calculateInternals().
|
||||
*/
|
||||
altphysics var desiredDeltaVelocity:Number;
|
||||
/**
|
||||
* Координаты точки контакта относительныо первого тела. Вычисляется в методе calculateInternals().
|
||||
*/
|
||||
altphysics var relativeContactPosition1:Point3D = new Point3D();
|
||||
/**
|
||||
* Координаты точки контакта относительныо второго тела. Вычисляется в методе calculateInternals().
|
||||
*/
|
||||
altphysics var relativeContactPosition2:Point3D = new Point3D();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index
|
||||
*/
|
||||
public function RigidBodyContact(index:int) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param body1
|
||||
* @param body2
|
||||
* @param friction
|
||||
* @param restitution
|
||||
*/
|
||||
public function setBodyData(body1:RigidBody, body2:RigidBody, friction:Number, restitution:Number):void {
|
||||
this.body1 = body1;
|
||||
this.body2 = body2;
|
||||
this.friction = friction;
|
||||
this.restitution = restitution;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function matchAwakeState():void {
|
||||
if (body2 == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (body1.awake != body2.awake) {
|
||||
if (body1.awake) {
|
||||
body2.setAwake();
|
||||
} else {
|
||||
body1.setAwake();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Вычисляет и сохраняет базис локальной системы координат контакта.
|
||||
*/
|
||||
public function calculateContactBasis():void {
|
||||
// Нормаль является ортом X локальной системы координат
|
||||
contactToWorld.a = contactNormal.x;
|
||||
contactToWorld.e = contactNormal.y;
|
||||
contactToWorld.i = contactNormal.z;
|
||||
var nx:Number = contactNormal.x > 0 ? contactNormal.x : -contactNormal.x;
|
||||
var ny:Number = contactNormal.y > 0 ? contactNormal.y : -contactNormal.y;
|
||||
var s:Number;
|
||||
if (nx > ny) {
|
||||
// Нормаль ближе к глобальной оси X, используем ось Y для вычислений. Локальный орт Y находится как результат векторного произведения globalY x contactNormal.
|
||||
s = 1/Math.sqrt(nx*nx + contactNormal.z*contactNormal.z);
|
||||
contactToWorld.b = contactNormal.z*s;
|
||||
contactToWorld.f = 0;
|
||||
contactToWorld.j = -contactNormal.x*s;
|
||||
// Локальный орт Z находится как результат векторного произведения contactNormal x localY.
|
||||
contactToWorld.c = contactNormal.y*contactToWorld.j;
|
||||
contactToWorld.g = contactNormal.z*contactToWorld.b - contactNormal.x*contactToWorld.j;
|
||||
contactToWorld.k = -contactNormal.y*contactToWorld.b;
|
||||
} else {
|
||||
// Нормаль ближе к глобальной оси Y, используем ось X для вычислений. Локальный орт Y находится как результат векторного произведения globalX x contactNormal.
|
||||
s = 1/Math.sqrt(ny*ny + contactNormal.z*contactNormal.z);
|
||||
contactToWorld.b = 0;
|
||||
contactToWorld.f = -contactNormal.z*s;
|
||||
contactToWorld.j = contactNormal.y*s;
|
||||
// Локальный орт Z находится как результат векторного произведения contactNormal x localY.
|
||||
contactToWorld.c = contactNormal.y*contactToWorld.j - contactNormal.z*contactToWorld.f;
|
||||
contactToWorld.g = -contactNormal.x*contactToWorld.j;
|
||||
contactToWorld.k = contactNormal.x*contactToWorld.f;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Вычисляет скорость точки заданного тела в точке контакта в его локальной системе координат.
|
||||
*
|
||||
* @param body тело, для которого выполняются вычисления
|
||||
* @param relativeContactPosition положение точки контакта относительно тела
|
||||
* @param time временной шаг
|
||||
* @param result в эту переменную записывается результат
|
||||
*/
|
||||
public function calculateLocalVelocity(body:RigidBody, relativeContactPosition:Point3D, time:Number, result:Point3D):void {
|
||||
// Расчёт прироста скорости за последний кадр от действующих сил
|
||||
var x:Number = body.lastFrameAcceleration.x*time;
|
||||
var y:Number = body.lastFrameAcceleration.y*time;
|
||||
var z:Number = body.lastFrameAcceleration.z*time;
|
||||
// Прирост скорости в системе координат контакта
|
||||
// Убираем прирост скорости в направлении контакта
|
||||
var accVelocityY:Number = contactToWorld.b*x + contactToWorld.f*y + contactToWorld.j*z;
|
||||
var accVelocityZ:Number = contactToWorld.c*x + contactToWorld.g*y + contactToWorld.k*z;
|
||||
|
||||
// Скорость точки контакта в мировой системе координат
|
||||
// Скорость за счёт вращения тела
|
||||
var rotation:Point3D = body.rotation;
|
||||
x = rotation.y*relativeContactPosition.z - rotation.z*relativeContactPosition.y + body.velocity.x;
|
||||
y = rotation.z*relativeContactPosition.x - rotation.x*relativeContactPosition.z + body.velocity.y;
|
||||
z = rotation.x*relativeContactPosition.y - rotation.y*relativeContactPosition.x + body.velocity.z;
|
||||
// Скорость точки контакта в системе координат контакта
|
||||
// Касательные компоненты прироста скорости добавляются к скорости точки контакта. В дальнейшем они либо уберутся силой трения,
|
||||
// либо уменьшатся ею.
|
||||
result.x = contactToWorld.a*x + contactToWorld.e*y + contactToWorld.i*z;
|
||||
result.y = contactToWorld.b*x + contactToWorld.f*y + contactToWorld.j*z + accVelocityY;
|
||||
result.z = contactToWorld.c*x + contactToWorld.g*y + contactToWorld.k*z + accVelocityZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Вычисляет и устанавливает внутреннее значение для требуемого изменения относительной скорости вдоль нормали контакта.
|
||||
* С реакциями опоры разбираемся путём вычитания из скорости сближения прироста скорости, полученного во время последнего кадра.
|
||||
*
|
||||
* @param time
|
||||
*/
|
||||
public function calculateDesiredVelocity(time:Number):void {
|
||||
// Вычисляем проекцию прироста скорости за текущий кадр на нормаль контакта. Для относительного прироста скорости, вызывающего
|
||||
// сближение объектов, значение будет отрицательным.
|
||||
var velocityFromAcc:Number = 0;
|
||||
if (body1.awake) {
|
||||
velocityFromAcc = (body1.lastFrameAcceleration.x*contactNormal.x + body1.lastFrameAcceleration.y*contactNormal.y + body1.lastFrameAcceleration.z*contactNormal.z)*time;
|
||||
}
|
||||
if (body2 != null && body2.awake) {
|
||||
velocityFromAcc -= (body2.lastFrameAcceleration.x*contactNormal.x + body2.lastFrameAcceleration.y*contactNormal.y + body2.lastFrameAcceleration.z*contactNormal.z)*time;
|
||||
}
|
||||
// Если относительная скорость вдоль нормали контакта слишком мала, игнорируем её
|
||||
var thisRestitution:Number = restitution;
|
||||
if (contactVelocity.x > -velocityLimit && contactVelocity.x < velocityLimit) {
|
||||
thisRestitution = 0;
|
||||
}
|
||||
// Вычисляем дельту для скорости отскока, убрав влияние прироста скорости за последний кадр
|
||||
desiredDeltaVelocity = -contactVelocity.x - thisRestitution*(contactVelocity.x - velocityFromAcc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Расчитывает внутренние данные о контакта на основе данных о его состоянии. Вызывается до того, как будет запущен
|
||||
* алгоритм разрешения контактов. Эта функция в нормальных условиях никогда не должна вызываться вручную.
|
||||
*
|
||||
* @param time
|
||||
*/
|
||||
public function calculateInternals(time:Number):void {
|
||||
// Расчёт базиса системы координат контакта
|
||||
// === inlined calculateContactBasis();
|
||||
contactToWorld.a = contactNormal.x;
|
||||
contactToWorld.e = contactNormal.y;
|
||||
contactToWorld.i = contactNormal.z;
|
||||
var nx:Number = contactNormal.x > 0 ? contactNormal.x : -contactNormal.x;
|
||||
var ny:Number = contactNormal.y > 0 ? contactNormal.y : -contactNormal.y;
|
||||
var s:Number;
|
||||
if (nx > ny) {
|
||||
// Нормаль ближе к глобальной оси X, используем ось Y для вычислений. Локальный орт Y находится как результат векторного произведения globalY x contactNormal.
|
||||
s = 1/Math.sqrt(nx*nx + contactNormal.z*contactNormal.z);
|
||||
contactToWorld.b = contactNormal.z*s;
|
||||
contactToWorld.f = 0;
|
||||
contactToWorld.j = -contactNormal.x*s;
|
||||
// Локальный орт Z находится как результат векторного произведения contactNormal x localY.
|
||||
contactToWorld.c = contactNormal.y*contactToWorld.j;
|
||||
contactToWorld.g = contactNormal.z*contactToWorld.b - contactNormal.x*contactToWorld.j;
|
||||
contactToWorld.k = -contactNormal.y*contactToWorld.b;
|
||||
} else {
|
||||
// Нормаль ближе к глобальной оси Y, используем ось X для вычислений. Локальный орт Y находится как результат векторного произведения globalX x contactNormal.
|
||||
s = 1/Math.sqrt(ny*ny + contactNormal.z*contactNormal.z);
|
||||
contactToWorld.b = 0;
|
||||
contactToWorld.f = -contactNormal.z*s;
|
||||
contactToWorld.j = contactNormal.y*s;
|
||||
// Локальный орт Z находится как результат векторного произведения contactNormal x localY.
|
||||
contactToWorld.c = contactNormal.y*contactToWorld.j - contactNormal.z*contactToWorld.f;
|
||||
contactToWorld.g = -contactNormal.x*contactToWorld.j;
|
||||
contactToWorld.k = contactNormal.x*contactToWorld.f;
|
||||
}
|
||||
// === end inlined
|
||||
|
||||
// Расчёт локальной скорости в точке контакта для первого тела
|
||||
relativeContactPosition1.x = contactPoint.x - body1.position.x;
|
||||
relativeContactPosition1.y = contactPoint.y - body1.position.y;
|
||||
relativeContactPosition1.z = contactPoint.z - body1.position.z;
|
||||
calculateLocalVelocity(body1, relativeContactPosition1, time, contactVelocity);
|
||||
// Расчёт локальной скорости в точке контакта для второго тела
|
||||
if (body2 != null) {
|
||||
relativeContactPosition2.x = contactPoint.x - body2.position.x;
|
||||
relativeContactPosition2.y = contactPoint.y - body2.position.y;
|
||||
relativeContactPosition2.z = contactPoint.z - body2.position.z;
|
||||
calculateLocalVelocity(body2, relativeContactPosition2, time, tmpVelocityVector);
|
||||
// Расчёт относительной скорости в точке контакта
|
||||
contactVelocity.x -= tmpVelocityVector.x;
|
||||
contactVelocity.y -= tmpVelocityVector.y;
|
||||
contactVelocity.z -= tmpVelocityVector.z;
|
||||
}
|
||||
// Расчёт вектора изменения скорости, требуемого для разрешения контакта
|
||||
calculateDesiredVelocity(time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Выполняет разделение контакта посредством импульса, пропорционально инерции тел.
|
||||
*/
|
||||
public function applyVelocityChange(velocityChange1:Point3D, velocityChange2:Point3D, rotationChange1:Point3D, rotationChange2:Point3D):void {
|
||||
var inverseInertiaTensor1:Matrix3D = body1.inverseInertiaTensorWorld;
|
||||
var inverseInertiaTensor2:Matrix3D;
|
||||
if (body2 != null) {
|
||||
inverseInertiaTensor2 = body2.inverseInertiaTensorWorld;
|
||||
}
|
||||
|
||||
if (friction == 0) {
|
||||
calculateFrictionlessImpulse(inverseInertiaTensor1, inverseInertiaTensor2, impulse);
|
||||
} else {
|
||||
calculateFrictionImpulse(inverseInertiaTensor1, inverseInertiaTensor2, impulse);
|
||||
}
|
||||
|
||||
// Переведём импульс в мировые координаты
|
||||
var x:Number = impulse.x;
|
||||
var y:Number = impulse.y;
|
||||
var z:Number = impulse.z;
|
||||
impulse.x = contactToWorld.a*x + contactToWorld.b*y + contactToWorld.c*z;
|
||||
impulse.y = contactToWorld.e*x + contactToWorld.f*y + contactToWorld.g*z;
|
||||
impulse.z = contactToWorld.i*x + contactToWorld.j*y + contactToWorld.k*z;
|
||||
|
||||
// Разделим импульс на вращательную и линейную часть
|
||||
x = relativeContactPosition1.y*impulse.z - relativeContactPosition1.z*impulse.y;
|
||||
y = relativeContactPosition1.z*impulse.x - relativeContactPosition1.x*impulse.z;
|
||||
z = relativeContactPosition1.x*impulse.y - relativeContactPosition1.y*impulse.x;
|
||||
rotationChange1.x = inverseInertiaTensor1.a*x + inverseInertiaTensor1.b*y + inverseInertiaTensor1.c*z;
|
||||
rotationChange1.y = inverseInertiaTensor1.e*x + inverseInertiaTensor1.f*y + inverseInertiaTensor1.g*z;
|
||||
rotationChange1.z = inverseInertiaTensor1.i*x + inverseInertiaTensor1.j*y + inverseInertiaTensor1.k*z;
|
||||
|
||||
velocityChange1.x = impulse.x*body1.inverseMass;
|
||||
velocityChange1.y = impulse.y*body1.inverseMass;
|
||||
velocityChange1.z = impulse.z*body1.inverseMass;
|
||||
|
||||
body1.velocity.x += velocityChange1.x;
|
||||
body1.velocity.y += velocityChange1.y;
|
||||
body1.velocity.z += velocityChange1.z;
|
||||
|
||||
body1.rotation.x += rotationChange1.x;
|
||||
body1.rotation.y += rotationChange1.y;
|
||||
body1.rotation.z += rotationChange1.z;
|
||||
|
||||
if (body2 != null) {
|
||||
x = relativeContactPosition2.z*impulse.y - relativeContactPosition2.y*impulse.z;
|
||||
y = relativeContactPosition2.x*impulse.z - relativeContactPosition2.z*impulse.x;
|
||||
z = relativeContactPosition2.y*impulse.x - relativeContactPosition2.x*impulse.y;
|
||||
rotationChange2.x = inverseInertiaTensor2.a*x + inverseInertiaTensor2.b*y + inverseInertiaTensor2.c*z;
|
||||
rotationChange2.y = inverseInertiaTensor2.e*x + inverseInertiaTensor2.f*y + inverseInertiaTensor2.g*z;
|
||||
rotationChange2.z = inverseInertiaTensor2.i*x + inverseInertiaTensor2.j*y + inverseInertiaTensor2.k*z;
|
||||
|
||||
velocityChange2.x = -impulse.x*body2.inverseMass;
|
||||
velocityChange2.y = -impulse.y*body2.inverseMass;
|
||||
velocityChange2.z = -impulse.z*body2.inverseMass;
|
||||
|
||||
body2.velocity.x += velocityChange2.x;
|
||||
body2.velocity.y += velocityChange2.y;
|
||||
body2.velocity.z += velocityChange2.z;
|
||||
|
||||
body2.rotation.x += rotationChange2.x;
|
||||
body2.rotation.y += rotationChange2.y;
|
||||
body2.rotation.z += rotationChange2.z;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Вычисляет импульс, необходимый для коррекции скоростей в точке контакта в отсутствие сил трения.
|
||||
*/
|
||||
public function calculateFrictionlessImpulse(inverseInertiaTensor1:Matrix3D, inverseInertiaTensor2:Matrix3D, result:Point3D):void {
|
||||
tmpVelocityVector.x = relativeContactPosition1.y*contactNormal.z - relativeContactPosition1.z*contactNormal.y;
|
||||
tmpVelocityVector.y = relativeContactPosition1.z*contactNormal.x - relativeContactPosition1.x*contactNormal.z;
|
||||
tmpVelocityVector.z = relativeContactPosition1.x*contactNormal.y - relativeContactPosition1.y*contactNormal.x;
|
||||
|
||||
var x:Number = inverseInertiaTensor1.a*tmpVelocityVector.x + inverseInertiaTensor1.b*tmpVelocityVector.y + inverseInertiaTensor1.c*tmpVelocityVector.z;
|
||||
var y:Number = inverseInertiaTensor1.e*tmpVelocityVector.x + inverseInertiaTensor1.f*tmpVelocityVector.y + inverseInertiaTensor1.g*tmpVelocityVector.z;
|
||||
var z:Number = inverseInertiaTensor1.i*tmpVelocityVector.x + inverseInertiaTensor1.j*tmpVelocityVector.y + inverseInertiaTensor1.k*tmpVelocityVector.z;
|
||||
|
||||
tmpVelocityVector.x = y*relativeContactPosition1.z - z*relativeContactPosition1.y;
|
||||
tmpVelocityVector.y = z*relativeContactPosition1.x - x*relativeContactPosition1.z;
|
||||
tmpVelocityVector.z = x*relativeContactPosition1.y - y*relativeContactPosition1.x;
|
||||
|
||||
var deltaVelocity:Number = tmpVelocityVector.x*contactNormal.x + tmpVelocityVector.y*contactNormal.y + tmpVelocityVector.z*contactNormal.z + body1.inverseMass;
|
||||
|
||||
if (body2 != null) {
|
||||
tmpVelocityVector.x = relativeContactPosition2.y*contactNormal.z - relativeContactPosition2.z*contactNormal.y;
|
||||
tmpVelocityVector.y = relativeContactPosition2.z*contactNormal.x - relativeContactPosition2.x*contactNormal.z;
|
||||
tmpVelocityVector.z = relativeContactPosition2.x*contactNormal.y - relativeContactPosition2.y*contactNormal.x;
|
||||
|
||||
x = inverseInertiaTensor2.a*tmpVelocityVector.x + inverseInertiaTensor2.b*tmpVelocityVector.y + inverseInertiaTensor2.c*tmpVelocityVector.z;
|
||||
y = inverseInertiaTensor2.e*tmpVelocityVector.x + inverseInertiaTensor2.f*tmpVelocityVector.y + inverseInertiaTensor2.g*tmpVelocityVector.z;
|
||||
z = inverseInertiaTensor2.i*tmpVelocityVector.x + inverseInertiaTensor2.j*tmpVelocityVector.y + inverseInertiaTensor2.k*tmpVelocityVector.z;
|
||||
|
||||
tmpVelocityVector.x = y*relativeContactPosition2.z - z*relativeContactPosition2.y;
|
||||
tmpVelocityVector.y = z*relativeContactPosition2.x - x*relativeContactPosition2.z;
|
||||
tmpVelocityVector.z = x*relativeContactPosition2.y - y*relativeContactPosition2.x;
|
||||
|
||||
deltaVelocity += tmpVelocityVector.x*contactNormal.x + tmpVelocityVector.y*contactNormal.y + tmpVelocityVector.z*contactNormal.z + body2.inverseMass;
|
||||
}
|
||||
|
||||
result.x = desiredDeltaVelocity/deltaVelocity;
|
||||
result.y = 0;
|
||||
result.z = 0;
|
||||
}
|
||||
|
||||
private var impulseToTorque:Matrix3D = new Matrix3D();
|
||||
private var deltaVelWorldMatrix:Matrix3D = new Matrix3D();
|
||||
private var deltaVelWorldMatrix2:Matrix3D = new Matrix3D();
|
||||
/**
|
||||
* Вычисляет импульс, необходимый для коррекции скоростей в точке контакта при наличии сил трения.
|
||||
*/
|
||||
public function calculateFrictionImpulse(inverseInertiaTensor1:Matrix3D, inverseInertiaTensor2:Matrix3D, result:Point3D):void {
|
||||
var inverseMass:Number = body1.inverseMass;
|
||||
|
||||
relativeContactPosition1.createSkewSymmetricMatrix(impulseToTorque);
|
||||
|
||||
deltaVelWorldMatrix.copy(impulseToTorque);
|
||||
deltaVelWorldMatrix.inverseCombine(inverseInertiaTensor1);
|
||||
deltaVelWorldMatrix.inverseCombine(impulseToTorque);
|
||||
deltaVelWorldMatrix.multByScalar(-1);
|
||||
|
||||
if (body2 != null) {
|
||||
relativeContactPosition2.createSkewSymmetricMatrix(impulseToTorque);
|
||||
deltaVelWorldMatrix2.copy(impulseToTorque);
|
||||
deltaVelWorldMatrix2.inverseCombine(inverseInertiaTensor2);
|
||||
deltaVelWorldMatrix2.inverseCombine(impulseToTorque);
|
||||
deltaVelWorldMatrix2.multByScalar(-1);
|
||||
|
||||
deltaVelWorldMatrix.add(deltaVelWorldMatrix2);
|
||||
inverseMass += body2.inverseMass;
|
||||
}
|
||||
|
||||
deltaVelWorldMatrix2.copy(contactToWorld);
|
||||
deltaVelWorldMatrix2.transpose();
|
||||
deltaVelWorldMatrix2.inverseCombine(deltaVelWorldMatrix);
|
||||
deltaVelWorldMatrix2.inverseCombine(contactToWorld);
|
||||
deltaVelWorldMatrix2.a += inverseMass;
|
||||
deltaVelWorldMatrix2.f += inverseMass;
|
||||
deltaVelWorldMatrix2.k += inverseMass;
|
||||
|
||||
deltaVelWorldMatrix.copy(deltaVelWorldMatrix2);
|
||||
deltaVelWorldMatrix.invert();
|
||||
|
||||
result.reset(desiredDeltaVelocity, -contactVelocity.y, -contactVelocity.z);
|
||||
result.transform(deltaVelWorldMatrix);
|
||||
|
||||
var planarImpulse:Number = Math.sqrt(result.y*result.y + result.z*result.z);
|
||||
if (planarImpulse > result.x*friction) {
|
||||
result.y /= planarImpulse;
|
||||
result.z /= planarImpulse;
|
||||
result.x = desiredDeltaVelocity/(deltaVelWorldMatrix2.a + deltaVelWorldMatrix2.b*friction*result.y + deltaVelWorldMatrix2.c*friction*result.z);
|
||||
result.y *= friction*result.x;
|
||||
result.z *= friction*result.x;
|
||||
}
|
||||
}
|
||||
|
||||
private var angularInertiaWorld:Point3D = new Point3D();
|
||||
/**
|
||||
* Выполняет разделение контакта с учётом инертности тел.
|
||||
*/
|
||||
public function applyPositionChange(linearChange1:Point3D, linearChange2:Point3D, angularChange1:Point3D, angularChange2:Point3D, penetration:Number):void {
|
||||
var totalInertia:Number = 0;
|
||||
var angularInertia1:Number;
|
||||
var angularInertia2:Number;
|
||||
var linearInertia1:Number;
|
||||
var linearInertia2:Number;
|
||||
|
||||
// body1
|
||||
angularInertiaWorld.x = relativeContactPosition1.y*contactNormal.z - relativeContactPosition1.z*contactNormal.y;
|
||||
angularInertiaWorld.y = relativeContactPosition1.z*contactNormal.x - relativeContactPosition1.x*contactNormal.z;
|
||||
angularInertiaWorld.z = relativeContactPosition1.x*contactNormal.y - relativeContactPosition1.y*contactNormal.x;
|
||||
var m:Matrix3D = body1.inverseInertiaTensorWorld;
|
||||
var x:Number = m.a*angularInertiaWorld.x + m.b*angularInertiaWorld.y + m.c*angularInertiaWorld.z;
|
||||
var y:Number = m.e*angularInertiaWorld.x + m.f*angularInertiaWorld.y + m.g*angularInertiaWorld.z;
|
||||
var z:Number = m.i*angularInertiaWorld.x + m.j*angularInertiaWorld.y + m.k*angularInertiaWorld.z;
|
||||
angularInertiaWorld.x = y*relativeContactPosition1.z - z*relativeContactPosition1.y;
|
||||
angularInertiaWorld.y = z*relativeContactPosition1.x - x*relativeContactPosition1.z;
|
||||
angularInertiaWorld.z = x*relativeContactPosition1.y - y*relativeContactPosition1.x;
|
||||
|
||||
angularInertia1 = angularInertiaWorld.x*contactNormal.x + angularInertiaWorld.y*contactNormal.y + angularInertiaWorld.z*contactNormal.z;
|
||||
linearInertia1 = body1.inverseMass;
|
||||
|
||||
totalInertia = linearInertia1 + angularInertia1;
|
||||
|
||||
if (body2 != null) {
|
||||
angularInertiaWorld.x = relativeContactPosition2.y*contactNormal.z - relativeContactPosition2.z*contactNormal.y;
|
||||
angularInertiaWorld.y = relativeContactPosition2.z*contactNormal.x - relativeContactPosition2.x*contactNormal.z;
|
||||
angularInertiaWorld.z = relativeContactPosition2.x*contactNormal.y - relativeContactPosition2.y*contactNormal.x;
|
||||
m = body2.inverseInertiaTensorWorld;
|
||||
x = m.a*angularInertiaWorld.x + m.b*angularInertiaWorld.y + m.c*angularInertiaWorld.z;
|
||||
y = m.e*angularInertiaWorld.x + m.f*angularInertiaWorld.y + m.g*angularInertiaWorld.z;
|
||||
z = m.i*angularInertiaWorld.x + m.j*angularInertiaWorld.y + m.k*angularInertiaWorld.z;
|
||||
angularInertiaWorld.x = y*relativeContactPosition2.z - z*relativeContactPosition2.y;
|
||||
angularInertiaWorld.y = z*relativeContactPosition2.x - x*relativeContactPosition2.z;
|
||||
angularInertiaWorld.z = x*relativeContactPosition2.y - y*relativeContactPosition2.x;
|
||||
|
||||
angularInertia2 = angularInertiaWorld.x*contactNormal.x + angularInertiaWorld.y*contactNormal.y + angularInertiaWorld.z*contactNormal.z;
|
||||
linearInertia2 = body2.inverseMass;
|
||||
|
||||
totalInertia += linearInertia2 + angularInertia2;
|
||||
}
|
||||
|
||||
// body1
|
||||
applyPostionChangeToBody(body1, relativeContactPosition1, angularInertia1, linearInertia1, totalInertia, 1, angularChange1, linearChange1);
|
||||
|
||||
if (body2 != null) {
|
||||
applyPostionChangeToBody(body2, relativeContactPosition2, angularInertia2, linearInertia2, totalInertia, -1, angularChange2, linearChange2);
|
||||
}
|
||||
}
|
||||
|
||||
private var projection:Point3D = new Point3D();
|
||||
/**
|
||||
*
|
||||
* @param body
|
||||
* @param relativeContactPosition
|
||||
* @param angularInertia
|
||||
* @param linearInertia
|
||||
* @param totalInertia
|
||||
* @param sign
|
||||
* @param angularChange
|
||||
* @param linearChange
|
||||
*/
|
||||
private function applyPostionChangeToBody(body:RigidBody, relativeContactPosition:Point3D, angularInertia:Number, linearInertia:Number, totalInertia:Number, sign:Number, angularChange:Point3D, linearChange:Point3D):void {
|
||||
var angularLimit:Number = 0.2;
|
||||
var angularMove:Number = sign*penetration*angularInertia/totalInertia;
|
||||
var linearMove:Number = sign*penetration*linearInertia/totalInertia;
|
||||
|
||||
projection.copy(contactNormal);
|
||||
projection.multiply(-relativeContactPosition.dot(contactNormal));
|
||||
projection.add(relativeContactPosition);
|
||||
|
||||
var maxMagnitude:Number = angularLimit*projection.length;
|
||||
|
||||
var totalMove:Number;
|
||||
if (angularMove < -maxMagnitude) {
|
||||
totalMove = angularMove + linearMove;
|
||||
angularMove = -maxMagnitude;
|
||||
linearMove = totalMove - angularMove;
|
||||
} else if (angularMove > maxMagnitude) {
|
||||
totalMove = angularMove + linearMove;
|
||||
angularMove = maxMagnitude;
|
||||
linearMove = totalMove - angularMove;
|
||||
}
|
||||
|
||||
if (angularMove == 0) {
|
||||
angularChange.reset();
|
||||
} else {
|
||||
angularChange.copy(relativeContactPosition);
|
||||
angularChange.cross(contactNormal);
|
||||
angularChange.transform(body.inverseInertiaTensorWorld);
|
||||
angularChange.multiply(angularMove/angularInertia);
|
||||
}
|
||||
|
||||
linearChange.copy(contactNormal);
|
||||
linearChange.multiply(linearMove);
|
||||
|
||||
body.position.add(linearChange);
|
||||
body.orientation.addScaledVector(angularChange, 1);
|
||||
if (!body.awake) {
|
||||
body.calculateDerivedData();
|
||||
}
|
||||
}
|
||||
|
||||
public function toString():String {
|
||||
return "RigidBodyContact" +
|
||||
"\n timeStamp: " + timeStamp +
|
||||
"\n body1: " + body1.getName() +
|
||||
"\n body2: " + (body2 == null ? "" : body2.getName()) +
|
||||
"\n contactPoint: " + contactPoint +
|
||||
"\n contactNormal: " + contactNormal +
|
||||
"\n restitution: " + restitution +
|
||||
"\n penetration: " + penetration +
|
||||
"\n friction: " + friction;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package alternativa.physics.rigid {
|
||||
|
||||
/**
|
||||
* Генератор контактов для твёрдых тел.
|
||||
*/
|
||||
public class RigidBodyContactGenerator {
|
||||
/**
|
||||
* Следующий генератор в списке.
|
||||
*/
|
||||
public var next:RigidBodyContactGenerator;
|
||||
|
||||
/**
|
||||
* Метод создаёт контакты.
|
||||
*
|
||||
* @param contact первый свободный для записи контакт в списке контактов мира
|
||||
* @return следующий свободный для записи контакт после окончания работы метода. Значение null означает, что доступные контакты исчерпаны.
|
||||
*/
|
||||
public function addContacts(contact:RigidBodyContact):RigidBodyContact {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
package alternativa.physics.rigid {
|
||||
|
||||
import alternativa.physics.*;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
use namespace altphysics;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class RigidBodyContactResolver {
|
||||
|
||||
private var velocityIterations:int;
|
||||
private var positionIterations:int;
|
||||
private var velocityEpsilon:Number;
|
||||
private var positionEpsilon:Number;
|
||||
|
||||
private var velocityIterationsUsed:int;
|
||||
private var positionIterationsUsed:int;
|
||||
|
||||
private var linearChange1:Point3D = new Point3D();
|
||||
private var linearChange2:Point3D = new Point3D();
|
||||
private var angularChange1:Point3D = new Point3D();
|
||||
private var angularChange2:Point3D = new Point3D();
|
||||
|
||||
private var velocityChange1:Point3D = new Point3D();
|
||||
private var velocityChange2:Point3D = new Point3D();
|
||||
private var rotationChange1:Point3D = new Point3D();
|
||||
private var rotationChange2:Point3D = new Point3D();
|
||||
|
||||
private var deltaVector:Point3D = new Point3D();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param velocityIterations
|
||||
* @param positionIterations
|
||||
* @param velocityEpsilon
|
||||
* @param positionEpsilon
|
||||
*/
|
||||
public function RigidBodyContactResolver(velocityIterations:int, positionIterations:int, velocityEpsilon:Number = 0.001, positionEpsilon:Number = 0.001) {
|
||||
this.velocityIterations = velocityIterations;
|
||||
this.positionIterations = positionIterations;
|
||||
this.velocityEpsilon = velocityEpsilon;
|
||||
this.positionEpsilon = positionEpsilon;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param velocityIterations
|
||||
* @param positionEpsilon
|
||||
*/
|
||||
public function setIterations(velocityIterations:int, positionIterations:int):void {
|
||||
this.velocityIterations = velocityIterations;
|
||||
this.positionIterations = positionIterations;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private function isValid():Boolean {
|
||||
return (positionIterations > 0) && (velocityIterations > 0) && (positionEpsilon >= 0) && (velocityEpsilon >= 0);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param firstContact
|
||||
* @param numContacts
|
||||
* @param time
|
||||
*/
|
||||
public function resolveContacts(firstContact:RigidBodyContact, numContacts:int, time:Number):void {
|
||||
if (numContacts == 0 || !isValid()) {
|
||||
return;
|
||||
}
|
||||
// Подготовка контактов к обработке
|
||||
prepareContacts(firstContact, numContacts, time);
|
||||
// Разделение взаимно проникающих контактов
|
||||
adjustPositions(firstContact, numContacts, time);
|
||||
// Коррекция скорости для контактов
|
||||
adjustVelocities(firstContact, numContacts, time);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param firstContact
|
||||
* @param numContacts
|
||||
* @param time
|
||||
*/
|
||||
public function prepareContacts(firstContact:RigidBodyContact, numContacts:int, time:Number):void {
|
||||
var contact:RigidBodyContact = firstContact;
|
||||
while (contact.index < numContacts) {
|
||||
// Вычисление внутренних данных контакта, необходимых для дальнейшей работы
|
||||
contact.calculateInternals(time);
|
||||
contact = contact.next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param firstContact
|
||||
* @param numContacts
|
||||
* @param time
|
||||
*/
|
||||
public function adjustPositions(firstContact:RigidBodyContact, numContacts:int, time:Number):void {
|
||||
positionIterationsUsed = 0;
|
||||
// Итерационное устранение взаимного проникновения тел в точках контактов в порядке наибольшего пересечения тел
|
||||
while (positionIterationsUsed < positionIterations) {
|
||||
var max:Number = positionEpsilon;
|
||||
var mostSevereContact:RigidBodyContact = null;
|
||||
// Поиск контакта с наибольшим пересечением
|
||||
var contact:RigidBodyContact = firstContact;
|
||||
while (contact.index < numContacts) {
|
||||
if (contact.penetration > max) {
|
||||
max = contact.penetration;
|
||||
mostSevereContact = contact;
|
||||
}
|
||||
contact = contact.next;
|
||||
}
|
||||
if (mostSevereContact == null) {
|
||||
// Алгоритм прерывается, если не осталось пересечений
|
||||
return;
|
||||
}
|
||||
// Будим спящего
|
||||
mostSevereContact.matchAwakeState();
|
||||
|
||||
// Разделяем контакт
|
||||
mostSevereContact.applyPositionChange(linearChange1, linearChange2, angularChange1, angularChange2, max);
|
||||
// Обновляем величину проникновения в каждом контакте, содержащем обработанные объекты
|
||||
contact = firstContact;
|
||||
while (contact.index < numContacts) {
|
||||
if (contact.body1 == mostSevereContact.body1) {
|
||||
deltaVector.copy(angularChange1);
|
||||
deltaVector.cross(contact.relativeContactPosition1);
|
||||
deltaVector.add(linearChange1);
|
||||
contact.penetration -= deltaVector.dot(contact.contactNormal);
|
||||
}
|
||||
if (contact.body1 == mostSevereContact.body2) {
|
||||
deltaVector.copy(angularChange2);
|
||||
deltaVector.cross(contact.relativeContactPosition1);
|
||||
deltaVector.add(linearChange2);
|
||||
contact.penetration -= deltaVector.dot(contact.contactNormal);
|
||||
}
|
||||
if (contact.body2 != null) {
|
||||
if (contact.body2 == mostSevereContact.body1) {
|
||||
deltaVector.copy(angularChange1);
|
||||
deltaVector.cross(contact.relativeContactPosition2);
|
||||
deltaVector.add(linearChange1);
|
||||
contact.penetration += deltaVector.dot(contact.contactNormal);
|
||||
}
|
||||
if (contact.body2 == mostSevereContact.body2) {
|
||||
deltaVector.copy(angularChange2);
|
||||
deltaVector.cross(contact.relativeContactPosition2);
|
||||
deltaVector.add(linearChange2);
|
||||
contact.penetration += deltaVector.dot(contact.contactNormal);
|
||||
}
|
||||
}
|
||||
contact = contact.next;
|
||||
}
|
||||
positionIterationsUsed++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param firstContact
|
||||
* @param numContacts
|
||||
* @param time
|
||||
*/
|
||||
public function adjustVelocities(firstContact:RigidBodyContact, numContacts:int, time:Number):void {
|
||||
velocityIterationsUsed = 0;
|
||||
while (velocityIterationsUsed < velocityIterations) {
|
||||
var max:Number = velocityEpsilon;
|
||||
var mostSevereContact:RigidBodyContact = null;
|
||||
var contact:RigidBodyContact = firstContact;
|
||||
while (contact.index < numContacts) {
|
||||
if (contact.desiredDeltaVelocity > max) {
|
||||
max = contact.desiredDeltaVelocity;
|
||||
mostSevereContact = contact;
|
||||
}
|
||||
contact = contact.next;
|
||||
}
|
||||
if (mostSevereContact == null) {
|
||||
return;
|
||||
}
|
||||
// Будим спящих
|
||||
mostSevereContact.matchAwakeState();
|
||||
// Корректируем скорости
|
||||
mostSevereContact.applyVelocityChange(velocityChange1, velocityChange2, rotationChange1, rotationChange2);
|
||||
// Обновляем скорости сближения для каждого контакта, содержащего обработанные объекты
|
||||
contact = firstContact;
|
||||
var needRecalculation:Boolean = false;
|
||||
while (contact.index < numContacts) {
|
||||
if (contact.body1 == mostSevereContact.body1) {
|
||||
deltaVector.copy(rotationChange1);
|
||||
deltaVector.cross(contact.relativeContactPosition1);
|
||||
deltaVector.add(velocityChange1);
|
||||
deltaVector.transformTranspose(contact.contactToWorld);
|
||||
contact.contactVelocity.add(deltaVector);
|
||||
needRecalculation = true;
|
||||
}
|
||||
if (contact.body1 == mostSevereContact.body2) {
|
||||
deltaVector.copy(rotationChange2);
|
||||
deltaVector.cross(contact.relativeContactPosition1);
|
||||
deltaVector.add(velocityChange2);
|
||||
deltaVector.transformTranspose(contact.contactToWorld);
|
||||
contact.contactVelocity.add(deltaVector);
|
||||
needRecalculation = true;
|
||||
}
|
||||
if (contact.body2 != null) {
|
||||
if (contact.body2 == mostSevereContact.body1) {
|
||||
deltaVector.copy(rotationChange1);
|
||||
deltaVector.cross(contact.relativeContactPosition2);
|
||||
deltaVector.add(velocityChange1);
|
||||
deltaVector.transformTranspose(contact.contactToWorld);
|
||||
contact.contactVelocity.subtract(deltaVector);
|
||||
needRecalculation = true;
|
||||
}
|
||||
if (contact.body2 == mostSevereContact.body2) {
|
||||
deltaVector.copy(rotationChange2);
|
||||
deltaVector.cross(contact.relativeContactPosition2);
|
||||
deltaVector.add(velocityChange2);
|
||||
deltaVector.transformTranspose(contact.contactToWorld);
|
||||
contact.contactVelocity.subtract(deltaVector);
|
||||
needRecalculation = true;
|
||||
}
|
||||
}
|
||||
if (needRecalculation) {
|
||||
contact.calculateDesiredVelocity(time);
|
||||
}
|
||||
contact = contact.next;
|
||||
}
|
||||
velocityIterationsUsed++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
136
0.0.0.18/src/alternativa/physics/rigid/RigidWorld.as
Normal file
136
0.0.0.18/src/alternativa/physics/rigid/RigidWorld.as
Normal file
@@ -0,0 +1,136 @@
|
||||
package alternativa.physics.rigid {
|
||||
|
||||
public class RigidWorld {
|
||||
|
||||
private var firstBody:RigidBody;
|
||||
private var lastBody:RigidBody;
|
||||
private var contactGenerators:RigidBodyContactGenerator;
|
||||
private var lastContactGenerator:RigidBodyContactGenerator;
|
||||
|
||||
public var contacts:RigidBodyContact;
|
||||
private var maxContacts:int;
|
||||
private var resolver:RigidBodyContactResolver;
|
||||
|
||||
public var forceRegistry:BodyForceRegistry = new BodyForceRegistry();
|
||||
public var calculateIterations:Boolean;
|
||||
|
||||
public var numContacts:int;
|
||||
|
||||
public function RigidWorld(maxContacts:int, iterations:int) {
|
||||
this.maxContacts = maxContacts;
|
||||
resolver = new RigidBodyContactResolver(iterations, iterations);
|
||||
createContactList(maxContacts);
|
||||
}
|
||||
|
||||
private function createContactList(numContacts:int):void {
|
||||
if (numContacts > 0) {
|
||||
var contact:RigidBodyContact = contacts = new RigidBodyContact(0);
|
||||
for (var i:int = 1; i < numContacts; i++) {
|
||||
contact.next = new RigidBodyContact(i);
|
||||
contact = contact.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function addBody(body:RigidBody):void {
|
||||
if (firstBody == null) {
|
||||
firstBody = body;
|
||||
} else {
|
||||
lastBody.next = body;
|
||||
}
|
||||
lastBody = body;
|
||||
while (lastBody.next != null) {
|
||||
lastBody = lastBody.next;
|
||||
}
|
||||
}
|
||||
|
||||
public function removeBody(body:RigidBody):void {
|
||||
if (body == firstBody) {
|
||||
firstBody = firstBody.next;
|
||||
body.next = null;
|
||||
} else {
|
||||
var current:RigidBody = firstBody;
|
||||
var prev:RigidBody = null;
|
||||
while (current != body && current != null) {
|
||||
prev = current;
|
||||
current = current.next;
|
||||
}
|
||||
if (current != null) {
|
||||
if (lastBody == body) {
|
||||
lastBody = prev;
|
||||
}
|
||||
prev.next = current.next;
|
||||
current.next = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function addContactGenerator(gen:RigidBodyContactGenerator):void {
|
||||
if (contactGenerators == null) {
|
||||
contactGenerators = gen;
|
||||
} else {
|
||||
lastContactGenerator.next = gen;
|
||||
}
|
||||
lastContactGenerator = gen;
|
||||
while (lastContactGenerator.next != null) {
|
||||
lastContactGenerator = lastContactGenerator.next;
|
||||
}
|
||||
}
|
||||
|
||||
public function removeContactGenerator(gen:RigidBodyContactGenerator):void {
|
||||
if (gen == contactGenerators) {
|
||||
contactGenerators = gen.next;
|
||||
gen.next = null;
|
||||
} else {
|
||||
var prev:RigidBodyContactGenerator = contactGenerators;
|
||||
var curr:RigidBodyContactGenerator = contactGenerators.next;
|
||||
while (curr != gen && curr != null) {
|
||||
prev = curr;
|
||||
curr = curr.next;
|
||||
}
|
||||
if (curr == gen) {
|
||||
if (lastContactGenerator == gen) {
|
||||
lastContactGenerator = prev;
|
||||
}
|
||||
prev.next = curr.next;
|
||||
curr.next = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function startFrame():void {
|
||||
var body:RigidBody = firstBody;
|
||||
while (body != null) {
|
||||
body.clearAccumulators();
|
||||
body.calculateDerivedData();
|
||||
body = body.next;
|
||||
}
|
||||
}
|
||||
|
||||
private function generateContacts():int {
|
||||
var contact:RigidBodyContact = contacts;
|
||||
var gen:RigidBodyContactGenerator = contactGenerators;
|
||||
while (gen != null && contact != null) {
|
||||
contact = gen.addContacts(contact);
|
||||
gen = gen.next;
|
||||
}
|
||||
return contact == null ? maxContacts : contact.index;
|
||||
}
|
||||
|
||||
public function runPhysics(time:Number):void {
|
||||
forceRegistry.updateForces(time);
|
||||
var body:RigidBody = firstBody;
|
||||
while (body != null) {
|
||||
body.integrate(time);
|
||||
body = body.next;
|
||||
}
|
||||
numContacts = generateContacts();
|
||||
// trace("[RigidWorld.runPhysics] numContacts", numContacts);
|
||||
if (calculateIterations) {
|
||||
resolver.setIterations(4*numContacts, 4*numContacts);
|
||||
}
|
||||
resolver.resolveContacts(contacts, numContacts, time);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 111
|
||||
/!svn/ver/4732/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/rigid/generators
|
||||
END
|
||||
AnchoredCableContactGenerator.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 144
|
||||
/!svn/ver/4732/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/rigid/generators/AnchoredCableContactGenerator.as
|
||||
END
|
||||
RigidBoxCollisionData.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 136
|
||||
/!svn/ver/4385/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/rigid/generators/RigidBoxCollisionData.as
|
||||
END
|
||||
BoxWithBoxContactGenerator.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 141
|
||||
/!svn/ver/4403/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/rigid/generators/BoxWithBoxContactGenerator.as
|
||||
END
|
||||
SphereWithPlaneContactGenerator.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 146
|
||||
/!svn/ver/4385/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/rigid/generators/SphereWithPlaneContactGenerator.as
|
||||
END
|
||||
RigidBox.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 123
|
||||
/!svn/ver/4603/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/rigid/generators/RigidBox.as
|
||||
END
|
||||
@@ -0,0 +1,89 @@
|
||||
8
|
||||
|
||||
dir
|
||||
46043
|
||||
http://svndev.alternativaplatform.com/platform/clients/fp9/libraries/AlternativaPhysics/trunk/src/alternativa/physics/rigid/generators
|
||||
http://svndev.alternativaplatform.com
|
||||
|
||||
|
||||
|
||||
2008-12-03T05:15:16.843707Z
|
||||
4732
|
||||
mike
|
||||
|
||||
|
||||
svn:special svn:externals svn:needs-lock
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
d9e2387a-1f3e-40e2-b57f-9df5970a2fa5
|
||||
|
||||
AnchoredCableContactGenerator.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
aa5b3540cfe5796ebad67e11f47a4aa9
|
||||
2008-12-03T05:15:16.843707Z
|
||||
4732
|
||||
mike
|
||||
|
||||
RigidBoxCollisionData.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
607a1d12afedbe3344ae967c6f599fd4
|
||||
2008-11-26T13:17:08.913613Z
|
||||
4385
|
||||
mike
|
||||
|
||||
BoxWithBoxContactGenerator.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
47da766c6f7ca03fb1622378c740abb4
|
||||
2008-11-26T16:00:07.127812Z
|
||||
4403
|
||||
mike
|
||||
|
||||
SphereWithPlaneContactGenerator.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
558aa2a28f3cc4a3932c19e5e2ab230c
|
||||
2008-11-26T13:17:08.913613Z
|
||||
4385
|
||||
mike
|
||||
has-props
|
||||
|
||||
RigidBox.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:34:31.000000Z
|
||||
505d9996c9461cc769d2accf7295c871
|
||||
2008-11-30T13:03:39.561308Z
|
||||
4603
|
||||
mike
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user