Hello. I am creating a script where it supposly gives a space ship (on a world where the Gravity property of the Workspace is set to 0).
Currently, I just have finished the rotating part; However, the ship is rotating oddly. If this helps to diagnose the problem:
1. The FilteringEnabled property of the Workspace is set to true
2. The rotation is made using a BodyGyro instance, with the following properties:
D= 500
MaxTorque= Vector3.new(400000, 400000, 400000)
P= 3000
3. The rotation control is made using two scripts: A LocalScript used to detect input, and a Script to make the ship actually turn.
The odd behaviour can be found here
Experience it by yourself here
The scripts can be found below:
LocalScript at directory game.StarterPlayer.StarterPlayerScripts
local camera = game:WaitForChild("Workspace").CurrentCamera -- gets the camera
local settings = game.Workspace.Ship.Settings:GetChildren() -- not needed for the question; It's about a remoteFunction that i'll use later
local remote = game.Workspace.Ship.ScriptContent.ShipChannels -- gets the folder where the remoteEvents and remoteFunctions are
local inpServ = game:GetService('UserInputService') -- gets UserInputService
local shipInfo = remote.AskForShipInfo:InvokeServer() -- invokes through a remoteFunction. I'll use this line later
local keys = {{"S", "W"},{"A", "D"},{"Q", "E"}} -- the keys that rotate the ship (first table to X axis, second for Y and third for Z; first element will rotate positive and the second, negative)
local rotDirTable = {0, 0, 0} -- A table that is going to be sent to the server
local previewRot = {0, 0, 0} -- For comparison purposes
for i,v in pairs (shipInfo) do -- manipulate the table retrieved from the remoteFunction
print("From localScript, "..settings[i].Name.." is set to "..v)
wait()
end
function rawequalTable(t1, t2) -- compares if two tables are equal or not; just using {0,0,0} == {0,0,0} would return false, as well as rawequal({0,0,0},{0,0,0}9
local result
if type(t1) == "table" and type(t2) == "table" then
if #(t1) == #(t2) then
for i = 1, #(t1) do
if t1[i] == t2[i] and i == #t1 then
result = true
break
elseif t1[i] ~= t2[i] then
print("they don't have the same val on the same indexes")
result = false
break
else
end
end
else
print("they don't have the same number of content.")
result = false
end
else
error("Arguments must to be tables")
end
return result
end
function isKeyDown(key) -- determines if a determined key is pressed
for i,v in pairs(inpServ:GetKeysPressed()) do
if v.KeyCode == Enum.KeyCode[key] then
return true
end
end
return false -- no keys found
end
function fireRotator(RotTable) -- fires the remoteEvent that will rotate the ship
print("yee.")
remote.RotationController:FireServer(RotTable)
end
camera.CameraSubject = workspace.Ship.Body.CameraGyroPart
camera.CameraType = Enum.CameraType.Track
while true do
for i,t in pairs({"Q","W","E","A","S","D"}) do
--this first loop was created for debugging purposes
if isKeyDown(t) then
game.Players.LocalPlayer.PlayerGui.Debug.Frame[t].BackgroundColor3 = Color3.new(0,0,0)
else
game.Players.LocalPlayer.PlayerGui.Debug.Frame[t].BackgroundColor3 = Color3.new(1,0.5,0)
end
end
-- this one will decide if it will send a new table or not.
for k,v in pairs(keys) do
local preValR = 0
for index, value in pairs(v) do
if index == 1 and isKeyDown(value)then -- positive keys take priority
preValR = 1
elseif index == 2 and isKeyDown(value) then
preValR = -1
end
end
previewRot[k] = preValR
end
if not rawequalTable(rotDirTable,previewRot) then -- if the previous table that was sent is different from this one
rotDirTable = previewRot
fireRotator(rotDirTable)
previewRot = {0,0,0}
end
wait()
end
Script at directory game.Workspace.Ship.ScriptContent.Script
local settings = script.Parent.Parent.Settings
local body = script.Parent.Parent.Body
local remote = script.Parent.ShipChannels -- gets the folder where the server will get orders form the client
local massCenter = body:WaitForChild("CameraGyroPart") -- the part that holds the bodyGyro Instance
function module(v) -- picks up the value and returns its actual value (positive only)
if v >= 0 then
return v
else
return (-1*v)
end
end
function NumSignal(v) -- determines if the number is positive, negative or null
if v > 0 then
return 1
elseif v == 0 then
return 0
else
return -1
end
end
function remote.AskForShipInfo.OnServerInvoke(p) -- ill use this later
print("invoked")
player = p -- gives the player who is controlling the ship
local returnSubject = {}
for i,v in pairs(settings:GetChildren()) do
table.insert(returnSubject,v.Value)
print(v.Name.." processed")
end
return returnSubject
end
repeat
wait()
until player
while wait(1) do -- this loop will attempt force the client to render the ship physics
local sucess, message = massCenter:CanSetNetworkOwnership()
if sucess then
body.CameraGyroPart:SetNetworkOwner(player)
print("Success giving ownership.")
break
else
warn("Network Ownership would fail for this reason: "..message.." Trying again in 1 second")
end
end
-- gyroscopeScript
-- call the values
local gyroscope = massCenter.BodyGyro
local rotS = settings.RotationSpeed.Value
local rotA = settings.RotationAcceleration.Value
local currentXrotSpeed = 0
local currentYrotSpeed = 0
local currentZrotSpeed = 0
local targetXspeed = 0
local targetYspeed = 0
local targetZspeed = 0
local rotatorThread = (coroutine.create(function() -- creates the thread that control the bodyGyro CFrame
while true do
local Ttick = wait()
-- X calculation
if module(targetXspeed - currentXrotSpeed) > rotS then -- if the ship is stopping and you are trying to force it to rotate on the inverse, it will reach zero as twice as fast (for realism)
local multiplier = NumSignal(targetXspeed - currentXrotSpeed)
currentXrotSpeed = currentXrotSpeed + (Ttick*2*multiplier*rotA)
else
local multiplier = NumSignal(targetXspeed - currentXrotSpeed)
currentXrotSpeed = currentXrotSpeed + (Ttick*2*multiplier*rotA)
if module(currentXrotSpeed) > rotS and module(targetXspeed) ~= 0 then
currentXrotSpeed = rotS
end
end
-- Y calculation
if module(targetYspeed - currentYrotSpeed) > rotS then
local multiplier = NumSignal(targetYspeed - currentYrotSpeed)
currentYrotSpeed = currentYrotSpeed + (Ttick*2*multiplier*rotA)
else
local multiplier = NumSignal(targetYspeed - currentYrotSpeed)
currentYrotSpeed = currentYrotSpeed + (Ttick*2*multiplier*rotA)
if module(currentYrotSpeed) > rotS then
currentYrotSpeed = rotS
end
end
-- Z calculation
if module(targetZspeed - currentZrotSpeed) > rotS then
local multiplier = NumSignal(targetZspeed - currentZrotSpeed)
currentZrotSpeed = currentZrotSpeed + (Ttick*2*multiplier*rotA)
else
local multiplier = NumSignal(targetZspeed - currentZrotSpeed)
currentZrotSpeed = currentZrotSpeed + (Ttick*2*multiplier*rotA)
if module(currentZrotSpeed) > rotS then
currentZrotSpeed = rotS
end
end
-- defines where should the massCenter point
gyroscope.CFrame = CFrame.new(0,0,0)*CFrame.Angles(
math.rad(massCenter.Rotation.X + currentXrotSpeed),
math.rad(massCenter.Rotation.Y + currentYrotSpeed),
math.rad(massCenter.Rotation.Z + currentZrotSpeed)
)
end
-- end of the thread
end))
coroutine.resume(rotatorThread) -- runs the thread.
remote.RotationController.OnServerEvent:connect(function(p,rotTable)
if #rotTable ~= 3 then
error("The table is composed of three elements.")
end
print("oke")
for i,v in pairs(rotTable) do
v = NumSignal(v)
end
targetXspeed = rotTable[1]*rotS
targetYspeed = rotTable[2]*rotS
targetZspeed = rotTable[3]*rotS
end)
I know this is a quite bit to read, and I am sorry. If you want any further info get in touch with me. Thanks!

1 comment
Looks like it's rotating wrong.