Common Projectiles examples
Here is a collection of regularly requested Projectiles and their implementation in All Projectiles.
The list will be continuously updated as requested.
Variable Speed over Lifetime
extends Node2D
@onready var projectile_caller: ProjectileCaller2D = $ProjectileCaller2D
func _ready() -> void:
projectile_caller.get_projectile(0).set_on_move(custom_update)
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())
func custom_update(proj: Projectile2D, _delta: float) -> Vector2:
var delta: float = (proj.resource.lifetime - proj.lifetime) / proj.resource.lifetime
var curve: Curve = proj.global_properties.get("SPEED_CURVE")
if (curve != null):
proj.speed = proj.resource.linear_speed * curve.sample(delta)
return proj.direction


Bouncing Projectile
extends Node2D
@onready var projectile_caller: ProjectileCaller2D = $ProjectileCaller2D
func _ready() -> void:
projectile_caller.get_projectile(0).set_on_collision(custom_collision)
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())
func custom_collision(proj: Projectile2D, area_rid: RID, area_node: Node2D, target_node: Node2D, area_shape_index: int, local_shape_index: int) -> void:
if not proj.validate_collision(area_rid, area_node):
return
var wall_layer: int = proj.global_properties["WALL_LAYER"]
if wall_layer & area_node.collision_layer != 0:
var query: PhysicsRayQueryParameters2D = PhysicsRayQueryParameters2D.create(proj.position - (proj.direction * 10), target_node.global_position, proj.collision_mask)
query.collide_with_areas = true;
var result: Dictionary = proj.current_space.intersect_ray(query)
if (result):
var prev: float = proj.direction.angle()
proj.direction = proj.direction.bounce(result.normal)
if (proj.look_at):
proj.transform = proj.transform.rotated(proj.direction.angle() - prev)
return
proj.is_expired = true
return
if target_node.has_method(proj.on_hit_call):
target_node.call(proj.on_hit_call, proj)
proj.on_pierced(area_rid)

