Enemy dies only with one hit from a bullet!

Godot Version

Godot_v4,3

Question

What if i want the enemy die with more than 1 hit when i shoot him ?
What is the code/ script for this

I want to hit them like 10 times

var health = 10

func got_hit():
    health -= 1
    if health <= 0:
        die() # whatever you do for a "dead" object; play sounds, sprite fx, whatever
1 Like

Should I put this code in the bullet script or the enemy script?

The enemy script, presumably. It’s basically the old Dungeons & Dragons/RPG concept of “hit points”.

You could potentially also give different shots different strength levels, so (say) if the player holds down the fire button for a bit they get a “charge shot” that does 5 damage; you then just subtract 5 rather than 1.

Ideally, in your enemy script, you’d have something like:

var health = 10
var incoming_damage = 0

func take_damage(amount: int): # call this from your collision response
    incoming_damage += amount

func _process(delta: float):
    if incoming_damage != 0: # We took a hit!
        if incoming_damage >= health: # DEAD!
            add_to_player_score()
            play_die_sound()
            spawn_explode_anim()
            [...whatever else...]
            delete_me()
        else: # Not enough to kill us...
            health -= incoming_damage
            incoming_damage = 0 # Zero the processed damage.
            play_stagger_anim()
            [...whatever else...] 
1 Like

I can’t get it to work still enemy die with one hit can you fix that for me I’m really a noob lol

this is the script for bullet

extends Area2D

@export var speed = 750

func _physics_process(delta):
	position += transform.x * speed * delta


func _on_bullet_body_entered(body):
	if body.is_in_group("mobs"):
		body.queue_free()
	queue_free()

and here is the script for enemy

extends CharacterBody2D

var speed = 50

func _ready():
	velocity = transform.x * speed
	
	
	
func _physics_process(delta):
#	move_and_slide()
#	var collision = get_last_slide_collision()
#	if collision:
#		print("bouncing ", collision.get_collider().name, collision.get_normal())
#		velocity = velocity.bounce(collision.get_normal())
#	rotation = velocity.angle()
	var collision = move_and_collide(velocity * delta)
	if collision:
		velocity = velocity.bounce(collision.get_normal())
		

That body.queue.free() in the bullet collision handler is killing (well, really, deleting) the thing it hits. Instead of that, you want to let body know that it has taken damage, and then let whatever took damage decide what to do about it.

I think you want this to be something like:

Bullet:

var damage = 1 # Raise this to hit harder.

[...stuff...]

func _on_body_bullet_entered(body):
    if body.is_in_group("mobs"): # Did we hit a mob?
        body.got_hit(damage)     # Damage it!
    queue_free() # We're done.

Enemy:

var health          = 10
var incoming_damage =  0

[...stuff...]

func got_hit(damage: int):
    # Just accumulate; we may take multiple hits this update.
    incoming_damage += damage

func _physics_process(delta: float):
    [...stuff...]

    # Deal with damage.
    if incoming_damage:
        if incoming_damage >= health: # Dead!
            # do score, effects, hit sounds &c. here.
            queue_free()
        else: # Still alive...
            # do stagger anims, effects &c. here.
            health -= incoming_damage # Apply the damage.
            incoming_damage = 0       # We've processed it, it can go.

    [...stuff...]

You can do all sorts of stuff with this basic framework. You could, for example, use float instead of int for health, and then you could have mobs with regenerating health; something in Enemy like:

const MAX_HEALTH      = 10.0
const REGENERATE      =  0.25 # Recover 1hp every 4 seconds.
var   health          = MAX_HEALTH
var   incoming_damage =  0.0

[...stuff...]

func got_hit(damage: float):
    incoming_damage += damage

[...stuff...]

func _physics_process(delta: float):
    [...stuff...]

    if incoming_damage > 0.0:
        [...same as above...]
    else: # Didn't get hit, regenerate if we need to...
        # Need to scale by delta so regenerate is consistent over time...
        health += clampf(health + REGENERATE * delta), 0.0, MAX_HEALTH)

    [...stuff...]

You can also do things like iframes (that is, making something invincible for a little while after taking a hit). That’s usually something for the player rather than mobs, but the idea is the same:

Enemy:

const IFRAME_TIME = 0.8
var   iframes     = 0.0

[...stuff...]

    if incoming_damage:
        if iframes >= 0.0:
            incoming_damage = 0 # Invincible!  Ignore!
        else: # Vincible!  We get hurt!
            if incoming_damage >= health: # Dead!
                [...as above...]
            else: # Still alive!
                [...other stuff...]
                iframes = IFRAME_TIME # Set up invulnerability.

    # Invincibility countdown.
    iframes = clampf(iframes - delta, 0.0, IFRAME_TIME)

[...stuff...]

There are lots of things you can do with a system like this. You can make shots that get weaker over time:

Bullet:

const MAX_LIFE = 2.0 # Done after 2 seconds...
var damage   = 1.0
var lifetime = 0.0

_func physics_process(delta: float):
    [...stuff...]
    lifetime += delta
    if lifetime > MAX_LIFE: # Shot ran out of power, delete it.
        queue_free()

func _on_bullet_body_entered(body):
    if body.is_in_group("mobs"):
        # Scale the damage based on lifetime:
        body.got_hit(damage * (MAX_LIFE - (lifetime / MAX_LIFE)))
    queue_free()

There are endless possibilities.

1 Like