Hello there, it’s me again with a small resource that I see lacking on the forum with many,unsolved, or ones that have the general idea but incomplete scripting support questions.
Credits
@sleitnick, PID Controller from AeroGameFramework, works great but semi modified to accommodate Vector3 variables.
@ThanksRoBama, Great tutorial on PID Controllers which had excellent yet simple explanation along with great examples. Never knew it was possible to just work with P alone.
Summary
What is it? Basically, if you have a Motor6D rig you input the Motor6D joint into this module and it will create an object which will rotate the C0 of the joint until it looks at the desired position. Moreover, you can place it in a run service loop in order to interpolate it and have linear speed and such.
Why use CFrames over physics-based constraints? Well for one you don’t have to set up the constraint Instances within the model and that’s enough for me I guess. But mainly there is a possibility the constraint-based physics of moving the turret will affect the main chassis of a vehicle as I have tried with BallSocketConstraints and AlignOrientation although I may have been doing it wrong.
Showcase
Dummy test place provided with 2 joints:
Or you can be a little more complex with 3 joints with the example:
MechGIF
Now includes PID Controller! Great if you want a reliable physics like feel to your turrets without pesky stuff like collisions with the turret and the main body due to weird modeling collisions or angular momentum getting in the way.
Assets
And always a test place is provided in the Github below with the funny dummy with a gun, just download the rbxlx file.
How to use it?
You can mainly look at the test place file or here though I recommend experimentation always.
Initial Attachment setup:
Select the Motor6D you want to control:
Place a “TurretAttachment” into part 1 of the motor6d you want to control. This will control where your Turret will lookAt so place the attachment near the nozzle of the gun like such and also the orientation which the turret will look at as the model of the orientation of the parts will not exactly be (0,0,0) like in some meshes which this attachment solves by applying an offset rotation.
Use the right hand rule to figure out the lookVector the attachment is facing. Your turret will also face that way.
and If need be if you want to define the constraint axis place a “BaseAttachment” attachment in the part0 of the motor. The secondary axis will define the elevation angle or depression angle, and the primary axis will define the yaw left or the yaw right of the turret. Position of this attachment rn doesn’t matter. If no BaseAttachment is provided it’ll use the axis of the previous TurretAttachment or if there is no TurretAttachment then the axis of the part1.
Codewise:
Require the module
local TurretController = require(ReplicatedStorage:FindFirstChild("TurretController",true))
Set up the constraints according to the template, currently, it only has these 4 axially constraints, maybe I’ll add a ball socket like constraint later if needed.
local gunHeadConstraints = {
["YawLeft"] = 89;
["YawRight"] = 89;
["ElevationAngle"] = 0;
["DepressionAngle"] = 0;
}
Create the controller object with the joint of the motor6D
local GunHead = TurretController.new(ModelMotor6Ds["GunHead"],gunHeadConstraints)
Then in a runservice loop, use the LookAt function of the turret controller:
RunService.Heartbeat:Connect(function(step)
local goalPos = Target.Position--some random part
GunHead:LookAt(goalPos,step)
end)
Turret Settings
Currently, there is support for the turrets to use interpolate the movements with linear speed, some arbritrary lerp alpha value controlled by the bool settings of the object, by default it’s set the lerp with constant speed:
self.LerpMotors = true
self.ConstantSpeed = true
--some arbritrary values feel free to change
self.LerpAlpha = 1/4
self.AngularSpeed = math.rad(180)
Now with PID variables:
self.Mass = 1 --makes it slower and feel bulkier
self.CurrentAngularVelocityClamp = nil --Clamps the angular velocity, number in radians per second
self.Restitution = 0.5 -- Value 0-1, 1 means elastic same amount of bounce, 0 means rigid no bounce
--[[
Constructs the PID controller with it's variables
maxAngularAcceleration is in radians per second squared.
]]
function TurretController:ConstructPIDController(maxAngularAcceleration,kP, kD, kI)
end
License
This project uses an MIT license, Feel free to use it but credit is very much appreciated.
Future Improvements
Bug fixes if I find any I’ll be using this in my main game project so yeah I’ll see what additional features would be useful to add to the controller.