Godot Version
4.3.stable
Question
I’ve been messing around with godot for about a week now and I’ve been looking at just about anything I can find on google related to hexagonal tile maps in 3D. I created a learning environment of sorts that I need help with so I can teach myself (with chatgpt) how to implement pathfinding, collisions, and eventual height traversal. Currently I have the script to make a map but cant seem to figure out how to get a coordinate system working. Can anyone provide some advice on how to handle this? I’m also trying to get the coordinates of each hex shown (currently using label3d) on top of each tile if anyone has advice on this as well.
Learning godot from scratch seems to be the equivalent of drinking from a fire hydrant.
I have 2 scripts for the map.
extends Node3D
# Grid coordinates for the hex cell
var coordinates: Vector2 = Vector2.ZERO
# Set the coordinates of the cell
func set_coordinates(x: int, z: int) -> void:
coordinates = Vector2(x, z)
update_label_text()
# Set the color of the cell
func set_color(color: Color) -> void:
if $MeshInstance3D.material_override is StandardMaterial3D:
$MeshInstance3D.material_override.albedo_color = color
# Update the Label3D text to display grid coordinates
func update_label_text() -> void:
# Ensure the Label3D node exists and update its text
if $Label3D:
$Label3D.text = "({}, {})".format(str((coordinates.x)), str((coordinates.y)))
# Optional: Identify this node as a hex cell
func is_hex_cell() -> bool:
return true
and
extends Node3D # Ensure the root extends Node3D for 3D environments
# Constants for hexagon metrics
const OUTER_RADIUS: float = 1
const INNER_RADIUS: float = OUTER_RADIUS * 0.866025404
const CORNERS: Array[Vector3] = [
Vector3(0, 0, OUTER_RADIUS),
Vector3(INNER_RADIUS, 0, OUTER_RADIUS * 0.5),
Vector3(INNER_RADIUS, 0, -OUTER_RADIUS * 0.5),
Vector3(0, 0, -OUTER_RADIUS),
Vector3(-INNER_RADIUS, 0, -OUTER_RADIUS * 0.5),
Vector3(-INNER_RADIUS, 0, OUTER_RADIUS * 0.5)
]
# Grid configuration
@export var grid_width: int = 6
@export var grid_height: int = 6
# Colors for cells
@export var default_color: Color = Color(1, 1, 1)
@export var touched_color: Color = Color(1, 0, 0)
# Packed scene for HexCell
@export var cell_scene: PackedScene # Drag `HexCell.tscn` here in the editor
# Storage for cells
var cells: Array = []
# Called when the node is added to the scene
func _ready() -> void:
create_grid()
# Create the grid of hexagonal cells
func create_grid() -> void:
for z in range(grid_height):
for x in range(grid_width):
create_cell(x, z)
# Create a single hex cell at a specific grid position
func create_cell(x: int, z: int) -> void:
# Create a new instance of the HexCell scene
var cell = cell_scene.instantiate()
add_child(cell) # Add the cell to the HexGrid node
# Calculate position based on hexagonal grid layout
var cell_position = Vector3(
(x + z * 0.5 - int(z / 2)) * INNER_RADIUS * 2, # X position
0, # Y position (flat grid, no height for now)
z * OUTER_RADIUS * 1.5 # Z position
)
cell.position = cell_position # Set the position of the Node3D root
# Set cell properties
cell.set_coordinates(x, z) # Assign coordinates
cell.set_color(default_color) # Assign default color
# Add the cell to the list for future reference
cells.append(cell)
# Handle mouse input for interacting with the grid
func _input(event: InputEvent) -> void:
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
var cell = get_cell_under_mouse()
if cell:
cell.set_color(touched_color)
# Get the hex cell under the mouse cursor using raycasting
func get_cell_under_mouse() -> Node:
var camera = get_viewport().get_camera_3d()
if not camera:
return null
var mouse_pos = get_viewport().get_mouse_position()
var ray_origin = camera.project_ray_origin(mouse_pos)
var ray_dir = camera.project_ray_normal(mouse_pos)
# Create the ray query
var ray_query = PhysicsRayQueryParameters3D.new()
ray_query.from = ray_origin
ray_query.to = ray_origin + ray_dir * 1000
# Perform the raycast
var result = get_world_3d().direct_space_state.intersect_ray(ray_query)
if result and result.collider.has_method("is_hex_cell"):
return result.collider
return null
here is a snip of it running