Rolling ball script

I’m editing an existing script that essentially welds your character to a ball, and using WASD keys rolls the ball in directions related to your camera. This script was originally a local script and essentially did nothing on the server. So I’ve been converting it to a server sided script so that other players can see the player rolling around.

The issue I’m having is that I think the camera is not right, the player can roll in all directions but it doesn’t seem to update the camera properly or is using wrong camera properties. Because when you rotate the screen the orientation of the player rolling doesn’t change and still rolls in specific directions not releated to the camera.

If I throw this in a local script and use the “CurrentCamera” it works properly and will roll the player in the direction of the camera. So I thought maybe if I just retrieve the camera from a local script and use that cameras properties. But is this possible? Can I within my function retrieve local data and then proceed with the rest of my function?

Or is this even my issue? Any ideas to solve this.

Server script:

local mouse
local tool = script.Parent
local speed = 60
local colors = {"Bright violet","Magenta","Royal purple","Bright blue","Really blue","Navy blue","Bright green","Lime green","Camo","Bright yellow","New Yeller","Bright orange","Neon orange","Deep orange","Bright red","Really red"}
local color = math.random(1,#colors)
local cball
local ball = Instance.new("Part")
ball.BrickColor = BrickColor.new(colors[color])
ball.FormFactor = "Symmetric"
ball.Size = Vector3.new(7,7,7)
ball.TopSurface = "Smooth"
ball.BottomSurface = "Smooth"
ball.Transparency = 9
ball.Shape = 0
ball.Name = "Ball http://www.roblox.com/asset/?id=112501918"
local active = false
local bodvel
function Clicked()
	local player = game:GetService("Players"):GetPlayerFromCharacter(tool.Parent)
	print("yes")
	if active then
		return
	end
	print("go")
	active = true
	if cball then
		cball:Remove()
	end
	cball = ball:clone()
	cball.BrickColor = BrickColor.new(colors[color])
	cball.Parent = player.Character
	cball.CFrame = player.Character.UpperTorso.CFrame
	weld = Instance.new("Weld",cball)
	weld.Part0 = player.Character.UpperTorso
	weld.Part1 = cball
	player.Character.Humanoid.PlatformStand = true
	bodvel = Instance.new("BodyVelocity",cball)
	bodvel.maxForce = Vector3.new(27500,0,27500)
	game.Workspace.CurrentCamera.CameraSubject = cball
	game.Workspace.CurrentCamera.CameraType = "Track"
	tool.Handle.Transparency = 1
end
local modes = {w = false,s = false,a = false,d = false}
function KeyDown(key)
	if not active then
		return
	end
	if key=="w" or key=="s" or key=="a" or key=="d" then
		print("go forward")
		modes[key] = true
	else
		if key=="q" then
			color = color - 1
			if color<=0 then
				color = #colors
			end
			cball.BrickColor = BrickColor.new(colors[color])
		elseif key=="e" then
			color = color + 1
			if color>#colors then
				color = 1
			end
			cball.BrickColor = BrickColor.new(colors[color])
		elseif key=="r" then
			color = math.random(1,#colors)
			cball.BrickColor = BrickColor.new(colors[color])
		end
	end
end
function KeyUp(key)
	if key=="w" or key=="s" or key=="a" or key=="d" then
		modes[key] = false
	end
end
function Control()
	local speeds = {x = 0,z = 0}
	while active do
		local x
		local z
		if modes.w==true and modes.s~=true then
			speeds.z = -1
		elseif modes.w==false and modes.s==true then
			speeds.z = 1
		else
			speeds.z = 0
		end
		if modes.a==true and modes.d~=true then
			speeds.x = -1
		elseif modes.a==false and modes.d==true then
			speeds.x = 1
		else
			speeds.x = 0
		end
		if speeds.x~=0 and speeds.z~=0 then
			x = speed * math.sqrt(2) * speeds.x
			z = speed * math.sqrt(2) * speeds.z
		elseif speeds.x~=0 and speeds.z==0 then
			x = speed * speeds.x
			z = 0
		elseif speeds.x==0 and speeds.z~=0 then
			x = 0
			z = speed * speeds.z
		else
			x = 0
			z = 0
		end
		if x~=0 or z~=0 then
			print("new cam")
			local cam = game.Workspace.CurrentCamera
			local vec = Vector3.new(cam.CoordinateFrame.x,cam.CoordinateFrame.y,cam.CoordinateFrame.z)
			local vec2 = Vector3.new(cball.Position.x,cam.CoordinateFrame.y,cball.Position.z)
			print(vec,vec2)
			local cframe = CFrame.new(vec,vec2)
			local cframe2 = cframe * CFrame.new(x,0,z)
			local dir = (cframe2.p - cframe.p).unit
			bodvel.velocity = dir * speed
		else
			bodvel.velocity = Vector3.new(0,0,0)
		end
		wait()
	end
end
function WaitForActive()
	repeat
		wait(0.25)
	until active==true
	return
end
function Equipped(m)
	print("connect")
	WaitForActive()
	Control()
--	mouse = m
	--mouse.Button1Down:connect(Clicked)
	--mouse.KeyDown:connect(KeyDown)
	--mouse.KeyUp:connect(KeyUp)

end
tool.Equipped:connect(Equipped)
--tool.Unequipped:connect(function()
--	game.Workspace.CurrentCamera.CameraSubject = player.Character
--	game.Workspace.CurrentCamera.CameraType = "Custom"
--	active = false
--	cball:Remove()
--	cball = nil
--	player.Character.Humanoid.PlatformStand = false
--	tool.Handle.Transparency = 0.5
--end)

tool.Activated:Connect(function()
--	Clicked()
end)

local RE = script.Parent:WaitForChild("RemoteEvent")
RE.OnServerEvent:Connect(function(player, arg, key)
	if arg == "Clicked" then
		print("click")
		Clicked()
	elseif arg == "KeyDown" then
		print("key down", key)
		KeyDown(key)
	elseif arg == "KeyUp" then
		print("key up", key)
		KeyUp(key)
	end
end)

Client script (Just listens for key press and mouse click):

local RE = script.Parent:WaitForChild("RemoteEvent")

local player = game:GetService("Players").LocalPlayer

script.Parent.Equipped:connect(function(mouse)	
	mouse.Button1Down:connect(function()
		RE:FireServer("Clicked")
	end)
	mouse.KeyDown:connect(function(key)
		RE:FireServer("KeyDown", key)
	end)
	
	mouse.KeyUp:connect(function(key)
		RE:FireServer("KeyUp", key)
	end)
end)
1 Like

I think the issue may be in the fact that you’re using workspace.CurrentCamera in a server script, which doesn’t work since the server has its own camera, and your script is retrieving that. If you meant to get the player’s camera instead, your best hopes are either transmitting the client’s camera CFrame through a remote event, or moving your control code to a LocalScript and granting the client network ownership of the ball so that it replicates to the server.

2 Likes

How do I “grant the client network ownership”?

Giving an ownership is done via a function called SetNetworkOwner.

ball:SetNetworkOwner(player)

Also, it is highly recommended to do the entire movement via client due to ping and latency. You can create the ball on the server for a specific player and then pass the network ownership to that player.

2 Likes