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
|
|
|
{
|
2014-11-29 13:57:30 +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]
|
2014-11-29 13:57:30 +01:00
|
|
|
|
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)
|
2014-11-29 13:57:30 +01:00
|
|
|
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
|
|
|
{
|
2015-01-22 16:10:36 +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(
|
2014-11-19 05:12:53 +01:00
|
|
|
n =>
|
|
|
|
{
|
2014-11-23 03:05:04 +01:00
|
|
|
n.torque = 0
|
2015-01-23 12:22:17 +01:00
|
|
|
n.angularVelocity -= Math.min(Math.abs(n.angularVelocity) * deltaTime * n.friction, Math.abs(n.angularVelocity)) * Math.signum(n.angularVelocity)
|
2014-11-19 05:12:53 +01:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2015-01-22 16:10:36 +01:00
|
|
|
//TODO: Add deceleration
|
|
|
|
|
2014-11-29 13:57:30 +01:00
|
|
|
if (!isLocked)
|
|
|
|
{
|
2015-01-22 16:10:36 +01:00
|
|
|
getNodes.filter(n => n.bufferTorque != 0).foreach(
|
2014-11-29 13:57:30 +01:00
|
|
|
n =>
|
|
|
|
{
|
2015-01-23 04:41:55 +01:00
|
|
|
allDistributed = Seq(n)
|
2015-01-22 16:10:36 +01:00
|
|
|
recurse(Seq(n), deltaTime, n.bufferTorque, 0)
|
2014-11-29 13:57:30 +01:00
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2015-01-23 04:41:55 +01:00
|
|
|
allDistributed = Seq.empty[NodeMechanical]
|
2014-11-13 14:11:00 +01:00
|
|
|
|
2014-11-22 11:13:04 +01:00
|
|
|
resetNodes()
|
|
|
|
}
|
|
|
|
}
|
2014-11-19 05:12:53 +01:00
|
|
|
|
2014-11-22 11:13:04 +01:00
|
|
|
def resetNodes()
|
|
|
|
{
|
|
|
|
getNodes.foreach(
|
|
|
|
n =>
|
|
|
|
{
|
|
|
|
if (n.prevTorque != n.torque)
|
|
|
|
{
|
|
|
|
n.prevTorque = n.torque
|
|
|
|
n.onTorqueChanged()
|
|
|
|
}
|
2014-11-21 05:17:28 +01:00
|
|
|
|
2014-11-22 11:13:04 +01:00
|
|
|
if (n.prevAngularVelocity != n.angularVelocity)
|
|
|
|
{
|
|
|
|
n.prevAngularVelocity = n.angularVelocity
|
|
|
|
n.onVelocityChanged()
|
2014-11-20 05:41:40 +01:00
|
|
|
}
|
2014-11-22 11:13:04 +01:00
|
|
|
|
|
|
|
n.bufferTorque = 0
|
|
|
|
}
|
|
|
|
)
|
2014-11-19 05:12:53 +01:00
|
|
|
}
|
2014-11-13 14:11:00 +01:00
|
|
|
|
2015-01-22 16:10:36 +01:00
|
|
|
def calculateEquivalentInertia(passed: Seq[NodeMechanical]): Double =
|
|
|
|
{
|
|
|
|
val curr = passed.last
|
2015-01-23 04:41:55 +01:00
|
|
|
allRecursed :+= curr
|
|
|
|
|
2015-01-22 16:10:36 +01:00
|
|
|
/**
|
|
|
|
* 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)(_ + _)
|
2015-01-22 16:10:36 +01:00
|
|
|
return inertia
|
|
|
|
}
|
|
|
|
|
2014-12-10 14:56:14 +01:00
|
|
|
def recurse(passed: Seq[NodeMechanical], deltaTime: Double, torque: Double, angularVelocity: Double)
|
2014-11-19 05:12:53 +01:00
|
|
|
{
|
2014-11-22 13:21:51 +01:00
|
|
|
val curr = passed.last
|
2014-11-13 14:11:00 +01:00
|
|
|
|
2014-11-19 05:12:53 +01:00
|
|
|
if (passed.size > 1)
|
|
|
|
{
|
2014-11-22 15:53:50 +01:00
|
|
|
//Pass energy to every single node
|
2014-11-19 05:12:53 +01:00
|
|
|
val prev = passed(passed.size - 2)
|
2014-11-22 11:13:04 +01:00
|
|
|
val ratio = curr.radius(prev) / prev.radius(curr)
|
2014-11-29 11:03:51 +01:00
|
|
|
val invert = if (curr.inverseRotation(prev) && prev.inverseNext(curr)) -1 else 1
|
2014-11-22 11:13:04 +01:00
|
|
|
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
|
2014-11-29 13:57:30 +01:00
|
|
|
|
|
|
|
curr.connections.foreach(c =>
|
|
|
|
{
|
|
|
|
if (c != prev)
|
|
|
|
{
|
2015-01-23 04:41:55 +01:00
|
|
|
if (!allDistributed.contains(c))
|
2014-11-29 13:57:30 +01:00
|
|
|
{
|
2015-01-23 04:41:55 +01:00
|
|
|
allDistributed :+= c
|
2014-12-10 14:56:14 +01:00
|
|
|
recurse(passed :+ c, deltaTime, addTorque, addVel)
|
2014-11-29 13:57:30 +01:00
|
|
|
}
|
|
|
|
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))
|
|
|
|
{
|
2014-12-10 14:56:14 +01:00
|
|
|
isLocked = true
|
2014-11-29 13:57:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
2014-11-10 14:41:46 +01:00
|
|
|
}
|
2014-11-19 05:12:53 +01:00
|
|
|
else
|
|
|
|
{
|
2015-01-22 16:10:36 +01:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
2015-01-23 07:54:19 +01:00
|
|
|
curr.torque += torque
|
2015-01-22 16:10:36 +01:00
|
|
|
curr.angularVelocity += netAcceleration * deltaTime
|
2014-11-29 13:57:30 +01:00
|
|
|
curr.connections.foreach(c =>
|
|
|
|
{
|
2015-01-23 04:41:55 +01:00
|
|
|
allDistributed :+= c
|
2015-01-23 07:54:19 +01:00
|
|
|
recurse(passed :+ c, deltaTime, torque, netAcceleration)
|
2014-11-29 13:57:30 +01:00
|
|
|
})
|
2014-11-19 05:12:53 +01:00
|
|
|
}
|
2014-11-09 05:06:09 +01:00
|
|
|
}
|
|
|
|
|
2015-01-19 07:20:04 +01:00
|
|
|
override def updatePeriod: Int = if (getNodes.size > 0) 50 else 0
|
2014-11-09 05:06:09 +01:00
|
|
|
}
|