Creating Attack patterns

As we saw previously, your Projectiles can spawn inactive to re-activate after a certain amount of time.

Fortunately, you can alter this behavior by modifying the wait_time property of your projectiles.

extends  Node2D

@onready var projectile_caller: ProjectileCaller2D = $ProjectileCaller2D


func _ready() -> void:
	projectile_caller.get_projectile(0).set_on_start(custom_start)


func _input(event):
	if event is InputEventMouseButton:
		if event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
			projectile_caller.request_projectile(0, position, get_global_mouse_position())


# We will modify the "wait_time" property right at the start of the projectile lifecycle.
func custom_start(proj: Projectile2D) -> void:
	proj.wait_time = 0.5

Here is a collection of different attack patterns for both ALL_AT_ONCE and ONE_BY_ONE instances.



ALL_AT_ONCE patterns

We will continue working on our previous project under the next Player script, only modifying the “custom_start” method:

extends  Node2D

@onready var projectile_caller: ProjectileCaller2D = $ProjectileCaller2D


func _ready() -> void:
	projectile_caller.get_projectile(0).set_on_start(custom_start)


func _input(event):
	if event is InputEventMouseButton:
		if event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
			projectile_caller.request_projectile(0, position, get_global_mouse_position())


# We will be modifying this method.
func custom_start(proj: Projectile2D) -> void:
	proj.wait_time = 0.5

  • Forwards (Default)
func custom_start(proj: Projectile2D) -> void:
	pass

  • Backwards
func custom_start(proj: Projectile2D) -> void:
	var index: int = (proj.instances - proj.index) - 1
	proj.wait_time = index * proj.spawn_interval

  • Center to extremes
func custom_start(proj: Projectile2D) -> void:
	var index: int = proj.instances / 2
	index = abs(proj.index - index)
	proj.wait_time = index * proj.spawn_interval

  • Extremes to center
func custom_start(proj: Projectile2D) -> void:
	var index: int = proj.instances / 2
	index = abs(abs(proj.index - index) - index)
	proj.wait_time = index * proj.spawn_interval

  • n Divided
func custom_start(proj: Projectile2D) -> void:
	var n: int = 4
	var div: int = proj.instances / n
	var rem: int = proj.index % div
	var index: int = (rem * n) + (proj.index / div)
	proj.wait_time = index * proj.spawn_interval

  • n Divided (Reverse)
func custom_start(proj: Projectile2D) -> void:
	var n: int = 4
	var div: int = proj.instances / n
	var rem: int = proj.index % div
	var index: int = ((div - rem - 1) * n) + (proj.index / div)
	proj.wait_time = index * proj.spawn_interval

  • n Divided (Centered)
func custom_start(proj: Projectile2D) -> void:
	var n: int = 4
	var div: int = proj.instances / n
	var rem: int = proj.index % div
	var index: int = (abs(rem - (div / 2)) * n) + (proj.index / div)
	proj.wait_time = index * proj.spawn_interval

  • n Divided (Extremes)
func custom_start(proj: Projectile2D) -> void:
	var n: int = 4
	var div: int = proj.instances / n
	var rem: int = proj.index % div
	var index: int = (abs(abs(rem - (div / 2)) - (div / 2)) * n) + (proj.index / div)
	proj.wait_time = index * proj.spawn_interval


ONE_BY_ONE patterns

We will continue working on our previous project under the next Player script, only modifying the “on_main_enter” method:

extends  Node2D

@export var separation: int = 30

@onready var projectile_manager: ProjectileManager2D = $ProjectileManager2D

@onready var bow: Sprite2D = $Bow
@onready var animation_player: AnimationPlayer = $AnimationPlayer


func _ready() -> void:
	animation_player.play("idle")
	projectile_manager.get_attack(0).set_on_charge_enter(on_charge_enter).set_on_charge_exit(on_charge_exit).set_on_main_enter(on_main_enter)


func _process(_delta: float) -> void:
	var direction: Vector2 = (get_global_mouse_position() - position).normalized()
	bow.position = direction * separation
	bow.rotation = direction.angle()

	projectile_manager.position = bow.position
	projectile_manager.rotation = bow.rotation

	if (Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT)):
		projectile_manager.request_execution(0, 0, position + (direction * separation), get_global_mouse_position())


func on_charge_enter(attack: Attack2D) -> void:
	animation_player.play("charge")
	attack.charge_enter()

func on_charge_exit(attack: Attack2D) -> void:
	animation_player.play("idle")
	attack.charge_exit()


# We will be modifying this method.
func on_main_enter(attack: Attack2D) -> void:
	attack.main_enter()
	attack.pi.instance_id = attack.remaining_shots - 1
  • Forwards (Default)
func on_main_enter(attack: Attack2D) -> void:
	attack.main_enter()

  • Backwards
func on_main_enter(attack: Attack2D) -> void:
	attack.main_enter()
	var index: int = attack.remaining_shots - 1
	attack.pi.instance_id = index

  • Center to extremes
func on_main_enter(attack: Attack2D) -> void:
	attack.main_enter()
	var index: int = attack.instances / 2
	var div: int = (attack.pi.instance_id + 1) / 2
	var sig: int = attack.pi.instance_id % 2
	sig = -1 if (sig == 1) else 1 
	index += div * sig
	attack.pi.instance_id = index

  • Extremes to center
func on_main_enter(attack: Attack2D) -> void:
	attack.main_enter()
	var index: int = attack.instances / 2
	var div: int = (attack.pi.instance_id + 1) / 2
	var rem: int = attack.pi.instance_id % 2
	index = div if (rem == 0) else attack.instances - div 
	attack.pi.instance_id = index

  • n Divided
func on_main_enter(attack: Attack2D) -> void:
	attack.main_enter()
	var n: int = 4
	var div: int = attack.pi.instance_id / n
	var rem: int = attack.pi.instance_id % n
	var sep: int = attack.instances % n
	sep = attack.instances / n if (sep == 0) else (attack.instances / n) + 1
	var index: int = (sep * rem) + div
	attack.pi.instance_id = index

  • n Divided (Reverse)
func on_main_enter(attack: Attack2D) -> void:
	attack.main_enter()
	var n: int = 4
	var div: int = attack.pi.instance_id / n
	var rem: int = attack.pi.instance_id % n
	var sep: int = attack.instances % n
	sep = attack.instances / n if (sep == 0) else (attack.instances / n) + 1
	div = abs(sep - div - 1)
	var index: int = (sep * rem) + div
	attack.pi.instance_id = index

  • n Divided (Centered)
func on_main_enter(attack: Attack2D) -> void:
	attack.main_enter()
	var n: int = 4
	var div: int = attack.pi.instance_id / n
	var rem: int = attack.pi.instance_id % n
	var sep: int = attack.instances % n
	sep = attack.instances / n if (sep == 0) else (attack.instances / n) + 1
	var sem: int = (div + 1) / 2
	var sig: int = div % 2
	sig = -1 if (sig == 0) else 1 
	div = (sep / 2) + (sem * sig)
	var index: int = (sep * rem) + div
	attack.pi.instance_id = index

  • n Divided (Extremes)
func on_main_enter(attack: Attack2D) -> void:
	attack.main_enter()
	var n: int = 4
	var div: int = attack.pi.instance_id / n
	var rem: int = attack.pi.instance_id % n
	var sep: int = attack.instances % n
	sep = attack.instances / n if (sep == 0) else (attack.instances / n) + 1
	var sem: int = (div + 1) / 2
	div = sem if (div % 2 == 0) else (sep - sem) 
	var index: int = (sep * rem) + div
	attack.pi.instance_id = index

  • n By n
func on_main_enter(attack: Attack2D) -> void:
	attack.main_enter()
	var n: int = 4
	var div: int = attack.pi.instance_id / n
	var rem: int = attack.pi.instance_id % n
	var sep: int = attack.instances % n
	sep = attack.instances / n if (sep == 0) else (attack.instances / n) + 1
	var index: int = (sep * rem) + (div * n)
	attack.pi.instance_id = index