Skip to content


DamageableObject is a CoreObject which implements the Damageable interface.


Property Name Return Type Description Tags
hitPoints number Current amount of hit points. Read-Write
maxHitPoints number Maximum amount of hit points. Read-Write
isDead boolean True if the object is dead, otherwise false. Death occurs when damage is applied which reduces hit points to 0, or when the Die() function is called. Read-Only
isImmortal boolean When set to true, this object cannot die. Read-Write
isInvulnerable boolean When set to true, this object does not take damage. Read-Write
destroyOnDeath boolean When set to true, this object will automatically be destroyed when it dies. Read-Only
destroyOnDeathDelay number Delay in seconds after death before this object is destroyed, if destroyOnDeath is set to true. Defaults to 0. Read-Only
destroyOnDeathClientTemplateId string Optional asset ID of a template to be spawned on clients when this object is automatically destroyed on death. Read-Only
destroyOnDeathNetworkedTemplateId string Optional asset ID of a networked template to be spawned on the server when this object is automatically destroyed on death. Read-Only


Function Name Return Type Description Tags
ApplyDamage(Damage) None Damages the object, unless it is invulnerable. If its hit points reach 0 and it is not immortal, it dies. Server-Only
Die([Damage]) None Kills the object, unless it is immortal. The optional Damage parameter is a way to communicate cause of death. Server-Only


Event Name Return Type Description Tags
damagedEvent Event<DamageableObject object, Damage damage> Fired when the object takes damage. Server-Only
diedEvent Event<DamageableObject object, Damage damage> Fired when the object dies. Server-Only


Hook Name Return Type Description Tags
damageHook Hook<DamageableObject object, Damage damage> Hook called when applying damage from a call to ApplyDamage(). The incoming damage may be modified or prevented by modifying properties on the damage parameter. Server-Only


Example using:



Vehicles implement the DamageableObject interface. As such, they have all the properties and events from that type. In this example, we add a script to a vehicle that causes it to pass to the driver some of the damage it receives. By default, a vehicle's damageable properties are configured to make them immune-- Change them for this example to work.

local VEHICLE = script:FindAncestorByType("Vehicle")

function ApplyDamageToDriver(newAmount, vehicleDamage)
    -- Create new damage object for the player
    local damage = Damage.New(newAmount)
    -- Copy properties from the vehicle's damage object
    damage.reason = vehicleDamage.reason
    damage.sourceAbility = vehicleDamage.sourceAbility
    damage.sourcePlayer = vehicleDamage.sourcePlayer

    local player = VEHICLE.driver
    -- If we think the player will die from this damage, eject them and
    -- wait a bit, so they will ragdoll correctly
    if player.hitPoints <= damage.amount then
    -- Apply it

function OnDamaged(_, damage)
    if damage.amount <= 0 then return end
    if not Object.IsValid(VEHICLE.driver) then return end

    -- Chance to apply damage to the player or prevent it completely
    if math.random() >= CHANCE_TO_PASS_DAMAGE then return end

    -- Reduction of the original damage amount
    local newAmount = damage.amount * (1 - DAMAGE_REDUCTION)
    newAmount = math.ceil(newAmount)

    -- Apply reduced damage
    ApplyDamageToDriver(newAmount, damage)

function OnDied(_, damage)
    if not Object.IsValid(VEHICLE.driver) then return end
    local player = VEHICLE.driver

    -- Apply the on-death damage
    ApplyDamageToDriver(ON_DEATH_DIRECT_DAMAGE_TO_DRIVER, damage)


See also: Vehicle.driver | CoreObject.FindAncestorByType | Damage.New | Player.ApplyDamage | Object.IsValid

Example using:





In this example, when the health of an NPC reaches a certain threshold, the NPC will become invulnerable to all damage for a certain amount of time. While the NPC is invulnerable, it will regenerate health. The NPC can only regenerate the health once so that it can be killed.

-- Place script as a child of a Damageable Object.

-- Reference to the Damageable Object
local DAMAGEABLE_OBJECT = script.parent

-- At what point should the object start regenerating health
local invulnerableThreshold = 0.25 -- 25 percent

-- Only allow the regen to happen once
local hasRegened = false

