I dont know how to help you really, but cant you use remote event if you need to transfer data and combine local script and server script?
You should prob research more on run service API
I just tried using a remote event, but it had the exact same effect. Plus, wouldnāt it overload the server having multiple players firing remote events every frame? Thatās sixty times per second for every player in the server.
Hmm then what about a remote function? Also i have no clue, im not really expedienced im sorry, and im bad at roblox physics
I donāt think the remote function would be any different. Iām pretty sure that the gravity bug is caused by calculating it on the server, but the local script wonāt affect it. I might open a bug report.
You can try, i tried my best atleast
Thank you for your help! I really appreciate it.
roblox is bad sometimes. try copying the script and deleting the original, and then publish changes. i have no guarantee if this would work but i do it sometimes to fix weird errors
Sadly, that didnāt work either.
Any help? Itās been months and I still havenāt found anything for this.
First off, I think your problem is caused because youāre only waiting a miniscule amount of time before trying to find the sphere and root. Iād recommend using :WaitForChild because an actual server is dozens of times slower than your computer on studio because studio has zero latency. (Time between client and server)
I also noticed that your code has some problems, and I would recommend not using some of the practices youāre using. For one, Roblox is horrible at updating parts positions and not having it be choppy with scripts. To this, I would recommend using network ownership for your marble.
Note, that if the sphere is anchored this will not work.
However, it did bother me that nobody would help you on this, so I made a functional version for this.
Server script:
local physicsService = game:GetService("PhysicsService")
physicsService:RegisterCollisionGroup("Character")
physicsService:RegisterCollisionGroup("Sphere")
physicsService:CollisionGroupSetCollidable("Character","Sphere",false)
local onDescendant = function(descendant)
if descendant:IsA("BasePart") and descendant.CollisionGroup ~= "Sphere" then
descendant.CollisionGroup = "Character"
end
end
local onCharacter = function(player,character)
local sphere = Instance.new("Part")
sphere.Size = Vector3.new(5,5,5)
sphere.Shape = Enum.PartType.Ball
sphere.Parent = character
sphere.Name = "Sphere"
sphere.CFrame = character.HumanoidRootPart.CFrame
sphere.CollisionGroup = "Sphere"
sphere.Massless = true
sphere:SetNetworkOwner(player)
character.DescendantAdded:Connect(onDescendant)
for _,descendant in pairs(character:GetDescendants()) do
onDescendant(descendant)
end
end
local onPlayer = function(player)
player.CharacterAdded:Connect(function(character)
onCharacter(player,character)
end)
if player.Character then
onCharacter(player,player.Character)
end
end
game.Players.PlayerAdded:Connect(onPlayer)
for k,v in pairs(game.Players:GetPlayers()) do
onPlayer(v)
end
Client script: (CharacterScripts)
local runService = game:GetService("RunService")
local character = script.Parent
local sphere = character:WaitForChild("Sphere")
local root = character:WaitForChild("HumanoidRootPart")
local humanoid = character:WaitForChild("Humanoid")
-- Align position will smoothly move parts to each other
-- https://create.roblox.com/docs/reference/engine/classes/AlignPosition
local alignPosition = Instance.new("AlignPosition")
alignPosition.Parent = sphere
alignPosition.Mode = Enum.PositionAlignmentMode.TwoAttachment
alignPosition.MaxForce = 9999999
alignPosition.MaxVelocity = 999999
-- Align orientation will align the rotation of parts
-- https://create.roblox.com/docs/reference/engine/classes/AlignOrientation
local alignOrientation = Instance.new("AlignOrientation")
alignOrientation.Parent = sphere
alignOrientation.Mode = Enum.OrientationAlignmentMode.TwoAttachment
alignOrientation.MaxTorque = 9999999
alignOrientation.MaxAngularVelocity = 999999
-- They're based off of "attachments", which are these cute thingies:
-- Think of them as 3d points, like in math when you learn about (x,y)
-- These have (x,y,z) and you can base things like rotation of off them
-- They're super cool!
-- https://create.roblox.com/docs/reference/engine/classes/Attachment
local attachment0 = Instance.new("Attachment")
attachment0.Parent = sphere
local attachment1 = Instance.new("Attachment")
attachment1.Parent = root
alignPosition.Attachment0 = attachment0
alignPosition.Attachment1 = attachment1
alignOrientation.Attachment0 = attachment0
alignOrientation.Attachment1 = attachment1
local lastPosition = root.Position
local totalRotation = Vector3.new(0, 0, 0)
local function safeNormalize(vector) -- Because of small updates, this can make it not work right >:(
if vector.Magnitude > 0.001 then
return vector.Unit
else
return Vector3.new(0, 0, -1) -- Default direction if movement is too small
end
end
-- Place the sphere at the bottom of the player's character:
local characterHeight = humanoid.HipHeight * 2
local sphereRadius = sphere.Size.Y / 2
local offsetY = -(characterHeight / 2) + sphereRadius
attachment1.Position = Vector3.new(0, -offsetY, 0)
-- ChatGPT wrote like 90% of this part below: (beyond me, it bothered me that the sphere didn't rotate lol)
-- I did do a little fixing, but that's not much
runService.Heartbeat:Connect(function(deltaTime)
local currentPosition = root.Position
local movement = currentPosition - lastPosition
local speed = movement.Magnitude / math.max(deltaTime, 0.001) -- Prevent division by zero
if speed > 0.1 then -- Adjust this threshold to determine when the player is "walking"
-- Calculate rotation based on movement
local direction = safeNormalize(movement)
local up = Vector3.new(0, 1, 0)
local right = direction:Cross(up)
local forward = up:Cross(right)
local distance = movement.Magnitude
local sphereCircumference = 2 * math.pi * sphere.Size.X
local rotationAmount = (distance / sphereCircumference) * 360 -- Calculate rotation based on sphere circumference
-- Update rotation
local newRotation = Vector3.new(
-direction:Dot(forward) * rotationAmount,
0,
-direction:Dot(right) * rotationAmount
)
totalRotation = totalRotation + newRotation
-- Apply rotation to attachment1
attachment1.Orientation = totalRotation
end
lastPosition = currentPosition
end)
Uncopylocked functional place:
File:
ball.rbxl (55.2 KB)
FYI: RenderStepped is only on the client because RenderStepped runs after every frame is rendered, however the server doesnāt have a rendering engine.
Thank you for helping, but Iām not sure this is what Iām looking for.
Hereās a video I took of what it should look like:
robloxapp-20240716-1402237.wmv (2.8 MB)
Note how Iām able to control the sphere to some degree while still being affected by physics. This is what Iām trying to achieve. However, it simply does nothing when playing outside of Studio.
Here is my current script:
human = script.Parent:WaitForChild("Humanoid")
sphere = script.Parent:WaitForChild("Sphere")
root = script.Parent:WaitForChild("HumanoidRootPart")
isOnGround = false
function move()
isOnGround = workspace:Raycast(root.Position, Vector3.new(0, -3, 0))
if isOnGround then
sphere.Velocity = sphere.Velocity + (human.MoveDirection * human.WalkSpeed)
else
sphere.Velocity = sphere.Velocity + (human.MoveDirection * (human.WalkSpeed / 2))
end
end
human:GetPropertyChangedSignal("Jump"):Connect(function()
if human.Jump == true then
if isOnGround then
sphere.Velocity = Vector3.new(sphere.Velocity.X, human.JumpPower, sphere.Velocity.Z)
end
end
end)
while wait(1/60) do
move()
end
Note how this is in a local script. I believe this is where the problem comes from, however when I move it to a server script it stops working and the physics get all wonky.
My current setup has the starter character as a model with a humanoid, a humanoid root part, and a sphere parented under it. The root part has an align orientation constraint with an anchor to keep it upright, and also a no collision constraint to keep it from colliding with the sphere. The sphere has an align position constraint to keep it in place with the root part.
I also have a script to set the root part and sphereās network owner to the player, but it doesnāt seem to do anything.
Note that my character is not generated with a script, it is a model placed under the starter player folder.
I hope this can provide some clarity to the situation and to my goal.
Okay, I figured it out. It was because scripts donāt run when placed in StarterCharacter, I donāt understand why, but they donāt.
local players = game:GetService("Players")
local runService = game:GetService("RunService")
local function onPlayer(player)
local function onCharacter(character)
local sphere = character:WaitForChild("Sphere")
local root = character:WaitForChild("HumanoidRootPart")
sphere:SetNetworkOwner(player)
end
player.CharacterAdded:Connect(onCharacter)
if player.Character then
onCharacter(player.Character)
end
end
players.PlayerAdded:Connect(onPlayer)
for _,player in pairs(players:GetPlayers()) do
task.spawn(onPlayer,player)
end
This script goes in ServerScriptService and will accordingly set network ownership, I believe studio has different replication properties than live games that allowed this to go unnoticed. The script was not running either way.
This solution also makes AlignPosition and AlignOrientation obselete.
local runService = game:GetService("RunService")
local character = script.Parent
local camera = workspace.CurrentCamera
local human = character:WaitForChild("Humanoid")
local sphere = character:WaitForChild("Sphere")
local root = character:WaitForChild("HumanoidRootPart")
isOnGround = false
camera.CameraType = Enum.CameraType.Follow
camera.CameraSubject = sphere
local function move()
isOnGround = workspace:Raycast(root.Position, Vector3.new(0, -3, 0))
if isOnGround then
sphere:ApplyImpulse(human.MoveDirection * human.WalkSpeed * sphere.Mass)
else
sphere:ApplyImpulse(human.MoveDirection * (human.WalkSpeed / 2) * sphere.Mass)
end
end
human:GetPropertyChangedSignal("Jump"):Connect(function()
if human.Jump == true then
if isOnGround then
sphere.Velocity = Vector3.new(sphere.Velocity.X, human.JumpPower, sphere.Velocity.Z)
end
end
end)
sphere.Changed:Connect(function()
root.CFrame = sphere.CFrame
end)
runService.RenderStepped:Connect(move)
Iād recommend using RenderStepped over wait(), noting that wait is also a deprecated function. That or task.wait().
Thank you so much! I was able to get this working by moving the script into StarterCharacterScripts.
Also, I use wait instead of RenderStepped because I want the movement to be consistent, while the render stepped varies because of performance.
This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.