How to make this Button?

Hey, how can I implement this feature? I tried building it myself but couldn’t get it to work. If you know how, please let me know where to start and which parts of the code I should modify. Any help would be greatly appreciated.

This is an example video

local UIS = game:GetService("UserInputService")
local player = game.Players.LocalPlayer

UIS.InputBegan:Connect(function(input, processed)
	if processed then return end
	if input.KeyCode == Enum.KeyCode.E then
		local char = player.Character
		local root = char:FindFirstChild("HumanoidRootPart")
		local hum = char:FindFirstChild("Humanoid")

		if root and hum then
			hum.Jump = true 
			local attachment = Instance.new("Attachment", root)
			local spin = Instance.new("AngularVelocity", root)

			spin.Attachment0 = attachment
			spin.AngularVelocity = Vector3.new(0, 15, 0) 
			spin.MaxTorque = 50000
			task.wait(0.6) 

			spin:Destroy()
			attachment:Destroy()
		end
	end
end)
4 Likes

You would have to do something like this

local UIS = game:GetService("UserInputService")
local player = game.Players.LocalPlayer

UIS.InputBegan:Connect(function(input, processed)
	if processed then return end
	if input.KeyCode == Enum.KeyCode.E then
		local char = player.Character
		local root = char:FindFirstChild("HumanoidRootPart")
		local hum = char:FindFirstChild("Humanoid")

		if root and hum then
			hum.Jump = true 
			local rotation = root.CFrame - root.Position
                        root.CFrame = root.CFrame * CFrame.Angles(0, math.rad(20), 0)
                        task.wait(0.1)
                        root.CFrame = CFrame.new(root.Position) * rotation
		end
	end
end)

Sorry if it’s incorrect, I am currently typing from my phone, but I’d say this would be it

1 Like

Thanks! This worked pretty well. I tweaked it a little bit to fit my needs. Thanks a lot for the help! :grinning_face:

1 Like

I took your script and made a cleaned up version of it, just to fix a few things and make it more reliable overall.

The idea you had is using UserInputService to detect the key press and then applying AngularVelocity for a spin effect works well. I just noticed a few small issues that could cause problems in actual gameplay.

For example the script assumes the character, Humanoid and HumanoidRootPart are always there, but in practice those can be nil sometimes (like right after respawn) which could cause errors. I also adjusted the flow a bit so everything is checked properly before running anything.

Another thing is the cleanup your version does destroy the attachment and angular velocity after a delay which is good, but I made it a bit safer and more consistent so it won’t break if something interrupts the timing

Overall I didn’t change the idea at all, just fixed up the structure and made it more stable and easier to build on later if you ever want to add cooldowns or extra features, So here’s the script I upgraded for you, It should match how you want the script to work. I made it because I have so much free time today so I hope it’s in your preferences:

local Players = game:GetService("Players")
local GuiService = game:GetService("GuiService")
local UserInputService = game:GetService("UserInputService")
local TweenService = game:GetService("TweenService")

local plr = Players.LocalPlayer
local gui = plr:WaitForChild("PlayerGui")

local busy = false
local input = nil
local btn

local info = TweenInfo.new(0.03, Enum.EasingStyle.Linear, Enum.EasingDirection.Out)

repeat
	task.wait(0.5)
until GuiService.TouchControlsEnabled and UserInputService.TouchEnabled

local function wallhop()
	if busy then return end

	local char = plr.Character
	if not char then return end

	local hum = char:FindFirstChildWhichIsA("Humanoid")
	local root = char:FindFirstChild("HumanoidRootPart")

	if not hum or not root then return end

	busy = true

	local oldRot = hum.AutoRotate

	task.delay(0.01, function()
		if hum
			and hum.FloorMaterial ~= Enum.Material.Air
			and hum.FloorMaterial ~= Enum.Material.Water then

			pcall(function()
				hum:ChangeState(Enum.HumanoidStateType.Jumping)
			end)
		end
	end)

	if UserInputService.MouseBehavior == Enum.MouseBehavior.LockCenter then
		hum.AutoRotate = false
	end

	TweenService:Create(root, info, {
		CFrame = root.CFrame * CFrame.Angles(0, math.pi, 0)
	}):Play()

	task.wait(0.12)

	TweenService:Create(root, info, {
		CFrame = root.CFrame * CFrame.Angles(0, -math.pi, 0)
	}):Play()

	task.wait(0.05)

	hum.AutoRotate = oldRot
	busy = false
end

local function makeButton()
	if btn then
		btn:Destroy()
	end

	local screen = Instance.new("ScreenGui")
	screen.Name = "WallhopGui"
	screen.ResetOnSpawn = false
	screen.Parent = gui

	btn = Instance.new("TextButton")
	btn.Parent = screen
	btn.Name = "btn"

	btn.AnchorPoint = Vector2.new(0.5, 0.5)
	btn.Position = UDim2.new(0.5, 0, 0.5, 0)
	btn.Size = UDim2.new(0, 80, 0, 80)

	btn.BackgroundColor3 = Color3.fromRGB(30, 30, 30)
	btn.BackgroundTransparency = 0.2
	btn.Text = "WH"
	btn.TextColor3 = Color3.fromRGB(255, 255, 255)
	btn.TextScaled = true

	local c = Instance.new("UICorner")
	c.CornerRadius = UDim.new(1, 0)
	c.Parent = btn

	btn.InputBegan:Connect(function(i)
		if input then return end

		if i.UserInputType == Enum.UserInputType.Touch then
			input = i
			btn.BackgroundColor3 = Color3.fromRGB(0, 170, 255)
			wallhop()
		end
	end)

	btn.InputEnded:Connect(function(i)
		if not input then return end

		if i.UserInputType == input.UserInputType then
			local dist = (i.Position - input.Position).Magnitude

			if dist < 100 then
				input = nil
				btn.BackgroundColor3 = Color3.fromRGB(30, 30, 30)
			end
		end
	end)
end

makeButton()

GuiService.MenuOpened:Connect(function()
	if input then
		input = nil
		if btn then
			btn.BackgroundColor3 = Color3.fromRGB(30, 30, 30)
		end
	end
end)
4 Likes

No problem! To make it frame independent, you could use game.RunService.Heartbeat:Wait() (later on). Happy developing

2 Likes

Thank you so much! This is exactly what I needed. I didn’t realize the Respawn issue could cause errors, so thanks for pointing that out and fixing the structure. This is much more stable now. Appreciate your time! :smiley: :slightly_smiling_face:

2 Likes

Appreciate the advice! Making it frame independent is a smart move. I’ll make sure to implement Heartbeat:Wait() in the next update. Cheers!

1 Like

Your code is actually pretty close! The main issue is likely where you’re placing this script and how you’re handling the spinning mechanic. Here’s what you need to fix:**Key Problems:**1. LocalScript placement — This needs to be in StarterPlayer > StarterPlayerScripts or StarterGui, not in ServerScriptService. LocalScripts can only run on the client.2. Physics setupAngularVelocity requires an Attachment parented to the part you want to spin. Your code does this, but you’re destroying it too fast (0.6s might feel jarring). Try 0.8–1.2 seconds instead for smoother feel.3. Missing debounce — Without debounce, spam-pressing E will create multiple spin instances. Add this:lualocal debounce = falseUIS.InputBegan:Connect(function(input, processed) if processed or debounce then return end if input.KeyCode == Enum.KeyCode.E then debounce = true local char = player.Character if not char then debounce = false return end local root = char:FindFirstChild("HumanoidRootPart") local hum = char:FindFirstChild("Humanoid") if root and hum and hum.Health > 0 then hum:SetStateEnabled(Enum.HumanoidStateType.Climbing, false) hum.Jump = true local attachment = Instance.new("Attachment", root) local spin = Instance.new("AngularVelocity") spin.Attachment0 = attachment spin.AngularVelocity = Vector3.new(0, 25, 0) spin.MaxTorque = 100000 spin.Parent = root task.wait(1) spin:Destroy() attachment:Destroy() hum:SetStateEnabled(Enum.HumanoidStateType.Climbing, true) end debounce = false endend)What changed:- Added debounce flag- Increased MaxTorque and AngularVelocity for more noticeable spin- Disabled climbing state so players can’t stick to walls mid-spin- Check hum.Health > 0 to prevent errorsTest this and adjust the `Angular