electrodynamics/src/main/scala/edx/mechanical/mech/grid/GridMechanical.scala

175 lines
4.4 KiB
Scala
Raw Normal View History

2015-01-14 12:06:03 +01:00
package edx.mechanical.mech.grid
2014-11-09 05:06:09 +01:00
2015-01-26 13:17:04 +01:00
import resonantengine.api.graph.IUpdate
2015-01-26 12:40:32 +01:00
import resonantengine.lib.grid.core.{GridNode, UpdateTicker}
2014-11-09 05:06:09 +01:00
import scala.collection.convert.wrapAll._
/**
* A grid that manages the mechanical objects
* @author Calclavia
*/
2015-01-18 02:58:31 +01:00
class GridMechanical extends GridNode[NodeMechanical] with IUpdate
2014-11-09 05:06:09 +01:00
{
/**
* Determines if this grid is locked (invalid opposite gear connections)
*/
private var isLocked = false
/**
* The nodes that the grid is currently recusing through
*/
2015-01-23 04:41:55 +01:00
private var allRecursed = Seq.empty[NodeMechanical]
private var allDistributed = Seq.empty[NodeMechanical]
2015-01-18 02:44:17 +01:00
nodeClass = classOf[NodeMechanical]
2014-11-09 06:28:58 +01:00
/**
* Rebuild the node list starting from the first node and recursively iterating through its connections.
*/
2014-11-13 03:22:46 +01:00
override def reconstruct(first: NodeMechanical)
2014-11-09 05:06:09 +01:00
{
2014-11-09 06:28:58 +01:00
super.reconstruct(first)
2015-01-18 14:36:34 +01:00
UpdateTicker.world.addUpdater(this)
isLocked = false
2014-11-09 05:06:09 +01:00
}
2015-01-18 02:44:17 +01:00
override def deconstruct(first: NodeMechanical)
{
super.deconstruct(first)
2015-01-18 14:36:34 +01:00
UpdateTicker.world.removeUpdater(this)
2015-01-18 02:44:17 +01:00
}
2014-11-09 05:06:09 +01:00
override def update(deltaTime: Double)
{
2015-01-18 14:36:34 +01:00
nodes synchronized
2014-11-09 06:28:58 +01:00
{
/**
* Consider this as the moment of inertia: how difficult it is to spin this object.
*/
2015-01-18 14:36:34 +01:00
nodes.foreach(
n =>
{
2014-11-23 03:05:04 +01:00
n.torque = 0
n.angularVelocity -= Math.min(Math.abs(n.angularVelocity) * deltaTime * n.friction, Math.abs(n.angularVelocity)) * Math.signum(n.angularVelocity)
}
)
//TODO: Add deceleration
if (!isLocked)
{
getNodes.filter(n => n.bufferTorque != 0).foreach(
n =>
{
2015-01-23 04:41:55 +01:00
allDistributed = Seq(n)
recurse(Seq(n), deltaTime, n.bufferTorque, 0)
}
)
}
2015-01-23 04:41:55 +01:00
allDistributed = Seq.empty[NodeMechanical]
2014-11-13 14:11:00 +01:00
resetNodes()
}
}
def resetNodes()
{
getNodes.foreach(
n =>
{
if (n.prevTorque != n.torque)
{
n.prevTorque = n.torque
n.onTorqueChanged()
}
2014-11-21 05:17:28 +01:00
if (n.prevAngularVelocity != n.angularVelocity)
{
n.prevAngularVelocity = n.angularVelocity
n.onVelocityChanged()
}
n.bufferTorque = 0
}
)
}
2014-11-13 14:11:00 +01:00
def calculateEquivalentInertia(passed: Seq[NodeMechanical]): Double =
{
val curr = passed.last
2015-01-23 04:41:55 +01:00
allRecursed :+= curr
/**
* I1 + n^2 * I
* where n is the acceleration ratio
*/
var inertia = curr.inertia
2015-01-23 04:41:55 +01:00
inertia += curr.connections.filterNot(allRecursed.contains).map(c => c.radius(curr) / curr.radius(c) * calculateEquivalentInertia(passed :+ c)).foldLeft(0d)(_ + _)
return inertia
}
def recurse(passed: Seq[NodeMechanical], deltaTime: Double, torque: Double, angularVelocity: Double)
{
2014-11-22 13:21:51 +01:00
val curr = passed.last
2014-11-13 14:11:00 +01:00
if (passed.size > 1)
{
2014-11-22 15:53:50 +01:00
//Pass energy to every single node
val prev = passed(passed.size - 2)
val ratio = curr.radius(prev) / prev.radius(curr)
val invert = if (curr.inverseRotation(prev) && prev.inverseNext(curr)) -1 else 1
val addTorque = torque * ratio * invert
val addVel = angularVelocity / ratio * invert
2014-11-23 03:05:04 +01:00
curr.torque += addTorque
curr.angularVelocity += addVel * deltaTime
curr.connections.foreach(c =>
{
if (c != prev)
{
2015-01-23 04:41:55 +01:00
if (!allDistributed.contains(c))
{
2015-01-23 04:41:55 +01:00
allDistributed :+= c
recurse(passed :+ c, deltaTime, addTorque, addVel)
}
else
{
//Check for grid lock
val sudoInvert = if (c.inverseRotation(curr) && curr.inverseNext(c)) -1 else 1
if (Math.signum(c.angularVelocity) != sudoInvert * Math.signum(addVel))
{
isLocked = true
}
}
}
})
2014-11-10 14:41:46 +01:00
}
else
{
/**
* This is the first node.
* 1. Calculate equivalent moment of inertia of the mechanical system.
* 2. Determine the angular acceleration:
* T = I * a
* a = T/I
* where I = inertia and a = angular acceleration
*/
val inertia = calculateEquivalentInertia(passed)
val netAcceleration = torque / inertia
2014-11-22 11:25:59 +01:00
curr.torque += torque
curr.angularVelocity += netAcceleration * deltaTime
curr.connections.foreach(c =>
{
2015-01-23 04:41:55 +01:00
allDistributed :+= c
recurse(passed :+ c, deltaTime, torque, netAcceleration)
})
}
2014-11-09 05:06:09 +01:00
}
override def updatePeriod: Int = if (getNodes.size > 0) 50 else 0
2014-11-09 05:06:09 +01:00
}