Some rework on mechanical torque

This commit is contained in:
Calclavia 2014-11-13 13:16:25 +08:00
parent 7f7bd3e696
commit 08977ccbfb
7 changed files with 47 additions and 77 deletions

View file

@ -51,9 +51,7 @@ trait TMechanicalNode extends INode with IVectorWorld
/**
* Applies rotational force and velocity to this node increasing its current rotation value
*
* @param source - The source object that is applying this force
* @param torque - force at an angle
* @param angularVelocity - speed of rotation
*/
def rotate(source: AnyRef, torque: Double, angularVelocity: Double)
def rotate(torque: Double)
}

View file

@ -48,7 +48,7 @@ class TileMotor extends TileAdvanced(Material.iron) with TElectric with TSpatial
if (mechRatio > 0)
{
mechNode.rotate(this, deltaPower * mechRatio, deltaPower / mechRatio)
mechNode.rotate(deltaPower)
//TODO: Resist DC energy
}
}

View file

@ -16,13 +16,13 @@ import resonantinduction.mechanical.mech.grid.NodeMechanical
*
* @author Calclavia, Edited by: Darkguardsman
*/
class GearNode(parent: PartGear) extends NodeMechanical(parent: PartGear)
class NodeGear(parent: PartGear) extends NodeMechanical(parent: PartGear)
{
angleDisplacement = Math.PI / 12
protected def gear = getParent.asInstanceOf[PartGear]
override def getTorqueLoad: Double =
override def getLoad: Double =
{
return gear.tier match
{

View file

@ -35,7 +35,7 @@ class PartGear extends PartMechanical with IMultiBlockStructure[PartGear]
var multiBlock: GearMultiBlockHandler = null
//Constructor
mechanicalNode = new GearNode(this)
mechanicalNode = new NodeGear(this)
mechanicalNode.onVelocityChanged = () =>
{
if (getMultiBlock.isPrimary)
@ -53,7 +53,7 @@ class PartGear extends PartMechanical with IMultiBlockStructure[PartGear]
{
if (manualCrankTime > 0)
{
mechanicalNode.rotate(this, if (isClockwiseCrank) 50 else -50, if (isClockwiseCrank) 0.05f else -0.05f)
mechanicalNode.rotate(if (isClockwiseCrank) 50 else -50)
manualCrankTime -= 0.1
}
}

View file

@ -5,12 +5,12 @@ import resonant.api.grid.INodeProvider
import resonant.lib.transform.vector.Vector3
import resonant.lib.wrapper.ForgeDirectionWrapper._
import resonantinduction.core.interfaces.TMechanicalNode
import resonantinduction.mechanical.mech.gear.{GearNode, PartGear}
import resonantinduction.mechanical.mech.gear.{NodeGear, PartGear}
import resonantinduction.mechanical.mech.grid.NodeMechanical
class GearShaftNode(parent: PartGearShaft) extends NodeMechanical(parent)
{
override def getTorqueLoad: Double =
override def getLoad: Double =
{
return shaft.tier match
{
@ -80,7 +80,7 @@ class GearShaftNode(parent: PartGearShaft) extends NodeMechanical(parent)
return from == shaft.placementSide || from == shaft.placementSide.getOpposite
}
override def inverseRotation(other: TMechanicalNode): Boolean = other.isInstanceOf[GearNode] && other.asInstanceOf[GearNode].parent.asInstanceOf[PartGear].placementSide.offset < Vector3.zero
override def inverseRotation(other: TMechanicalNode): Boolean = other.isInstanceOf[NodeGear] && other.asInstanceOf[NodeGear].parent.asInstanceOf[PartGear].placementSide.offset < Vector3.zero
def shaft: PartGearShaft = getParent.asInstanceOf[PartGearShaft]
}

View file

@ -19,13 +19,7 @@ class MechanicalGrid extends GridNode[NodeMechanical](classOf[NodeMechanical]) w
*/
val spinMap = mutable.WeakHashMap.empty[NodeMechanical, Boolean]
/**
* The power of the mechanical grid
* Unit: Watts or Joules per second
*/
private var _power = 0D
def power = _power
private var friction = 0D
/**
* Rebuild the node list starting from the first node and recursively iterating through its connections.
@ -34,6 +28,8 @@ class MechanicalGrid extends GridNode[NodeMechanical](classOf[NodeMechanical]) w
{
super.reconstruct(first)
UpdateTicker.addUpdater(this)
friction = getNodes.map(n => n.getLoad).foldLeft(0D)(_ + _)
}
override protected def populateNode(node: NodeMechanical, prev: NodeMechanical)
@ -41,7 +37,7 @@ class MechanicalGrid extends GridNode[NodeMechanical](classOf[NodeMechanical]) w
super.populateNode(node, prev)
//TODO: Check if gears are LOCKED (when two nodes obtain undesirable spins)
val dir = if (prev != null) (if (node.inverseRotation(prev)) !spinMap(prev) else spinMap(prev)) else false
val dir = if (prev != null) if (node.inverseRotation(prev)) !spinMap(prev) else spinMap(prev) else false
spinMap += (node -> dir)
//Set mechanical node's initial angle
@ -54,59 +50,36 @@ class MechanicalGrid extends GridNode[NodeMechanical](classOf[NodeMechanical]) w
getNodes synchronized
{
//Find all nodes that are currently producing energy
val inputs = getNodes.filter(n => n.bufferTorque != 0 && n.bufferAngle != 0)
val inputs = getNodes.filter(n => n.bufferTorque != 0)
//Calculate the total input equivalent torque and angular velocity
val input = inputs
.map(
n =>
{
val inversion = if (spinMap(n)) 1 else -1
(n.bufferTorque * n.ratio * inversion, n.bufferAngle / deltaTime / n.ratio * inversion)
})
.foldLeft((0D, 0D))((b, a) => (a._1 + b._1, a._2 + b._2))
//Calculate the total input equivalent torque
val inputTorque = inputs
.map(n => n.bufferTorque * (if (spinMap(n)) 1 else -1))
.foldLeft(0D)(_ + _)
var delta = (0D, 0D)
if (input._1 != 0 && input._2 != 0)
{
//Calculate the total resistance of all nodes
//TODO: Cache this
val resistance = getNodes.view
.map(n => (n.getTorqueLoad, n.getAngularVelocityLoad))
.foldLeft((0D, 0D))((b, a) => (a._1 + b._1, a._2 + b._2))
//Calculate the total change in torque and angular velocity
delta = (input._1 - input._1 * resistance._1 / getNodes.size(), input._2 - input._2 * resistance._2 / getNodes.size())
}
//Calculate power
_power = delta._1 * delta._2
val deltaTorque = inputTorque - friction * inputTorque
//Set torque and angular velocity of all nodes
getNodes.foreach(n =>
{
val prevTorque = n.torque
val prevAngularVelocity = n.angularVelocity
getNodes.foreach(
n =>
{
val prevTorque = n.torque
val prevAngularVelocity = n.angularVelocity
val inversion = if (spinMap(n)) 1 else -1
n.torque = delta._1 * n.ratio * inversion
n.angularVelocity = delta._2 / n.ratio * inversion
val inversion = if (spinMap(n)) 1 else -1
n.torque = deltaTorque * inversion
val angularAcceleration = deltaTorque / n.momentOfInertia
n.angularVelocity = angularAcceleration * deltaTime * inversion
if (Math.abs(prevTorque - n.torque) >= 0.1)
n.onTorqueChanged()
if (Math.abs(prevTorque - n.torque) >= 0.1)
n.onTorqueChanged()
if (Math.abs(prevAngularVelocity - n.angularVelocity) >= 0.1)
n.onVelocityChanged()
})
if (Math.abs(prevAngularVelocity - n.angularVelocity) >= 0.1)
n.onVelocityChanged()
})
//Clear buffers
inputs.foreach(n =>
{
n.bufferTorque = 0
n.bufferAngle = 0
})
inputs.foreach(_.bufferTorque = 0)
}
}

View file

@ -8,6 +8,8 @@ import resonant.lib.transform.vector.IVectorWorld
import resonantinduction.core.interfaces.TMechanicalNode
import resonantinduction.core.prefab.node.TMultipartNode
import scala.beans.BeanProperty
/**
* Prefab node for the mechanical system used by almost ever mechanical object in Resonant Induction. Handles connections to other tiles, and shares power with them
*
@ -22,12 +24,11 @@ class NodeMechanical(parent: INodeProvider) extends NodeGrid[NodeMechanical](par
* Buffer values used by the grid to transfer mechanical energy.
*/
protected[grid] var bufferTorque = 0D
protected[grid] var bufferAngle = 0D
/**
* A percentage value indicating how much friction the node has.
* A percentage value indicating how much friction the loss.
*/
var load = 0.2
var load = 0.1D
/**
* Angle calculations
@ -43,7 +44,9 @@ class NodeMechanical(parent: INodeProvider) extends NodeGrid[NodeMechanical](par
/**
* Events
*/
@BeanProperty
var onTorqueChanged: () => Unit = () => ()
@BeanProperty
var onVelocityChanged: () => Unit = () => ()
/**
@ -64,27 +67,23 @@ class NodeMechanical(parent: INodeProvider) extends NodeGrid[NodeMechanical](par
}
@deprecated
override def getRadius(dir: ForgeDirection, `with`: TMechanicalNode): Double = 0.5
//Moment of inertia = m * r ^ 2
def momentOfInertia = 1d
override def rotate(from: AnyRef, torque: Double, angle: Double)
def getLoad = load
override def rotate(torque: Double)
{
bufferTorque += torque
bufferAngle += angle
}
/**
* The percentage of torque loss every second
*/
def getTorqueLoad: Double = load
/**
* The percentage of angular velocity loss every second
*/
def getAngularVelocityLoad: Double = load
def getAngularVelocityLoad: Double = getLoad
//TODO: Create new grids automatically?
def power: Double = if (getMechanicalGrid != null) getMechanicalGrid.power else 0
def power: Double = torque * angularVelocity
def getMechanicalGrid: MechanicalGrid = super.grid.asInstanceOf[MechanicalGrid]