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

0

Looks like it's rotating wrong.