Thursday, April 4, 2024

Sprite Overlap

 Today, we are going to create a new scene(node) to handle enemy sprites overlapping on screen:
- Area2D root node
- and a collisionShape

Then attach a script to your Area2D. In this script, we're going to check if there are two sprites in the same position (overlapping), and if they are, one of them is going to receive a little push to separate them.

```
extends Area2D

func is_colliding():
    var areas = get_overlapping_areas()
    return areas.size() > 0

func get_push_vector():
    var areas = get_overlapping_areas()
    var push_vector = Vector2.ZERO
    if is_colliding():
        var area = areas[0]
        push_vector = area.global_position.direction_to(global_position)
        push_vector = push_vector.normalized()
    return push_vector
```


For this to work, we also need to create a layer for this collision.

And then set it up to be used

Once the new Area2D scene is set up, instance it to your enemy nodes, and add their collision shapes

> I bet you think that's all, but you need to use those functions in your bat script for them to work

`onready var spriteOverlap = $SpriteOverlap`

and at the end of your physic_process:
```
    if spriteOverlap.is_colliding():
        velocity += spriteOverlap.get_push_vector() * delta * 400
    velocity = move_and_slide(velocity)
```


In other words, your enemy script should be eventually something like this:
```
extends KinematicBody2D

const EnemyDeathEffect = preload("res://Effects/EnemyDeathEffect.tscn")

export var ACCELERATION = 300
export var MAX_SPEED = 50
export var FRICTION = 200
export var WANDER_TARGET_RANGE = 4

enum {
    IDLE,
    WANDER,
    CHASE
}

var velocity = Vector2.ZERO
var knockback = Vector2.ZERO

var state = CHASE

onready var stats = $Stats
onready var playerDetectionZone = $PlayerDetectionZone
onready var spriteOverlap = $SpriteOverlap

func _physics_process(delta):
    knockback = knockback.move_toward(Vector2.ZERO, FRICTION * delta)
    knockback = move_and_slide(knockback)
    
    match state:
        IDLE:
            velocity = velocity.move_toward(Vector2.ZERO, FRICTION * delta)
            seek_player()
        WANDER:
            pass
        CHASE:
            var player = playerDetectionZone.player
            if player != null:
                var direction = (player.global_position - global_position).normalized()
                velocity = velocity.move_toward(direction * MAX_SPEED, ACCELERATION * delta)
            else:
                state = IDLE
                
    if spriteOverlap.is_colliding():
        velocity += spriteOverlap.get_push_vector() * delta * 400
    velocity = move_and_slide(velocity)

func seek_player():
    if playerDetectionZone.can_see_player():
        state = CHASE

func _on_Hurtbox_area_entered(area):
    stats.health -= area.damage
    knockback = area.knockback_vector * 150

func _on_Stats_no_health():
    queue_free()
    var enemyDeathEffect = EnemyDeathEffect.instance()
    get_parent().add_child(enemyDeathEffect)
    enemyDeathEffect.global_position = global_position

```

And that's all for this entry

No comments:

Post a Comment