How do games like the strongest battle grounds handle user input?

The whole context is basically in the title.

To be more specific, in a battlegrounds game lets say that you are stunned and you hold F (to block).
When your stunned you obviously can’t block, I want it so when you aren’t stunned anymore (still holding F from when you were stunned) you run the block function. That’s basically what I want to find out

3 Likes

While I don’t know for sure the exact way they achieved that in The Strongest Battlegrounds, I created a proof of concept which would make that possible through the usage of loops and the ContextActionService.


My general thought process for achieving that was the following:

  1. Detect when a player presses the intended keybind

  2. Check if the player is currently stunned

  3. If the player is already stunned when trying to block, yield the code until they are no longer stunned

  4. If the player releases the keybind or is unstunned, allow the code to continue

  5. Before successfully processing the request to activate the block, check one more time if the player is still trying to block (and has not released the keybind while stunned)

  6. Lastly (not included in the code below), make sure the code that handles the request to activate the block ability on the server-side performs additional sanity checks to ensure that the player has met all of the necessary requirements to block, as to avoid situations where exploiters skip past all of the client-sided checks.


In order to test that, I created two scripts:

  • #1 - LocalScript in the StarterPlayerScripts container that handles the user input and checks for the conditions mentioned above. (This is the most important script out of the two for this example)

  • #2 - Script in the ServerScriptService, specifically for creating a “Stunned” Attribute for the player and also having a quick way to swap its current value (by walking over a Part in the Workspace). This enables you to quickly simulate what would happen in different scenarios.

To test the scenario outlined in the original post, you would walk over the part once, then begin holding the block keybind. Walk over the part again while still holding down the keybind and then it should warn “Request to activate the Block ability has succeeded” in the Output since the player is no longer stunned and was already holding down the correct key.

I can explain it further if you’d like, but for now, here’s the example code:

#1 - Example LocalScript

local RunService = game:GetService("RunService")
local ContextActionService = game:GetService("ContextActionService")
local Players = game:GetService("Players")

local player = Players.LocalPlayer

---

local blockKeybind = Enum.KeyCode.F

local currentlyStunned = false
local tryingToBlock = false


local function updateCurrentlyStunned()
	currentlyStunned = player:GetAttribute("Stunned")
	print("currentlyStunned Value: "..tostring(currentlyStunned))
	
	player:GetAttributeChangedSignal("Stunned"):Connect(function()
		currentlyStunned = player:GetAttribute("Stunned")
		warn("New 'Stunned' value is "..tostring(currentlyStunned))
	end)
end

if player:GetAttribute("Stunned") then
	updateCurrentlyStunned()
else
	local temporaryConnection
	
	temporaryConnection = player.AttributeChanged:Connect(function(attributeName)
		if attributeName == "Stunned" then
			updateCurrentlyStunned()
			
			temporaryConnection:Disconnect()
			temporaryConnection = nil
		end
	end)
end


local function activateBlockAbility(actionName, userInputState, inputObject)
	
	if userInputState == Enum.UserInputState.End then
		tryingToBlock = false
		print("Player is no longer holding the block keybind")
	
	elseif userInputState == Enum.UserInputState.Begin then
		
		if tryingToBlock == true then return end
		tryingToBlock = true
		print("Player is trying to block")
		
		if currentlyStunned == true then
			
			warn("Player is currently stunned!")
			
			while true do
				if currentlyStunned ~= true then
					print("Player is no longer stunned")
					break
				end
				
				if tryingToBlock ~= true then
					print("Player is no longer trying to block")
					break
				end
					
				RunService.RenderStepped:Wait()
			end
			
		end
		-- Player is now allowed to block
		
		if tryingToBlock == true then
			warn("Request to activate the Block ability has succeeded")
			-- Run relevant code here since player is still holding down the key
		end
		
		tryingToBlock = false
	end
end

ContextActionService:BindAction("Block", activateBlockAbility, true, blockKeybind)

#2 - Example Script

local Players = game:GetService("Players")

local function onPlayerJoin(player)
	player:SetAttribute("Stunned", false)
end

for _, player in Players:GetPlayers() do
	task.spawn(onPlayerJoin, player)
end
Players.PlayerAdded:Connect(onPlayerJoin)

---

local Part = workspace:FindFirstChild("BlockTestPart")

if not Part then
	local newPart = Instance.new("Part")
	newPart.Name = "BlockTestPart"
	newPart.Anchored = true
	newPart.Position = Vector3.new(0, 5, 0)
	newPart.Parent = workspace
	
	Part = newPart
end

local debounce = false
Part.Touched:Connect(function(otherPart)
	local model = otherPart:FindFirstAncestorOfClass("Model")
	if not model then return end
	
	local Player = Players:GetPlayerFromCharacter(model)
	if not Player then return end
	
	if debounce == true then return end
	debounce = true
	
	local currentStunnedValue = Player:GetAttribute("Stunned")
	Player:SetAttribute("Stunned", not currentStunnedValue)
	print("Part touched")
	
	task.wait(3)
	
	debounce = false
end)
5 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.