extends Node3D class_name TowerManager @onready var cam : Camera3D = $"../Camera3D" @onready var selection_icon : Sprite3D = $Sprite3DSelection var towers : Dictionary var usedLocations : Dictionary var selectedTile : Vector3 var selected_tower : Tower func _ready() -> void: EventBus.tower_selected.connect(selectTower) #$AnimationPlayer.play("arrow_bobbing") func _process(_delta: float) -> void: var collider : CollisionObject3D = handle_player_controls() var tower : Tower if collider is GameTile: tower = usedLocations.get(collider.global_position.round()) if Input.is_action_just_pressed("build"): if not collider is GameTile: return if isTileFree(collider): placeTower() elif tower && selected_tower.builded: EventBus.tower_selected.emit(tower.tower_type) if Input.is_action_just_pressed("rest"): if tower: moveTower(tower, Vector3.INF) else: EventBus.tower_selected.emit(Tower.TYPE.NONE) func handle_player_controls() -> Node3D: var space_state : PhysicsDirectSpaceState3D = get_world_3d().direct_space_state var mouse_pos : Vector2 = get_viewport().get_mouse_position() var origin : Vector3 = cam.project_ray_origin(mouse_pos) var end : Vector3 = origin + cam.project_ray_normal(mouse_pos) * 100 var ray : PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.create(origin, end) ray.collide_with_bodies = true var ray_result : Dictionary = space_state.intersect_ray(ray) if ray_result.is_empty(): visible = false return null var collider : Node3D = ray_result.get("collider") visible = true selection_icon.visible = true global_position = collider.global_position + Vector3(0.0, 0.21, 0.0) if selected_tower && not selected_tower.builded: selected_tower.sprite.modulate = "ff4545c8" # If the tower can't be placed he is red selection_icon.visible = false # If we are placing a tower, hide the selector model if collider is GameTile && isTileFree(collider): selected_tower.sprite.modulate = "61ff45c8" # If the tower can be placed he is green return collider func placeTower() -> void: if not selected_tower: return if not selected_tower.builded: if not selected_tower.build(): return remove_child(selected_tower) $"../Towers".add_child(selected_tower) moveTower(selected_tower, global_position) func isTileFree(tile: GameTile) -> bool: return not usedLocations.has(tile.global_position.round()) \ && tile.type == GameTile.TYPE.TOWER ## Set [param toPosition] with [Vector3.INF] to make the tower rest func moveTower(tower: Tower, toPosition: Vector3) -> void: usedLocations.erase(tower.global_position.round()) if toPosition == Vector3.INF: tower.resting() else: usedLocations.set(global_position.round(), tower) tower.global_position = toPosition tower.in_action() emitTeamChanges() func selectTower(towerType: Tower.TYPE): # Hide current not builded tower if selected_tower && not selected_tower.builded: selected_tower.visible = false if selected_tower && selected_tower.tower_type == towerType || towerType == Tower.TYPE.NONE: selected_tower = null elif towers.has(towerType): selected_tower = towers.get(towerType) selected_tower.visible = true else: selected_tower = Game.towers.get(towerType).instantiate() towers.set(towerType, selected_tower) add_child(selected_tower) func emitTeamChanges() -> void: var team_in_action : int = 0 var team_in_rest : int = 0 var tower_count : int = 0 for towerType in towers: var tower : Tower = towers[towerType] if tower.builded: tower_count += 1 if tower.is_rest: team_in_rest += 1 else: team_in_action += 1 EventBus.team_in_action_changed.emit(team_in_action) EventBus.team_in_rest_changed.emit(team_in_rest) EventBus.tower_count_changed.emit(tower_count)