Merge remote-tracking branch 'origin/master'

# Conflicts:
#	koptilnya/engine_remastered/clutch.txt
#	koptilnya/engine_remastered/differential.txt
#	koptilnya/engine_remastered/engine.txt
#	koptilnya/engine_remastered/gearboxes/base.txt
#	koptilnya/engine_remastered/novojiloff_diff.txt
This commit is contained in:
Nikita Kruglickiy 2022-07-28 15:49:54 +03:00
commit 1cc473d6ac
18 changed files with 621 additions and 222 deletions

View File

@ -1 +1,3 @@
Не забудьте установить форматтер ```koihik.vscode-lua-format``` Не забудьте установить форматтер ```koihik.vscode-lua-format```
<br>
Для WebStorm нужно поставить ```EmmyLua```

5
koptilnya/.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,5 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/

12
koptilnya/.idea/koptilnya.iml generated Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

8
koptilnya/.idea/modules.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/koptilnya.iml" filepath="$PROJECT_DIR$/.idea/koptilnya.iml" />
</modules>
</component>
</project>

6
koptilnya/.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>

View File

@ -0,0 +1,28 @@
-- @name Better steering sample config
-- @author Koptilnya1337
-- @server
-- @include /koptilnya/better_steering/steering.txt
require('/koptilnya/better_steering/steering.txt')
Steering:new({
Sensitivity = 0.04,
PowerSteer = 0.5,
Axles = {{
Lock = 30,
Camber = -2,
Caster = 8,
Ackermann = 15.43,
Toe = 0,
LeftOffset = 180,
RightOffset = 180
}, {
Lock = 0,
Camber = -2,
Caster = 0,
Ackermann = 0,
Toe = 0,
LeftOffset = 180,
RightOffset = 180,
Direction = -1
}}
})

View File

@ -0,0 +1,105 @@
-- @include /koptilnya/libs/wire_component.txt
-- @include /koptilnya/libs/constants.txt
-- @include /koptilnya/libs/entity.txt
require('/koptilnya/libs/wire_component.txt')
require('/koptilnya/libs/constants.txt')
require('/koptilnya/libs/entity.txt')
Slave = class('Slave', WireComponent)
function Slave:initialize(options)
options = options or {}
self.lock = options.Lock or 0
self.camber = options.Camber or 0
self.caster = options.Caster or 0
self.ackermann = options.Ackermann or 0
self.toe = options.Toe or 0
self.offset = options.Offset or 0
self.isRight = options.IsRight or false
self.direction = options.Direction or 1
self.order = options.Order or 0
self.entity = options.Slave
self.wheel = options.Wheel
self.base = options.Base or nil
self.steer = 0
self.steeringAngle = 0
self.lateralVel = 0
self.baseLngVel = 0
self.lateralForce = 0
self.selfAligningTorque = 0
self.correctingAngle = 0
end
function Slave:getOutputs()
local outputs = {}
outputs['SL_' .. self.order .. '_LateralForce'] = 'number'
outputs['SL_' .. self.order .. '_SelfAligningTq'] = 'number'
outputs['SL_' .. self.order .. '_CorrectingAngle'] = 'number'
outputs['W_' .. self.order .. '_LateralVel'] = 'number'
outputs['SL_' .. self.order .. '_SteeringAngle'] = 'number'
outputs['SL_' .. self.order .. '_BaseLngVel'] = 'number'
return outputs
end
function Slave:updateOutputs()
wire.ports['SL_' .. self.order .. '_LateralForce'] = self.lateralForce
wire.ports['SL_' .. self.order .. '_SelfAligningTq'] = self.selfAligningTorque
wire.ports['SL_' .. self.order .. '_CorrectingAngle'] = self.correctingAngle
wire.ports['W_' .. self.order .. '_LateralVel'] = self.lateralVel
wire.ports['SL_' .. self.order .. '_SteeringAngle'] = self.steeringAngle
wire.ports['SL_' .. self.order .. '_BaseLngVel'] = self.baseLngVel
end
function Slave:update()
if isValid(self.entity) and isValid(self.base) and isValid(self.wheel) then
if not self.entity:isFrozen() and not self.entity:isPlayerHolding() then
self.entity:setFrozen(1)
end
local wheelMass = self.wheel:getMass()
local wheelInertia = self.wheel:getInertia():getLength()
local wheelRadius = self.wheel:getModelRadius() / UNITS_PER_METER
local wheelFriction = self.wheel:getFriction()
local wheelLocalVel = getLocalVelocity(self.wheel)
local baseLocalVel = getLocalVelocity(self.base)
local lateralVel = wheelLocalVel[2]
local baseLngVel = baseLocalVel[1]
local camber = self.isRight and -self.camber or self.camber
local steerRatio = self.lock ~= 0 and self.steeringAngle / self.lock or 0
local caster = steerRatio * self.caster
local toe = self.isRight and self.toe or -self.toe
local ackermann = 0
if steerRatio > 0 then
ackermann = self.isRight and -steerRatio * self.ackermann or steerRatio * self.ackermann
elseif steerRatio < 0 then
ackermann = self.isRight and steerRatio * self.ackermann or -steerRatio * self.ackermann
end
self.lateralForce = wheelFriction * wheelMass * lateralVel / UNITS_PER_METER
self.selfAligningTorque = self.lateralForce * wheelRadius
self.correctingAngle = self.selfAligningTorque / wheelInertia * math.sin(math.rad(math.abs(self.caster * 2))) *
math.sign(baseLngVel) * (self.isRight and -1 or 1)
local inc = self.steer * self.lock * self.direction * math.cos(math.rad(math.abs(self.caster * 2)))
self.steeringAngle = math.clamp(self.steeringAngle + inc + self.correctingAngle, -self.lock, self.lock)
-- Dividing ackermann by 2 because ackermann angle is difference between wheels angle
-- So if we don't divide it by 2, the result angle will be 2 times more than expected
local angle = Angle(0, self.offset + self.steeringAngle + toe + ackermann / 2, camber + caster)
local localizedAngle = self.base:localToWorldAngles(angle)
self.entity:setAngles(localizedAngle)
self.lateralVel = lateralVel
self.baseLngVel = baseLngVel
end
end

View File

@ -0,0 +1,79 @@
-- @include /koptilnya/libs/wire_component.txt
-- @include ./steering_axle.txt
-- @include /koptilnya/libs/table.txt
require('/koptilnya/libs/wire_component.txt')
require('./steering_axle.txt')
require('/koptilnya/libs/table.txt')
Steering = class('Steering', WireComponent)
function Steering:initialize(options)
options = options or {}
self.axles = {}
self.steer = 0
self.sensitivity = options.Sensitivity or 1
for key, axle in ipairs(options.Axles) do
axle.Order = key
axle.Base = wire.ports.Base
table.insert(self.axles, SteeringAxle:new(axle))
end
self:_adjustPorts()
hook.add('tick', 'update', function()
self:update()
end)
end
function Steering:_adjustPorts()
local inputs = {}
local outputs = {}
inputs = table.merge(inputs, self:getInputs())
outputs = table.merge(outputs, self:getOutputs())
for _, axle in ipairs(self.axles) do
inputs = table.merge(inputs, axle:getInputs())
outputs = table.merge(outputs, axle:getOutputs())
end
wire.adjustPorts(inputs, outputs)
end
function Steering:getInputs()
return {
TargetSteer = 'number',
Base = 'entity'
}
end
function Steering:getOutputs()
return {
Steer = 'number'
}
end
function Steering:updateOutputs()
-- local totalSteeringAngle = table.reduce(self.slaves, function(steer, slave)
-- return steer + slave.direction * slave.steeringAngle / (slave.lock ~= 0 and slave.lock or 1)
-- end, 0)
-- local steerableSlaves = table.filter(self.slaves, function(slave)
-- return slave.lock ~= 0
-- end)
-- wire.ports.Steer = totalSteeringAngle / #steerableSlaves
end
function Steering:update()
self.steer = wire.ports.TargetSteer * self.sensitivity
self:updateOutputs()
for _, axle in ipairs(self.axles) do
axle.steer = self.steer
axle:update()
axle:updateOutputs()
end
end

View File

@ -0,0 +1,69 @@
-- @include /koptilnya/libs/wire_component.txt
-- @include /koptilnya/libs/constants.txt
-- @include /koptilnya/libs/entity.txt
-- @include ./slave.txt
require('/koptilnya/libs/wire_component.txt')
require('/koptilnya/libs/constants.txt')
require('/koptilnya/libs/entity.txt')
require('./slave.txt')
SteeringAxle = class('SteeringAxle', WireComponent)
function SteeringAxle:createSlave(options, isRight)
local config = {
Lock = options.Lock,
Camber = options.Camber,
Caster = options.Caster,
Ackermann = options.Ackermann,
Toe = options.Toe,
Direction = options.Direction,
IsRight = isRight,
Slave = wire.ports[self._prefix .. (isRight and '_RightSlave' or '_LeftSlave')],
Wheel = wire.ports[self._prefix .. (isRight and '_RightWheel' or '_LeftWheel')],
Offset = isRight and options.RightOffset or options.LeftOffset,
Prefix = self._prefix .. (isRight and '_RightWheel' or '_LeftWheel'),
Base = wire.ports.Base
}
return Slave:new(config)
end
function SteeringAxle:initialize(options)
options = options or {}
self.steer = 0
self._prefix = 'Axle' .. options.Order
self.leftSlave = self:createSlave(options, false)
self.rightSlave = self:createSlave(options, true)
end
function SteeringAxle:getInputs()
local inputs = {}
inputs[self._prefix .. '_LeftSlave'] = 'entity'
inputs[self._prefix .. '_RightSlave'] = 'entity'
inputs[self._prefix .. '_LeftWheel'] = 'entity'
inputs[self._prefix .. '_RightWheel'] = 'entity'
return inputs
end
function SteeringAxle:getOutputs()
local outputs = {}
table.merge(outputs, self.leftSlave:getOutputs())
table.merge(outputs, self.rightSlave:getOutputs())
return outputs
end
function SteeringAxle:updateOutputs()
self.leftSlave:updateOutputs()
self.rightSlave:updateOutputs()
end
function SteeringAxle:update()
self.leftSlave:update()
self.rightSlave:update()
end

View File

@ -0,0 +1,45 @@
-- @shared
-- @name BMW M4 G82 Competition
-- @author Koptilnya1337
-- @include /koptilnya/mesh_loader/builder.txt
require("/koptilnya/mesh_loader/builder.txt")
DEBUG_MODE = true
local LINK = "https://drive.google.com/u/0/uc?id=1yxjPtVhoMROwSB56tfL_dbBPrW1Yjr9h&export=download"
local SCALE = Vector(1)
local Materials =
{
Body = "phoenix_storms/fender_white",
Carbon = "sprops/textures/sprops_cfiber2"
}
local Colors =
{
Body = Color(115,218,201),
Carbon = Color(255,255,255)
}
local builder = {}
if SERVER then
builder = MeshBuilder:new(LINK)
local this = chip()
-- Body group
builder:build("Body", Vector(0), Angle(0), SCALE, Colors.Body, Materials.Body, this, this)
builder:build("LeftDoor", Vector(0), Angle(0), SCALE, Colors.Body, Materials.Body, this, this)
builder:build("RightDoor", Vector(0), Angle(0), SCALE, Colors.Body, Materials.Body, this, this)
builder:build("Bonnet", Vector(0), Angle(0), SCALE, Colors.Body, Materials.Body, this, this)
builder:build("Trunk", Vector(0), Angle(0), SCALE, Colors.Body, Materials.Body, this, this)
builder:build("Roof", Vector(0), Angle(0), SCALE, Colors.Carbon, Materials.Carbon, this, this)
local result = builder:getResult()
else
PERMA.onPermissionsGained = function()
builder = MeshBuilder:new(LINK)
end
PERMA.build()
end

View File

@ -0,0 +1,151 @@
-- @shared
-- @name VW Golf Mk 7.5
-- @author Koptilnya1337
-- @include /koptilnya/mesh_loader/builder.txt
require("/koptilnya/mesh_loader/builder.txt")
DEBUG_MODE = true
local LINK = "https://drive.google.com/u/0/uc?id=1FNn5_6PMmurvraVqlJNNV3WXTMnozMJM&export=download"
local SCALE = Vector(1)
local Materials = {
{
Match = "Shadow",
Material = "",
Color = Color(20,20,20)
},
{
Match = "BumpersVents",
Material = "models/debug/debugwhite",
Color = Color(20,20,20)
},
{
Match = { "Body", ".*Body*" },
Material = "phoenix_storms/fender_white",
Color = Color(230,229,231)
},
{
Match = "Badges",
Material = "debug/env_cubemap_model",
Color = Color(255,255,255)
},
{
Match = ".*Lights_Glass*",
Material = "phoenix_storms/mrref2",
Color = Color(255,255,255,120)
},
{
Match = { ".*Lights_Base*", "RearLights_Chrome" },
Material = "models/debug/debugwhite",
Color = Color(20,20,20)
},
{
Match = { "WindowsRubber", "WindshieldOutline" },
Material = "phoenix_storms/mrref2",
Color = Color(25,25,25)
},
{
Match = ".*Seat.*",
Material = "models/debug/debugwhite",
Color = Color(60,60,60)
},
{
Match = "Interior_DoorMaps",
Material = "models/debug/debugwhite",
Color = Color(40,40,40)
},
{
Match = "Interior_Plastic",
Material = "models/debug/debugwhite",
Color = Color(50,50,50)
}
}
local Bodyparts = {
"Body",
"Bonnet_Body",
"DoorHandles",
"BumpersVents",
"ExhaustPipes",
"ExhaustPipes",
"FrontBumper_Body",
"FrontLeftDoor_Body",
"FrontQuaterpanels_Body",
"FrontRightDoor_Body",
"FrontRightDoor_Body",
"Mirrors_Plastic",
"RearBumper_Body",
"RearLeftDoor_Body",
"RearRightDoor_Body",
"RearRightDoor_Body",
"Shadow",
"Sidepanels_Body",
"Sideskirts_Body",
"Trunk_Body",
}
local Details = {
"Badges",
}
local FrontLights = {
"FrontLights_Base",
-- "FrontLights_Glass",
}
local RearLights = {
"RearLights",
"RearLights_Base",
"RearLights_Chrome",
-- "RearLights_Glass",
}
local Windows = {
"WindowsRubber",
"WindshieldOutline",
}
local Interior = {
"FrontLeftSeat",
"FrontRightSeat",
"RearSeats",
-- "Interior_Decals",
"Interior_DoorMaps",
"Interior_Plastic",
"SoundDynamics",
"SteeringWheel",
"SteeringWheel_Badge",
-- "SteeringWheel_Decals",
"SteeringWheel_Plastic",
}
local Meshes = {}
table.add(Meshes, Bodyparts)
table.add(Meshes, Details)
table.add(Meshes, FrontLights)
table.add(Meshes, RearLights)
table.add(Meshes, Windows)
table.add(Meshes, Interior)
local builder = {}
if SERVER then
local this = chip()
builder = MeshBuilder:new(LINK)
:useGlobalScale(SCALE)
:useGlobalParent(this)
:useGlobalRelative(this)
builder:buildAll(Meshes)
builder:getResult()
else
PERMA.onPermissionsGained = function()
builder = MeshBuilder:new(LINK)
builder:useMaterialPipeline(Materials)
end
PERMA.build()
end

View File

@ -26,7 +26,8 @@ Vehicle:new({
Clutch = {Stiffness = 20, Damping = 0.5, MaxTorque = 400}, Clutch = {Stiffness = 20, Damping = 0.5, MaxTorque = 400},
Gearbox = {Type = 'MANUAL', ShiftDuration = 0.2, ShiftSmoothness = 0.3, Ratios = {3.321, 1.902, 1.308, 1, 0.838}, Reverse = 3.382}, Gearbox = {Type = 'MANUAL', ShiftDuration = 0.2, ShiftSmoothness = 0.3, Ratios = {3.321, 1.902, 1.308, 1, 0.838}, Reverse = 3.382},
Axles = { Axles = {
{Power = 0.96, Coast = 0.96, Preload = 10, UsePowerBias = 10, ViscousCoeff = 0.96, Axle = Vector(1, 0, 0), DistributionCoeff = 1, FinalDrive = 3.9} {Power = 0.96, Coast = 0.96, Preload = 10, UsePowerBias = 10, ViscousCoeff = 0.96, Axle = Vector(1, 0, 0), DistributionCoeff = 0.8, FinalDrive = 3.9},
{Power = 0.96, Coast = 0.96, Preload = 10, UsePowerBias = 10, ViscousCoeff = 0.96, Axle = Vector(1, 0, 0), DistributionCoeff = 1.2, FinalDrive = 3.9},
}, },
Systems = {{Type = 'LAUNCH', Limit = 3500}, {Type = 'TRACTION', Limit = 1.5}} Systems = {{Type = 'LAUNCH', Limit = 3500}, {Type = 'TRACTION', Limit = 1.5}}
}) })

View File

@ -24,7 +24,7 @@ Vehicle:new({
} }
}, },
Clutch = {Stiffness = 20, Damping = 0.7, MaxTorque = 400}, Clutch = {Stiffness = 20, Damping = 0.7, MaxTorque = 400},
Gearbox = {Type = 'MANUAL', ShiftDuration = 0.2, ShiftSmoothness = 0.3, Ratios = {3.626, 2.200, 1.541, 1.213, 1.000, 0.767}, Reverse = 3.437}, Gearbox = {Type = 'MANUAL', ShiftDuration = 0.2, ShiftSmoothness = 0.3, Ratios = {3.626, 2.200, 1.541, 1.213, 1.000, 0.767}, Reverse = 3.437},
Axles = {{Power = 0.96, Coast = 0.96, Preload = 10, UsePowerBias = 10, ViscousCoeff = 0.96, Axle = Vector(1, 0, 0), DistributionCoeff = 1, FinalDrive = 3.392}}, Axles = {{Power = 0.96, Coast = 0.96, Preload = 10, UsePowerBias = 10, ViscousCoeff = 0.96, Axle = Vector(1, 0, 0), DistributionCoeff = 1, FinalDrive = 3.392}},
Systems = {{Type = 'LAUNCH', Limit = 3500}, {Type = 'TRACTION', Limit = 1.5}} Systems = {{Type = 'LAUNCH', Limit = 3500}, {Type = 'TRACTION', Limit = 1.5}}
}) })

View File

@ -1,188 +0,0 @@
-- @name Grip Steering
-- @author DarkSupah
-- @server
-- @include ./slave.txt
Steering = class('Steering')
require('./slave.txt')
function inrange(val, min, max)
return val >= min and val <= max
end
function isNaN(val)
return val ~= val
end
function vectorIsNaN(vec)
return isNaN(vec[1]) or isNaN(vec[2]) or isNaN(vec[3])
end
function getLocalVelocity(ent)
return ent:worldToLocal((ent:getVelocity() + ent:getPos()))
end
local options = {
Camber = -2,
Caster = 5,
Ackermann = 15,
Lock = 45,
ZeroThreshold = 2,
StartSpeedThreshold = 40,
EndSpeedThreshold = 150,
SpeedCoeff = 0.2,
StartCorrectionThreshold = 5,
EndCorrectionThreshold = 40,
CorrectionOnCoeff = 0.6,
CorrectionOffCoeff = 1,
CorrectionOnLerp = 0.3,
CorrectionOffLerp = 0.6
}
function Steering:_adjustPorts()
local inputs = {
Axles = 'table',
Base = 'entity',
LeftSlave = 'entity',
RightSlave = 'entity'
}
local outputs = {
SteerAngle = 'number',
TargetAngle = 'number',
CorrectionAngle = 'number'
}
wire.adjustPorts(inputs, outputs)
end
function Steering:_createSlaves()
local entities = {wire.ports.LeftSlave, wire.ports.RightSlave}
local slaves = {}
for k, v in pairs(entities) do
local slave = Slave:new({
Entity = v,
IsLeft = k % 2 == 1,
Offset = 180,
Base = wire.ports.Base,
Camber = self.slavesConfig.Camber,
Caster = self.slavesConfig.Caster,
Ackermann = self.slavesConfig.Ackermann
})
table.insert(self.slaves, slave)
end
end
function Steering:_updateOutputs()
wire.ports.TargetAngle = self.targetAngle
wire.ports.SteerAngle = self.angle
wire.ports.CorrectionAngle = self.correction
end
function Steering:_getCorrectionGradient(speed)
return math.clamp(math.remap(speed, self.startCorrectionThreshold, self.endCorrectionThreshold, 0, 1), 0, 1)
end
function Steering:getBaseSpeed()
local MPH = self.base:getVelocity():getLength() * 3600 / 63360
local KPH = MPH * 1.609
return KPH
end
function Steering:_getSpeedCorrectionGradient(speed)
return math.clamp(math.remap(speed, self.startSpeedThreshold, self.endSpeedThreshold, 0, 1), 0, 1)
end
function Steering:_getCorrectionAngle()
local localVel = getLocalVelocity(self.base)
local forwardVel = (localVel * Vector(1, 0, 0)):getNormalized()
local planarVec = (localVel * Vector(1, 1, 0)):getNormalized()
forwardVel = vectorIsNaN(forwardVel) and Vector(0, 0, 0) or forwardVel
planarVec = vectorIsNaN(planarVec) and Vector(0, 0, 0) or planarVec
local cross = forwardVel:cross(planarVec)
return math.deg(math.acos(forwardVel:dot(planarVec))) * math.sign(localVel[2])
end
function Steering:initialize(options)
self:_adjustPorts()
options = options or {}
self.base = wire.ports.Base
self.slavesConfig = {
Camber = options.Camber,
Caster = options.Caster,
Ackermann = options.Ackermann
}
self.lock = options.Lock
self.targetAngle = 0
self.angle = 0
self.zeroThreshold = options.ZeroThreshold
self.speedCoeff = options.SpeedCoeff
self.startSpeedThreshold = options.StartSpeedThreshold
self.endSpeedThreshold = options.EndSpeedThreshold
self.startCorrectionThreshold = options.StartCorrectionThreshold
self.endCorrectionThreshold = options.EndCorrectionThreshold
self.correctionOnCoeff = options.CorrectionOnCoeff
self.correctionOffCoeff = options.CorrectionOffCoeff
self.correctionOnLerp = options.CorrectionOnLerp
self.correctionOffLerp = options.CorrectionOffLerp
self.correction = 0
self.slaves = {}
self:_createSlaves()
end
function Steering:update()
local horizontal = wire.ports.Axles.Horizontal.Value
local horizontalTarget = wire.ports.Axles.Horizontal.Target
local baseSpeedKMH = self:getBaseSpeed()
local angleCorrection = self:_getCorrectionGradient(baseSpeedKMH)
local speedCorrection = self.angle * self:_getSpeedCorrectionGradient(baseSpeedKMH) * self.speedCoeff
self.targetAngle = horizontal * self.lock
local correctionCoeff = horizontalTarget ~= 0 and self.correctionOnCoeff or self.correctionOffCoeff
local correctionLerpCoeff = horizontalTarget ~= 0 and self.correctionOnLerp or self.correctionOffLerp
local correction = self:_getCorrectionAngle() * angleCorrection * correctionCoeff
self.correction = math.lerp(correctionLerpCoeff, self.correction, isNaN(correction) and 0 or correction)
local possibleAngle = math.clamp(horizontal * self.lock + speedCorrection + self.correction, -self.lock, self.lock)
if inrange(possibleAngle, -self.zeroThreshold, self.zeroThreshold) then
self.angle = 0
else
self.angle = possibleAngle
end
for k, v in pairs(self.slaves) do
v:rotate(self.angle)
end
self:_updateOutputs()
end
local steering = Steering:new(options)
hook.add('think', 'SteeringUpdate', function()
steering:update()
end)

View File

