98 lines
2.6 KiB
GDScript3
98 lines
2.6 KiB
GDScript3
|
|
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)
|