upgrade: godot 4.5 #6
					 5 changed files with 140 additions and 39 deletions
				
			
		|  | @ -73,13 +73,14 @@ static func showConfirmPopup( | |||
| 	text : String, | ||||
| 	nodeToAppend : Node, | ||||
| 	confirmCallback : Callable, | ||||
| 	cancelCallback : Callable = func(): null | ||||
| 	cancelCallback : Callable = func(): pass | ||||
| ) -> void: | ||||
| 	var confirmPopup : ConfirmPopup = CONFIRM_POPUP.instantiate() | ||||
| 	nodeToAppend.add_child(confirmPopup) | ||||
| 	nodeToAppend.get_tree().paused = true | ||||
| 	confirmPopup.label.text = text | ||||
| 	confirmPopup.confirmed.connect(confirmCallback) | ||||
| 	confirmPopup.canceled.connect(cancelCallback) | ||||
| 	confirmPopup.confirmed.connect(func(): confirmCallback.call(); nodeToAppend.get_tree().paused = false) | ||||
| 	confirmPopup.canceled.connect(func(): cancelCallback.call(); nodeToAppend.get_tree().paused = false) | ||||
| 
 | ||||
| enum POSITION { TOP, CENTER, DOWN } | ||||
| static func getHitBoxLocation(body : CollisionObject3D, position : POSITION) -> float: | ||||
|  |  | |||
|  | @ -2,6 +2,9 @@ extends CharacterBody3D | |||
| class_name Projectile | ||||
| 
 | ||||
| 
 | ||||
| enum State { INIT, TRAVEL, EFFECT, DESPAWN } | ||||
| 
 | ||||
| 
 | ||||
