Code sample for doing wave spring physics

April 16, 2015 ยท View on GitHub

//Note: This does not compile, it's just to demonstrate the relevant physics bits

class Main extends luxe.Game { var fieldWidth:Int = 60; var fieldDepth:Int = 60; var physTimeStep:Float = 1 / 60; var physTimeCounter:Float = 0;

var springK:Float = 100;
var springDampening:Float = 0.00;
var springSpread:Float = 600;
var startHeight:Float = -1500;
var heightTintRange:Float = 10;

var physStepCounter:Int = 0;
var maxPhysSteps:Int = 20;

var fieldVertices:Array<Vertex>;
var springVelocities:Array<Float>;

override function update(dt:Float) {
	if (dt > 1) {
		return;
	}
	
	physTimeCounter += dt;
	physStepCounter = 0;
	while (physTimeCounter >= physTimeStep && physStepCounter < maxPhysSteps) {
		updateSprings(physTimeStep);
		physTimeCounter -= physTimeStep;
		physStepCounter++;
	}
} //update

function updateSprings(dt:Float):Void {
	
	for (x in 0...fieldWidth) {
		for (y in 0...fieldDepth) {
			runHooke(x, y, dt);
		}
	}
	
	var avgHeight:Float = 0;
	var heightDiff:Float = 0;
	for (x in 0...fieldWidth) {
		for (y in 0...fieldDepth) {
			avgHeight = getNeighborAverage(x, y);
			heightDiff = fieldVertices[x * fieldWidth + y].pos.z - avgHeight;
			
			springVelocities[x * fieldWidth + y] += -springSpread * heightDiff * dt; //Effectively another hooke's law, springSpread is k
			//springVelocities[x * fieldWidth + y] -= springDampening * springVelocities[x * fieldWidth + y];
		}
	}
	
}

function runHooke(x:Int, y:Int, dt:Float):Void {
	//0 represents rest height
	springVelocities[x * fieldWidth + y] += -springK * (fieldVertices[x * fieldWidth + y].pos.z - 0) * dt;
	springVelocities[x * fieldWidth + y] -= springDampening * springVelocities[x * fieldWidth + y];
	fieldVertices[x * fieldWidth + y].pos.z += springVelocities[x * fieldWidth + y] * dt;
}

function getNeighborAverage(x:Int, y:Int):Float {
	var sum:Float = 0;
	var springCounter:Int = 0;
	var xStart:Int = x - 1;
	var xEnd:Int = x + 1;
	var yStart:Int = y - 1;
	var yEnd:Int = y + 1;
	if (xStart < 0) {
		xStart = 0;
	}
	if (xEnd > fieldWidth - 1) {
		xEnd = fieldWidth - 1;
	}
	if (yStart < 0) {
		yStart = 0;
	}
	if (yEnd > fieldDepth - 1) {
		yEnd = fieldDepth - 1;
	}
	var springCounter:Int = 0;
	for (_x in xStart...xEnd + 1) {
		for (_y in yStart...yEnd + 1) {
			if (!(_x == x && _y == y)) {
				if ((_x == xStart || _x == xEnd) && (_y == yStart || _y == yEnd)) {
					sum += fieldVertices[_x * fieldWidth + _y].pos.z * 0.7071067811865475;// 1 / sqrt(2), adjusting distance to neighbour by dividing by sart($1^{2}$ + 1^@)
				}
				else {
					sum += fieldVertices[_x * fieldWidth + _y].pos.z;
				}
				springCounter++;
			}
		}
	}
	if (springCounter != 0) {
		sum /= springCounter;
	}
	return sum;
}

} //Main