Making A Sliding System Tutorial [Youtube]

Player.Character:FindFirstChildOfClass(“Humanoid”).RootPart.Velocity *= 2

2 Likes

do you think I could make wall running out of this system by attaching some hitboxes to the arms/ torso and then have a ray point out that direction? I just feel like it could work with this really well I just don’t know how to execute it

1 Like

Super creative use of RaycastHitboxes, I just started using them for my weapons system and I love your explanation and showing of modification and results of everything. Thanks for taking the time to make this!

2 Likes

tysmmm!!!

2 Likes

baby mama you deserve a smoochie woochie mwah mwah

1 Like

Hello! Decently new scripter here. I love the tutorial, but I had a few hiccups along the way. While following along, I found that

  1. My hitboxes weren’t being attached onto the character/were not visible
  2. My slide animation was not loading
  3. None of my print statements were being shown in the output.

If OP or anyone else would be able to help me fix these problems I would be extremely thankful. Here is my LocalScript code. I can supply my module code if need be as well.

OnSlide
local ContextActionService = game:GetService("ContextActionService")
local Promise = require(ReplicatedStorage.Modules.Promise)

local RaycastModule = require(ReplicatedStorage.Modules.RaycastHitboxV4)

local plr = game.Players.LocalPlayer
local playerConfig = require(plr.PlayerScripts:WaitForChild("PlayerModule"))
local ctrls = playerConfig:GetControls()
local char = script.parent
local hrp = char:WaitForChild("HumanoidRootPart")
local slideHitboxModel = plr.Backpack.SlideHitboxes

local slideHitbox = RaycastModule.new(slideHitboxModel)
slideHitbox.DetectionMode = RaycastModule.DetectionMode.PartMode
slideHitbox.Visualizer = true
slideHitbox.RayDirection = Vector3.new(0, -0.6, 0.3)

local params = RaycastParams.new()
params.FilterDescendantsInstances = {plr.Character}
params.FilterType = Enum.RaycastFilterType.Blacklist
params.IgnoreWater = true

slideHitbox.RaycastParams = params

local slidingAttachment = Instance.new("Attachment")
slidingAttachment.Name = "SlidingAttachment"
slidingAttachment.Parent = hrp
local alignOrientation = Instance.new("AlignOrientation")
alignOrientation.Enabled = false
alignOrientation.RigidityEnabled = true
alignOrientation.Mode = Enum.OrientationAlignmentMode.OneAttachment
alignOrientation.Attachment0 = slidingAttachment
alignOrientation.Parent = hrp

local animator = plr.Character.Humanoid:WaitForChild("Animator")
local slidingAnim = ReplicatedStorage.Assets.Animations.Slide

local slideAccel = 32

function onSlideKeyPressed(actionName, inputState, inputObject)
	if inputState == Enum.UserInputState.Begin then
		doSlide()
	end
end

ContextActionService:BindAction("SLIDE_ACTION", onSlideKeyPressed, true, Enum.KeyCode.Q)


function doSlide()
	ReplicatedStorage.Remotes.AttachSlideHitbox:InvokeServer()
	
	local isInSlideMode = false
	
	local postMovementEvent
	local onHitEv
	local floorNormal
	
	local slidingAnimTrack = animator:LoadAnimation(slidingAnim)
	local timeSinceSlideStart = 0 
	
	local function reset()
		if onHitEv then
			onHitEv:Disconnect()
		end
		
		if postMovementEvent then
			postMovementEvent:Disconnect()
		end
		
		ctrls:Enable()
		slidingAnimTrack:Stop()
		slideHitbox:HitStop()
		
		hrp.AssemblyLinearVelocity = Vector3.zero
		alignOrientation.Enabled = false
		
		char.Humanoid:ChangeState(Enum.HumanoidStateType.GettingUp)
	end
	onHitEv = slideHitbox.OnHit:Connect(function(part, _, raycastResult)
		slideHitbox:HitStart()
		
		floorNormal = raycastResult.Normal
		
		local slopeVector = hrp.CFrame.RightVector:Cross(floorNormal).y
		if slopeVector >= 0.1  then
			if isInSlideMode then
				print("Stopped slide: Slope too steep!")
				reset()
			end
			return
		end
		
		if not isInSlideMode then
			print("In slide mode")
			isInSlideMode = true
			
			alignOrientation.Enabled = true
			hrp.AssemblyLinearVelocity = Vector3.zero
			
			char.Humanoid:ChangeState(Enum.HumanoidStateType.Physics)
			ctrls:Disable()
			
			slidingAnimTrack.Looped = true
			slidingAnimTrack:Play()
			
			local forwardForce = slopeVector.Unit + hrp.AssemblyMass + slideAccel
			hrp:ApplyImpulse(forwardForce)
			
			slideHitbox.onHitNothing:Connect(function()
				floorNormal = nil				
			end)
			
			postMovementEvent = game:GetService("RunService").Heartbeat:Connect(function(dt)
				timeSinceSlideStart *= dt
				local linearVelocity = hrp.AssemblyLinearVelocity
				hrp.AssemblyLinearVelocity = linearVelocity - floorNormal * linearVelocity:Dot(floorNormal)
				alignOrientation.CFrame = CFrame.lookAt(Vector3.Zero, hrp.AssemblyLinearVelocity)
				
				if timeSinceSlideStart >= 0.2 then
					if ((hrp.AssemblyLinearVelocity * Vector3.new(1, 0, 1)).Magnitude < 0.1) then
						print("Stopped slide: Reached 0 Velocity")
						reset()
						return
					end
				end
			end)
		end
		
	end)
	
	ReplicatedStorage.Remotes.AttachSlideHitbox:InvokeServer()
	slideHitbox:HitStart()
	
	game:GetService("RunService").Heartbeat:Wait()
	game:GetService("RunService").Heartbeat:Wait()
	
	if not isInSlideMode then
		if onHitEv then
			onHitEv:Disconnect()
			--not on the ground so exit then
		end
		print("Stopped slide: Not on valid ground")
	end
