Nikita Kruglickiy 09be0ea795 UPDATE
2023-05-22 19:06:26 +03:00

114 lines
3.8 KiB
Plaintext

--@include ./powertrain_component.txt
--@include /koptilnya/libs/constants.txt
local PowertrainComponent = require('./powertrain_component.txt')
require('/koptilnya/libs/constants.txt')
local Engine = class('Engine', PowertrainComponent)
function Engine:initialize(vehicle, name, config)
PowertrainComponent.initialize(self, vehicle, name, config)
self.wireInputs = {
Throttle = 'number'
}
self.wireOutputs = {
Engine_RPM = 'number',
Engine_Torque = 'number',
Engine_MasterThrottle = 'number',
Engine_ReactTorque = 'number',
Engine_ReturnedTorque = 'number',
Engine_FinalTorque = 'number'
}
self.idleRPM = config.IdleRPM or 900
self.maxRPM = config.MaxRPM or 7000
self.inertia = config.Inertia or 0.4
self.startFriction = config.StartFriction or -50
self.frictionCoeff = config.FrictionCoeff or 0.02
self.limiterDuration = config.LimiterDuration or 0.05
self.torqueMap = config.TorqueMap or {}
self.rpmFrac = 0
self.friction = 0
self.masterThrottle = 0
self.limiterTimer = 0
self.reactTorque = 0
self.returnedTorque = 0
end
function Engine:updateWireOutputs()
wire.ports.Engine_RPM = self:getRPM()
wire.ports.Engine_Torque = self.torque
wire.ports.Engine_MasterThrottle = self.masterThrottle
wire.ports.Engine_ReactTorque = self.reactTorque
wire.ports.Engine_ReturnedTorque = self.returnedTorque
wire.ports.Engine_FinalTorque = self.finalTorque
end
function Engine:getThrottle()
return wire.ports.Throttle
end
function Engine:_generateTorque()
local throttle = self:getThrottle()
local rpm = self:getRPM()
local rpmFrac = math.clamp((rpm - self.idleRPM) / (self.maxRPM - self.idleRPM), 0, 1)
self.friction = self.startFriction - self:getRPM() * self.frictionCoeff
local tqIdx = math.clamp(math.floor(rpmFrac * #self.torqueMap), 1, #self.torqueMap)
local maxInitialTorque = self.torqueMap[tqIdx] - self.friction
local idleFadeStart = math.clamp(math.remap(rpm, self.idleRPM - 300, self.idleRPM, 1, 0), 0, 1)
local idleFadeEnd = math.clamp(math.remap(rpm, self.idleRPM, self.idleRPM + 600, 1, 0), 0, 1)
local additionalEnergySupply = idleFadeEnd * (-self.friction / maxInitialTorque) + idleFadeStart
if rpm > self.maxRPM then
throttle = 0
self.limiterTimer = timer.systime()
else
throttle = timer.systime() >= self.limiterTimer + self.limiterDuration and throttle or 0
end
self.masterThrottle = math.clamp(additionalEnergySupply + throttle, 0, 1)
local realInitialTorque = maxInitialTorque * self.masterThrottle
self.torque = realInitialTorque + self.friction
return self.torque
end
function Engine:forwardStep()
if self.output == nil then
local generatedTorque = self:_generateTorque()
self.angularVelocity = self.angularVelocity + generatedTorque / self.inertia * TICK_INTERVAL
self.angularVelocity = math.max(self.angularVelocity, 0)
end
local outputInertia = self.output:queryInertia()
local inertiaSum = self.inertia + outputInertia
local outputW = self.output:queryAngularVelocity(self.angularVelocity)
local targetW = self.inertia / inertiaSum * self.angularVelocity + outputInertia / inertiaSum * outputW
local generatedTorque = self:_generateTorque()
local reactTorque = (targetW - self.angularVelocity) * self.inertia / TICK_INTERVAL
local returnedTorque = self.output:forwardStep(generatedTorque - reactTorque, 0) -- ??? 0 -> self.inertia
self.reactTorque = reactTorque
self.returnedTorque = returnedTorque
local finalTorque = generatedTorque + reactTorque + returnedTorque
self.finalTorque = finalTorque
self.angularVelocity = self.angularVelocity + finalTorque / inertiaSum * TICK_INTERVAL
self.angularVelocity = math.max(self.angularVelocity, 0)
end
return Engine