Creating an armor/shield system

I’m trying to create an armor system where if a player has armor and takes damage then only the armor gets damaged (eg: player has 50 health and 5 armor and takes 10 damage leaving them with 0 armor and 45 health).

Nothings working and I don’t really know what I’m doing here.

LocalScript:

local players = game:GetService("Players")

local player = players.LocalPlayer
local character = player.Character
local humanoid = character:WaitForChild("Humanoid")

local armorBar = script.Parent:WaitForChild("container"):WaitForChild("bar")
local totalArmor = player:SetAttribute("armor", 50)
local fullHealth = 100

function updateGui(armorAmount)
	local y = armorAmount / totalArmor
	armorBar.Size = UDim2.new(y, 0, 1, 0)
end

humanoid.HealthChanged:Connect(function(currentHealth)
	local armor = player:GetAttribute("armor")
	local change = fullHealth - currentHealth
	
	if armor > 0 then
		player:SetAttribute("armor", armor - change)
	end
end)

while true do
	wait()
	print(player:GetAttribute("armor"), humanoid.Health)
end
  1. I removed the players variable since you’re using Players.LocalPlayer directly.
  2. The totalArmor should be a constant value and not stored as an attribute. I’ve removed the line where you set it as an attribute.
  3. I added a default value of totalArmor when retrieving the player’s armor attribute. This ensures that if the attribute is not yet set, the initial armor value will be used.
local Players = game:GetService("Players")

local player = Players.LocalPlayer
local character = player.Character
local humanoid = character:WaitForChild("Humanoid")

local armorBar = script.Parent:WaitForChild("container"):WaitForChild("bar")
local totalArmor = 50 -- Initial armor value
local fullHealth = 100

-- Function to update the GUI based on armor amount
function updateGui(armorAmount)
	local y = armorAmount / totalArmor
	armorBar.Size = UDim2.new(y, 0, 1, 0)
end

-- Connect a function to HealthChanged event
humanoid.HealthChanged:Connect(function(currentHealth)
	local armor = player:GetAttribute("armor") or totalArmor -- Retrieve current armor or use initial value
	local change = fullHealth - currentHealth
	
	if armor > 0 then
		local newArmor = armor - change
		
		if newArmor < 0 then
			newArmor = 0
		end
		
		-- Update armor attribute and GUI
		player:SetAttribute("armor", newArmor)
		updateGui(newArmor)
	end
end)

1 Like

It seems that when I use this the player still takes damage even if they have health and everytime the player slowly gains their health back from health regen it takes even more armor away

I have readjusted the system to now be from the part that inflicts the damage (in this case a kill brick for now) and things are looking better but still some bits are off.

local debounce = false

local function damagePlayer(humanoid, damage)
	local armor = humanoid:GetAttribute("armor") 

	if armor > 0 then
		humanoid:SetAttribute("armor", armor - damage)
		
		if armor < 0 then 
			armor = 0
		end
	else
		humanoid:TakeDamage(damage)
	end
end

script.Parent.Touched:connect(function(hit)
	if debounce then return end
	debounce = true

	local humanoid = hit.Parent:findFirstChild("Humanoid")
	
	if humanoid ~= nil then
		damagePlayer(humanoid, 20)
	end

	task.wait(.6)
	debounce = false
end)

Now there is an issue where if the player has 50 armor and they get hit 3 times. Instead of making the armor 0 and deducting the remainder from the players health (for this example 10) it just makes the armor go to -10 and then only on the next hit iteration is the health deducted.

You would have to keep track of the damage the armor is taking and limit it to no more than its current value. The reason I believe your armor is going into the negatives is that you are not checking the new value after you inflict damage to it.
The armor variable still stores the armor before damage is applied.

This might help:

local armor = humanoid:GetAttribute("armor")
local armorDamage = math.min(damage, armor) -- Prevents negative armor values
local healthDamage = damage - armorDamage

if armorDamage > 0 then
	humanoid:SetAttribute("armor", armor - armorDamage)
end

if healthDamage > 0 then
	humanoid:TakeDamage(damage)
end

1 Like

Yep this seems to have solved this perfectly! I’ve added RemoteEvents to update to the client when the attributes value changes and update the armor bar GUI. Thanks!

1 Like

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