| enum Mode { | ||||
| 	FOLLOW, ## Follow target | ||||
| 	LOCATION, ## Go to target location | ||||
|  | @ -9,9 +12,15 @@ enum Mode { | |||
| 	HITSCAN, ## Spawn on target location | ||||
| } | ||||
| 
 | ||||
| enum Duration { | ||||
| 
 | ||||
| enum Effect { | ||||
| 	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 | ||||
|  | @ -23,14 +32,17 @@ enum Type { ## Types of projectiles | |||
| 
 | ||||
| 
 | ||||
| @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 speed : int | ||||
| ## Usefull when [enum Type] is not [constant BASIC][br] | ||||
| ## [code]-1[/code] for no maximum | ||||
| ## Used as time when [enum Duration] is [constant HITSCAN] | ||||
| ## Usefull when [enum Type] is not [constant BASIC][br][code]-1[/code] for no maximum | ||||
| @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 target : PhysicsBody3D | ||||
| var vectorTarget : Vector3 | ||||
|  | @ -41,25 +53,30 @@ var affectedTarget : Array[Node3D] | |||
| 
 | ||||
| func _ready() -> void: | ||||
| 	$HitBox.body_entered.connect(collidingBodies.append) | ||||
| 	#$HitBox.body_entered.connect(test) | ||||
| 	$HitBox.body_exited.connect(collidingBodies.erase) | ||||
| 	$EffectArea.body_entered.connect(bodiesInRange.append) | ||||
| 	$EffectArea.body_exited.connect(bodiesInRange.erase) | ||||
| 
 | ||||
| 
 | ||||
| func test(body): | ||||
| 	print(body) | ||||
| 
 | ||||
| var firstTick : bool = true | ||||
| func _physics_process(_delta: float) -> void: | ||||
| 	if firstTick: | ||||
| 		firstTick = false | ||||
| 	if state == State.INIT: | ||||
| 		state = State.TRAVEL | ||||
| 		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(): | ||||
| 		queue_free.call_deferred() | ||||
| 		state = State.DESPAWN | ||||
| 
 | ||||
| 	if state != State.TRAVEL: | ||||
| 		return | ||||
| 
 | ||||
| 	if mode == Mode.FOLLOW: | ||||
|  | @ -72,39 +89,63 @@ func _physics_process(_delta: float) -> void: | |||
| 
 | ||||
| 
 | ||||
| func shouldQueueFree() -> bool: | ||||
| 	if maxTargets == 0 || !is_instance_valid(target) && mode == Mode.FOLLOW: | ||||
| 		return true | ||||
| 	elif mode != Mode.FOLLOW: | ||||
| 		return isOnTarget() | ||||
| 	if !is_instance_valid(target): | ||||
| 		return mode == Mode.FOLLOW || maxTargets == 0 | ||||
| 	elif target is Tower: | ||||
| 		return not target.visible | ||||
| 
 | ||||
| 	return false | ||||
| 	return maxTargets == 0 | ||||
| 
 | ||||
| 
 | ||||
| func isOnTarget() -> bool: | ||||
| 	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.HITSCAN: return true | ||||
| 		Mode.HITSCAN, Mode.SPAWN_ON_TARGET: return true | ||||
| 		_: return false | ||||
| 
 | ||||
| 
 | ||||
| func resolveContact() -> void: | ||||
| 	if collidingBodies.is_empty() || not isOnTarget(): | ||||
| 		return | ||||
| func applyEffects() -> void: | ||||
| 	if not collidingBodies.is_empty() && isOnTarget(): | ||||
| 		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: | ||||
| 		Type.AOE: | ||||
| 			if maxTargets > 0: # No need to sort if we want to hit all targets | ||||
| 				collidingBodies.sort_custom(sortTargets) | ||||
| 			collidingBodies.map(resolveEffect) | ||||
| 		_ when collidingBodies.has(target): | ||||
| 			resolveEffect(target) | ||||
| 			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: | ||||
| 	if affectedTarget.has(body) || body is GameTile || maxTargets == 0: | ||||
| 	if body is GameTile || maxTargets == 0: | ||||
| 		return | ||||
| 
 | ||||
| 	if type == Type.DISABLING && body.has_method("disable"): | ||||
|  | @ -112,12 +153,21 @@ func resolveEffect(body : Node3D) -> void: | |||
| 	elif body.has_method("take_damage"): | ||||
| 		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) | ||||
| 	maxTargets -= 1 | ||||
| 	state = State.DESPAWN | ||||
| 
 | ||||
| 
 | ||||
| func shoot(_target: Node3D, globalPos: Vector3) -> void: | ||||
| 	target = _target | ||||
| 	vectorTarget = globalPos | ||||
| 
 | ||||
| 	var transform3D : Transform3D = Transform3D() | ||||
| 	transform3D.origin = globalPos | ||||
|  | @ -127,12 +177,11 @@ func shoot(_target: Node3D, globalPos: Vector3) -> void: | |||
| 	transform3D = transform3D.looking_at(targetPosition) | ||||
| 	match mode: | ||||
| 		Mode.SPAWN_ON_TARGET: | ||||
| 			vectorTarget = targetPosition | ||||
| 			transform3D.origin = targetPosition | ||||
| 			transform3D = transform3D.looking_at(globalPos) | ||||
| 			vectorTarget = targetPosition | ||||
| 		Mode.LOCATION: | ||||
| 			vectorTarget = targetPosition | ||||
| 			velocity = transform3D.origin.direction_to(vectorTarget) * speed | ||||
| 
 | ||||
| 	print(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"] | ||||
| 
 | ||||
| [sub_resource type="SphereShape3D" id="SphereShape3D_k24mn"] | ||||
| radius = 1.5 | ||||
| [sub_resource type="SphereShape3D" id="SphereShape3D_878kj"] | ||||
| 
 | ||||
| [node name="Projectile" instance=ExtResource("1_suva6")] | ||||
| type = 2 | ||||
| speed = 5 | ||||
| maxTargets = 3 | ||||
| 
 | ||||
| [node name="DamageArea#BoucingRange" type="CollisionShape3D" parent="." index="0"] | ||||
| shape = SubResource("SphereShape3D_k24mn") | ||||
| 
 | ||||
| [node name="HitBox" parent="." index="3"] | ||||
| [node name="HitBox" parent="." index="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="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"] | ||||
| radius = 4.0 | ||||
|  | @ -14,7 +15,14 @@ tower_name = "Evan" | |||
| type = 5 | ||||
| icone = ExtResource("2_5uh04") | ||||
| bio = "" | ||||
| price = 300 | ||||
| damage = 1 | ||||
| projectileScene = ExtResource("3_5uh04") | ||||
| 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"] | ||||
| texture = SubResource("ViewportTexture_fegyx") | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue