extends CharacterBody3D class_name Projectile const TARGET_ENEMY : int = 1 ## Flag to target enemy const TARGET_ALLY : int = 2 ## Flag to target ally const MINIMUN_AREA : float = .1 enum TYPE { ## Types of projectiles AOE, ## One target BASIC, ## Multiple targets[br]work with [member ProjectileResource.damageArea] PIERCING ## Piercing through many enemy[br]work with [member ProjectileResource.maxTarets] } var type : TYPE = TYPE.BASIC var speed : int = 20 var allowedTargets : int = TARGET_ENEMY var target : PhysicsBody3D var vectorTarget : Vector3 var maxTargets : int = 1 var damage : int = 1 var enemiesInRange : Array[Enemy] var affectedTarget : Array[Enemy] var allyInRange : Array[Tower] func _physics_process(delta: float) -> void: prints(vectorTarget, is_instance_valid(target), vectorTarget == Vector3.ZERO) if !is_instance_valid(target) && vectorTarget == Vector3.ZERO: queue_free() return var globalPos : Vector3 = vectorTarget if vectorTarget else target.global_position velocity = global_position.direction_to(globalPos) * speed look_at(globalPos) move_and_slide() func onBodyEnteredDamageArea(body: Node3D) -> void: if type == TYPE.AOE && targetable(body): addTarget(body) func onBodyCollideWithProjectile(body: Node3D) -> void: if not affectedTarget.has(body) && (body == target || type == TYPE.PIERCING && targetable(body)): addTarget(body) resolveDamages() func targetable(body: Node3D) -> bool: if body is Enemy: return TARGET_ENEMY & allowedTargets if body is Tower: return TARGET_ALLY & allowedTargets return false func resolveDamages() -> void: for enemy in enemiesInRange: if is_instance_valid(enemy): maxTargets -= 1 enemy.take_damage(damage) affectedTarget.append(enemy) if maxTargets < 1: queue_free() func loadProjectile(resource: ProjectileResource, startPosition: Vector3, _target: PhysicsBody3D) -> void: target = _target global_position = startPosition type = resource.type if type == TYPE.PIERCING: vectorTarget = target.global_position # NOTE removing colision layer for pierce effect $HitBox.collision_layer = 0 speed = resource.speed maxTargets = resource.maxTargets damage = resource.damage allowedTargets = resource.allowedTargets $Sprite3D.texture = resource.sprite if type == TYPE.AOE && resource.damageArea: $DamageArea/ProjectileArea.shape = resource.damageArea func addTarget(body: Node3D) -> void: if body is Enemy: enemiesInRange.append(body) if body is Tower: allyInRange.append(body) func removeTarget(body: Node3D) -> void: if body is Enemy: enemiesInRange.erase(body) if body is Tower: allyInRange.erase(body)