I have open sourced code for a custom character movement system but it breaks when I publish the game to roblox. Here’s the code…not sure why it would break after publishing to roblox as before publishing it works fine:
--[[
Looking at this script a year later, yeah, I don't know what I was thinking.
]]
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local Player = Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Humanoid = Character:WaitForChild("Humanoid")
local HRP = Character:WaitForChild("HumanoidRootPart")
local VectorForce = HRP:WaitForChild("VectorForce")
local Rotator = HRP:WaitForChild("Rotator")
local PlayerScripts = Player:WaitForChild("PlayerScripts")
local PlayerModule = require(PlayerScripts:WaitForChild("PlayerModule"))
local Controls = PlayerModule:GetControls()
local PlrGui = Player.PlayerGui
--[[
All of this is pretty janky, so gl
tbh even I don't know what exactly I was aiming for with this
]]
--vars
local IsJumping = false
local IsLanded = false
local Mobile = false
local MobileJump = false
local function CustomJump()
if IsLanded == true and IsJumping == false and MobileJump == false then
IsLanded = false
MobileJump = true
end
end
--check if player has touch gui, this is bad practice but it's only for the sake of the Demo
if Controls["touchGui"] then
local currentTouchGui = PlrGui:WaitForChild("TouchGui")
local touchControlFrame = currentTouchGui:WaitForChild("TouchControlFrame")
local JumpButton = touchControlFrame:WaitForChild("JumpButton")
if JumpButton then
JumpButton.Activated:Connect(CustomJump)
end
Mobile = true
end
---- Settings
local MASS = 10 -- Could use GetMass, but slime and it's baseparts are set to massless
local ACCELERATION = 120
local MAX_VELOCITY = 13
local LIMITER_SUM = 0
local RATE = 60 -- limit runservice to 60fps
local RAYLIMITER_SUM = 0
local RAY_RATE = 20 -- limit runservice to 20fps for the raycasts
local Viscosity = MASS * ACCELERATION / MAX_VELOCITY
---- State variables
local ZERO_VEC = Vector3.new()
local PROJ_VEC = Vector3.new(1, 0, 1)
local Y_VEC = Vector3.new(0, -1.5, 0)
local PROJ_Y_VEC = Vector3.new(0, 1, 0)
--sound dir
local Sounds = {
["Died"] = "rbxassetid://12631617531",
["Landing"] = "rbxassetid://12631617618",
["Jumping"] = "rbxassetid://12631617689",
}
local SoundInst = {}
local function ReplaceSound()
for ind, Inst in pairs(HRP:GetChildren()) do
if Inst:IsA("Sound") then
if Sounds[Inst.Name] then
Inst.SoundId = Sounds[Inst.Name]
SoundInst[Inst.Name] = Inst
end
end
end
end
ReplaceSound()
---- Initialize
Humanoid:ChangeState(Enum.HumanoidStateType.Physics)
Humanoid.CameraOffset = Vector3.new(0,-1,0)
RunService.Heartbeat:Connect(function(dT)
LIMITER_SUM = LIMITER_SUM + dT
RAYLIMITER_SUM = RAYLIMITER_SUM + dT
if LIMITER_SUM >= 1/RATE then
local moveVec = Controls:GetMoveVector()
local cameraCF = workspace.CurrentCamera.CFrame
moveVec = (-cameraCF.LookVector * moveVec.Z + cameraCF.RightVector * moveVec.X) * PROJ_VEC
moveVec = moveVec.Unit -- All these 4 lines do is get the direction we are moving in
local vel = HRP.Velocity * PROJ_VEC -- velocity on the x-z plane
local velOnY = HRP.Velocity * PROJ_Y_VEC
local drag = -vel * Viscosity
local jump = ZERO_VEC -- start at the 0 vector in case we aren't even jumping
--[[
PC & mobile check for jumping,
It has to be in seperate blocks because the mobile and
PC controller module behave differently for the jump logic
and TouchGui jump button isn't the same as Spacebar keycode
]]--
if Controls.activeController and Controls.activeController:GetIsJumping() and not IsJumping then
local result = workspace:Raycast(
HRP.Position,
Vector3.new(0, -2, 0),
RaycastParams.new()
)
--[[
Raycast downwards to check if the player jumps above the certain distance (2 dist. on Y axis)
if no raycast resul then start falling
]]--
if result then
IsJumping = true --if there's a result this variable will stay true
IsLanded = false
coroutine.wrap(function()
local t = tick()
while tick() - t < 0.1 do
RunService.Heartbeat:Wait()
end
IsJumping = false
end)()
end
elseif Mobile == true and MobileJump and not IsJumping then
local result = workspace:Raycast(
HRP.Position,
Vector3.new(0, -2, 0),
RaycastParams.new()
)
if result then
IsJumping = true
coroutine.wrap(function()
local t = tick()
while tick() - t < 0.1 do
RunService.Heartbeat:Wait()
end
IsJumping = false
MobileJump = false
end)()
end
end
if IsJumping then
-- on jump
SoundInst["Jumping"]:Play()
jump = Vector3.new(0, MASS * workspace.Gravity * 3, 0) -- add value to jump
else
-- on falling down
if not IsLanded and RAYLIMITER_SUM >= 1/RAY_RATE then
if velOnY.Y < 0 then
-- fire a ray twoards the ground to check if the player has landed
local result = workspace:Raycast(
HRP.Position,
Y_VEC,
RaycastParams.new()
)
if result then
--if player lands
IsLanded = true
MobileJump = false
SoundInst["Landing"]:Play()
end
end
-- limit raycast
RAYLIMITER_SUM = RAYLIMITER_SUM - 1/RAY_RATE
end
end
if moveVec.Magnitude > 0 then
-- thrust is (nan, nan, nan) if plr isnt moving
local thrust = MASS * ACCELERATION * moveVec
VectorForce.Force = thrust + drag + jump -- calculate vectorforce
Rotator.PrimaryAxis = moveVec -- rotate slime to the latest direction it was moving in
else
VectorForce.Force = drag * 6 + jump -- slow down
end
LIMITER_SUM = LIMITER_SUM - 1/RATE
end
end)
--some algorithms were taken off of the devforum but I forgot where I got them from so sadly I won't be able to credit anyone.
Here’s the file if you want to see for yourself:
charactermodel (1).rbxl (66.8 KB)