feat: add piercing and bouncing projectile

This commit is contained in:
Varylios 2025-09-03 00:03:15 +02:00
parent 1accc24fdb
commit 927486d456
8 changed files with 107 additions and 34 deletions

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
# Godot 4+ specific ignores # Godot 4+ specific ignores
.godot/ .godot/
.vscode

View file

@ -1,4 +1,4 @@
[gd_resource type="Resource" script_class="Level" load_steps=9 format=3 uid="uid://ob41fnhkjr3o"] [gd_resource type="Resource" script_class="Level" load_steps=11 format=3 uid="uid://ob41fnhkjr3o"]
[ext_resource type="Script" uid="uid://cuhq6u67cbbqm" path="res://Levels/Scripts/Resource/Level.gd" id="1_ftl6b"] [ext_resource type="Script" uid="uid://cuhq6u67cbbqm" path="res://Levels/Scripts/Resource/Level.gd" id="1_ftl6b"]
[ext_resource type="Script" uid="uid://chu8s12rtdeqx" path="res://Levels/Scripts/Resource/Wave.gd" id="2_457yt"] [ext_resource type="Script" uid="uid://chu8s12rtdeqx" path="res://Levels/Scripts/Resource/Wave.gd" id="2_457yt"]
@ -9,17 +9,31 @@ script = ExtResource("3_ub8wd")
enemy = "res://Enemies/Scenes/enemy-a.tscn" enemy = "res://Enemies/Scenes/enemy-a.tscn"
number_to_spawn = 1 number_to_spawn = 1
lane_to_spawn = 0 lane_to_spawn = 0
spawn_delay = 5.0 spawn_delay = 4.0
metadata/_custom_type_script = "uid://blxx3vs2wnfet" metadata/_custom_type_script = "uid://blxx3vs2wnfet"
[sub_resource type="Resource" id="Resource_e6yyc"]
script = ExtResource("3_ub8wd")
enemy = "res://Enemies/Scenes/enemy-a.tscn"
number_to_spawn = 1
lane_to_spawn = 0
spawn_delay = 1.5
[sub_resource type="Resource" id="Resource_fhv1k"]
script = ExtResource("3_ub8wd")
enemy = "res://Enemies/Scenes/enemy-a.tscn"
number_to_spawn = 1
lane_to_spawn = 0
spawn_delay = 1.5
[sub_resource type="Resource" id="Resource_457yt"] [sub_resource type="Resource" id="Resource_457yt"]
script = ExtResource("2_457yt") script = ExtResource("2_457yt")
troops = Array[ExtResource("3_ub8wd")]([SubResource("Resource_87wss")]) troops = Array[ExtResource("3_ub8wd")]([SubResource("Resource_87wss"), SubResource("Resource_e6yyc"), SubResource("Resource_fhv1k")])
metadata/_custom_type_script = "uid://chu8s12rtdeqx" metadata/_custom_type_script = "uid://chu8s12rtdeqx"
[sub_resource type="Resource" id="Resource_qfjse"] [sub_resource type="Resource" id="Resource_qfjse"]
script = ExtResource("3_ub8wd") script = ExtResource("3_ub8wd")
enemy = "res://Enemies/Scenes/enemy-a.tscn" enemy = "uid://1kwye5yjf40d"
number_to_spawn = 3 number_to_spawn = 3
lane_to_spawn = 0 lane_to_spawn = 0
spawn_delay = 5.0 spawn_delay = 5.0
@ -39,6 +53,6 @@ troops = Array[ExtResource("3_ub8wd")]([SubResource("Resource_qfjse"), SubResour
script = ExtResource("1_ftl6b") script = ExtResource("1_ftl6b")
waves = Array[ExtResource("2_457yt")]([SubResource("Resource_457yt"), SubResource("Resource_qeljc")]) waves = Array[ExtResource("2_457yt")]([SubResource("Resource_457yt"), SubResource("Resource_qeljc")])
auto_start = false auto_start = false
allowedTowers = Array[int]([1, 2]) allowedTowers = Array[int]([1, 2, 3, 4])
laneCount = 1 laneCount = 1
metadata/_custom_type_script = "uid://cuhq6u67cbbqm" metadata/_custom_type_script = "uid://cuhq6u67cbbqm"

View file

@ -4,12 +4,20 @@ class_name Projectile
const TARGET_ENEMY : int = 1 ## Flag to target enemy const TARGET_ENEMY : int = 1 ## Flag to target enemy
const TARGET_ALLY : int = 2 ## Flag to target ally const TARGET_ALLY : int = 2 ## Flag to target ally
const MINIMUN_AREA : float = .1
enum TYPE { ## Types of projectiles enum TYPE { ## Types of projectiles
AOE, ## One target
BASIC, ## Multiple targets[br]work with [member ProjectileResource.damageArea] ## One target
PIERCING ## Piercing through many enemy[br]work with [member ProjectileResource.maxTarets] BASIC,
## Multiple targets[br]work with [member ProjectileResource.damageArea]
AOE,
## Piercing through enemies[br]work with [member ProjectileResource.maxTarets] and [member ProjectileResource.damageArea]
PIERCING,
## Bouncing over enemies[br]work with [member ProjectileResource.maxTarets] and [member ProjectileResource.damageArea]
BOUNCING,
} }
var type : TYPE = TYPE.BASIC var type : TYPE = TYPE.BASIC
@ -23,9 +31,9 @@ var enemiesInRange : Array[Enemy]
var affectedTarget : Array[Enemy] var affectedTarget : Array[Enemy]
var allyInRange : Array[Tower] var allyInRange : Array[Tower]
func _physics_process(delta: float) -> void: func _physics_process(delta: float) -> void:
prints(vectorTarget, is_instance_valid(target), vectorTarget == Vector3.ZERO) if !is_instance_valid(target) && type != TYPE.PIERCING || vectorTarget.distance_squared_to(global_position) < .4:
if !is_instance_valid(target) && vectorTarget == Vector3.ZERO:
queue_free() queue_free()
return return
@ -36,17 +44,22 @@ func _physics_process(delta: float) -> void:
func onBodyEnteredDamageArea(body: Node3D) -> void: func onBodyEnteredDamageArea(body: Node3D) -> void:
if type == TYPE.AOE && targetable(body): if type != TYPE.BASIC && targetable(body):
if type == TYPE.PIERCING:
resolveDamages(body)
else:
addTarget(body) addTarget(body)
func onBodyCollideWithProjectile(body: Node3D) -> void: func onBodyCollideWithProjectile(body: Node3D) -> void:
if not affectedTarget.has(body) && (body == target || type == TYPE.PIERCING && targetable(body)): if (body == target || type == TYPE.PIERCING && targetable(body)):
addTarget(body) resolveDamages(body)
resolveDamages()
func targetable(body: Node3D) -> bool: func targetable(body: Node3D) -> bool:
if affectedTarget.has(body):
return false
if body is Enemy: if body is Enemy:
return TARGET_ENEMY & allowedTargets return TARGET_ENEMY & allowedTargets
if body is Tower: if body is Tower:
@ -55,15 +68,32 @@ func targetable(body: Node3D) -> bool:
return false return false
func resolveDamages() -> void: func resolveDamages(body: Node3D) -> void:
damageEnemy(body)
if type == TYPE.AOE:
for enemy in enemiesInRange: for enemy in enemiesInRange:
if is_instance_valid(enemy): if is_instance_valid(enemy):
damageEnemy(enemy)
if maxTargets < 1 || type == TYPE.AOE:
return queue_free()
if type == TYPE.BOUNCING:
enemiesInRange.erase(body)
if enemiesInRange.size():
target = enemiesInRange.pop_front()
vectorTarget = target.global_position
else:
queue_free()
func damageEnemy(enemy: Enemy) -> void:
if not affectedTarget.has(enemy):
maxTargets -= 1 maxTargets -= 1
enemy.take_damage(damage) enemy.take_damage(damage)
affectedTarget.append(enemy) affectedTarget.append(enemy)
if maxTargets < 1:
queue_free()
func loadProjectile(resource: ProjectileResource, startPosition: Vector3, _target: PhysicsBody3D) -> void: func loadProjectile(resource: ProjectileResource, startPosition: Vector3, _target: PhysicsBody3D) -> void:
@ -79,14 +109,14 @@ func loadProjectile(resource: ProjectileResource, startPosition: Vector3, _targe
damage = resource.damage damage = resource.damage
allowedTargets = resource.allowedTargets allowedTargets = resource.allowedTargets
$Sprite3D.texture = resource.sprite $Sprite3D.texture = resource.sprite
if type == TYPE.AOE && resource.damageArea: if type != TYPE.BASIC && resource.damageArea:
$DamageArea/ProjectileArea.shape = resource.damageArea $DamageArea/ProjectileArea.shape = resource.damageArea
func addTarget(body: Node3D) -> void: func addTarget(body: Node3D) -> void:
if body is Enemy: if body is Enemy && not enemiesInRange.has(body):
enemiesInRange.append(body) enemiesInRange.append(body)
if body is Tower: if body is Tower && not allyInRange.has(body):
allyInRange.append(body) allyInRange.append(body)

View file

@ -4,8 +4,10 @@ class_name ProjectileResource
@export var speed : int = 20 @export var speed : int = 20
@export var damage : int = 1 @export var damage : int = 1
@export var maxTargets : int = 1 ## Only usefull if [enum Projectile.TYPE] is [param PIERCING] @export var maxTargets : int = 1 ## Usefull when [enum Projectile.TYPE] is [param PIERCING] or [param BOUNCING]
@export var type : Projectile.TYPE = Projectile.TYPE.BASIC @export var type : Projectile.TYPE = Projectile.TYPE.BASIC
@export_flags("Enemies", "Alliés") var allowedTargets : int = 1 @export_flags("Enemies", "Alliés") var allowedTargets : int = 1
@export var damageArea : Shape3D ## Only usefull if [enum Projectile.TYPE] is [param AOE] ## Usefull when [enum Projectile.TYPE] is [param AOE], [param PIERCING] or [param BOUNCING]
## When [enum Projectile.TYPE] is [param BOUNCING] the shape is for target new entity in range
@export var damageArea : Shape3D
@export var sprite : Texture2D = load("res://Assets/Emotes/emote_star.png") @export var sprite : Texture2D = load("res://Assets/Emotes/emote_star.png")

View file

@ -15,7 +15,7 @@ script = ExtResource("4_ck6a3")
speed = 5 speed = 5
damage = 10 damage = 10
maxTargets = 1 maxTargets = 1
type = 0 type = 1
allowedTargets = 1 allowedTargets = 1
damageArea = SubResource("SphereShape3D_lhd8w") damageArea = SubResource("SphereShape3D_lhd8w")
sprite = ExtResource("5_lhd8w") sprite = ExtResource("5_lhd8w")

View file

@ -1,17 +1,21 @@
[gd_scene load_steps=7 format=3 uid="uid://b1pg1hgysx3am"] [gd_scene load_steps=8 format=3 uid="uid://b1pg1hgysx3am"]
[ext_resource type="PackedScene" uid="uid://trg7ag3dqr2l" path="res://Towers/tower.tscn" id="1_laam8"] [ext_resource type="PackedScene" uid="uid://trg7ag3dqr2l" path="res://Towers/tower.tscn" id="1_laam8"]
[ext_resource type="Script" uid="uid://ddgbr0n8kic3y" path="res://Towers/Projectiles/ProjectileResource.gd" id="2_7fox5"] [ext_resource type="Script" uid="uid://ddgbr0n8kic3y" path="res://Towers/Projectiles/ProjectileResource.gd" id="2_7fox5"]
[ext_resource type="Texture2D" uid="uid://boxdrq4nrq7hv" path="res://Assets/Icones/flamingo.svg" id="2_sciv6"] [ext_resource type="Texture2D" uid="uid://boxdrq4nrq7hv" path="res://Assets/Icones/flamingo.svg" id="2_sciv6"]
[ext_resource type="Script" uid="uid://bg0x4egeu17qb" path="res://Towers/Scripts/Upgrades/TowerUpgrade.gd" id="4_l8w4i"] [ext_resource type="Script" uid="uid://bg0x4egeu17qb" path="res://Towers/Scripts/Upgrades/TowerUpgrade.gd" id="4_l8w4i"]
[sub_resource type="SphereShape3D" id="SphereShape3D_sciv6"]
radius = 0.2
[sub_resource type="Resource" id="Resource_sciv6"] [sub_resource type="Resource" id="Resource_sciv6"]
script = ExtResource("2_7fox5") script = ExtResource("2_7fox5")
speed = 40 speed = 40
damage = 10 damage = 10
maxTargets = 5 maxTargets = 5
type = 1 type = 2
allowedTargets = 1 allowedTargets = 1
damageArea = SubResource("SphereShape3D_sciv6")
metadata/_custom_type_script = "uid://ddgbr0n8kic3y" metadata/_custom_type_script = "uid://ddgbr0n8kic3y"
[sub_resource type="SphereShape3D" id="SphereShape3D_pw4mj"] [sub_resource type="SphereShape3D" id="SphereShape3D_pw4mj"]
@ -27,6 +31,7 @@ projectileRessource = SubResource("Resource_sciv6")
towerRange = SubResource("SphereShape3D_pw4mj") towerRange = SubResource("SphereShape3D_pw4mj")
action_cooldown = 3.0 action_cooldown = 3.0
energy_regen = 20.0 energy_regen = 20.0
energy_cost = 25.0
tower_shop = Array[ExtResource("4_l8w4i")]([]) tower_shop = Array[ExtResource("4_l8w4i")]([])
[node name="Sprite3D" parent="." index="5"] [node name="Sprite3D" parent="." index="5"]

View file

@ -10,7 +10,7 @@ script = ExtResource("3_5tgsk")
speed = 20 speed = 20
damage = 5 damage = 5
maxTargets = 1 maxTargets = 1
type = 1 type = 0
allowedTargets = 1 allowedTargets = 1
sprite = ExtResource("4_r52mr") sprite = ExtResource("4_r52mr")
metadata/_custom_type_script = "uid://ddgbr0n8kic3y" metadata/_custom_type_script = "uid://ddgbr0n8kic3y"

View file

@ -1,15 +1,36 @@
[gd_scene load_steps=5 format=3 uid="uid://db6aq2wdrcjtp"] [gd_scene load_steps=9 format=3 uid="uid://db6aq2wdrcjtp"]
[ext_resource type="PackedScene" uid="uid://trg7ag3dqr2l" path="res://Towers/tower.tscn" id="1_ki73m"] [ext_resource type="PackedScene" uid="uid://trg7ag3dqr2l" path="res://Towers/tower.tscn" id="1_ki73m"]
[ext_resource type="Texture2D" uid="uid://m6jwakrus50v" path="res://Assets/Icones/sea-star.svg" id="2_n34tq"] [ext_resource type="Texture2D" uid="uid://m6jwakrus50v" path="res://Assets/Icones/sea-star.svg" id="2_n34tq"]
[ext_resource type="Script" uid="uid://ddgbr0n8kic3y" path="res://Towers/Projectiles/ProjectileResource.gd" id="3_sf52i"]
[ext_resource type="Script" uid="uid://bg0x4egeu17qb" path="res://Towers/Scripts/Upgrades/TowerUpgrade.gd" id="4_uso5g"] [ext_resource type="Script" uid="uid://bg0x4egeu17qb" path="res://Towers/Scripts/Upgrades/TowerUpgrade.gd" id="4_uso5g"]
[ext_resource type="Texture2D" uid="uid://315k07rsgf6t" path="res://Assets/Characters/Female1.png" id="5_2rqsg"] [ext_resource type="Texture2D" uid="uid://315k07rsgf6t" path="res://Assets/Characters/Female1.png" id="5_2rqsg"]
[sub_resource type="SphereShape3D" id="SphereShape3D_rbuca"]
radius = 3.0
[sub_resource type="Resource" id="Resource_c1yif"]
script = ExtResource("3_sf52i")
speed = 5
damage = 5
maxTargets = 3
type = 3
allowedTargets = 1
damageArea = SubResource("SphereShape3D_rbuca")
metadata/_custom_type_script = "uid://ddgbr0n8kic3y"
[sub_resource type="SphereShape3D" id="SphereShape3D_sf52i"]
radius = 4.0
[node name="Victoria" instance=ExtResource("1_ki73m")] [node name="Victoria" instance=ExtResource("1_ki73m")]
tower_name = "Victoria" tower_name = "Victoria"
tower_type = 4 tower_type = 4
icone = ExtResource("2_n34tq") icone = ExtResource("2_n34tq")
bio = "" bio = ""
projectileRessource = SubResource("Resource_c1yif")
towerRange = SubResource("SphereShape3D_sf52i")
energy_regen = 25.0
energy_cost = 20.0
tower_shop = Array[ExtResource("4_uso5g")]([]) tower_shop = Array[ExtResource("4_uso5g")]([])
[node name="Sprite3D" parent="." index="5"] [node name="Sprite3D" parent="." index="5"]