Super-Mario-Bros-Remastered.../Scripts/Classes/Entities/Projectile.gd
SkyanUltra 2733876d29 Fixed Projectiles playing incorrect hit sounds
Fireball should be the only one that plays a hit sound now
2025-12-01 18:18:53 -05:00

111 lines
4.5 KiB
GDScript

class_name Projectile
extends Enemy
## Determines if this projectile deals damage to the player or not.
@export var is_friendly := false
## Which particle scene to load.
@export var PARTICLE: Resource = null
## Determines if the projectile will display a particle upon making contact with something, but hasn't been destroyed.
@export var PARTICLE_ON_CONTACT := false
## Determines what sound will play when the projectile makes contact with something.
@export var SFX_COLLIDE := ""
## Determines how many entities a projectile can hit before being destroyed. Negative values are considered infinite.
@export var PIERCE_COUNT: int = -1
## Determines how much time must pass in seconds before the projectile can hit the same enemy it is currently intersecting with again. Negative values are considered infinite.
@export var PIERCE_HITRATE := -1
## Determines how many times a projectile can bounce on tiles before being destroyed. Negative values are considered infinite.
@export var BOUNCE_COUNT: int = -1
## Controls if the projectile will make contact with the environment.
@export var HAS_COLLISION := false
## Controls if the projectile will bounce on the ground rather than being destroyed.
@export var GROUND_BOUNCE := false
## Controls if the projectile will bounce off of walls rather than being destroyed.
@export var WALL_BOUNCE := false
## Controls if the projectile will bounce off the ceiling rather than being destroyed.
@export var CEIL_BOUNCE := false
## Controls if the projectile will collect coins when it comes in contact with them.
@export var COLLECT_COINS := false
## Controls how long the projectile will exist for in seconds.
@export var LIFETIME := -1
## Controls the horizontal speed of the projectile.
@export var MOVE_SPEED := 0
## Controls the horizontal speed of the projectile.
@export var MOVE_SPEED_CAP := [-INF, INF]
## Controls the amount of deceleration the projectile will experience on the ground.
@export var GROUND_DECEL := 0
## Controls the amount of deceleration the projectile will experience in the air.
@export var AIR_DECEL := 0
## Controls the value of gravity the projectile will experience.
@export var GRAVITY := 0
## Controls the velocity the projectile will gain when bouncing off of the floor or ceiling.
@export var BOUNCE_HEIGHT := 0
## Controls the maximum speed the projectile can fall at.
@export var MAX_FALL_SPEED := 280.0
func _ready() -> void:
var collision = get_node_or_null("Collision")
if not HAS_COLLISION and collision != null: collision.disabled = true
if LIFETIME >= 0:
await get_tree().create_timer(LIFETIME).timeout
hit(true, true)
func _physics_process(delta: float) -> void:
$Sprite.flip_h = direction == 1
handle_movement(delta)
handle_collection()
func handle_movement(delta: float) -> void:
var CUR_GRAVITY = GRAVITY * (Global.entity_gravity * 0.1)
var DECEL_TYPE = GROUND_DECEL if is_on_floor() else AIR_DECEL
velocity.y += (CUR_GRAVITY / delta) * delta
velocity.y = clamp(velocity.y, -INF, MAX_FALL_SPEED)
if is_on_floor():
if GROUND_BOUNCE and BOUNCE_COUNT != 0:
BOUNCE_COUNT -= 1
velocity.y = -BOUNCE_HEIGHT
else: hit(true, true)
if is_on_ceiling():
if CEIL_BOUNCE and BOUNCE_COUNT != 0:
BOUNCE_COUNT -= 1
velocity.y = BOUNCE_HEIGHT
else: hit(true, true)
if is_on_wall():
if WALL_BOUNCE and BOUNCE_COUNT != 0:
BOUNCE_COUNT -= 1
direction *= -1
else: hit(true, true)
MOVE_SPEED = clamp(move_toward(MOVE_SPEED, 0, (DECEL_TYPE / delta) * delta), MOVE_SPEED_CAP[0], MOVE_SPEED_CAP[1])
velocity.x = MOVE_SPEED * direction
move_and_slide()
func damage_player(player: Player) -> void:
if !is_friendly:
player.damage(damage_type if damage_type != "Normal" else "")
hit()
func hit(play_sfx := true, force_destroy := false) -> void:
if play_sfx and SFX_COLLIDE != "":
AudioManager.play_sfx(SFX_COLLIDE, global_position)
if PIERCE_COUNT == 0 or BOUNCE_COUNT == 0 or force_destroy:
summon_explosion()
queue_free()
else:
var hitbox = get_node_or_null("Hitbox")
PIERCE_COUNT -= 1
if PARTICLE_ON_CONTACT: summon_explosion()
if PIERCE_HITRATE >= 0 and hitbox != null:
hitbox.monitoring = false
await get_tree().create_timer(PIERCE_HITRATE, false).timeout
hitbox.monitoring = true
func summon_explosion() -> void:
if PARTICLE is PackedScene and PARTICLE.can_instantiate():
var node = PARTICLE.instantiate()
node.global_position = global_position
add_sibling(node)
func handle_collection() -> void:
if COLLECT_COINS:
var areas = get_node_or_null("Hitbox").get_overlapping_areas()
for i in areas:
if i.owner.is_in_group("Coins"): i.owner.collect()