How to replicate this vehicle controller:

Hi there, I wanted to make a project thats essentially a custom car controller, something like this :

However, I wasn’t able to replicate this correctly in Roblox Studio, this is the closest I got :

While I can roll around, it feels like I’m controller a marble rather than a car.

3 Issues I have is:

  1. How can I keep a kart model within the sphere, while also rotating it based on player input.

  2. How can I roll the sphere towards the Kart model’s forward direction.

  3. How can I make the kart rotate independently of the sphere.

I’ve been on this for days and frankly i am stuck. Please help.

Can you provide your existing code?

Here it is

(Client)

local UIS = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local Camera = workspace.CurrentCamera
local Player = game:GetService("Players").LocalPlayer
local RS = game:GetService("ReplicatedStorage")
local MarbleCreate = RS.MarbleCreate
local MarbleUpdate = RS.MarbleRemote
local PlayerMarble = MarbleCreate:InvokeServer()

print(PlayerMarble)

--local marble = Instance.new("Part")
--marble.Size = Vector3.new(8,8,8)
--marble.BrickColor = BrickColor.White()
--marble.Transparency = .5
--marble.Name = "MarbleFollowed"
--marble.Position = Vector3.new(-222.8, 1.5, 253.7)
--marble.Shape = Enum.PartType.Ball
--marble.Parent = workspace
--marble.Material = Enum.Material.SmoothPlastic
--local Velocity = Instance.new("BodyAngularVelocity")
--Velocity.Parent = marble


local walkKeyBinds = {
	Forward = { Key = Enum.KeyCode.W, Direction = Enum.NormalId.Front },
	Backward = { Key = Enum.KeyCode.S, Direction = Enum.NormalId.Back },
	Left = { Key = Enum.KeyCode.A, Direction = Enum.NormalId.Left },
	Right = { Key = Enum.KeyCode.D, Direction = Enum.NormalId.Right }
}


local function getWalkDirectionCameraSpace()
	local walkDir = Vector3.new()

	for keyBindName, keyBind in pairs(walkKeyBinds) do
		if UIS:IsKeyDown(keyBind.Key) then
			walkDir = Vector3.FromNormalId( keyBind.Direction )
			
		end
	end

	if walkDir.Magnitude > 0 then --(0, 0, 0).Unit = NaN, do not want
		walkDir = walkDir.Unit --Normalize, because we (probably) changed an Axis so it's no longer a unit vector
	end
	
	

	return walkDir
end


local function getWalkDirectionWorldSpace()
	local walkDir = Camera.CFrame:VectorToWorldSpace(getWalkDirectionCameraSpace() )
	
	walkDir *= Vector3.new(1, 0, 1) --Set Y axis to 0

	if walkDir.Magnitude > 0 then --(0, 0, 0).Unit = NaN, do not want
		walkDir = walkDir.Unit --Normalize, because we (probably) changed an Axis so it's no longer a unit vector
	end
	
	
	return walkDir
end




RunService.RenderStepped:Connect(function(dt)
	UIS.MouseBehavior = Enum.MouseBehavior.LockCenter
	Camera.CameraSubject = PlayerMarble
	Camera.CameraType = Enum.CameraType.Follow
	
	MarbleUpdate:FireServer(getWalkDirectionWorldSpace(), PlayerMarble)
end)

(Server)

local RS = game:GetService("ReplicatedStorage")
local Event = RS.MarbleRemote
local CreateMarbleEvent = RS.MarbleCreate

local function CreateMarble()
	print("Server has been fired")
	local marble = Instance.new("Part")
	marble.Size = Vector3.new(8,8,8)
	marble.BrickColor = BrickColor.White()
	marble.Transparency = 0.5
	marble.Name = "MarbleFollowed"
	marble.Position = Vector3.new(-222.8, 1.5, 253.7)
	marble.Shape = Enum.PartType.Ball
	print("marble made")
	
	marble.Parent = workspace
	
	print("Marble Added To Workspace")
	marble.Anchored = true
	marble.Material = Enum.Material.SmoothPlastic
	local Velocity = Instance.new("BodyAngularVelocity")
	Velocity.Parent = marble
	marble.Anchored = false
	
	local AttachMarble = Instance.new("Attachment")
	AttachMarble.Parent = marble
	
	
	print(marble.Name.." is defo not nil")
	
	workspace["Meshes/Car (1)"].AlignPosition.Attachment1 = AttachMarble
	workspace["Meshes/Car (1)"].AlignOrientation.CFrame = CFrame.new(AttachMarble.WorldPosition, Vector3.new(0,0,0))
	
	
	task.wait(6.24)
	return marble
end

CreateMarbleEvent.OnServerInvoke = CreateMarble

local lastTick = os.clock()
local maxdrift = math.huge
local mindrift = 1

Event.OnServerEvent:Connect(function(p, WalkDir:Vector3, marble)
	if marble ~= nil then
		local velo = marble.Velocity -- you can replace with your own movement vector
		local KartModel = workspace["Meshes/Car (1)"]
		local kartvelo = KartModel.Velocity
		local diff = (math.abs(velo.x-WalkDir.X)<1) and 0 or ((velo.x<WalkDir.X) and (math.max(math.min(lastTick*maxdrift,math.abs(velo.x-WalkDir.X)),mindrift)) or (-math.max(math.min(lastTick*maxdrift,math.abs(velo.x-WalkDir.X)),mindrift)))
		print(diff)
		KartModel.AlignOrientation.CFrame = CFrame.Angles(0, -math.rad(velo.x+diff), 0)
		marble.BodyAngularVelocity.AngularVelocity = Vector3.new(WalkDir.Z * 32,0,WalkDir.X * -32)
		marble.BodyAngularVelocity.MaxTorque = Vector3.new(40000,40000,40000)
		if WalkDir == Vector3.new(0,0,0) then
			marble.BodyAngularVelocity.MaxTorque = Vector3.new(0,0,0)
		end
	end
	lastTick = os.clock()
end)

Actually sorry… it would be easier if I had the place file.

Are comfortable DMing the place file?

1 Like
-- Client Script fix
local UIS = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local Camera = workspace.CurrentCamera
local Player = game:GetService("Players").LocalPlayer
local RS = game:GetService("ReplicatedStorage")
local MarbleCreate = RS.MarbleCreate
local MarbleUpdate = RS.MarbleRemote
local PlayerMarble = MarbleCreate:InvokeServer()

local walkKeyBinds = {
    Forward = { Key = Enum.KeyCode.W, Direction = Enum.NormalId.Front },
    Backward = { Key = Enum.KeyCode.S, Direction = Enum.NormalId.Back },
    Left = { Key = Enum.KeyCode.A, Direction = Enum.NormalId.Left },
    Right = { Key = Enum.KeyCode.D, Direction = Enum.NormalId.Right }
}

local function getWalkDirectionCameraSpace()
    local walkDir = Vector3.new()
    for keyBindName, keyBind in pairs(walkKeyBinds) do
        if UIS:IsKeyDown(keyBind.Key) then
            walkDir = Vector3.FromNormalId(keyBind.Direction)
        end
    end
    if walkDir.Magnitude > 0 then
        walkDir = walkDir.Unit
    end
    return walkDir
end

local function getWalkDirectionWorldSpace()
    local walkDir = Camera.CFrame:VectorToWorldSpace(getWalkDirectionCameraSpace())
    walkDir *= Vector3.new(1, 0, 1)
    if walkDir.Magnitude > 0 then
        walkDir = walkDir.Unit
    end
    return walkDir
end

RunService.RenderStepped:Connect(function(dt)
    UIS.MouseBehavior = Enum.MouseBehavior.LockCenter
    Camera.CameraSubject = PlayerMarble
    Camera.CameraType = Enum.CameraType.Follow
    MarbleUpdate:FireServer(getWalkDirectionWorldSpace(), PlayerMarble)
end)
-- Server Script fix
local RS = game:GetService("ReplicatedStorage")
local Event = RS.MarbleRemote
local CreateMarbleEvent = RS.MarbleCreate

local function CreateMarble()
    local marble = Instance.new("Part")
    marble.Size = Vector3.new(8, 8, 8)
    marble.BrickColor = BrickColor.White()
    marble.Transparency = 0.5
    marble.Name = "MarbleFollowed"
    marble.Position = Vector3.new(-222.8, 1.5, 253.7)
    marble.Shape = Enum.PartType.Ball
    marble.Parent = workspace
    marble.Anchored = true
    marble.Material = Enum.Material.SmoothPlastic
    local Velocity = Instance.new("BodyAngularVelocity")
    Velocity.Parent = marble
    marble.Anchored = false
    local AttachMarble = Instance.new("Attachment")
    AttachMarble.Parent = marble
    workspace["Meshes/Car (1)"].AlignPosition.Attachment1 = AttachMarble
    workspace["Meshes/Car (1)"].AlignOrientation.CFrame = CFrame.new(AttachMarble.WorldPosition, Vector3.new(0,0,0))
    return marble
end

CreateMarbleEvent.OnServerInvoke = CreateMarble

local lastTick = os.clock()
local maxdrift = math.huge
local mindrift = 1

Event.OnServerEvent:Connect(function(p, WalkDir, marble)
    if marble ~= nil then
        local velo = marble.Velocity
        local KartModel = workspace["Meshes/Car (1)"]
        local diff = (math.abs(velo.x-WalkDir.X)<1) and 0 or ((velo.x<WalkDir.X) and (math.max(math.min(lastTick*maxdrift,math.abs(velo.x-WalkDir.X)),mindrift)) or (-math.max(math.min(lastTick*maxdrift,math.abs(velo.x-WalkDir.X)),mindrift)))
        KartModel.AlignOrientation.CFrame = CFrame.Angles(0, -math.rad(velo.x+diff), 0)
        marble.BodyAngularVelocity.AngularVelocity = Vector3.new(WalkDir.Z * 32,0,WalkDir.X * -32)
        marble.BodyAngularVelocity.MaxTorque = Vector3.new(40000,40000,40000)
        if WalkDir == Vector3.new(0,0,0) then
            marble.BodyAngularVelocity.MaxTorque = Vector3.new(0,0,0)
        end
    end
    lastTick = os.clock()
end)

Are you even testing code or are you just throwing questions into ChatGPT and regurgitating the answer?

It’s not chatgpt it’s something else than that and also trying to help him fix it

How does this help him? Anyone can ask ChatGPT? You didn’t even provide what was changed. Your code is basically useless?

It’s a starting help and it’s not chatgpt in the website like I said

yeah sure if u need it.

Ill send u a dm