Projectile Physics

Add projectiles using a PackedScene with physics in Godot.

1. Setup

2. Projectile art

3. Create the Projectile scene

4. Modify PlayerController.gd

5. Add one of the following

6. Documentation

Update to PlayerController.gd

# add to global values
export (PackedScene) var projectile
var is_moving = true

func player_update(delta):
	# after input
	# shoot projectile
	if Input.is_action_just_pressed("shoot"):
		$AnimatedSprite.play('Shoot')
		is_moving = false
		shoot()

	# updated animations
	if not is_on_floor() and is_moving:
		$AnimatedSprite.play("Jump")
	elif abs(velocity.x) > 1 and is_moving:
		$AnimatedSprite.play("Walk")
	elif is_moving:
		$AnimatedSprite.play("Idle")

func shoot():
	var p = projectile.instance()
	p.position = self.position
#	p.velocity.x = p.speed * (-1 if $AnimatedSprite.flip_h else 1)
#	p.rotation = p.velocity.angle()
	owner.add_child(p)
	

Full Projectile.gd script

extends Area2D

var speed = 400
var velocity = Vector2()
var is_flying = true

func _ready():
	velocity = get_local_mouse_position().normalized()

func _physics_process(delta):
	if is_flying:
		velocity.y += gravity * delta / speed
		position += velocity * delta * speed
		rotation = velocity.angle()
		
	if not $VisibilityNotifier2D.is_on_screen():
		queue_free()


func _on_Projectile_area_entered(area):
	# this area will be obstacle hit area
	area.get_parent().hit()
	is_flying = false
	$AnimatedSprite.play('Hit')


func _on_AnimatedSprite_animation_finished():
	if not is_flying:
		queue_free()


func _on_Projectile_body_entered(body):
	# this is masked for the tilemap
	is_flying = false
	$AnimatedSprite.play('Hit')
	$SFX.play()