extends Node3D class_name TowerManager @onready var cam : Camera3D = $"../Camera3D" @onready var selection_icon : Sprite3D = $Sprite3DSelection var usedLocations : Dictionary var selectedTile : Vector3 var selected_tower : Tower var buildedTower : int = 0 var is_on_gui : bool = false func _ready() -> void: EventBus.tower_selected.connect(onTowerSelect) #$AnimationPlayer.play("arrow_bobbing") EventBus.mouse_entered_gui.connect(onMouseEnteredGui) EventBus.mouse_exited_gui.connect(onMouseExitedGui) Game.allowed_tower_has_change.connect(connectTowerSignals) 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()) selection_icon.frame = 5 selection_icon.axis = Vector3.Axis.AXIS_Y selection_icon.pixel_size = .03 else: selection_icon.frame = 68 selection_icon.pixel_size = .02 if collider is Tower else .01 selection_icon.axis = Vector3.Axis.AXIS_Z if collider is Tower: tower = collider if Input.is_action_just_pressed("build"): if tower == selected_tower && selected_tower: return if isTileAndFree(collider): placeTower() elif tower: selectTower(tower.type) elif collider is TheCube: selected_tower = null EventBus.cube_selected.emit() if Input.is_action_just_pressed("rest"): if tower: moveTower(tower, Vector3.INF) if tower != selected_tower: EventBus.tower_selected.emit(tower.type) else: EventBus.tower_selected.emit(Tower.TYPE.NONE) func _input(event: InputEvent) -> void: if event is InputEventKey: handleTowerShortCuts(event) func handle_player_controls() -> CollisionObject3D: #If the player has the mouse on the GUI, player can't place tower if is_on_gui: return 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 : CollisionObject3D = ray_result.get("collider") visible = true selection_icon.visible = true global_position = collider.global_position 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 selection_icon.visible = false # If we are placing a tower, hide the selector model if isTileAndFree(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 selected_tower.state == Tower.STATE.BLUEPRINT: if not selected_tower.build(): return buildedTower += 1 EventBus.tower_count_changed.emit(buildedTower) remove_child(selected_tower) $"../Towers".add_child(selected_tower) moveTower(selected_tower, global_position) func isTileAndFree(collider: CollisionObject3D) -> bool: return collider is GameTile && collider.type == GameTile.TYPE.TOWER \ && not usedLocations.has(collider.global_position.round()) ## 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.changeState(Tower.STATE.REST) else: usedLocations.set(toPosition.round(), tower) tower.global_position = toPosition tower.changeState(Tower.STATE.ACTION) var inAction : int = usedLocations.size() EventBus.team_in_action_changed.emit(inAction) EventBus.team_in_rest_changed.emit(buildedTower - inAction) func onTowerSelect(towerType: Tower.TYPE): # Hide current not builded tower if selected_tower && selected_tower.state == Tower.STATE.BLUEPRINT: selected_tower.visible = false if selected_tower && selected_tower.type == towerType || towerType == Tower.TYPE.NONE: if selected_tower && selected_tower.state == Tower.STATE.BLUEPRINT: remove_child(selected_tower) selected_tower = null else: selected_tower = Game.towers.get(towerType) if selected_tower.state == Tower.STATE.BLUEPRINT: selected_tower.visible = true add_child(selected_tower) func selectTower(towerType: Tower.TYPE, force : bool = false) -> void: if towerType && (force || not selected_tower || selected_tower.state): EventBus.tower_selected.emit(towerType) func handleTowerShortCuts(event: InputEventKey) -> void: if event.pressed: return var towerType : Tower.TYPE = Tower.TYPE.NONE match event.physical_keycode: KEY_Q: towerType = Tower.TYPE.PIERRE KEY_W: towerType = Tower.TYPE.ALINE KEY_E: towerType = Tower.TYPE.MAXENCE KEY_R: towerType = Tower.TYPE.VICTORIA KEY_A: towerType = Tower.TYPE.EVAN KEY_S: towerType = Tower.TYPE.ALEX KEY_D: towerType = Tower.TYPE.GERALDINE #KEY_F: towerType = Tower.TYPE if Game.towers.has(towerType): selectTower(towerType, true) func onMouseEnteredGui() -> void: is_on_gui = true func onMouseExitedGui() -> void: is_on_gui = false func connectTowerSignals() -> void: for tower : Tower in Game.towers.values(): tower.state_changed.connect(onTowerStateChange.bind(tower)) func onTowerStateChange(tower : Tower) -> void: if tower.state == Tower.STATE.DISABLED && tower == selected_tower: EventBus.tower_selected.emit(Tower.TYPE.NONE) moveTower(tower, Vector3.INF)