How to prevent the overlapping of two events?

I want to make damage and heal system for my game. The problem is, when the player takes damage and heals at the same time, only one of the event happened while the other one is abandoned. For example:

image

I think instead of changing the HP directly, I should calculate (Heal - Damage) first then add it to HP, but how do I calculate (Heal - Damage) without other event overlap problem to happen?

The only solution I can think of is to make a “calculation folder”. Everytime the player is healed or damaged, an IntValue representating one source of HP changes will be created. The script will get all children of the folder and get the (Heal - Damage) value by iterating through all IntValues every some miliseconds. This is the visualization:

image

But is it efficient? Is there any other approach that is more efficient and doesn’t require the game to iterate all of the children every some miliseconds?

2 Likes

If events come in at the same time, it’s even more important to consider the implications of ordering. For example, if a player has 5 HP and I do 10 HP of damage to them they should die, but what if somebody also heals them by 15 HP?

The way I would do this is to have a priority event stack. Each event has a specific priority and the outcome of the stack is calculated once every frame on the server.

local eventStack = {}

local function createEvent(callback, priority, ...)
    table.insert(eventStack, {
        Priority = priority,
        Action = callback,
        Args = table.pack(...)
    })
end

local function processEventStack()
    -- sort lowest priority to the bottom of the stack
    table.sort(eventStack , function (a, b)
        return a.Priority < b.Priority
    end)
    -- remove highest priority elements first from the top of the eventStack 
    while #eventStack > 0 do
        local event = table.remove(eventStack)
        event.Action(table.unpack(event.Args))
    end
end

RunService.Heartbeat:Connect(proccessEventStack)

Then, to use it you would add an event to the stack as follows:

local function heal(humanoid, amount)
    humanoid.Health += amount
end

local function damage(humanoid, amount)
    humanoid:TakeDamage(amount)
end

createEvent(damage, 1, someHumanoid, 5) -- priority 1, remove 5 health
createEvent(heal, 2, someHumanoid, 10) -- priority 2, add 10 health

No matter which order the event comes in, as long as they are in the same frame, the health will be added first followed by the damage. This prevents the player from dying if the damage is being out-healed.

It also solves your issue where both events will be applied. If the humanoid started with 50 health, they will be healed up to 60 and damaged down to 55.

2 Likes

Yes there is you can use

Folder.ChildAdded:connect(function(children)

end)

Or

Folder.DescendantAdded:connect(function(descendant)

end)