Help with replicating battleground front dash

Hello Developers,

I’m currently practicing making a battleground game. While making the dash system, I’m not sure how I can replicate the front dash like “Ultimate Battleground”.

The front dash allows me to perform these techniques:

Bone Dash - 3:03 to 3:23 reference from video below
Loop (The Spin) - 1:19 to 2:30 reference from video below

Video:

Game Link:

What I’m not really sure about:

  • How does the knockback on the front dash work?
  • How to add the techniques I listed above to the front dash?

My current code:

There is no animations yet because I don’t have any.

local Players = game:GetService('Players')
local RunService = game:GetService('RunService')
local UserInputService = game:GetService('UserInputService')
local ReplicatedStorage = game:GetService('ReplicatedStorage')

local Effects = require(ReplicatedStorage.Modules.Shared.Services.Effects)

local Player = Players.LocalPlayer

local Camera = workspace.CurrentCamera

local Character = Player.Character or Player.CharacterAdded:Wait()
local HumanoidRootPart = Character:FindFirstChild('HumanoidRootPart') or Character:WaitForChild('HumanoidRootPart')
local Humanoid = Character:FindFirstChildWhichIsA('Humanoid') or Character:WaitForChild('Humanoid')

local RootAttachment = HumanoidRootPart:FindFirstChild('RootAttachment') or HumanoidRootPart:WaitForChild('RootAttachment')

local DashCooldown = 0

local DashesDuration = {
	Forward = 1,
	Backward = 1,
	Left = .5,
	Right = .5,
}

local DashesSpeed = {
	Forward = 70,
	Backward = 70,
	Left = 90,
	Right = 90,
}

local TrailIndex = 0

local DashDebounces = {}

local DashConnection

local function SetMovementState(IsActive: boolean)
	Humanoid.WalkSpeed = IsActive and 16 or 0
	Humanoid.JumpPower = IsActive and 50 or 0
end

Player.CharacterAdded:Connect(function(NewCharacter: Model)
	Character = NewCharacter
	HumanoidRootPart = NewCharacter:FindFirstChild('HumanoidRootPart') or NewCharacter:WaitForChild('HumanoidRootPart')
	RootAttachment = HumanoidRootPart:FindFirstChild('RootAttachment') or HumanoidRootPart:WaitForChild('RootAttachment')
	Humanoid = NewCharacter:FindFirstChildWhichIsA('Humanoid') or NewCharacter:WaitForChild('Humanoid')
end)

UserInputService.InputBegan:Connect(function(Input: InputObject, GPE: boolean)
	if GPE then return end
	
	if Input.KeyCode == Enum.KeyCode.Q and Humanoid.Health > 0 then
		local DirectionType = 'Forward'
		
		if UserInputService:IsKeyDown(Enum.KeyCode.A) then
			DirectionType = 'Left'
		elseif UserInputService:IsKeyDown(Enum.KeyCode.S) then
			DirectionType = 'Backward'
		elseif UserInputService:IsKeyDown(Enum.KeyCode.D) then
			DirectionType = 'Right'
		end
		
		local DashElapsed = 0
		local TrailElapsed = 0
		
		local StartSpeed = DashesSpeed[DirectionType]
		local Duration = DashesDuration[DirectionType]
		
		local IsShiftlock = UserInputService.MouseBehavior == Enum.MouseBehavior.LockCenter
		local IsSideDash = DirectionType ~= 'Forward' and DirectionType ~= 'Backward'
		
		local DebounceKey = IsSideDash and 'SideDashes' or 'LongDashes'
		
		if DashDebounces[DebounceKey] or DashConnection then return end
		DashDebounces[DebounceKey] = true
		
		SetMovementState(IsSideDash)
		
		local DashForce = Instance.new('LinearVelocity')
		DashForce.ForceLimitMode = Enum.ForceLimitMode.PerAxis
		DashForce.MaxAxesForce = Vector3.new(500000, 0, 500000)
		DashForce.Attachment0 = RootAttachment
		DashForce.Parent = HumanoidRootPart
		
		DashConnection = RunService.Heartbeat:Connect(function(Delta: number)
			DashElapsed += Delta
			TrailElapsed += Delta
			
			if not IsShiftlock then
				Humanoid.AutoRotate = false

				local _, Y = Camera.CFrame.Rotation:ToEulerAnglesYXZ()
				HumanoidRootPart.CFrame = CFrame.new(HumanoidRootPart.Position) * CFrame.Angles(0, Y, 0)
			end
			
			local Alpha = math.clamp(DashElapsed / Duration, 0, 1)
			local Speed = StartSpeed * (1 - Alpha)
			
			local Directions = {
				Forward = HumanoidRootPart.CFrame.LookVector,
				Backward = -HumanoidRootPart.CFrame.LookVector,
				Right = HumanoidRootPart.CFrame.RightVector,
				Left = -HumanoidRootPart.CFrame.RightVector
			}
			
			if DashElapsed >= Duration then
				DashForce.Parent = nil
				DashForce.Attachment0 = nil
				Humanoid.AutoRotate = true
				SetMovementState(true)
				DashConnection:Disconnect()
				DashConnection = nil
			end
			
			if TrailElapsed >= .06 then
				local Direction = IsSideDash and HumanoidRootPart.CFrame.LookVector or HumanoidRootPart.CFrame.RightVector
				Direction *= TrailIndex % 2 == 0 and 2 or -2

				Effects.Rocks.SpawnDebris {
					Origin = CFrame.new(HumanoidRootPart.Position + Direction),
					AmountOfDebris = 1,
					Duration = 5,
					SizeRanges = {X = {.5, .7}, Y = {.5, .7}, Z = {.5, .7}},
					CastRange = Character:GetExtentsSize().Y / 2 + 8
				}
				
				TrailIndex += 1
				
				if TrailIndex > 1 then
					TrailIndex = 0
				end
				
				TrailElapsed = 0
			end
			
			local DashDirection = Directions[DirectionType]
			
			DashForce.VectorVelocity = DashDirection * Speed
		end)
		
		while DashConnection do
			task.wait()
		end
		
		task.wait(IsSideDash and DashCooldown / 2 or DashCooldown)
		
		DashDebounces[DebounceKey] = nil
	end
end)