133 lines
4.3 KiB
Plaintext
133 lines
4.3 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.friction = 0
|
|
self.masterThrottle = 0
|
|
|
|
self.limiterTimer = 0
|
|
|
|
self.reactTorque = 0
|
|
self.returnedTorque = 0
|
|
|
|
if CLIENT then
|
|
--@include /koptilnya/engine_sound_2.txt
|
|
local Sound = require('/koptilnya/engine_sound_2.txt')
|
|
|
|
Sound(config.MaxRPM or 7000, chip())
|
|
end
|
|
end
|
|
|
|
function Engine:updateWireOutputs()
|
|
PowertrainComponent.updateWireOutputs(self)
|
|
|
|
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(torque, inertia)
|
|
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(torque + generatedTorque - reactTorque, inertia + 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)
|
|
|
|
net.start("ENGINE_RPM")
|
|
net.writeFloat(self:getRPM() / self.maxRPM)
|
|
net.send(self.vehicle.playersConnectedToHUD, true)
|
|
|
|
net.start("ENGINE_FULLRPM")
|
|
net.writeUInt(self:getRPM(), 16)
|
|
net.writeFloat(self.masterThrottle)
|
|
net.send(nil, true)
|
|
end
|
|
|
|
return Engine
|