@ -1,29 +0,0 @@
Slave = class('Slave')
function Slave:initialize(options)
options = options or {}
self.entity = options.Entity
self.base = options.Base
self.camber = options.Camber
self.caster = options.Caster
self.ackermann = options.Ackermann
self.isLeft = options.IsLeft
self.offset = options.Offset
end
function Slave:rotate(ang)
if self.entity:isFrozen() == false then
self.entity:setFrozen(1)
end
local ackermann = math.sin(math.rad(ang)) ^ 2 * self.ackermann * (self.isLeft and -1 or 1)
local yaw = self.offset + ang + ackermann
local roll = (self.isLeft and 1 or -1) * self.camber - ang / 270 * self.caster
local angle = Angle(0, yaw, roll)
local transformedAngle = self.base:localToWorldAngles(angle)
self.entity:setAngles(transformedAngle)
end

View File

@ -2,8 +2,8 @@ Axles = {
Horizontal = { Horizontal = {
Negative = KEY.D, Negative = KEY.D,
Positive = KEY.A, Positive = KEY.A,
Gravity = 0.1, Gravity = 1,
Sensitivity = 0.2 Sensitivity = 1
}, },
Throttle = { Throttle = {
Positive = KEY.W, Positive = KEY.W,
@ -15,10 +15,15 @@ Axles = {
Gravity = 0.15, Gravity = 0.15,
Sensitivity = 0.25 Sensitivity = 0.25
}, },
Brakes = {
Positive = KEY.S,
Gravity = 0.15,
Sensitivity = 0.25
},
Shifter = { Shifter = {
Positive = MOUSE.LEFT, Positive = MOUSE.LEFT,
Negative = MOUSE.RIGHT, Negative = MOUSE.RIGHT,
Gravity = 1, Gravity = 1,
Sensitivity = 1 Sensitivity = 1
}, }
} }

View File

@ -0,0 +1,100 @@
--@name apply force suspension
--@author Koptilnya1337
--@shared
local _restLength = 26.0
local _springTravel = 20.0
local _springStiffness = 45000
local _compressionDamper = 250000 -- 45000
local _reboundDamper = 150000 -- 196000
local _maxForce = 800000
local _minLength = 0
local _maxLength = 0
local _lastLength = 0
local _springLength = 0
local _springVelocity = 0
local _springForce = 0
local _damperForce = 0
if SERVER then
wire.adjustInputs(
{
'Wheel1',
'Wheel2',
'Wheel3',
'Wheel4',
'Strut1',
'Strut2',
'Strut3',
'Strut4',
'Base'
},
{
'entity',
'entity',
'entity',
'entity',
'entity',
'entity',
'entity',
'entity',
'entity'
}
)
local wheel1 = wire.ports.Wheel1
local wheel2 = wire.ports.Wheel2
local wheel3 = wire.ports.Wheel3
local wheel4 = wire.ports.Wheel4
local strut1 = wire.ports.Strut1
local strut2 = wire.ports.Strut2
local strut3 = wire.ports.Strut3
local strut4 = wire.ports.Strut4
local wheels = { wheel1, wheel2, wheel3, wheel4 }
local struts = { strut1, strut2, strut3, strut4 }
local base = wire.ports.Base
function handleWheel(base, wheel, strut)
local lastLength = 0
return function ()
if not base:isValid() then return end
if not wheel:isValid() then return end
if not strut:isValid() then return end
local distance = strut:getPos():getDistance(wheel:getPos()) - _restLength
local strutToWheelDirection = (strut:getPos() - wheel:getPos()):setX(0):setY(0):getNormalized()
local springVelocity = (distance - lastLength)
local usedDamper = springVelocity > 0 and _reboundDamper or _compressionDamper
local spring = distance * _springStiffness
local dampener = springVelocity * usedDamper
local force = math.clamp((spring + dampener) * game.getTickInterval(), -_maxForce, _maxForce)
local direction = (strut:getPos() - wheel:getPos()):getNormalized()
local baseDirection = direction * Vector(0, 0, math.clamp(base:getUp().z, 0, 1))
lastLength = distance
base:applyForceOffset(-force * baseDirection, wheel:getPos())
wheel:applyForceCenter(force * direction)
end
end
local wheelHandlers = {}
for idx, wheel in ipairs(wheels) do
table.insert(wheelHandlers, handleWheel(base, wheel, struts[idx]))
end
hook.add('tick', 'runtime', function()
for _, handler in ipairs(wheelHandlers) do
handler()
end
end)
end