Section 1
//NeverMind (KXG164_GamesPhysics.TestCases.NeverMind)
package KXG164_GamesPhysics.TestCases {
import flash.events.*;
import flash.display.*;
import KXG164_GamesPhysics.*;
import flash.text.*;
public class NeverMind extends PhysicsTest {
public var NonPlayerCharacterLimit:Number;
public var PlayerCharacterCurrentScore:TextField;
public var PlayerCharacterBestScore:TextField;
public var PlayerCharacter:Ball;
public var BestScore:Number;
public var NonPlayerCharacterCount:Number;
public var CurrentScore:Number;
public var NonPlayerCharacter:Array;
public function NeverMind(container:Sprite, framerate:Number){
var NonPlayerCharacterIdentity:int;
var NonPlayerCharacterPosition:Vector2D;
var NonPlayerCharacterVelocity:Vector2D;
var NonPlayerCharacterRadius:Number;
var NonPlayerCharacterColour:uint;
var Increment2:Number;
PlayerCharacterCurrentScore = new TextField();
PlayerCharacterBestScore = new TextField();
NonPlayerCharacter = new Array();
NonPlayerCharacterCount = new Number(0);
NonPlayerCharacterLimit = new Number(1);
CurrentScore = Number(0);
BestScore = Number(0);
super(container, framerate);
container.stage.addEventListener(Event.ENTER_FRAME, PlayerCharacterInput);
physics.addContactGenerator(new ContactGenerator(physics));
var PlayerCharacterPosition:Vector2D = new Vector2D(400, 300);
var PlayerCharacterVelocity:Vector2D = new Vector2D();
var PlayerCharacterRadius:Number = new Number(10);
var PlayerCharacterColour:uint = (Math.random() * 0xFFFFFF);
PlayerCharacter = new Ball(-1, PlayerCharacterPosition, PlayerCharacterVelocity, PlayerCharacterRadius, PlayerCharacterColour);
PlayerCharacter.fixed = false;
PlayerCharacter.sprite.x = PlayerCharacter.position.x;
PlayerCharacter.sprite.y = PlayerCharacter.position.y;
container.addChild(PlayerCharacter.sprite);
physics.addParticle(PlayerCharacter);
PlayerCharacter.setMass(PlayerCharacterRadius);
PlayerCharacterCurrentScore.mouseEnabled = false;
PlayerCharacterCurrentScore.width = 800;
PlayerCharacterCurrentScore.y = 20;
container.addChild(PlayerCharacterCurrentScore);
PlayerCharacterBestScore.mouseEnabled = false;
PlayerCharacterBestScore.width = 800;
PlayerCharacterBestScore.y = 40;
container.addChild(PlayerCharacterBestScore);
var Increment:Number = 0;
while (Increment < NonPlayerCharacterLimit) {
NonPlayerCharacterIdentity = Increment;
NonPlayerCharacterPosition = new Vector2D((Math.random() * 800), (Math.random() * 600));
NonPlayerCharacterVelocity = new Vector2D((Math.random() * 0), (Math.random() * 0));
NonPlayerCharacterRadius = new Number((((Math.random() * 1) * PlayerCharacter.radius) / ((1 / PlayerCharacter.inverseMass) / 10)));
NonPlayerCharacterColour = (Math.random() * 0xFFFFFF);
NonPlayerCharacter[Increment] = new Ball(NonPlayerCharacterIdentity, NonPlayerCharacterPosition, NonPlayerCharacterVelocity, NonPlayerCharacterRadius, NonPlayerCharacterColour);
NonPlayerCharacter[Increment].fixed = false;
NonPlayerCharacter[Increment].sprite.x = NonPlayerCharacter[Increment].position.x;
NonPlayerCharacter[Increment].sprite.y = NonPlayerCharacter[Increment].position.y;
container.addChild(NonPlayerCharacter[Increment].sprite);
physics.addParticle(NonPlayerCharacter[Increment]);
NonPlayerCharacter[Increment].collider = new BallCollider(this, NonPlayerCharacter[Increment]);
NonPlayerCharacter[Increment].setMass(NonPlayerCharacterRadius);
physics.addForceGenerator(new GravityGenerator([NonPlayerCharacter[Increment], PlayerCharacter], 10000));
Increment++;
};
Increment = 0;
while (Increment < (NonPlayerCharacterLimit - 1)) {
Increment2 = (Increment + 1);
while (Increment2 < (NonPlayerCharacterLimit - 1)) {
physics.addForceGenerator(new GravityGenerator([NonPlayerCharacter[Increment], NonPlayerCharacter[Increment2]], 10000));
Increment2++;
};
Increment++;
};
}
override public function update():void{
physics.step(dt);
}
public function PlayerCharacterCollision(NonPlayerCharacterInstance:Ball):void{
var NonPlayerCharacterIdentity:int;
var NonPlayerCharacterPosition:Vector2D;
var NonPlayerCharacterVelocity:Vector2D;
var NonPlayerCharacterRadius:Number;
var NonPlayerCharacterColour:uint;
var Increment:Number;
var Increment2:Number;
if ((1 / PlayerCharacter.inverseMass) >= (1 / NonPlayerCharacterInstance.inverseMass)){
CurrentScore = (CurrentScore + (1 / NonPlayerCharacterInstance.inverseMass));
if (CurrentScore > BestScore){
BestScore = CurrentScore;
};
NonPlayerCharacterIdentity = NonPlayerCharacterInstance.identity;
NonPlayerCharacterPosition = new Vector2D((Math.random() * 800), (Math.random() * 600));
NonPlayerCharacterVelocity = new Vector2D((Math.random() * 0), (Math.random() * 0));
NonPlayerCharacterRadius = new Number(((Math.random() * 1) * PlayerCharacter.radius));
NonPlayerCharacterColour = (Math.random() * 0xFFFFFF);
container.removeChild(NonPlayerCharacterInstance.sprite);
physics.removeParticle(NonPlayerCharacterInstance);
NonPlayerCharacter[NonPlayerCharacterIdentity] = new Ball(NonPlayerCharacterIdentity, NonPlayerCharacterPosition, NonPlayerCharacterVelocity, NonPlayerCharacterRadius, NonPlayerCharacterColour);
NonPlayerCharacter[NonPlayerCharacterIdentity].fixed = false;
NonPlayerCharacter[NonPlayerCharacterIdentity].sprite.x = NonPlayerCharacter[NonPlayerCharacterIdentity].position.x;
NonPlayerCharacter[NonPlayerCharacterIdentity].sprite.y = NonPlayerCharacter[NonPlayerCharacterIdentity].position.y;
container.addChild(NonPlayerCharacter[NonPlayerCharacterIdentity].sprite);
physics.addParticle(NonPlayerCharacter[NonPlayerCharacterIdentity]);
NonPlayerCharacter[NonPlayerCharacterIdentity].collider = new BallCollider(this, NonPlayerCharacter[NonPlayerCharacterIdentity]);
NonPlayerCharacter[NonPlayerCharacterIdentity].setMass(NonPlayerCharacterRadius);
Increment = 0;
while (Increment < (NonPlayerCharacterLimit - 1)) {
if (Increment != NonPlayerCharacterIdentity){
physics.addForceGenerator(new GravityGenerator([NonPlayerCharacter[NonPlayerCharacterIdentity], NonPlayerCharacter[Increment]], 10000));
};
Increment++;
};
physics.addForceGenerator(new GravityGenerator([NonPlayerCharacter[NonPlayerCharacterIdentity], PlayerCharacter], 10000));
NonPlayerCharacterLimit++;
NonPlayerCharacterIdentity = (NonPlayerCharacterLimit - 1);
NonPlayerCharacterPosition = new Vector2D((Math.random() * 800), (Math.random() * 600));
NonPlayerCharacterVelocity = new Vector2D((Math.random() * 0), (Math.random() * 0));
NonPlayerCharacterRadius = new Number((((Math.random() * 1) * PlayerCharacter.radius) + 5));
NonPlayerCharacterColour = (Math.random() * 0xFFFFFF);
NonPlayerCharacter[NonPlayerCharacterIdentity] = new Ball(NonPlayerCharacterIdentity, NonPlayerCharacterPosition, NonPlayerCharacterVelocity, NonPlayerCharacterRadius, NonPlayerCharacterColour);
NonPlayerCharacter[NonPlayerCharacterIdentity].fixed = false;
NonPlayerCharacter[NonPlayerCharacterIdentity].sprite.x = NonPlayerCharacter[NonPlayerCharacterIdentity].position.x;
NonPlayerCharacter[NonPlayerCharacterIdentity].sprite.y = NonPlayerCharacter[NonPlayerCharacterIdentity].position.y;
container.addChild(NonPlayerCharacter[NonPlayerCharacterIdentity].sprite);
physics.addParticle(NonPlayerCharacter[NonPlayerCharacterIdentity]);
NonPlayerCharacter[NonPlayerCharacterIdentity].collider = new BallCollider(this, NonPlayerCharacter[NonPlayerCharacterIdentity]);
NonPlayerCharacter[NonPlayerCharacterIdentity].setMass(NonPlayerCharacterRadius);
Increment = 0;
while (Increment < (NonPlayerCharacterLimit - 1)) {
if (Increment != NonPlayerCharacterIdentity){
physics.addForceGenerator(new GravityGenerator([NonPlayerCharacter[NonPlayerCharacterIdentity], NonPlayerCharacter[Increment]], 10000));
};
Increment++;
};
physics.addForceGenerator(new GravityGenerator([NonPlayerCharacter[NonPlayerCharacterIdentity], PlayerCharacter], 10000));
} else {
CurrentScore = 0;
Increment = (NonPlayerCharacterLimit - 1);
while (Increment >= 0) {
container.removeChild(NonPlayerCharacter[Increment].sprite);
physics.removeParticle(NonPlayerCharacter[Increment]);
NonPlayerCharacterLimit--;
Increment--;
};
NonPlayerCharacterLimit = 1;
Increment = 0;
while (Increment < NonPlayerCharacterLimit) {
NonPlayerCharacterIdentity = Increment;
NonPlayerCharacterPosition = new Vector2D((Math.random() * 800), (Math.random() * 600));
NonPlayerCharacterVelocity = new Vector2D((Math.random() * 0), (Math.random() * 0));
NonPlayerCharacterRadius = new Number((((Math.random() * 1) * PlayerCharacter.radius) / ((1 / PlayerCharacter.inverseMass) / 10)));
NonPlayerCharacterColour = (Math.random() * 0xFFFFFF);
NonPlayerCharacter[Increment] = new Ball(NonPlayerCharacterIdentity, NonPlayerCharacterPosition, NonPlayerCharacterVelocity, NonPlayerCharacterRadius, NonPlayerCharacterColour);
NonPlayerCharacter[Increment].fixed = false;
NonPlayerCharacter[Increment].sprite.x = NonPlayerCharacter[Increment].position.x;
NonPlayerCharacter[Increment].sprite.y = NonPlayerCharacter[Increment].position.y;
container.addChild(NonPlayerCharacter[Increment].sprite);
physics.addParticle(NonPlayerCharacter[Increment]);
NonPlayerCharacter[Increment].collider = new BallCollider(this, NonPlayerCharacter[Increment]);
NonPlayerCharacter[Increment].setMass(NonPlayerCharacterRadius);
physics.addForceGenerator(new GravityGenerator([NonPlayerCharacter[Increment], PlayerCharacter], 10000));
Increment++;
};
Increment = 0;
while (Increment < (NonPlayerCharacterLimit - 1)) {
Increment2 = (Increment + 1);
while (Increment2 < (NonPlayerCharacterLimit - 1)) {
physics.addForceGenerator(new GravityGenerator([NonPlayerCharacter[Increment], NonPlayerCharacter[Increment2]], 10000));
Increment2++;
};
Increment++;
};
};
}
public function PlayerCharacterInput(event:Event):void{
var Increment:Number = 0;
while (Increment < NonPlayerCharacterLimit) {
Increment++;
};
var PlayerCharacterVelocity:Vector2D = new Vector2D(container.stage.mouseX, container.stage.mouseY);
PlayerCharacterVelocity.sub(PlayerCharacter.position);
PlayerCharacterVelocity.scale(33.33);
PlayerCharacter.velocity = PlayerCharacterVelocity;
Increment = 0;
while (Increment < NonPlayerCharacterLimit) {
Increment++;
};
PlayerCharacterCurrentScore.text = ("Current Score - " + Math.round(CurrentScore));
PlayerCharacterBestScore.text = ("Best Score - " + Math.round(BestScore));
}
}
}//package KXG164_GamesPhysics.TestCases
Section 2
//PhysicsTest (KXG164_GamesPhysics.TestCases.PhysicsTest)
package KXG164_GamesPhysics.TestCases {
import flash.display.*;
import KXG164_GamesPhysics.*;
import flash.geom.*;
public class PhysicsTest {
protected var container:Sprite;
protected var physics:PhysicsEngine;
protected var dt:Number;
protected var arena:Particle;
protected var physicsdt:Number;
protected var stepsPerFrame:int;
public function PhysicsTest(container:Sprite, framerate:Number){
physics = new PhysicsEngine();
super();
this.container = container;
dt = (1 / framerate);
physics = new PhysicsEngine();
arena = new Particle(drawArena(), -10);
arena.collider = new ArenaCollider(arena, new Rectangle(0, 0, 800, 600));
arena.fixed = true;
container.addChild(arena.sprite);
physics.addStaticParticle(arena);
}
public function drawArena():Sprite{
var sprite:Sprite = new Sprite();
sprite.graphics.beginFill(16777200);
sprite.graphics.lineStyle(2, 0);
sprite.graphics.drawRect(0, 0, 800, 600);
sprite.graphics.endFill();
return (sprite);
}
public function SetSteps(n:int):void{
stepsPerFrame = n;
physicsdt = (dt / n);
}
public function update():void{
var Increment:Number = 0;
while (Increment < stepsPerFrame) {
physics.step(physicsdt);
Increment++;
};
}
}
}//package KXG164_GamesPhysics.TestCases
Section 3
//ArenaCollider (KXG164_GamesPhysics.ArenaCollider)
package KXG164_GamesPhysics {
import flash.geom.*;
public class ArenaCollider extends Collider {
public var rect:Rectangle;
public function ArenaCollider(particle:Particle, rect:Rectangle, restitution:Number=1){
super(particle, restitution);
this.rect = rect;
}
override public function collideWithCircle(c:CircleCollider):ParticleContact{
return (c.collideWithArena(this));
}
override public function collideWithArena(c:ArenaCollider):ParticleContact{
return (null);
}
override public function collide(c:Collider):ParticleContact{
return (c.collideWithArena(this));
}
}
}//package KXG164_GamesPhysics
Section 4
//Ball (KXG164_GamesPhysics.Ball)
package KXG164_GamesPhysics {
import flash.display.*;
public class Ball extends Particle {
public var radius:Number;
public var colour:uint;
public function Ball(identity:int, position:Vector2D, velocity:Vector2D, radius:Number, colour:uint=0){
super(null, identity);
collider = new CircleCollider(this, radius);
sprite = new Sprite();
sprite.graphics.beginFill(colour);
sprite.graphics.lineStyle(1, 0);
sprite.graphics.drawCircle(0, 0, radius);
sprite.graphics.endFill();
this.position = position;
this.velocity = velocity;
this.radius = radius;
this.colour = colour;
}
}
}//package KXG164_GamesPhysics
Section 5
//BallCollider (KXG164_GamesPhysics.BallCollider)
package KXG164_GamesPhysics {
import KXG164_GamesPhysics.TestCases.*;
public class BallCollider extends CircleCollider {
public var NeverMindInstance:NeverMind;
public var BallInstance:Ball;
public function BallCollider(NeverMindInstance:NeverMind, BallInstance:Ball){
this.NeverMindInstance = NeverMindInstance;
this.BallInstance = BallInstance;
super(BallInstance, BallInstance.radius);
}
override public function onCollision(c:Collider):void{
if ((((c.particle.identity == -1)) || ((particle.identity == -1)))){
NeverMindInstance.PlayerCharacterCollision(BallInstance);
};
}
}
}//package KXG164_GamesPhysics
Section 6
//CircleCollider (KXG164_GamesPhysics.CircleCollider)
package KXG164_GamesPhysics {
public class CircleCollider extends Collider {
public var radius:Number;
public function CircleCollider(particle:Particle, radius:Number, restitution:Number=1){
super(particle, restitution);
this.radius = radius;
}
override public function collideWithCircle(c:CircleCollider):ParticleContact{
var separationVector:Vector2D = Vector2D.diff(particle.position, c.particle.position);
var separation:Number = separationVector.length();
var penetration:Number = ((radius + c.radius) - separation);
if (penetration > 0){
separationVector.normalize();
return (new ParticleContact(particle, c.particle, separationVector, penetration, ((restitution + c.restitution) / 2)));
};
return (null);
}
override public function collideWithArena(c:ArenaCollider):ParticleContact{
if (particle.position.x < (c.rect.left + radius)){
return (new ParticleContact(particle, c.particle, new Vector2D(1, 0), ((c.rect.left + radius) - particle.position.x)));
};
if (particle.position.x > (c.rect.right - radius)){
return (new ParticleContact(particle, c.particle, new Vector2D(-1, 0), (particle.position.x - (c.rect.right - radius))));
};
if (particle.position.y < (c.rect.top + radius)){
return (new ParticleContact(particle, c.particle, new Vector2D(0, 1), ((c.rect.top + radius) - particle.position.y)));
};
if (particle.position.y > (c.rect.bottom - radius)){
return (new ParticleContact(particle, c.particle, new Vector2D(0, -1), (particle.position.y - (c.rect.bottom - radius))));
};
return (null);
}
override public function collideWithLineSegment(c:LineSegmentCollider):ParticleContact{
return (c.collideWithCircle(this));
}
override public function collide(c:Collider):ParticleContact{
return (c.collideWithCircle(this));
}
}
}//package KXG164_GamesPhysics
Section 7
//Collider (KXG164_GamesPhysics.Collider)
package KXG164_GamesPhysics {
public class Collider {
public var particle:Particle;
public var restitution:Number;
public function Collider(particle:Particle, restitution:Number=1){
super();
this.particle = particle;
this.restitution = restitution;
}
public function collideWithArena(c:ArenaCollider):ParticleContact{
return (null);
}
public function onCollision(c:Collider):void{
}
public function collideWithCircle(c:CircleCollider):ParticleContact{
return (null);
}
public function collideWithLineSegment(c:LineSegmentCollider):ParticleContact{
return (null);
}
public function collide(c:Collider):ParticleContact{
return (null);
}
}
}//package KXG164_GamesPhysics
Section 8
//ContactGenerator (KXG164_GamesPhysics.ContactGenerator)
package KXG164_GamesPhysics {
public class ContactGenerator {
public var physics:PhysicsEngine;
public function ContactGenerator(physics:PhysicsEngine){
super();
this.physics = physics;
}
public function generateContacts():void{
var p:Particle;
var c1:Collider;
var j:int;
var c2:Collider;
var contact:ParticleContact;
var s:Particle;
var i:int;
while (i < physics.particles.length) {
c1 = (physics.particles[i] as Particle).collider;
j = (i + 1);
while (j < physics.particles.length) {
c2 = (physics.particles[j] as Particle).collider;
contact = c1.collide(c2);
if (contact){
physics.addContact(contact);
handleCollision(contact);
};
j++;
};
i++;
};
for each (p in physics.particles) {
for each (s in physics.staticParticles) {
contact = s.collider.collide(p.collider);
if (contact){
physics.addContact(contact);
handleCollision(contact);
};
};
};
}
public function handleCollision(contact:ParticleContact):void{
contact.p1.collider.onCollision(contact.p2.collider);
contact.p2.collider.onCollision(contact.p1.collider);
}
}
}//package KXG164_GamesPhysics
Section 9
//ForceGenerator (KXG164_GamesPhysics.ForceGenerator)
package KXG164_GamesPhysics {
public class ForceGenerator {
protected var particles:Array;
public function ForceGenerator(ps:Array){
super();
particles = ps;
}
public function updateForce(dt:Number):void{
}
}
}//package KXG164_GamesPhysics
Section 10
//GravityGenerator (KXG164_GamesPhysics.GravityGenerator)
package KXG164_GamesPhysics {
public class GravityGenerator extends ForceGenerator {
public var gravityConstant:Number;
public function GravityGenerator(ps:Array, gravityConstantPar:Number){
super(ps);
gravityConstant = gravityConstantPar;
}
override public function updateForce(dt:Number):void{
var separation:Vector2D = Vector2D.diff(particles[1].position, particles[0].position);
var rsquared:Number = separation.lengthSquared();
var force:Number = (gravityConstant / ((particles[0].inverseMass * particles[1].inverseMass) * rsquared));
separation.normalize();
particles[0].addForce(Vector2D.prod(separation, force));
particles[1].addForce(Vector2D.prod(separation, -(force)));
}
}
}//package KXG164_GamesPhysics
Section 11
//LineSegmentCollider (KXG164_GamesPhysics.LineSegmentCollider)
package KXG164_GamesPhysics {
public class LineSegmentCollider extends Collider {
public var p1:Vector2D;
public var p1p2length:Number;
public var p2:Vector2D;
public var p1p2dir:Vector2D;
public function LineSegmentCollider(particle:Particle, p1Par:Vector2D, p2Par:Vector2D, restitution:Number=1){
super(particle, restitution);
p1 = p1Par;
p2 = p2Par;
var p1p2separation:Vector2D = Vector2D.diff(p2, p1);
p1p2length = p1p2separation.length();
p1p2separation.normalize();
p1p2dir = p1p2separation.copy();
}
override public function collideWithCircle(c:CircleCollider):ParticleContact{
var p1clength:Number;
var p2c:Vector2D;
var p2clength:Number;
var closestPoint:Vector2D;
var closestPointc:Vector2D;
var closestPointclength:Number;
var p1c:Vector2D = Vector2D.diff(c.particle.position, p1);
var p1p2dist:Number = p1c.dot(p1p2dir);
if (p1p2dist < 0){
p1clength = p1c.length();
if (p1clength < c.radius){
return (new ParticleContact(c.particle, particle, p1c.normalized(), (c.radius - p1clength)));
};
} else {
if (p1p2dist > p1p2length){
p2c = Vector2D.diff(c.particle.position, p2);
p2clength = p2c.length();
if (p2clength < c.radius){
return (new ParticleContact(c.particle, particle, p2c.normalized(), (c.radius - p2clength)));
};
} else {
closestPoint = Vector2D.sum(p1, Vector2D.prod(p1p2dir, p1p2dist));
closestPointc = Vector2D.diff(c.particle.position, closestPoint);
closestPointclength = closestPointc.length();
if (closestPointclength < c.radius){
return (new ParticleContact(c.particle, particle, closestPointc.normalized(), (c.radius - closestPointclength)));
};
};
};
return (null);
}
override public function collide(c:Collider):ParticleContact{
return (c.collideWithLineSegment(this));
}
}
}//package KXG164_GamesPhysics
Section 12
//Particle (KXG164_GamesPhysics.Particle)
package KXG164_GamesPhysics {
import flash.display.*;
public class Particle {
public var engine:PhysicsEngine;
public var sprite:Sprite;
public var damping:Number;// = 0.98
public var inverseMass:Number;
public var velocity:Vector2D;
public var position:Vector2D;
public var forceAccum:Vector2D;
public var collider:Collider;// = null
public var fixed:Boolean;// = false
public var identity:int;
public function Particle(s:Sprite, identity:int=-1){
super();
sprite = s;
position = Vector2D.zero();
velocity = Vector2D.zero();
forceAccum = Vector2D.zero();
this.identity = identity;
}
public function setEngine(e:PhysicsEngine):void{
engine = e;
}
public function clearAccum():void{
forceAccum = Vector2D.zero();
}
public function addForce(m:Vector2D):void{
forceAccum.add(m);
}
public function integrate(dt:Number):void{
position.add(Vector2D.prod(velocity, dt));
var acceleration:Vector2D = Vector2D.prod(forceAccum, inverseMass);
velocity.scale(damping);
if (engine != null){
acceleration.add(engine.gravity);
};
velocity.add(Vector2D.prod(acceleration, dt));
sprite.x = position.x;
sprite.y = position.y;
}
public function setMass(m:Number):void{
if (m > 0){
inverseMass = (1 / m);
};
}
}
}//package KXG164_GamesPhysics
Section 13
//ParticleContact (KXG164_GamesPhysics.ParticleContact)
package KXG164_GamesPhysics {
public class ParticleContact {
public var p1:Particle;
public var contactNormal:Vector2D;
public var p2:Particle;
public var restitution:Number;// = 1
public var penetration:Number;
public var p1Movement:Vector2D;
public var p2Movement:Vector2D;
public function ParticleContact(p1:Particle, p2:Particle, contactNormal:Vector2D, penetration:Number=0, resitution:Number=1){
p1Movement = Vector2D.zero();
p2Movement = Vector2D.zero();
super();
this.p1 = p1;
this.p2 = p2;
this.contactNormal = contactNormal;
this.penetration = penetration;
this.restitution = resitution;
}
public function resolve(dt:Number):void{
resolveVelocity(dt);
resolveInterpenetration(dt);
}
public function resolveVelocity(dt:Number):void{
var totalInverseMass:Number;
var impulse:Number;
var impulsePerIMass:Vector2D;
var seperatingVelocity:Number = calcSeperatingVelocity();
if (seperatingVelocity > 0){
return;
};
var newSeparatingVelocity:Number = (-(seperatingVelocity) * restitution);
var deltaVelocity:Number = (newSeparatingVelocity - seperatingVelocity);
if (p2.fixed){
p1.velocity.add(Vector2D.prod(contactNormal, deltaVelocity));
} else {
if (p1.fixed){
p2.velocity.add(Vector2D.prod(contactNormal, -(deltaVelocity)));
} else {
totalInverseMass = (p1.inverseMass + p2.inverseMass);
impulse = (deltaVelocity / totalInverseMass);
impulsePerIMass = Vector2D.prod(contactNormal, impulse);
p1.velocity.add(Vector2D.prod(impulsePerIMass, p1.inverseMass));
p2.velocity.add(Vector2D.prod(impulsePerIMass, -(p2.inverseMass)));
};
};
}
public function resolveInterpenetration(dt:Number):void{
var totalInverseMass:Number;
var movePerIMass:Vector2D;
if (penetration <= 0){
return;
};
if (p2.fixed){
p1Movement = Vector2D.prod(contactNormal, penetration);
p2Movement = Vector2D.zero();
} else {
if (p1.fixed){
p1Movement = Vector2D.zero();
p2Movement = Vector2D.prod(contactNormal, -(penetration));
} else {
totalInverseMass = (p1.inverseMass + p2.inverseMass);
movePerIMass = Vector2D.prod(contactNormal, (penetration / totalInverseMass));
p1Movement = Vector2D.prod(movePerIMass, p1.inverseMass);
p2Movement = Vector2D.prod(movePerIMass, -(p2.inverseMass));
};
};
p1.position.add(p1Movement);
p2.position.add(p2Movement);
}
public function calcSeperatingVelocity():Number{
var relativeVelocity:Vector2D;
relativeVelocity = Vector2D.diff(p1.velocity, p2.velocity);
return (relativeVelocity.dot(contactNormal));
}
}
}//package KXG164_GamesPhysics
Section 14
//PhysicsEngine (KXG164_GamesPhysics.PhysicsEngine)
package KXG164_GamesPhysics {
public class PhysicsEngine {
private var contactGenerators:Array;
public var forceGenerators:Array;
private var contacts:Array;
public var gravity:Vector2D;
public var staticParticles:Array;
public var particles:Array;
protected var iterations:int;// = 3
public function PhysicsEngine(){
particles = new Array();
staticParticles = new Array();
contacts = new Array();
contactGenerators = new Array();
gravity = Vector2D.zero();
forceGenerators = new Array();
super();
}
public function removeForceGenerator(c:ForceGenerator):void{
var pos:int = contacts.indexOf(c);
forceGenerators.splice(pos, 1);
}
public function addParticle(p:Particle):void{
particles.push(p);
p.setEngine(this);
}
public function clearContacts():void{
contacts = new Array();
}
public function addContactGenerator(c:ContactGenerator):void{
contactGenerators.push(c);
c.physics = this;
}
public function step(dt:Number):void{
var p:Particle;
var g:ContactGenerator;
var i:int;
var fg:ForceGenerator;
var max:Number;
var maxIndex:int;
var c:int;
var maxContact:ParticleContact;
var sepVel:Number;
var contact:ParticleContact;
var sep:Number;
for each (p in particles) {
p.integrate(dt);
};
clearContacts();
for each (g in contactGenerators) {
g.generateContacts();
};
i = 0;
while (i < (contacts.length * iterations)) {
max = 0;
maxIndex = -1;
c = 0;
while (c < contacts.length) {
sepVel = (contacts[c] as ParticleContact).calcSeperatingVelocity();
if (sepVel < max){
max = sepVel;
maxIndex = c;
};
c++;
};
if (maxIndex == -1){
break;
};
maxContact = (contacts[maxIndex] as ParticleContact);
maxContact.resolveVelocity(dt);
i++;
};
i = 0;
while (i < (contacts.length * iterations)) {
max = 0;
maxIndex = -1;
c = 0;
while (c < contacts.length) {
sep = (contacts[c] as ParticleContact).penetration;
if (sep > max){
max = sep;
maxIndex = c;
};
c++;
};
if (maxIndex == -1){
break;
};
maxContact = (contacts[maxIndex] as ParticleContact);
maxContact.resolveInterpenetration(dt);
for each (contact in contacts) {
if (contact.p1 == maxContact.p1){
contact.penetration = (contact.penetration - maxContact.p1Movement.dot(contact.contactNormal));
} else {
if (contact.p1 == maxContact.p2){
contact.penetration = (contact.penetration - maxContact.p2Movement.dot(contact.contactNormal));
};
};
if (contact.p2 == maxContact.p1){
contact.penetration = (contact.penetration + maxContact.p1Movement.dot(contact.contactNormal));
} else {
if (contact.p2 == maxContact.p2){
contact.penetration = (contact.penetration + maxContact.p2Movement.dot(contact.contactNormal));
};
};
};
i++;
};
for each (p in particles) {
p.clearAccum();
};
for each (fg in forceGenerators) {
fg.updateForce(dt);
};
}
public function addStaticParticle(p:Particle):void{
staticParticles.push(p);
p.setEngine(this);
}
public function addForceGenerator(c:ForceGenerator):void{
forceGenerators.push(c);
}
public function removeParticle(p:Particle):void{
var pos:int = particles.indexOf(p);
particles.splice(pos, 1);
p.setEngine(null);
}
public function removeContactGenerator(c:ContactGenerator):void{
var pos:int = contacts.indexOf(c);
contactGenerators.splice(pos, 1);
}
public function removeStaticParticle(p:Particle):void{
var pos:int = staticParticles.indexOf(p);
staticParticles.splice(pos, 1);
p.setEngine(null);
}
public function removeContact(c:ParticleContact):void{
var pos:int = contacts.indexOf(c);
contacts.splice(pos, 1);
}
public function addContact(c:ParticleContact):void{
contacts.push(c);
}
}
}//package KXG164_GamesPhysics
Section 15
//Vector2D (KXG164_GamesPhysics.Vector2D)
package KXG164_GamesPhysics {
public class Vector2D {
public var x:Number;
public var y:Number;
public function Vector2D(x:Number=0, y:Number=0){
super();
this.x = x;
this.y = y;
}
public function sub(v:Vector2D):void{
x = (x - v.x);
y = (y - v.y);
}
public function add(v:Vector2D):void{
x = (x + v.x);
y = (y + v.y);
}
public function length():Number{
return (Math.sqrt(((x * x) + (y * y))));
}
public function lengthSquared():Number{
return (((x * x) + (y * y)));
}
public function dot(v:Vector2D):Number{
return (((x * v.x) + (y * v.y)));
}
public function scale(a:Number):void{
x = (x * a);
y = (y * a);
}
public function normalize():void{
var length:Number = Math.sqrt(((x * x) + (y * y)));
if (length > 0){
x = (x / length);
y = (y / length);
};
}
public function copy():Vector2D{
return (new Vector2D(x, y));
}
public function normalized():Vector2D{
var length:Number = Math.sqrt(((x * x) + (y * y)));
if (length > 0){
return (new Vector2D((x / length), (y / length)));
};
return (Vector2D.zero());
}
public static function zero():Vector2D{
return (new (Vector2D));
}
public static function sum(v1:Vector2D, v2:Vector2D):Vector2D{
return (new Vector2D((v1.x + v2.x), (v1.y + v2.y)));
}
public static function diff(v1:Vector2D, v2:Vector2D):Vector2D{
return (new Vector2D((v1.x - v2.x), (v1.y - v2.y)));
}
public static function prod(v1:Vector2D, a:Number):Vector2D{
return (new Vector2D((v1.x * a), (v1.y * a)));
}
}
}//package KXG164_GamesPhysics
Section 16
//KXG164_Week5 (KXG164_Week5)
package {
import flash.events.*;
import flash.display.*;
import KXG164_GamesPhysics.TestCases.*;
import flash.text.*;
import flash.utils.*;
public class KXG164_Week5 extends Sprite {
private const framerate:Number = 50;
private var prevTime:int;// = 0
private var fps_txt:TextField;
private var fpsCount:int;// = 0
private var test:PhysicsTest;
public function KXG164_Week5(){
super();
test = new NeverMind(this, framerate);
test.SetSteps(10);
fps_txt = new TextField();
fps_txt.mouseEnabled = false;
fps_txt.width = 800;
addChild(fps_txt);
stage.frameRate = framerate;
addEventListener(Event.ENTER_FRAME, update);
}
private function update(event:Event):void{
var time:int;
var fps:Number;
fpsCount++;
if (fpsCount >= 5){
time = getTimer();
fps = Math.round((1000 / ((time - prevTime) / 5)));
fps_txt.text = ("Frames per second - " + fps);
prevTime = time;
fpsCount = (fpsCount - 5);
};
test.update();
}
private function makeButton(text:String, colour:uint):Sprite{
var button:Sprite = new Sprite();
button.graphics.beginFill(colour);
button.graphics.drawRect(0, 0, 100, 20);
button.graphics.endFill();
var buttonText:TextField = new TextField();
var tmpFormat:TextFormat = buttonText.getTextFormat();
tmpFormat.align = "center";
buttonText.defaultTextFormat = tmpFormat;
buttonText.mouseEnabled = false;
button.addChild(buttonText);
buttonText.text = text;
return (button);
}
private function startTest():void{
fps_txt = new TextField();
var tmpFormat:TextFormat = fps_txt.getTextFormat();
tmpFormat.align = "right";
fps_txt.defaultTextFormat = tmpFormat;
fps_txt.mouseEnabled = false;
addChild(fps_txt);
stage.frameRate = framerate;
addEventListener(Event.ENTER_FRAME, update);
}
}
}//package