-- Regenerate the health of the object passed in by adding 25 health
-- every .5 seconds.
local function regenHealth(obj)
    local counter = 0

    -- Spawn a repeating task that runs 6 times. Each iteration is counted
    -- so that the object can be vulnerable again at >= 6
    local regenTask = Task.Spawn(function()

        -- Prevent hitPoints being bigger than maxHitPoints
        obj.hitPoints = math.min(obj.hitPoints + 15, obj.maxHitPoints)

        -- At 6 or more iterations, make the object vulnerable so it can be killed
        if counter >= 6 then
            obj.isInvulnerable = false

        counter = counter + 1

    regenTask.repeatCount = 6
    regenTask.repeatInterval = .5

local function OnDamaged(obj, damage)

    -- Check the object is valid
    if Object.IsValid(obj) then
        local currentHealth = obj.hitPoints
        local maxHealth = obj.maxHitPoints
        local percentageLeft = currentHealth / maxHealth

        -- Check if the health is less than or equal to the threshold and make sure
        -- the object hasn't already regened health
        if percentageLeft <= invulnerableThreshold and not hasRegened then
            hasRegened = true
            obj.isInvulnerable = true


-- Print out to the Event Log the current health of the damageable object.
-- This is for debugging so you can see the health going down, and stops
-- when the health threshold is reached.
function Tick()
    print("Current Health: ", DAMAGEABLE_OBJECT.hitPoints)

-- Listen for when the damage is received.

See also: Task.Spawn | Object.IsValid | CoreObject.parent

Example using:


In Core, many gameplay objects are kitbashed from various Static Meshes. In this example an object explodes, sending all its kitbashed parts flying. A pair of server/client scripts are added to the hierarchy of the DamageableObject. The server script detects the death and forwards that event to all clients by use of a broadcast. The client script then searches its local hierarchy for all Static Meshes and enables debris physics on them. Because the Damageable Object is most likely being destroyed, we need to move the meshes to a new parent that will outlive it: For the script to work, add a Client-Context group to the hierarchy and rename it to "DebrisParent".

-- Server Script:
local DAMAGEABLE = script:FindAncestorByType("Damageable")

function OnDied(_, _)
    -- Detects the death and forwards it to clients

-- Client Script:
local DAMAGEABLE = script:FindAncestorByType("Damageable")
local EXPLOSION_POWER = 2000
local RNG = RandomStream.New()

function OnDied()
    -- The client script receive the death event
    -- Finds all Static Meshes in the local hierarchy
    local childMeshes = script.parent:FindDescendantsByType("StaticMesh")
    -- Finds the new parent, a Client-context named "DebrisParent"
    local clientContext = World.FindObjectByName("DebrisParent")
    for _,mesh in ipairs(childMeshes) do
        -- Change parent, as we assume the old one is being destroyed
        mesh.parent = clientContext
        -- Enable debris physics
        mesh.isSimulatingDebrisPhysics = true
        -- Some Static Meshes don't support debris physics, so we must check
        if mesh.isSimulatingDebrisPhysics then
            -- Additional collision settings
            mesh.collision = Collision.FORCE_ON
            mesh.cameraCollision = Collision.FORCE_OFF
            -- Set a life span, so the mesh destroys itself after a few seconds
            mesh.lifeSpan = RNG:GetNumber(3, 5)
            -- Give a random velocity to the mesh, away from ground
            local vel = RNG:GetVector3FromCone(Vector3.UP, 90) * EXPLOSION_POWER
            -- Destroy meshes immediately if they don't support debris physics

Events.Connect("Scatter", OnDied)

See also: StaticMesh.isSimulatingDebrisPhysics | | Events.BroadcastToAllPlayers | RandomStream.GetVector3FromCone | World.FindObjectByName

Example using:


In this example, 2 teams battle it out by destroying objects that match their team color. Everytime a Damageable Object is destroyed, it respawns a new one with a random team color by using the property "Destroy on Death Networked Template ID".

-- Place script as a child of a Damageable Object

-- Set the "Destroy on Death Networked Template ID" on the Damageable Object
-- with a copy of the template that contains this script so that it gets
-- respawned each time the Damageable Object has died

-- Reference to the damageable object
local DAMAGEABLE_OBJECT = script.parent

-- Reference to the static mesh which will be colored either red or blue
-- Enable the property "Is Team Color Used" on the static mesh
local MESH_OBJECT = script:GetCustomProperty("MeshObj"):WaitForObject()

-- Amount of score to give to the team for destroying an object
-- that matches the team they are on
local score = 5

local function OnDied(obj, damage)
    if Object.IsValid(obj) then

        -- Get the static mesh team number
        local meshObjTeam =

        -- Get the team number from the player who destroyed the object
        local team =

        -- Compare the static mesh team value against the player team value
        if meshObjTeam == team then
            Game.IncreaseTeamScore(team, score)

            -- Print to the Event log when a player destroys an object
            -- for the other team
            print("Wrong color", team, meshObjTeam)

        -- Print out the team scores to the Event Log after each object
        -- is destroyed.
        print("Team 1 Score: ", Game.GetTeamScore(1))
        print("Team 2 Score: ", Game.GetTeamScore(2))

-- Connect the died event that will fire when the object is destroyed

-- Set to a random team number between 1 and 2 (both inclusive) = math.random(1, 2)

See also: Object.IsValid | CoreObject.parent | Game.IncreaseTeamScore | Damage.sourcePlayer |

Example using:


In this example, damage can be applied to all objects in an area, by calling Explosion(), passing the epicenter of the explosion. First, all damageable objects that are inside the area are found with GetDamageablesInArea(). Then, a damage object is created and applied to each one.

local RADIUS = 500
local DAMAGE_AMOUNT = 50

function Explosion(center)
    local objects = GetDamageablesInArea(center, RADIUS)
    for _,obj in ipairs(objects) do
        local damage = Damage.New(DAMAGE_AMOUNT)

function GetDamageablesInArea(center, radius)
    --CPU optimization, to avoid square root later
    local radiusSquared = radius * radius

    local result = {}
    local allDamageables = World.FindObjectsByType("DamageableObject")
    for _,obj in ipairs(allDamageables) do
        local position = obj:GetWorldPosition()
        local v = position - center
        if v.sizeSquared <= RADIUS_SQUARED then
            table.insert(result, obj)
    return result

See also: Damage.New | Vector3.sizeSquared | World.FindObjectsByType | CoreObject.GetWorldPosition

Example using:


In this example, the function ApplyPoison() can be called, passing any damageable object as parameter. Each object keeps track of how much poison they have, using the serverUserData table. When an object receives 10 or more poison they are killed.

function ApplyPoison(damageableObject)
    if damageableObject.serverUserData.poisonCount then
        damageableObject.serverUserData.poisonCount = damageableObject.serverUserData.poisonCount + 1

        if damageableObject.serverUserData.poisonCount >= 10 then
        damageableObject.serverUserData.poisonCount = 1

See also: CoreObject.serverUserData

Example using:


This example shows how to search the game for all damageables and then filter them by some criteria. In this case, we create a function that returns all dead objects by checking the isDead property.

function GetAllDeadObjects()
    local result = {}
    local allDamageables = World.FindObjectsByType("Damageable")
    for _,obj in ipairs(allDamageables) do
        if obj.isDead then
            table.insert(result, obj)
    return result

See also: World.FindObjectsByType

Example using:


In this example, whenever a Damageable object overlaps a trigger it temporarily gains immortality. We keep track of the immortalCount in the case where the object would gain immortality a second time before the wait period completes from the first overlap. This could happen if the object went back and forth and hit the trigger multiple times, or if there are multiple triggers near each other with this same script.

local TRIGGER = script:GetCustomProperty("Trigger"):WaitForObject()

function OnTriggerOverlap(_, other)
    if other:IsA("Damageable") then
        other.isImmortal = true

        if not other.serverUserData.immortalCount then
            other.serverUserData.immortalCount = 0
        other.serverUserData.immortalCount = other.serverUserData.immortalCount + 1


        other.serverUserData.immortalCount = other.serverUserData.immortalCount - 1
        if other.serverUserData.immortalCount <= 0 then
            other.isImmortal = false


See also: CoreObject.serverUserData | CoreObjectReference.WaitForObject | Other.IsA | Task.Wait

Last update: January 27, 2022