Hey, I have problem with movement system of custom characters in my game.
prop = custom character that the player changed to (always a model)
Problems
Problem 1) ground clipping - some props get stuck in the ground
Problem 2) some of the props are rotated the wrong way - for example pumpkin
Problem 3) as you can see in the video the lantern is a assymetrical object and it has “weird rotations”
Problem 4) if the HumanoidRootPart doesnt touch ground the whole prop just begins sliding wherever it want
Problem 5) some of the props play some lying down animation when i change to them (even when they dont have Animate script inside them) [not seen in the video]
Problem 6) some props bounce after jumping or slow down when autojumping
Not all props have these problems, just some, and not all props have the same problems
How the change of player to the custom character works:
- you click an item → the prop gets found in the ReplicatedStorage
This is how a model can look like - one of the more complex ones
- the prop gets cloned and it sets the important data to the prop (Value, Owner, Prop tag etc.)
- HumanoidRootPart gets set as primaryPart in it gets moved to be a child of the prop (prolly not needed)
HRP.Parent = newProp
newProp.PrimaryPart = HRP
- the scripts get cloned
for _, child in pairs(oldChar:GetChildren()) do
if child:IsA("Script") or child:IsA("LocalScript") then
--if child.Name == "Animate" or child.Name == "Health" then continue end
child:Clone().Parent = newProp
end
end
- the props gets tped to the ground unless in air (to prevent being stuck in the ground)
local newCf = propUtils.groundFinder(newProp)
if newCf then
newProp:PivotTo(newCf)
end
propUtils.groundFinder script:
function propUtils.groundFinder(prop : Instance) : CFrame
local primaryPart = prop.PrimaryPart
if not primaryPart then
primaryPart = prop:FindFirstChild("HumanoidRootPart")
if not primaryPart then
return nil -- no primary part to work with
end
end
local humanoid = prop:FindFirstChildOfClass("Humanoid")
if humanoid then
if humanoid.FloorMaterial == Enum.Material.Air then
print("In the air!")
return nil -- prop is in the air, skip repositioning
end
end
local rayOrigin = primaryPart.Position
local rayDirection = Vector3.new(0, -50, 0)
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {prop}
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
local raycastResult = workspace:Raycast(rayOrigin, rayDirection, raycastParams)
if raycastResult then
local cf, size = prop:GetBoundingBox()
local bottomY = cf.Position.Y - (size.Y / 2)
local groundY = raycastResult.Position.Y
local yOffset = groundY - bottomY
local newCf = primaryPart.CFrame * CFrame.new(0, yOffset, 0)
return newCf
end
return nil
end
The print statement - In the Air! always gets fired and the prop always spawns a little bit over the ground for some reason
newProp.Parent = workspace
the props get parented to the workspaceaddGroundColliderToModel(newProp)
- addGroundColliderToModel adds “feet” (non colidable part that touches the ground) to the prop, but it doesnt work with complex models
addGroundColliderToModel script:
local function addGroundColliderToModel(model : Model)
local cf, size = model:GetBoundingBox()
local bottomY = cf.Position.Y - (size.Y / 2)
local groundCollider = Instance.new("Part")
groundCollider.Name = "GroundCollider"
groundCollider.Anchored = true
groundCollider.CanCollide = false
groundCollider.Transparency = 1
groundCollider.Size = Vector3.new(size.X, 10, size.Z)
groundCollider.CFrame = CFrame.new(cf.Position.X, bottomY - 0.15, cf.Position.Z)
groundCollider.Parent = model
end
weldAndUnanchor(newProp)
it gets all welded together to the HumanoidRootPart and unanchoredsetNetworkOwnership(player, newProp)
player gets set NetworkOwnership over the propsizeChanger.scaleProp(player)
the prop gets scaledcameraRotation.ApplyCameraCFrameEvent:FireClient(player, direction)
the camera gets rotated in the direction of the playerbounceHandling(prop, hum)
just setting some customPhysicalProperties for the prop. you can see in tried solutions
Tried solutions
Bouncing:
- the issue is just with some props for some reason
for _,v in prop:GetDescendants() do
if v:IsA("BasePart") then
v.CustomPhysicalProperties = PhysicalProperties.new(
100, -- Density
0, -- Friction
0, -- Elasticity
0, -- FrictionWeight
100 -- ElasticityWeight
)
end
end
- doesnt fully fix the problem - its just a little better
local downwardForce = -15 -- the lower the number, the more the player will be pushed down
while task.wait() do
repeat task.wait() until rootPart.Position.Y > oldHeight
repeat
local moveDirection = humanoid.MoveDirection.Unit
local newForce = Vector3.new(moveDirection.X * moveMultiplier,
rootPart.AssemblyLinearVelocity.Y,
moveDirection.Z * moveMultiplier)
rootPart.AssemblyLinearVelocity = newForce
task.wait()
until rootPart.Position.Y <= oldHeight
local oldHeight = rootPart.Position.Y
rootPart.AssemblyLinearVelocity = Vector3.new(0, downwardForce, 0)
end
- fixes the issue with models slowing down, but the bouncing after jumping is a little worse
props look different on the server and on the client. i had to handle the scaling on the client, cuz its too laggy on the server