upgrade: godot 4.5 #6
5 changed files with 140 additions and 39 deletions
|
|
@ -73,13 +73,14 @@ static func showConfirmPopup(
|
||||||
text : String,
|
text : String,
|
||||||
nodeToAppend : Node,
|
nodeToAppend : Node,
|
||||||
confirmCallback : Callable,
|
confirmCallback : Callable,
|
||||||
cancelCallback : Callable = func(): null
|
cancelCallback : Callable = func(): pass
|
||||||
) -> void:
|
) -> void:
|
||||||
var confirmPopup : ConfirmPopup = CONFIRM_POPUP.instantiate()
|
var confirmPopup : ConfirmPopup = CONFIRM_POPUP.instantiate()
|
||||||
nodeToAppend.add_child(confirmPopup)
|
nodeToAppend.add_child(confirmPopup)
|
||||||
|
nodeToAppend.get_tree().paused = true
|
||||||
confirmPopup.label.text = text
|
confirmPopup.label.text = text
|
||||||
confirmPopup.confirmed.connect(confirmCallback)
|
confirmPopup.confirmed.connect(func(): confirmCallback.call(); nodeToAppend.get_tree().paused = false)
|
||||||
confirmPopup.canceled.connect(cancelCallback)
|
confirmPopup.canceled.connect(func(): cancelCallback.call(); nodeToAppend.get_tree().paused = false)
|
||||||
|
|
||||||
enum POSITION { TOP, CENTER, DOWN }
|
enum POSITION { TOP, CENTER, DOWN }
|
||||||
static func getHitBoxLocation(body : CollisionObject3D, position : POSITION) -> float:
|
static func getHitBoxLocation(body : CollisionObject3D, position : POSITION) -> float:
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@ extends CharacterBody3D
|
||||||
class_name Projectile
|
class_name Projectile
|
||||||
|
|
||||||
|
|
||||||
|
enum State { INIT, TRAVEL, EFFECT, DESPAWN }
|
||||||
|
|
||||||
|
|
||||||
enum Mode {
|
enum Mode {
|
||||||
FOLLOW, ## Follow target
|
FOLLOW, ## Follow target
|
||||||
LOCATION, ## Go to target location
|
LOCATION, ## Go to target location
|
||||||
|
|
@ -9,9 +12,15 @@ enum Mode {
|
||||||
HITSCAN, ## Spawn on target location
|
HITSCAN, ## Spawn on target location
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Duration {
|
|
||||||
|
enum Effect {
|
||||||
ONE_HIT, ## Make damage on hit
|
ONE_HIT, ## Make damage on hit
|
||||||
DAMAGE_OVER_TIME, ## Make damage every tick for specified duration[br]work with [member maxTargets] for number of tick
|
## Make damage every tick for specified duration[br]
|
||||||
|
## work with [member dotTicks] for number of tick
|
||||||
|
DAMAGE_OVER_TIME,
|
||||||
|
## Make damage over time on hitted target for the specified duration[br]
|
||||||
|
## work with [member dotTicks] for number of tick
|
||||||
|
POISON,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Type { ## Types of projectiles
|
enum Type { ## Types of projectiles
|
||||||
|
|
@ -23,14 +32,17 @@ enum Type { ## Types of projectiles
|
||||||
|
|
||||||
|
|
||||||
@export var mode : Mode = Mode.FOLLOW
|
@export var mode : Mode = Mode.FOLLOW
|
||||||
@export var duration : Duration = Duration.ONE_HIT
|
@export var effect : Effect = Effect.ONE_HIT
|
||||||
@export var type : Type = Type.BASIC
|
@export var type : Type = Type.BASIC
|
||||||
@export var speed : int
|
@export var speed : int
|
||||||
## Usefull when [enum Type] is not [constant BASIC][br]
|
## Usefull when [enum Type] is not [constant BASIC][br][code]-1[/code] for no maximum
|
||||||
## [code]-1[/code] for no maximum
|
|
||||||
## Used as time when [enum Duration] is [constant HITSCAN]
|
|
||||||
@export var maxTargets : int = 1
|
@export var maxTargets : int = 1
|
||||||
|
## The amount of ticks
|
||||||
|
## Used as time when [enum Effect] is [constant DAMAGE_OVER_TIME] or [constant POISON]
|
||||||
|
@export var dotTicks : int
|
||||||
|
@export var tickInterval : float ##
|
||||||
|
|
||||||
|
var state : State = State.INIT
|
||||||
var amount : float
|
var amount : float
|
||||||
var target : PhysicsBody3D
|
var target : PhysicsBody3D
|
||||||
var vectorTarget : Vector3
|
var vectorTarget : Vector3
|
||||||
|
|
@ -41,25 +53,30 @@ var affectedTarget : Array[Node3D]
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
$HitBox.body_entered.connect(collidingBodies.append)
|
$HitBox.body_entered.connect(collidingBodies.append)
|
||||||
#$HitBox.body_entered.connect(test)
|
|
||||||
$HitBox.body_exited.connect(collidingBodies.erase)
|
$HitBox.body_exited.connect(collidingBodies.erase)
|
||||||
$EffectArea.body_entered.connect(bodiesInRange.append)
|
$EffectArea.body_entered.connect(bodiesInRange.append)
|
||||||
$EffectArea.body_exited.connect(bodiesInRange.erase)
|
$EffectArea.body_exited.connect(bodiesInRange.erase)
|
||||||
|
|
||||||
|
|
||||||
func test(body):
|
|
||||||
print(body)
|
|
||||||
|
|
||||||
var firstTick : bool = true
|
|
||||||
func _physics_process(_delta: float) -> void:
|
func _physics_process(_delta: float) -> void:
|
||||||
if firstTick:
|
if state == State.INIT:
|
||||||
firstTick = false
|
state = State.TRAVEL
|
||||||
return
|
return
|
||||||
|
|
||||||
resolveContact()
|
match state:
|
||||||
|
State.TRAVEL when isOnTarget():
|
||||||
|
state = State.EFFECT
|
||||||
|
applyEffects()
|
||||||
|
return
|
||||||
|
State.EFFECT: return
|
||||||
|
State.DESPAWN:
|
||||||
|
queue_free.call_deferred()
|
||||||
|
return
|
||||||
|
|
||||||
if shouldQueueFree():
|
if shouldQueueFree():
|
||||||
queue_free.call_deferred()
|
state = State.DESPAWN
|
||||||
|
|
||||||
|
if state != State.TRAVEL:
|
||||||
return
|
return
|
||||||
|
|
||||||
if mode == Mode.FOLLOW:
|
if mode == Mode.FOLLOW:
|
||||||
|
|
@ -72,39 +89,63 @@ func _physics_process(_delta: float) -> void:
|
||||||
|
|
||||||
|
|
||||||
func shouldQueueFree() -> bool:
|
func shouldQueueFree() -> bool:
|
||||||
if maxTargets == 0 || !is_instance_valid(target) && mode == Mode.FOLLOW:
|
if !is_instance_valid(target):
|
||||||
return true
|
return mode == Mode.FOLLOW || maxTargets == 0
|
||||||
elif mode != Mode.FOLLOW:
|
|
||||||
return isOnTarget()
|
|
||||||
elif target is Tower:
|
elif target is Tower:
|
||||||
return not target.visible
|
return not target.visible
|
||||||
|
|
||||||
return false
|
return maxTargets == 0
|
||||||
|
|
||||||
|
|
||||||
func isOnTarget() -> bool:
|
func isOnTarget() -> bool:
|
||||||
match mode:
|
match mode:
|
||||||
Mode.LOCATION, Mode.SPAWN_ON_TARGET: return vectorTarget.distance_squared_to(global_position) < .4
|
Mode.LOCATION: return vectorTarget.distance_squared_to(global_position) < .4
|
||||||
Mode.FOLLOW: return collidingBodies.has(target)
|
Mode.FOLLOW: return collidingBodies.has(target)
|
||||||
Mode.HITSCAN: return true
|
Mode.HITSCAN, Mode.SPAWN_ON_TARGET: return true
|
||||||
_: return false
|
_: return false
|
||||||
|
|
||||||
|
|
||||||
func resolveContact() -> void:
|
func applyEffects() -> void:
|
||||||
if collidingBodies.is_empty() || not isOnTarget():
|
if not collidingBodies.is_empty() && isOnTarget():
|
||||||
return
|
resolveContacts()
|
||||||
|
|
||||||
|
if effect == Effect.DAMAGE_OVER_TIME:
|
||||||
|
dotTicks -= 1
|
||||||
|
state = State.DESPAWN
|
||||||
|
if dotTicks > 0:
|
||||||
|
state = State.EFFECT
|
||||||
|
await get_tree().create_timer(tickInterval).timeout
|
||||||
|
applyEffects.call_deferred()
|
||||||
|
|
||||||
|
|
||||||
|
func resolveContacts() -> void:
|
||||||
match type:
|
match type:
|
||||||
Type.AOE:
|
Type.AOE:
|
||||||
|
if maxTargets > 0: # No need to sort if we want to hit all targets
|
||||||
|
collidingBodies.sort_custom(sortTargets)
|
||||||
collidingBodies.map(resolveEffect)
|
collidingBodies.map(resolveEffect)
|
||||||
_ when collidingBodies.has(target):
|
_ when collidingBodies.has(target):
|
||||||
resolveEffect(target)
|
resolveEffect(target)
|
||||||
if type == Type.BOUNCING:
|
if type == Type.BOUNCING:
|
||||||
target = null if bodiesInRange.is_empty() else bodiesInRange[0]
|
target = chooseNextTarget()
|
||||||
|
state = State.TRAVEL
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
func sortTargets(body1: Node3D, body2: Node3D) -> bool:
|
||||||
|
return vectorTarget.distance_to(body1.global_position) < vectorTarget.distance_to(body2.global_position)
|
||||||
|
|
||||||
|
|
||||||
|
func chooseNextTarget() -> Node3D:
|
||||||
|
var bodies = bodiesInRange.filter(func(body): return not affectedTarget.has(body))
|
||||||
|
if bodies.is_empty():
|
||||||
|
return null
|
||||||
|
bodies.sort_custom(sortTargets)
|
||||||
|
return bodies[0]
|
||||||
|
|
||||||
|
|
||||||
func resolveEffect(body : Node3D) -> void:
|
func resolveEffect(body : Node3D) -> void:
|
||||||
if affectedTarget.has(body) || body is GameTile || maxTargets == 0:
|
if body is GameTile || maxTargets == 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
if type == Type.DISABLING && body.has_method("disable"):
|
if type == Type.DISABLING && body.has_method("disable"):
|
||||||
|
|
@ -112,12 +153,21 @@ func resolveEffect(body : Node3D) -> void:
|
||||||
elif body.has_method("take_damage"):
|
elif body.has_method("take_damage"):
|
||||||
body.take_damage(amount)
|
body.take_damage(amount)
|
||||||
|
|
||||||
|
if effect == Effect.POISON:
|
||||||
|
dotTicks -= 1
|
||||||
|
while dotTicks > 0 && is_instance_valid(body):
|
||||||
|
dotTicks -= 1
|
||||||
|
await get_tree().create_timer(tickInterval).timeout
|
||||||
|
body.take_damage(amount)
|
||||||
|
|
||||||
affectedTarget.append(body)
|
affectedTarget.append(body)
|
||||||
maxTargets -= 1
|
maxTargets -= 1
|
||||||
|
state = State.DESPAWN
|
||||||
|
|
||||||
|
|
||||||
func shoot(_target: Node3D, globalPos: Vector3) -> void:
|
func shoot(_target: Node3D, globalPos: Vector3) -> void:
|
||||||
target = _target
|
target = _target
|
||||||
|
vectorTarget = globalPos
|
||||||
|
|
||||||
var transform3D : Transform3D = Transform3D()
|
var transform3D : Transform3D = Transform3D()
|
||||||
transform3D.origin = globalPos
|
transform3D.origin = globalPos
|
||||||
|
|
@ -127,12 +177,11 @@ func shoot(_target: Node3D, globalPos: Vector3) -> void:
|
||||||
transform3D = transform3D.looking_at(targetPosition)
|
transform3D = transform3D.looking_at(targetPosition)
|
||||||
match mode:
|
match mode:
|
||||||
Mode.SPAWN_ON_TARGET:
|
Mode.SPAWN_ON_TARGET:
|
||||||
|
vectorTarget = targetPosition
|
||||||
transform3D.origin = targetPosition
|
transform3D.origin = targetPosition
|
||||||
transform3D = transform3D.looking_at(globalPos)
|
transform3D = transform3D.looking_at(globalPos)
|
||||||
vectorTarget = targetPosition
|
|
||||||
Mode.LOCATION:
|
Mode.LOCATION:
|
||||||
vectorTarget = targetPosition
|
vectorTarget = targetPosition
|
||||||
velocity = transform3D.origin.direction_to(vectorTarget) * speed
|
velocity = transform3D.origin.direction_to(vectorTarget) * speed
|
||||||
|
|
||||||
print(transform3D)
|
|
||||||
EventBus.projectile_shooted.emit(self, transform3D)
|
EventBus.projectile_shooted.emit(self, transform3D)
|
||||||
|
|
|
||||||
41
Projectiles/Scenes/projectile-Evan.tscn
Normal file
41
Projectiles/Scenes/projectile-Evan.tscn
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
[gd_scene load_steps=7 format=3 uid="uid://dp8tg6cpu3ftd"]
|
||||||
|
|
||||||
|
[ext_resource type="PackedScene" uid="uid://oykrff3g74eo" path="res://Projectiles/projectile.tscn" id="1_yw5ty"]
|
||||||
|
|
||||||
|
[sub_resource type="SphereShape3D" id="SphereShape3D_xshf4"]
|
||||||
|
|
||||||
|
[sub_resource type="Gradient" id="Gradient_yw5ty"]
|
||||||
|
offsets = PackedFloat32Array(0, 0.5, 1)
|
||||||
|
colors = PackedColorArray(1, 0.007843138, 0, 1, 1, 0.54901963, 0, 1, 1, 0, 0, 1)
|
||||||
|
metadata/_snap_enabled = true
|
||||||
|
|
||||||
|
[sub_resource type="GradientTexture1D" id="GradientTexture1D_xshf4"]
|
||||||
|
gradient = SubResource("Gradient_yw5ty")
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_yw5ty"]
|
||||||
|
transparency = 4
|
||||||
|
albedo_color = Color(1, 1, 1, 0.43137255)
|
||||||
|
albedo_texture = SubResource("GradientTexture1D_xshf4")
|
||||||
|
|
||||||
|
[sub_resource type="SphereMesh" id="SphereMesh_q317a"]
|
||||||
|
material = SubResource("StandardMaterial3D_yw5ty")
|
||||||
|
|
||||||
|
[node name="Projectile" instance=ExtResource("1_yw5ty")]
|
||||||
|
mode = 2
|
||||||
|
effect = 1
|
||||||
|
type = 1
|
||||||
|
maxTargets = -1
|
||||||
|
dotTicks = 6
|
||||||
|
tickInterval = 0.5
|
||||||
|
|
||||||
|
[node name="Sprite3D" parent="." index="1"]
|
||||||
|
visible = false
|
||||||
|
|
||||||
|
[node name="HitBox" parent="." index="2"]
|
||||||
|
collision_mask = 2
|
||||||
|
|
||||||
|
[node name="ProjectileSize" parent="HitBox" index="0"]
|
||||||
|
shape = SubResource("SphereShape3D_xshf4")
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="." index="4"]
|
||||||
|
mesh = SubResource("SphereMesh_q317a")
|
||||||
|
|
@ -2,16 +2,18 @@
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://oykrff3g74eo" path="res://Projectiles/projectile.tscn" id="1_suva6"]
|
[ext_resource type="PackedScene" uid="uid://oykrff3g74eo" path="res://Projectiles/projectile.tscn" id="1_suva6"]
|
||||||
|
|
||||||
[sub_resource type="SphereShape3D" id="SphereShape3D_k24mn"]
|
[sub_resource type="SphereShape3D" id="SphereShape3D_878kj"]
|
||||||
radius = 1.5
|
|
||||||
|
|
||||||
[node name="Projectile" instance=ExtResource("1_suva6")]
|
[node name="Projectile" instance=ExtResource("1_suva6")]
|
||||||
type = 2
|
type = 2
|
||||||
speed = 5
|
speed = 5
|
||||||
maxTargets = 3
|
maxTargets = 3
|
||||||
|
|
||||||
[node name="DamageArea#BoucingRange" type="CollisionShape3D" parent="." index="0"]
|
[node name="HitBox" parent="." index="2"]
|
||||||
shape = SubResource("SphereShape3D_k24mn")
|
|
||||||
|
|
||||||
[node name="HitBox" parent="." index="3"]
|
|
||||||
collision_mask = 2
|
collision_mask = 2
|
||||||
|
|
||||||
|
[node name="EffectArea" parent="." index="3"]
|
||||||
|
collision_mask = 2
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="EffectArea" index="0"]
|
||||||
|
shape = SubResource("SphereShape3D_878kj")
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
[gd_scene load_steps=5 format=3 uid="uid://c4ta0aynybpis"]
|
[gd_scene load_steps=6 format=3 uid="uid://c4ta0aynybpis"]
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://trg7ag3dqr2l" path="res://Towers/tower.tscn" id="1_yctfx"]
|
[ext_resource type="PackedScene" uid="uid://trg7ag3dqr2l" path="res://Towers/tower.tscn" id="1_yctfx"]
|
||||||
[ext_resource type="Texture2D" uid="uid://dwwgho6f8f4kj" path="res://Assets/Icones/penguin.svg" id="2_5uh04"]
|
[ext_resource type="Texture2D" uid="uid://dwwgho6f8f4kj" path="res://Assets/Icones/penguin.svg" id="2_5uh04"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://dp8tg6cpu3ftd" path="res://Projectiles/Scenes/projectile-Evan.tscn" id="3_5uh04"]
|
||||||
|
|
||||||
[sub_resource type="SphereShape3D" id="SphereShape3D_y05yr"]
|
[sub_resource type="SphereShape3D" id="SphereShape3D_y05yr"]
|
||||||
radius = 4.0
|
radius = 4.0
|
||||||
|
|
@ -14,7 +15,14 @@ tower_name = "Evan"
|
||||||
type = 5
|
type = 5
|
||||||
icone = ExtResource("2_5uh04")
|
icone = ExtResource("2_5uh04")
|
||||||
bio = ""
|
bio = ""
|
||||||
|
price = 300
|
||||||
|
damage = 1
|
||||||
|
projectileScene = ExtResource("3_5uh04")
|
||||||
towerRange = SubResource("SphereShape3D_y05yr")
|
towerRange = SubResource("SphereShape3D_y05yr")
|
||||||
|
action_cooldown = 3.0
|
||||||
|
max_energy = 30.0
|
||||||
|
energy_regen = 5.0
|
||||||
|
energy_cost = 10.0
|
||||||
|
|
||||||
[node name="EnergyBar3D" parent="." index="6"]
|
[node name="EnergyBar3D" parent="." index="6"]
|
||||||
texture = SubResource("ViewportTexture_fegyx")
|
texture = SubResource("ViewportTexture_fegyx")
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue