feat: add James Boss
- Add standard boss class - Improve projectile - Update layer and mask collision
This commit is contained in:
parent
0e3a7697ba
commit
d352574618
21 changed files with 197 additions and 94 deletions
50
Enemies/Scenes/boss-james.tscn
Normal file
50
Enemies/Scenes/boss-james.tscn
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
[gd_scene load_steps=9 format=3 uid="uid://dyl4wiga2goi"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://dg8bjkjuddnhg" path="res://Enemies/enemy.tscn" id="1_ohyx6"]
|
||||
[ext_resource type="Script" uid="uid://dw53e0rr7qc02" path="res://Enemies/boss.gd" id="2_vnmiq"]
|
||||
[ext_resource type="Texture2D" uid="uid://d38rvmky1mr5f" path="res://Assets/Characters/72 Character Free/Char 5/Character 5.png" id="3_831fr"]
|
||||
[ext_resource type="Script" uid="uid://ddgbr0n8kic3y" path="res://Towers/Projectiles/ProjectileResource.gd" id="3_vnmiq"]
|
||||
[ext_resource type="Texture2D" uid="uid://dqyhhvxpwtpsy" path="res://Assets/Emotes/emote_star.png" id="4_831fr"]
|
||||
|
||||
[sub_resource type="Resource" id="Resource_831fr"]
|
||||
script = ExtResource("3_vnmiq")
|
||||
speed = 2
|
||||
damage = 3
|
||||
maxTargets = 1
|
||||
type = 4
|
||||
allowedTargets = 2
|
||||
sprite = ExtResource("4_831fr")
|
||||
metadata/_custom_type_script = "uid://ddgbr0n8kic3y"
|
||||
|
||||
[sub_resource type="ViewportTexture" id="ViewportTexture_mw235"]
|
||||
viewport_path = NodePath("Enemy/HealthBar3D/SubViewport")
|
||||
|
||||
[sub_resource type="ConvexPolygonShape3D" id="ConvexPolygonShape3D_tviqb"]
|
||||
points = PackedVector3Array(0, 0, 0, -2, 1, 3, 2, 1, 3, 2, 0, 3, -2, 0, 3)
|
||||
|
||||
[node name="PathFollow3D" instance=ExtResource("1_ohyx6")]
|
||||
|
||||
[node name="Enemy" parent="." index="0"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.32, 0)
|
||||
script = ExtResource("2_vnmiq")
|
||||
projectile = SubResource("Resource_831fr")
|
||||
speed = 0.7
|
||||
base_attack_damage = 10
|
||||
max_life = 20
|
||||
money = 120
|
||||
|
||||
[node name="Sprite3D" parent="Enemy" index="1"]
|
||||
transform = Transform3D(2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0)
|
||||
texture = ExtResource("3_831fr")
|
||||
|
||||
[node name="HealthBar3D" parent="Enemy" index="2"]
|
||||
transform = Transform3D(0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0.34, 0)
|
||||
texture = SubResource("ViewportTexture_mw235")
|
||||
|
||||
[node name="TowerAttackRange" type="Area3D" parent="Enemy" index="4"]
|
||||
collision_layer = 4
|
||||
collision_mask = 4
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="Enemy/TowerAttackRange" index="0"]
|
||||
shape = SubResource("ConvexPolygonShape3D_tviqb")
|
||||
debug_color = Color(0.419608, 0, 0.584314, 0.419608)
|
||||
25
Enemies/boss.gd
Normal file
25
Enemies/boss.gd
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
extends Enemy
|
||||
class_name Boss
|
||||
|
||||
|
||||
@export var projectile : ProjectileResource
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
super._ready()
|
||||
$TowerAttackRange.body_entered.connect(onAttackRangeBodyEntered)
|
||||
$TowerAttackRange.body_exited.connect(onAttackRangeBodyExited)
|
||||
|
||||
|
||||
func attack() -> bool:
|
||||
# already attacked TheCube
|
||||
if super.attack():
|
||||
return true
|
||||
|
||||
var towerTargets : Array[Node3D] = targets.filter(func(b): return b is Tower)
|
||||
if $AttackCooldown.is_stopped() && not towerTargets.is_empty():
|
||||
projectile.shoot(towerTargets[0], global_position)
|
||||
targets.erase(towerTargets[0])
|
||||
$AttackCooldown.start()
|
||||
|
||||
return false
|
||||
1
Enemies/boss.gd.uid
Normal file
1
Enemies/boss.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dw53e0rr7qc02
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
extends CharacterBody3D
|
||||
class_name Enemy
|
||||
|
||||
|
||||
signal died
|
||||
|
||||
|
||||
@onready var death_vfx_packed : PackedScene = preload("res://VFX/death_particles.tscn")
|
||||
@onready var sad_vfx_packed : PackedScene = preload("res://VFX/sad_particles.tscn")
|
||||
|
||||
|
|
@ -20,37 +22,41 @@ var health : int = 0 :
|
|||
@onready var path : PathFollow3D = get_parent()
|
||||
@onready var healthBar : ProgressBar = $HealthBar3D/SubViewport/HealthBar2D
|
||||
|
||||
var attack_target : Node3D
|
||||
var targets : Array[Node3D]
|
||||
var is_alive : bool = true
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
healthBar.value = health
|
||||
healthBar.max_value = max_life
|
||||
$CubeAttackRange.body_entered.connect(onAttackRangeBodyEntered)
|
||||
$CubeAttackRange.body_exited.connect(onAttackRangeBodyExited)
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if !is_alive:
|
||||
return
|
||||
|
||||
if attack_target:
|
||||
attack()
|
||||
else:
|
||||
if not attack():
|
||||
path.progress += speed * delta
|
||||
|
||||
|
||||
func take_damage(damage : int) -> void:
|
||||
func take_damage(damage: int) -> void:
|
||||
health += damage
|
||||
healthBar.visible = true
|
||||
healthBar.value = health
|
||||
|
||||
|
||||
func attack():
|
||||
if $AttackCooldown.is_stopped():
|
||||
func attack() -> bool:
|
||||
if targets.is_empty():
|
||||
return false
|
||||
|
||||
var cubeTarget : Array[Node3D] = targets.filter(func(b): return b is TheCube)
|
||||
if $AttackCooldown.is_stopped() && not cubeTarget.is_empty():
|
||||
cubeTarget[0].take_damage(base_attack_damage)
|
||||
$AttackCooldown.start()
|
||||
attack_target.take_damage(base_attack_damage)
|
||||
attack_target = null
|
||||
path.progress = 0
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
|
||||
func death() -> void:
|
||||
|
|
@ -61,15 +67,13 @@ func death() -> void:
|
|||
var death_vfx : CPUParticles3D = death_vfx_packed.instantiate()
|
||||
get_tree().current_scene.add_child(death_vfx)
|
||||
death_vfx.global_position = global_position
|
||||
|
||||
path.queue_free()
|
||||
|
||||
|
||||
func _on_attack_range_body_entered(body: Node3D) -> void:
|
||||
if body is TheCube:
|
||||
attack_target = body
|
||||
func onAttackRangeBodyEntered(body: Node3D) -> void:
|
||||
if (body is TheCube || body is Tower) && not targets.has(body):
|
||||
targets.append(body)
|
||||
|
||||
|
||||
func _on_attack_range_body_exited(body: Node3D) -> void:
|
||||
if body is TheCube:
|
||||
attack_target = null
|
||||
func onAttackRangeBodyExited(body: Node3D) -> void:
|
||||
targets.erase(body)
|
||||
|
|
|
|||
|
|
@ -22,14 +22,14 @@ color = 0
|
|||
metadata/_custom_type_script = "uid://blnmjxmusrsa7"
|
||||
|
||||
[sub_resource type="SphereShape3D" id="SphereShape3D_cmo2f"]
|
||||
radius = 1.0
|
||||
radius = 0.6
|
||||
|
||||
[node name="PathFollow3D" type="PathFollow3D"]
|
||||
|
||||
[node name="Enemy" type="CharacterBody3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.25, 0)
|
||||
collision_layer = 4
|
||||
collision_mask = 4
|
||||
collision_layer = 2
|
||||
collision_mask = 2
|
||||
script = ExtResource("1_orwns")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="Enemy"]
|
||||
|
|
@ -68,16 +68,14 @@ theme_override_styles/fill = SubResource("StyleBoxFlat_d6lpy")
|
|||
show_percentage = false
|
||||
metadata/_custom_type_script = "uid://blnmjxmusrsa7"
|
||||
|
||||
[node name="AttackRange" type="Area3D" parent="Enemy"]
|
||||
collision_layer = 8
|
||||
collision_mask = 8
|
||||
[node name="CubeAttackRange" type="Area3D" parent="Enemy"]
|
||||
collision_layer = 4
|
||||
collision_mask = 4
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="Enemy/AttackRange"]
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="Enemy/CubeAttackRange"]
|
||||
shape = SubResource("SphereShape3D_cmo2f")
|
||||
debug_color = Color(0.994297, 0, 0.224345, 0.42)
|
||||
|
||||
[node name="AttackCooldown" type="Timer" parent="Enemy"]
|
||||
wait_time = 4.0
|
||||
one_shot = true
|
||||
|
||||
[connection signal="body_entered" from="Enemy/AttackRange" to="Enemy" method="_on_attack_range_body_entered"]
|
||||
[connection signal="body_exited" from="Enemy/AttackRange" to="Enemy" method="_on_attack_range_body_exited"]
|
||||
|
|
|
|||
|
|
@ -81,17 +81,21 @@ static func showConfirmPopup(
|
|||
confirmPopup.confirmed.connect(confirmCallback)
|
||||
confirmPopup.canceled.connect(cancelCallback)
|
||||
|
||||
|
||||
static func getTopOfHitBox(body : CollisionObject3D) -> float:
|
||||
enum POSITION { TOP, CENTER, DOWN }
|
||||
static func getHitBoxLocation(body : CollisionObject3D, position : POSITION) -> float:
|
||||
if body is GameTile:
|
||||
return .2
|
||||
|
||||
if body.has_node("CollisionShape3D"):
|
||||
var shape : Shape3D = body.shape_owner_get_shape(0, 0)
|
||||
var transform : Transform3D = body.shape_owner_get_transform(0)
|
||||
if shape is CapsuleShape3D:
|
||||
return shape.height + shape.radius + transform.origin.y
|
||||
if shape is SphereShape3D:
|
||||
return shape.radius + transform.origin.y
|
||||
if position == POSITION.CENTER:
|
||||
return transform.origin.y
|
||||
else:
|
||||
var factor : int = 1 if POSITION.TOP == position else -1
|
||||
if shape is CapsuleShape3D:
|
||||
return factor * (shape.height + shape.radius) + transform.origin.y
|
||||
if shape is SphereShape3D:
|
||||
return factor * shape.radius + transform.origin.y
|
||||
|
||||
return 0
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
extends Resource
|
||||
class_name Troop
|
||||
|
||||
@export_file("*.tscn") var enemy : String = "res://enemies/"
|
||||
@export_file("*.tscn") var enemy : String = "res://enemies/Scenes"
|
||||
@export var number_to_spawn : int = 1
|
||||
@export var lane_to_spawn : int = 0
|
||||
@export var spawn_delay : float = 1
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@
|
|||
size = Vector3(1.2, 1, 1.2)
|
||||
|
||||
[node name="TheCube" type="StaticBody3D"]
|
||||
collision_layer = 8
|
||||
collision_mask = 8
|
||||
collision_layer = 4
|
||||
collision_mask = 4
|
||||
script = ExtResource("1_wrmut")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@ enum TYPE { ## Types of projectiles
|
|||
|
||||
## Bouncing over enemies[br]work with [member ProjectileResource.maxTarets] and [member ProjectileResource.damageArea]
|
||||
BOUNCING,
|
||||
|
||||
## Disable ally tower for [param damage] duration [br]Usable on [Boss] projectiles
|
||||
DISABLING,
|
||||
}
|
||||
|
||||
var type : TYPE = TYPE.BASIC
|
||||
|
|
@ -27,63 +30,86 @@ var target : PhysicsBody3D
|
|||
var vectorTarget : Vector3
|
||||
var maxTargets : int = 1
|
||||
var damage : int = 1
|
||||
var enemiesInRange : Array[Enemy]
|
||||
var bodiesInRange : Array[Enemy]
|
||||
var affectedTarget : Array[Enemy]
|
||||
var allyInRange : Array[Tower]
|
||||
|
||||
|
||||
func _physics_process(_delta: float) -> void:
|
||||
if !is_instance_valid(target) && type != TYPE.PIERCING || vectorTarget.distance_squared_to(global_position) < .4:
|
||||
if shouldQueueFree():
|
||||
queue_free()
|
||||
return
|
||||
|
||||
var globalPos : Vector3 = vectorTarget if vectorTarget else target.global_position
|
||||
if target is Tower:
|
||||
globalPos.y += Helper.getHitBoxLocation(target, Helper.POSITION.CENTER)
|
||||
velocity = global_position.direction_to(globalPos) * speed
|
||||
look_at(globalPos)
|
||||
move_and_slide()
|
||||
|
||||
|
||||
func shouldQueueFree() -> bool:
|
||||
match type:
|
||||
TYPE.PIERCING: return vectorTarget.distance_squared_to(global_position) < .4
|
||||
_ when target is Tower: return not target.visible
|
||||
_ when !is_instance_valid(target): return true
|
||||
|
||||
return false
|
||||
|
||||
|
||||
func onBodyEnteredDamageArea(body: Node3D) -> void:
|
||||
if type != TYPE.BASIC && targetable(body):
|
||||
if type == TYPE.PIERCING:
|
||||
resolveDamages(body)
|
||||
else:
|
||||
addTarget(body)
|
||||
resolveContact(body)
|
||||
elif not bodiesInRange.has(body):
|
||||
bodiesInRange.append(body)
|
||||
|
||||
|
||||
func onBodyCollideWithProjectile(body: Node3D) -> void:
|
||||
if (body == target || type == TYPE.PIERCING && targetable(body)):
|
||||
resolveDamages(body)
|
||||
resolveContact(body)
|
||||
|
||||
|
||||
func targetable(body: Node3D) -> bool:
|
||||
if body is Enemy:
|
||||
return TARGET_ENEMY & allowedTargets && not affectedTarget.has(body)
|
||||
if body is Tower:
|
||||
if body is Tower || body is TheCube:
|
||||
return TARGET_ALLY & allowedTargets
|
||||
|
||||
return false
|
||||
|
||||
|
||||
func resolveDamages(body: Node3D) -> void:
|
||||
damageEnemy(body)
|
||||
func resolveContact(body: Node3D) -> void:
|
||||
if body is Enemy:
|
||||
resolveEnemyDamages(body)
|
||||
if body is Tower || body is TheCube:
|
||||
resolveAllyEffects(body)
|
||||
|
||||
|
||||
func resolveEnemyDamages(enemy: Enemy) -> void:
|
||||
damageEnemy(enemy)
|
||||
|
||||
if type == TYPE.AOE:
|
||||
for enemy in enemiesInRange:
|
||||
if is_instance_valid(enemy):
|
||||
damageEnemy(enemy)
|
||||
for body in bodiesInRange:
|
||||
if is_instance_valid(body):
|
||||
damageEnemy(body)
|
||||
|
||||
if maxTargets < 1 || type == TYPE.AOE:
|
||||
return queue_free()
|
||||
|
||||
if type == TYPE.BOUNCING:
|
||||
enemiesInRange.erase(body)
|
||||
if enemiesInRange.size():
|
||||
target = enemiesInRange.pop_front()
|
||||
bodiesInRange.erase(enemy)
|
||||
if bodiesInRange.size():
|
||||
target = bodiesInRange.pop_front()
|
||||
else:
|
||||
queue_free()
|
||||
|
||||
|
||||
func resolveAllyEffects(ally: Node3D) -> void:
|
||||
if ally is Tower && type == TYPE.DISABLING:
|
||||
ally.disable(damage)
|
||||
queue_free()
|
||||
|
||||
|
||||
func damageEnemy(enemy: Enemy) -> void:
|
||||
if not affectedTarget.has(enemy):
|
||||
maxTargets -= 1
|
||||
|
|
@ -91,7 +117,6 @@ func damageEnemy(enemy: Enemy) -> void:
|
|||
affectedTarget.append(enemy)
|
||||
|
||||
|
||||
|
||||
func loadProjectile(resource: ProjectileResource, _target: PhysicsBody3D) -> void:
|
||||
target = _target
|
||||
type = resource.type
|
||||
|
|
@ -104,19 +129,9 @@ func loadProjectile(resource: ProjectileResource, _target: PhysicsBody3D) -> voi
|
|||
damage = resource.damage
|
||||
allowedTargets = resource.allowedTargets
|
||||
$Sprite3D.texture = resource.sprite
|
||||
if type != TYPE.BASIC && resource.damageArea:
|
||||
if [TYPE.AOE, TYPE.PIERCING, TYPE.BOUNCING].has(type) && resource.damageArea:
|
||||
$DamageArea/ProjectileArea.shape = resource.damageArea
|
||||
|
||||
|
||||
func addTarget(body: Node3D) -> void:
|
||||
if body is Enemy && not enemiesInRange.has(body):
|
||||
enemiesInRange.append(body)
|
||||
if body is Tower && not allyInRange.has(body):
|
||||
allyInRange.append(body)
|
||||
|
||||
|
||||
func removeTarget(body: Node3D) -> void:
|
||||
if body is Enemy:
|
||||
enemiesInRange.erase(body)
|
||||
if body is Tower:
|
||||
allyInRange.erase(body)
|
||||
bodiesInRange.erase(body)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
extends Resource
|
||||
class_name ProjectileResource
|
||||
|
||||
const projectileScene : PackedScene = preload("res://Towers/Projectiles/projectile.tscn")
|
||||
|
||||
@export var speed : int = 20
|
||||
@export var damage : int = 1
|
||||
|
|
@ -11,3 +12,8 @@ class_name ProjectileResource
|
|||
## 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")
|
||||
|
||||
func shoot(target: Node3D, gobalPos: Vector3) -> void:
|
||||
var projectile : Projectile = projectileScene.instantiate()
|
||||
projectile.loadProjectile(self, target)
|
||||
EventBus.projectile_shooted.emit(projectile, gobalPos)
|
||||
|
|
|
|||
|
|
@ -21,16 +21,16 @@ billboard = 2
|
|||
texture = ExtResource("2_08w86")
|
||||
|
||||
[node name="HitBox" type="Area3D" parent="."]
|
||||
collision_layer = 4
|
||||
collision_mask = 4
|
||||
collision_layer = 6
|
||||
collision_mask = 6
|
||||
|
||||
[node name="ProjectileSize" type="CollisionShape3D" parent="HitBox"]
|
||||
shape = SubResource("SphereShape3D_dsts2")
|
||||
debug_color = Color(0.926858, 0.237749, 0.335021, 0.42)
|
||||
|
||||
[node name="DamageArea" type="Area3D" parent="."]
|
||||
collision_layer = 4
|
||||
collision_mask = 4
|
||||
collision_layer = 6
|
||||
collision_mask = 6
|
||||
|
||||
[node name="ProjectileArea" type="CollisionShape3D" parent="DamageArea"]
|
||||
debug_color = Color(0.926858, 0.237749, 0.335021, 0.42)
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ type = 2
|
|||
icone = ExtResource("3_6h033")
|
||||
bio = ""
|
||||
price = 150
|
||||
projectileRessource = SubResource("Resource_lhd8w")
|
||||
projectile = SubResource("Resource_lhd8w")
|
||||
towerRange = SubResource("SphereShape3D_6bcjo")
|
||||
action_cooldown = 2.5
|
||||
max_energy = 100.0
|
||||
|
|
|
|||
|
|
@ -22,6 +22,6 @@ tower_name = "Evan"
|
|||
type = 5
|
||||
icone = ExtResource("2_5uh04")
|
||||
bio = ""
|
||||
projectileRessource = SubResource("Resource_mf185")
|
||||
projectile = SubResource("Resource_mf185")
|
||||
towerRange = SubResource("SphereShape3D_y05yr")
|
||||
tower_shop = Array[ExtResource("4_v32j5")]([])
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ type = 3
|
|||
icone = ExtResource("2_sciv6")
|
||||
bio = ""
|
||||
price = 200
|
||||
projectileRessource = SubResource("Resource_sciv6")
|
||||
projectile = SubResource("Resource_sciv6")
|
||||
towerRange = SubResource("SphereShape3D_pw4mj")
|
||||
action_cooldown = 3.0
|
||||
max_energy = 50.0
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ tower_name = "Pierre"
|
|||
type = 1
|
||||
icone = ExtResource("2_lcjqw")
|
||||
price = 100
|
||||
projectileRessource = SubResource("Resource_r52mr")
|
||||
projectile = SubResource("Resource_r52mr")
|
||||
towerRange = SubResource("SphereShape3D_c55ds")
|
||||
action_cooldown = 1.0
|
||||
max_energy = 25.0
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
[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="Script" uid="uid://ddgbr0n8kic3y" path="res://Towers/Projectiles/ProjectileResource.gd" id="3_sf52i"]
|
||||
[ext_resource type="Script" uid="uid://bg0x4egeu17qb" path="res://Upgrades/TowerUpgrade.gd" id="4_uso5g"]
|
||||
[ext_resource type="Texture2D" uid="uid://315k07rsgf6t" path="res://Assets/Characters/Female1.png" id="5_2rqsg"]
|
||||
|
||||
[sub_resource type="SphereShape3D" id="SphereShape3D_rbuca"]
|
||||
|
|
@ -22,17 +21,22 @@ metadata/_custom_type_script = "uid://ddgbr0n8kic3y"
|
|||
[sub_resource type="SphereShape3D" id="SphereShape3D_sf52i"]
|
||||
radius = 4.0
|
||||
|
||||
[sub_resource type="ViewportTexture" id="ViewportTexture_n34tq"]
|
||||
viewport_path = NodePath("EnergyBar3D/SubViewport")
|
||||
|
||||
[node name="Victoria" instance=ExtResource("1_ki73m")]
|
||||
tower_name = "Victoria"
|
||||
type = 4
|
||||
icone = ExtResource("2_n34tq")
|
||||
bio = ""
|
||||
projectileRessource = SubResource("Resource_c1yif")
|
||||
projectile = SubResource("Resource_c1yif")
|
||||
towerRange = SubResource("SphereShape3D_sf52i")
|
||||
energy_regen = 25.0
|
||||
energy_cost = 20.0
|
||||
tower_shop = Array[ExtResource("4_uso5g")]([])
|
||||
|
||||
[node name="Sprite3D" parent="." index="5"]
|
||||
texture = ExtResource("5_2rqsg")
|
||||
frame = 59
|
||||
|
||||
[node name="EnergyBar3D" parent="." index="6"]
|
||||
texture = SubResource("ViewportTexture_n34tq")
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@ signal changed
|
|||
# DANGER "NONE" Should always be first
|
||||
enum TYPE { NONE, PIERRE, ALINE, MAXENCE, VICTORIA, EVAN, ALEX, GERALDINE }
|
||||
|
||||
var projectileScene : PackedScene = preload("res://Towers/Projectiles/projectile.tscn")
|
||||
|
||||
@export var tower_name : String = "None"
|
||||
@export var type : TYPE
|
||||
@export_group("Base data")
|
||||
|
|
@ -24,7 +22,7 @@ var projectileScene : PackedScene = preload("res://Towers/Projectiles/projectile
|
|||
@export var price : int
|
||||
|
||||
@export_group("Attack")
|
||||
@export var projectileRessource : ProjectileResource
|
||||
@export var projectile : ProjectileResource
|
||||
@export var towerRange : Shape3D
|
||||
@export var action_cooldown : float = 0.3 :
|
||||
set(value):
|
||||
|
|
@ -59,8 +57,6 @@ var energy : float :
|
|||
energy = clampf(value, 0, max_energy)
|
||||
energyBar.value = energy
|
||||
energy_changed.emit()
|
||||
if not energy && state != STATE.BLUEPRINT:
|
||||
state = STATE.EXHAUSTED
|
||||
|
||||
var availableTargets : Array[Enemy]
|
||||
var selectable : bool :
|
||||
|
|
@ -96,23 +92,23 @@ func changeState(newState : STATE) -> void:
|
|||
|
||||
match newState:
|
||||
STATE.ACTION when state == STATE.REST: in_action()
|
||||
STATE.ACTION when not energy: newState = STATE.EXHAUSTED
|
||||
STATE.ACTION: pass
|
||||
STATE.REST: resting()
|
||||
_: return # NOTE Prevent changing of state
|
||||
_: return # NOTE Prevent change of state
|
||||
|
||||
state = newState
|
||||
|
||||
|
||||
func shoot() -> void:
|
||||
if energy < energy_cost:
|
||||
state = STATE.EXHAUSTED
|
||||
return
|
||||
|
||||
var target : Enemy = choose_target()
|
||||
if not target:
|
||||
return
|
||||
|
||||
energy -= energy_cost
|
||||
var projectile : Projectile = projectileScene.instantiate()
|
||||
projectile.loadProjectile(projectileRessource, target)
|
||||
EventBus.projectile_shooted.emit(projectile, $Aim.global_position)
|
||||
projectile.shoot(target, $Aim.global_position)
|
||||
$AttackCooldown.start(action_cooldown)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ func handle_player_controls() -> CollisionObject3D:
|
|||
visible = true
|
||||
selection_icon.visible = true
|
||||
global_position = collider.global_position
|
||||
global_position.y += Helper.getTopOfHitBox(collider) + .01
|
||||
global_position.y += Helper.getHitBoxLocation(collider, Helper.POSITION.TOP) + .01
|
||||
|
||||
if selected_tower && selected_tower.state == Tower.STATE.BLUEPRINT:
|
||||
selected_tower.sprite.modulate = "ff4545c8" # If the tower can't be placed he is red
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ shape = SubResource("CapsuleShape3D_ynmsb")
|
|||
|
||||
[node name="Range" type="Area3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.4, 0)
|
||||
collision_layer = 4
|
||||
collision_mask = 4
|
||||
collision_layer = 2
|
||||
collision_mask = 2
|
||||
|
||||
[node name="Range" type="CollisionShape3D" parent="Range"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.475708, 0)
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ func onTowerChange() -> void:
|
|||
onEnergyChange()
|
||||
%TowerIcon.texture = tower.icone
|
||||
%TowerName.text = tower.tower_name
|
||||
%TowerDamage.text = "Dmg : %d" % tower.projectileRessource.damage
|
||||
%TowerDamage.text = "Dmg : %d" % tower.projectile.damage
|
||||
%TowerCooldown.text = "cooldown : %.1f" % tower.action_cooldown
|
||||
# TODO Check for better UI to display it
|
||||
#%TowerBio.text = tower.bio
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ func upgrade(tower: Tower = null) -> bool:
|
|||
TYPE.MAX_ENERGY: upgradeProperty(tower, "max_energy")
|
||||
TYPE.ENERGY_REGEN: upgradeProperty(tower, "energy_regen")
|
||||
TYPE.ENERGY_COST: upgradeProperty(tower, "energy_cost")
|
||||
TYPE.DAMAGE: upgradeProperty(tower.projectileRessource, "damage")
|
||||
TYPE.AOE_INCREASE: upgradeProperty(tower.projectileRessource.damageArea, "radius")
|
||||
TYPE.DAMAGE: upgradeProperty(tower.projectile, "damage")
|
||||
TYPE.AOE_INCREASE: upgradeProperty(tower.projectile.damageArea, "radius")
|
||||
TYPE.COOLDOWN: upgradeProperty(tower, "action_cooldown")
|
||||
|
||||
upgradeUpgrade()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue