Files
godot-playground/scenes/Grid/grid_highlight_controller.gd

81 lines
2.5 KiB
GDScript

@tool
extends MeshInstance3D
class_name GridHighlightController
@export var grid_manager_path: NodePath
@export var camera_path: NodePath
var _grid_manager: GridPlaneManager = null
var _camera: Camera3D = null
var _hovered_cell: Vector2i = Vector2i(-1, -1)
func _ready() -> void:
set_process(true)
_resolve_references()
_refresh_mesh()
if _grid_manager:
_grid_manager.grid_layout_changed.connect(_on_grid_layout_changed)
func _on_grid_layout_changed(_cells: Dictionary) -> void:
_refresh_mesh()
_hovered_cell = Vector2i(-1, -1)
visible = false
func _process(_delta: float) -> void:
if Engine.is_editor_hint():
return
if not _grid_manager or not _camera:
return
var viewport: Viewport = get_viewport()
if viewport == null:
return
var mouse_position: Vector2 = viewport.get_mouse_position()
_update_hovered_cell(mouse_position)
func _resolve_references() -> void:
if grid_manager_path != NodePath():
_grid_manager = get_node_or_null(grid_manager_path) as GridPlaneManager
else:
_grid_manager = get_parent() as GridPlaneManager
if camera_path != NodePath():
_camera = get_node_or_null(camera_path) as Camera3D
func _refresh_mesh() -> void:
if not _grid_manager:
return
mesh = _grid_manager.make_highlight_mesh()
visible = false
func _update_hovered_cell(mouse_position: Vector2) -> void:
var ray_origin: Vector3 = _camera.project_ray_origin(mouse_position)
var ray_direction: Vector3 = _camera.project_ray_normal(mouse_position)
var plane_normal: Vector3 = _grid_manager.global_transform.basis.y.normalized()
var plane_point: Vector3 = _grid_manager.global_transform.origin
var denominator: float = plane_normal.dot(ray_direction)
if abs(denominator) < 0.0001:
_set_hover_visible(false)
return
var t: float = plane_normal.dot(plane_point - ray_origin) / denominator
if t <= 0.0:
_set_hover_visible(false)
return
var world_point: Vector3 = ray_origin + ray_direction * t
var cell_index: Vector2i = _grid_manager.world_to_cell(world_point, false)
if cell_index.x < 0 or cell_index.y < 0 or not _grid_manager.has_cell(cell_index):
_set_hover_visible(false)
return
if cell_index == _hovered_cell:
return
_hovered_cell = cell_index
var local_center: Vector3 = _grid_manager.cell_to_world(cell_index)
var target_position: Vector3 = _grid_manager.to_global(local_center)
global_position = target_position + plane_normal * 0.02
_set_hover_visible(true)
func _set_hover_visible(state: bool) -> void:
if not state:
visible = false
_hovered_cell = Vector2i(-1, -1)
else:
visible = true