end

image
This error also showed up in the output when I tried playtesting. It leads back to the GoodSignal module script, and specifically to the line that handles these Signal()s. Not sure what this means.

‘Signal::Create’ is wrong, Signal:Create()

1 Like

Hey man I liked this tutorial and I have implemented the same concept of what you have done without the use external modules and my sliding looks a lot more cleaner now :v::grin:

But one thing I will say is it would’ve been better if u had omitted the use of external modules and implemented your own since the only need for the raycasthitbox module is just on a loop raycasting toward the opposite direction of the look direction of the heels/foot of the player.

First, glad it worked out! Over the course of development I’ve improved aspects of the code and added new features. So much so, that I want to remake this tutorial at some point. Even after garnering hindsight through the passage of time, I have not had second thoughts about using the Promise and RaycastHitbox modules.

In the current version I’m operating with, slide can be cancelled by letting go of the key or jumping out of it and using promises just makes handling these external cancellations very easy and bug-free. Also the ability to immediately resolve the promise is awesome. They are really just better coroutines.

RaycastHitbox module, I would rather not re-implement the logic being handled in this module, it’s nice to have one interface through which I do all this, since sliding is not the only place I’m using it. I can simply attach attachments, send a few parameters and it’ll handle the raycasting for me along with visualization and other useful features. For more trivial one-time raycast use-cases, sure I’ll simply use workspace:Raycast, and I have in fact opted for this for the initial ground detection (is he on ground? just cast a ray down from each knee to the ground, simple enough) and if the character is, I still use raycasthitbox for continual ground detection during the slide, all I do is subscribe to events and handle them appropriately, I find it simpler to work at this level of abstraction.

1 Like

Hi,
Can you provide a .rbxl file for us to check out, along with your sweet YT?

thanks

I understand that this only constituted a role in a larger system for you, however it can be a valuable tool for teaching raycasting and thread handling practically while avoiding external modules; so you could consider making it from scratch for the sake of the tutorial in the future :blush:

It’s not largely about it constituting a larger role in a system for me. If I have to re-invent the wheel every time in a tutorial things would be difficult. It would consume unnecessary time among other things. I’d rather show users commonly used modules that are robust and can make their development process easier. Those things you mention are imo better done in a separate and dedicated tutorial. As such, I do assume some base level of familiarity, or willingness to go out and learn more of these modules, I do post links so one can learn more, and I do provide a brief explanation as to how they fit in within the context of the tutorial.

1 Like

very nice tutorial, i like how it wasnt just a download video and that you guide us through it, actually learned a lot watching it

1 Like

this tutorial was very useful, is there any way to make slide cancelling? from my trials it just ends up giving the player a HUGEEE speed boost lol

1 Like

Hello,

Will you be remaking the tutorial with what you have learned since posting it like you mentioned?

Thanks

2 Likes

What did you do / change? The tutorial seems a bit tedious for just a singular mechanic.

I don’t quite understand where in the part (LeftFootSlide and RightFootSlide) the Attachments are placed.
Does the placement matter?

Remade tutorial. Place file is now available for viewing! See original post for more details :slight_smile:

1 Like

Hello,

Is there a way you can add to the dummy the sliding animation key frames, so they can be loaded in via the animation editor?

Thanks

Also I noticed (without sliding animation yet :frowning: )… that when I start the slide on the top brick, and go over down to the slope, it stops sliding, when I think it should continue the slide, because I am now on a slope…

Example 1:

Example 2:

EDIT:
I see now you have the slide animations, in severstorage, and moved them into the dummy… Thanks!

1 Like