Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Navigation AStar Hexagonal demo #1085

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions 2d/navigation_astar_hexagonal/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Tile-based navigation on hexagonal Tilemap (2D)

Example of using 2D navigation (tile based) on a hexagonal map, using :
- [`TileMap`](https://docs.godotengine.org/en/stable/classes/class_tilemap.html)
- [`AStar2D`](https://docs.godotengine.org/en/stable/classes/class_astar2d.html)

Language: GDScript

Renderer: Compatibility

Use mouse left click to interact.

## Screenshots

![Screenshot](screenshots/Hexagon_Navigation_2D.png)
28 changes: 28 additions & 0 deletions 2d/navigation_astar_hexagonal/astar_hex_2d.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
class_name AStarHex2D
extends AStar2D

var map: TileMap


# Final cost used for pathfinding would be weight * cost.
# See https://docs.godotengine.org/fr/4.x/classes/class_astar3d.html#class-astar3d
func _compute_cost(_from_id: int, _to_id: int):
return 1


func _estimate_cost(_from_id: int, _to_id: int):
return 1

# Euclidian distance heuristic would not work on hexagonal map with global position because
# we are not using regular hexagon.
# https://github.com/godotengine/godot/issues/92338

#func _compute_cost( from_id:int, to_id:int ):
#var position_from = get_point_position(from_id)
#var position_to = get_point_position(to_id)
#return (position_to - position_from).length_squared()

#func _estimate_cost( from_id:int, to_id:int ):
#var position_from = get_point_position(from_id)
#var position_to = get_point_position(to_id)
#return (position_to - position_from).length_squared()
139 changes: 139 additions & 0 deletions 2d/navigation_astar_hexagonal/debug/debug_astar.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
extends Node2D

const BASE_LINE_WIDTH = 3.0
const DRAW_COLOR: Color = Color.WHITE
const OFFSET_POSITIONS = Vector2(10, 30)
const OFFSET_WEIGHT = Vector2(10, -10)

@export var map: Map

var _debug_connections = false
var _debug_position = false
var _debug_weights = false
var _debug_costs = false
var _debug_path = true

@onready var _font: Font = ThemeDB.fallback_font


func _process(_delta):
queue_redraw()


func draw_arrow(src, dst, color, width, aa = true):
var angle = 0.6
var size_head = 20
var head: Vector2 = (dst - src).normalized() * size_head
draw_line(src, dst - head / 2, color, width, aa)
draw_polygon(
[dst, dst - head.rotated(angle), dst - head.rotated(-angle)], [color, color, color]
)


func _draw():
if _debug_connections:
_draw_connections()
if _debug_position:
_draw_positions()
if _debug_weights:
_draw_weights()
if _debug_costs:
_draw_costs()
if _debug_path:
_draw_path()


func _draw_path():
if not map._point_path:
return
var point_start: Vector2i = map._point_path[0]
var point_end: Vector2i = map._point_path[len(map._point_path) - 1]

var last_point = point_start
for index in range(1, len(map._point_path)):
var current_point = map._point_path[index]
draw_line(last_point, current_point, DRAW_COLOR, BASE_LINE_WIDTH, true)
draw_circle(current_point, BASE_LINE_WIDTH * 2.0, DRAW_COLOR)
last_point = current_point


func _draw_weights():
for id in map.astar_node.get_point_ids():
var position_weight = map.astar_node.get_point_position(id)
var cost = map.astar_node.get_point_weight_scale(id)
draw_string(
_font,
position_weight + OFFSET_WEIGHT,
str(cost),
HORIZONTAL_ALIGNMENT_FILL,
-1,
16,
Color.RED
)


func _draw_positions():
for id in map.astar_node.get_point_ids():
var position_label = map.astar_node.get_point_position(id)
var position_map = map.local_to_map(map.to_local(map.astar_node.get_point_position(id)))
draw_string(
_font,
position_label + OFFSET_POSITIONS,
str(position_map),
HORIZONTAL_ALIGNMENT_FILL,
-1,
16,
Color.RED
)


func _draw_connections():
for id in map.astar_node.get_point_ids():
for id_con in map.astar_node.get_point_connections(id):
var position_start = map.astar_node.get_point_position(id)
var position_end = map.astar_node.get_point_position(id_con)
var direction = position_end - position_start
draw_arrow(
position_start,
position_end - direction / 4.0,
Color(0.0, 1.0, 1.0, 1.0),
BASE_LINE_WIDTH * 2,
true
)


func _draw_costs():
for id in map.astar_node.get_point_ids():
for id_con in map.astar_node.get_point_connections(id):
var position_cost_start = map.astar_node.get_point_position(id)
var position_cost_end = map.astar_node.get_point_position(id_con)
var cost = map.astar_node._compute_cost(id, id_con)
draw_string(
_font,
(position_cost_start + position_cost_end) / 2.0,
str("%.2f" % cost),
HORIZONTAL_ALIGNMENT_CENTER,
-1,
16,
Color.PINK
)


func _on_d_path_toggled(toggled_on):
_debug_path = toggled_on


func _on_d_costs_toggled(toggled_on):
_debug_costs = toggled_on


func _on_d_positions_toggled(toggled_on):
_debug_position = toggled_on


func _on_d_connections_toggled(toggled_on):
_debug_connections = toggled_on


func _on_d_weights_toggled(toggled_on):
_debug_weights = toggled_on
121 changes: 121 additions & 0 deletions 2d/navigation_astar_hexagonal/icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 37 additions & 0 deletions 2d/navigation_astar_hexagonal/icon.svg.import
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
[remap]

importer="texture"
type="CompressedTexture2D"
uid="uid://brh8t0d5w2mkc"
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://icon.svg"
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]

[params]

compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false
Binary file added 2d/navigation_astar_hexagonal/icon.webp
Binary file not shown.
34 changes: 34 additions & 0 deletions 2d/navigation_astar_hexagonal/icon.webp.import
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[remap]

importer="texture"
type="CompressedTexture2D"
uid="uid://bnujvgksdtkex"
path="res://.godot/imported/icon.webp-e94f9a68b0f625a567a797079e4d325f.ctex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://icon.webp"
dest_files=["res://.godot/imported/icon.webp-e94f9a68b0f625a567a797079e4d325f.ctex"]

[params]

compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Loading