commit 4b5d01c2a79dc8084041f1b3af6bc9a17342d0c2 Author: Katja Date: Mon May 20 16:31:11 2024 +0200 Initial commit. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..54b4bd8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.obj +*.exp +*.lib +.sconsign.dblite +*.dll diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..ad039fc --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "godot-cpp"] + path = godot-cpp + url = https://github.com/godotengine/godot-cpp + branch = 4.2 diff --git a/SConstruct b/SConstruct new file mode 100644 index 0000000..74d9e6d --- /dev/null +++ b/SConstruct @@ -0,0 +1,32 @@ +#!/usr/bin/env python +import os +import sys + +env = SConscript("godot-cpp/SConstruct") + +# For reference: +# - CCFLAGS are compilation flags shared between C and C++ +# - CFLAGS are for C-specific compilation flags +# - CXXFLAGS are for C++-specific compilation flags +# - CPPFLAGS are for pre-processor flags +# - CPPDEFINES are for pre-processor defines +# - LINKFLAGS are for linking flags + +# tweak this if you want to use different folders, or more folders, to store your source code in. +env.Append(CPPPATH=["src/"]) +sources = Glob("src/*.cpp") + +if env["platform"] == "macos": + library = env.SharedLibrary( + "demo/bin/libMultilevelAStarExt.{}.{}.framework/libMultilevelAStarExt.{}.{}".format( + env["platform"], env["target"], env["platform"], env["target"] + ), + source=sources, + ) +else: + library = env.SharedLibrary( + "demo/bin/libMultilevelAStarExt{}{}".format(env["suffix"], env["SHLIBSUFFIX"]), + source=sources, + ) + +Default(library) diff --git a/build.cmd b/build.cmd new file mode 100644 index 0000000..8f98c94 --- /dev/null +++ b/build.cmd @@ -0,0 +1 @@ +scons platform=windows diff --git a/demo/.gitattributes b/demo/.gitattributes new file mode 100644 index 0000000..8ad74f7 --- /dev/null +++ b/demo/.gitattributes @@ -0,0 +1,2 @@ +# Normalize EOL for all files that Git considers text files. +* text=auto eol=lf diff --git a/demo/.gitignore b/demo/.gitignore new file mode 100644 index 0000000..78e73a1 --- /dev/null +++ b/demo/.gitignore @@ -0,0 +1,5 @@ +# Godot 4+ specific ignores +.godot/ + +# Misc +*.tmp diff --git a/demo/bin/MultilevelAStarExt.gdextension b/demo/bin/MultilevelAStarExt.gdextension new file mode 100644 index 0000000..fe82ee4 --- /dev/null +++ b/demo/bin/MultilevelAStarExt.gdextension @@ -0,0 +1,13 @@ +[configuration] + +entry_symbol = "my_astar_ext_init" +compatibility_minimum = "4.2" + +[libraries] + +macos.debug = "res://bin/libMultilevelAStarExt.macos.template_debug.framework" +macos.release = "res://bin/libMultilevelAStarExt.macos.template_release.framework" +windows.debug.x86_64 = "res://bin/libMultilevelAStarExt.windows.template_debug.x86_64.dll" +windows.release.x86_64 = "res://bin/libMultilevelAStarExt.windows.template_release.x86_64.dll" +linux.debug.x86_64 = "res://bin/libMultilevelAStarExt.linux.template_debug.x86_64.so" +linux.release.x86_64 = "res://bin/libMultilevelAStarExt.linux.template_release.x86_64.so" diff --git a/demo/bin/multilevel_astar.gd b/demo/bin/multilevel_astar.gd new file mode 100644 index 0000000..bf2b73b --- /dev/null +++ b/demo/bin/multilevel_astar.gd @@ -0,0 +1,63 @@ +extends RefCounted +class_name MultilevelAStar + +# tile custom data "type": +# 0 => blocked +# 1(+) => can move to same number +# -1(-) => can move to same, one larger or one smaller as long as they're both negative +# => can move to and from its absolute value and one larger than its absolute value + +# private variables start with an _ as per the GDScript style guide +var _used_rect: Rect2i +var _astar: MultilevelAStarEx + + +func _init(map: TileMap): + _used_rect = map.get_used_rect() + + # assert stuff here because the extension's assertions just crash without a message + assert(_used_rect.get_area() > 0) + + _astar = MultilevelAStarEx.new() + _astar.init(_used_rect) + + for layer in map.get_layers_count(): + var cells := map.get_used_cells(layer) + for cell in cells: + var tile_data := map.get_cell_tile_data(layer, cell) + if tile_data != null: + var type = tile_data.get_custom_data("type") + assert(type is int) + _astar.set_terrain(cell, type) + + +func is_unit(point: Vector2i) -> bool: + assert(_used_rect.has_point(point)) + return _astar.get_unit(point) + + +func set_unit(point: Vector2i, solid: bool = true) -> void: + assert(_used_rect.has_point(point)) + _astar.set_unit(point, solid) + + +func get_terrain(point: Vector2i) -> MultilevelAStarEx.TerrainType: + assert(_used_rect.has_point(point)) + return _astar.get_terrain(point) + + +func set_terrain(point: Vector2i, type: MultilevelAStarEx.TerrainType) -> void: + assert(_used_rect.has_point(point)) + _astar.set_terrain(point, type) + + +func find_path(from: Vector2i, to: Vector2i, return_closest: bool = false) -> Array[Vector2i]: + assert(_used_rect.has_point(from)) + assert(_used_rect.has_point(to)) + + var res = _astar.find_path(from, to, return_closest) # vrne Variant: null ali Array[Vector2i] + + if res != null: + return res + else: + return [] diff --git a/demo/icon.svg b/demo/icon.svg new file mode 100644 index 0000000..3fe4f4a --- /dev/null +++ b/demo/icon.svg @@ -0,0 +1 @@ + diff --git a/demo/icon.svg.import b/demo/icon.svg.import new file mode 100644 index 0000000..fd9ae2c --- /dev/null +++ b/demo/icon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cpupav84hxj1u" +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 diff --git a/demo/main.gd b/demo/main.gd new file mode 100644 index 0000000..11366a7 --- /dev/null +++ b/demo/main.gd @@ -0,0 +1,74 @@ +extends Node2D + + +const CELL_SIZE: int = 32 + +@onready var map: TileMap = $TileMap +@onready var marker_from: Node2D = $MarkerFrom +@onready var marker_to: Node2D = $MarkerTo +@onready var path_line: Line2D = $PathLine +@onready var check_box: CheckBox = $CheckBox + +var astar: MultilevelAStar +var used_rect: Rect2i + + +# Called when the node enters the scene tree for the first time. +func _ready() -> void: + # mapa začne na -1, -1. tukaj premaknem da se vidi vse na mapi + # (saj verjetno obstaja boljši način ma ga ne poznam - mogoče kakšna kamera) + position = Vector2i.ONE * CELL_SIZE + + used_rect = map.get_used_rect() + print(used_rect) + + astar = MultilevelAStar.new(map) + + mark_units() + + marker_from.modulate = Color.html("#ff0000ff") + marker_to.modulate = Color.html("#00ff00ff") + + marker_from.position = Vector2i(-1, -1) * CELL_SIZE + marker_to.position = (used_rect.position + used_rect.size - Vector2i.ONE) * CELL_SIZE + + find_path() + + +func mark_units() -> void: + for unit in $Units.get_tree().get_nodes_in_group("unit"): + astar.set_unit(unit.position / CELL_SIZE) + + +func _unhandled_input(event: InputEvent) -> void: + if event is InputEventMouseButton: + if event.pressed: + var cell := map.local_to_map(map.get_local_mouse_position()) + if map.get_used_rect().has_point(cell): + if event.button_index == 1: + marker_to.position = Vector2(cell.x * CELL_SIZE, cell.y * CELL_SIZE) + find_path(); + elif event.button_index == 2: + marker_from.position = Vector2(cell.x * CELL_SIZE, cell.y * CELL_SIZE) + find_path(); + + +func find_path() -> void: + path_line.clear_points() + + var from: Vector2i = Vector2i(marker_from.position / CELL_SIZE) + var to: Vector2i = Vector2i(marker_to.position / CELL_SIZE) + + var arr = astar.find_path(from, to, check_box.button_pressed) # vrne Variant: null ali Array + #print(arr) + + if arr.size() > 0: + # add new path + path_line.add_point(from * CELL_SIZE + Vector2i(16, 16)) + for vec in arr: + #print("%s, %s" % [vec.x, vec.y]) + path_line.add_point(vec * CELL_SIZE + Vector2i(16, 16)) + + +func _on_check_box_pressed() -> void: + find_path() diff --git a/demo/main.tscn b/demo/main.tscn new file mode 100644 index 0000000..1492fcd --- /dev/null +++ b/demo/main.tscn @@ -0,0 +1,84 @@ +[gd_scene load_steps=5 format=3 uid="uid://1bko0mopl8r7"] + +[ext_resource type="Script" path="res://main.gd" id="1_ub2iy"] +[ext_resource type="TileSet" uid="uid://dsc2e3ohtmv01" path="res://tiles/socerb.tres" id="2_c6ah4"] +[ext_resource type="PackedScene" uid="uid://cnrhrho63n4n2" path="res://markers/marker.tscn" id="3_iwmvr"] +[ext_resource type="PackedScene" uid="uid://cj34xrleexqf6" path="res://markers/unit.tscn" id="4_rc8be"] + +[node name="Main" type="Node2D"] +script = ExtResource("1_ub2iy") + +[node name="TileMap" type="TileMap" parent="."] +tile_set = ExtResource("2_c6ah4") +format = 2 +layer_0/name = "Ground" +layer_0/tile_data = PackedInt32Array(65536, 0, 0, 131072, 0, 0, 196608, 0, 0, 262144, 0, 0, 327680, 0, 0, 393216, 0, 0, 458752, 0, 0, 524288, 0, 0, 589824, 0, 0, 655360, 0, 0, 720896, 0, 0, 786432, 0, 0, 851968, 0, 0, 1, 0, 0, 65537, 0, 0, 131073, 0, 0, 196609, 0, 0, 262145, 0, 0, 327681, 0, 0, 393217, 0, 0, 458753, 0, 0, 524289, 0, 0, 589825, 0, 0, 655361, 0, 0, 720897, 0, 0, 786433, 0, 0, 851969, 0, 0, 2, 0, 0, 65538, 0, 0, 131074, 0, 0, 196610, 0, 0, 262146, 0, 0, 327682, 0, 0, 393218, 0, 0, 458754, 0, 0, 524290, 0, 0, 589826, 0, 0, 655362, 0, 0, 720898, 0, 0, 786434, 0, 0, 851970, 0, 0, 3, 0, 0, 65539, 0, 0, 131075, 0, 0, 196611, 0, 0, 262147, 0, 0, 327683, 0, 0, 393219, 0, 0, 458755, 0, 0, 524291, 0, 0, 589827, 0, 0, 655363, 0, 0, 720899, 0, 0, 786435, 0, 0, 851971, 0, 0, 4, 0, 0, 65540, 0, 0, 131076, 0, 0, 196612, 0, 0, 262148, 0, 0, 327684, 0, 0, 393220, 0, 0, 458756, 0, 0, 524292, 0, 0, 589828, 0, 0, 655364, 0, 0, 720900, 0, 0, 786436, 0, 0, 851972, 0, 0, 5, 0, 0, 65541, 0, 0, 131077, 0, 0, 196613, 0, 0, 262149, 0, 0, 327685, 0, 0, 393221, 0, 0, 458757, 0, 0, 524293, 0, 0, 589829, 0, 0, 655365, 0, 0, 720901, 0, 0, 786437, 0, 0, 851973, 0, 0, 6, 0, 0, 65542, 0, 0, 131078, 0, 0, 196614, 0, 0, 262150, 0, 0, 327686, 0, 0, 393222, 0, 0, 458758, 0, 0, 524294, 0, 0, 589830, 0, 0, 655366, 0, 0, 720902, 0, 0, 786438, 0, 0, 851974, 0, 0, 7, 0, 0, 65543, 0, 0, 131079, 0, 0, 196615, 0, 0, 262151, 0, 0, 327687, 0, 0, 393223, 0, 0, 458759, 0, 0, 524295, 0, 0, 589831, 0, 0, 655367, 0, 0, 720903, 0, 0, 786439, 0, 0, 851975, 0, 0, 8, 0, 0, 65544, 0, 0, 131080, 0, 0, 196616, 0, 0, 262152, 0, 0, 327688, 0, 0, 393224, 0, 0, 458760, 0, 0, 589832, 0, 0, 655368, 0, 0, 720904, 0, 0, 786440, 0, 0, 851976, 0, 0, 9, 0, 0, 65545, 0, 0, 131081, 0, 0, 196617, 0, 0, 262153, 0, 0, 327689, 0, 0, 393225, 0, 0, 458761, 0, 0, 655369, 0, 0, 720905, 0, 0, 786441, 0, 0, 851977, 0, 0, 10, 0, 0, 65546, 0, 0, 131082, 0, 0, 196618, 0, 0, 262154, 0, 0, 327690, 0, 0, 393226, 0, 0, 458762, 0, 0, 524298, 0, 0, 720906, 0, 0, 786442, 0, 0, 851978, 0, 0, 11, 0, 0, 65547, 0, 0, 131083, 0, 0, 196619, 0, 0, 262155, 0, 0, 327691, 0, 0, 393227, 0, 0, 458763, 0, 0, 524299, 0, 0, 589835, 0, 0, 720907, 0, 0, 786443, 0, 0, 851979, 0, 0, 12, 0, 0, 65548, 0, 0, 131084, 0, 0, 196620, 0, 0, 262156, 0, 0, 327692, 0, 0, 393228, 0, 0, 458764, 0, 0, 524300, 0, 0, 589836, 0, 0, 786444, 0, 0, 851980, 0, 0, 13, 0, 0, 65549, 0, 0, 131085, 0, 0, 196621, 0, 0, 262157, 0, 0, 327693, 0, 0, 393229, 0, 0, 458765, 0, 0, 524301, 0, 0, 589837, 0, 0, 655373, 0, 0, 786445, 0, 0, 14, 0, 0, 65550, 0, 0, 131086, 0, 0, 196622, 0, 0, 262158, 0, 0, 327694, 0, 0, 393230, 0, 0, 458766, 0, 0, 524302, 0, 0, 589838, 0, 0, 655374, 0, 0, 786446, 0, 0, 15, 0, 0, 65551, 0, 0, 131087, 0, 0, 196623, 0, 0, 262159, 0, 0, 327695, 0, 0, 393231, 0, 0, 458767, 0, 0, 524303, 0, 0, 589839, 0, 0, 655375, 0, 0, 786447, 0, 0, 16, 0, 0, 65552, 0, 0, 131088, 0, 0, 196624, 0, 0, 262160, 0, 0, 327696, 0, 0, 393232, 0, 0, 458768, 0, 0, 524304, 0, 0, 589840, 0, 0, 655376, 0, 0, 786448, 0, 0, 17, 0, 0, 65553, 0, 0, 131089, 0, 0, 196625, 0, 0, 262161, 0, 0, 327697, 0, 0, 393233, 0, 0, 458769, 0, 0, 524305, 0, 0, 589841, 0, 0, 655377, 0, 0, 720913, 0, 0, 18, 0, 0, 65554, 0, 0, 131090, 0, 0, 196626, 0, 0, 262162, 0, 0, 327698, 0, 0, 393234, 0, 0, 458770, 0, 0, 524306, 0, 0, 589842, 0, 0, 655378, 0, 0, 720914, 0, 0, 19, 0, 0, 65555, 0, 0, 131091, 0, 0, 196627, 0, 0, 262163, 0, 0, 327699, 0, 0, 393235, 0, 0, 458771, 0, 0, 524307, 0, 0, 589843, 0, 0, 655379, 0, 0, 720915, 0, 0, 20, 0, 0, 65556, 0, 0, 131092, 0, 0, 196628, 0, 0, 262164, 0, 0, 327700, 0, 0, 393236, 0, 0, 458772, 0, 0, 524308, 0, 0, 589844, 0, 0, 655380, 0, 0, 720916, 0, 0, 786452, 0, 0, 21, 0, 0, 65557, 0, 0, 131093, 0, 0, 196629, 0, 0, 262165, 0, 0, 327701, 0, 0, 393237, 0, 0, 458773, 0, 0, 524309, 0, 0, 589845, 0, 0, 655381, 0, 0, 720917, 0, 0, 786453, 0, 0, 917504, 0, 0, 917505, 0, 0, 917506, 0, 0, 917507, 0, 0, 917508, 0, 0, 917509, 0, 0, 917510, 0, 0, 917511, 0, 0, 917512, 0, 0, 917513, 0, 0, 917514, 0, 0, 917515, 0, 0, 917516, 0, 0, 851981, 0, 0, 851982, 0, 0, 851983, 0, 0, 851984, 0, 0, 851985, 0, 0, 851986, 0, 0, 851987, 0, 0, 851988, 0, 0, 851989, 0, 0, 917524, 0, 0, 917523, 0, 0, 917522, 0, 0, 917521, 0, 0, 917520, 0, 0, 917519, 0, 0, 917518, 0, 0, 917517, 0, 0, 0, 0, 0, 917525, 0, 0, 524296, 0, 0, 524297, 0, 0, 589833, 0, 0, 589834, 0, 0, 655370, 0, 0, 655371, 0, 0, 655372, 0, 0, 720908, 0, 0, 720909, 0, 0, 720910, 0, 0, 720911, 0, 0, 720912, 0, 0, 786449, 0, 0, 786450, 0, 0, 786451, 0, 0, 983040, 0, 0, 1048576, 0, 0, 1114112, 0, 0, 1179648, 0, 0, 983041, 0, 0, 1048577, 0, 0, 1114113, 0, 0, 1179649, 0, 0, 983042, 0, 0, 1048578, 0, 0, 1114114, 0, 0, 1179650, 0, 0, 983043, 0, 0, 1048579, 0, 0, 1114115, 0, 0, 1179651, 0, 0, 983044, 0, 0, 1048580, 0, 0, 1114116, 0, 0, 1179652, 0, 0, 983045, 0, 0, 1048581, 0, 0, 1114117, 0, 0, 1179653, 0, 0, 983046, 0, 0, 1048582, 0, 0, 1114118, 0, 0, 1179654, 0, 0, 983047, 0, 0, 1048583, 0, 0, 1114119, 0, 0, 1179655, 0, 0, 983048, 0, 0, 1048584, 0, 0, 1114120, 0, 0, 1179656, 0, 0, 983049, 0, 0, 1048585, 0, 0, 1114121, 0, 0, 1179657, 0, 0, 983050, 0, 0, 1048586, 0, 0, 1114122, 0, 0, 1179658, 0, 0, 983051, 0, 0, 1048587, 0, 0, 1114123, 0, 0, 1179659, 0, 0, 983052, 0, 0, 1048588, 0, 0, 1114124, 0, 0, 1179660, 0, 0, 983053, 0, 0, 1048589, 0, 0, 1114125, 0, 0, 1179661, 0, 0, 983054, 0, 0, 1048590, 0, 0, 1114126, 0, 0, 1179662, 0, 0, 983055, 0, 0, 1048591, 0, 0, 1114127, 0, 0, 1179663, 0, 0, 983056, 0, 0, 1048592, 0, 0, 1114128, 0, 0, 1179664, 0, 0, 983057, 0, 0, 1048593, 0, 0, 1114129, 0, 0, 1179665, 0, 0, 983058, 0, 0, 1048594, 0, 0, 1114130, 0, 0, 1179666, 0, 0, 983059, 0, 0, 1048595, 0, 0, 1114131, 0, 0, 1179667, 0, 0, 983060, 0, 0, 1048596, 0, 0, 1114132, 0, 0, 1179668, 0, 0, 983061, 0, 0, 1048597, 0, 0, 1114133, 0, 0, 1179669, 0, 0, 983062, 0, 0, 1048598, 0, 0, 1114134, 0, 0, 1179670, 0, 0, 983063, 0, 0, 1048599, 0, 0, 1114135, 0, 0, 1179671, 0, 0, 983064, 0, 0, 1048600, 0, 0, 1114136, 0, 0, 1179672, 0, 0, 983065, 0, 0, 1048601, 0, 0, 1114137, 0, 0, 1179673, 0, 0, 983066, 0, 0, 1048602, 0, 0, 1114138, 0, 0, 1179674, 0, 0, 983067, 0, 0, 1048603, 0, 0, 1114139, 0, 0, 1179675, 0, 0, 983068, 0, 0, 1048604, 0, 0, 1114140, 0, 0, 1179676, 0, 0, 983069, 0, 0, 1048605, 0, 0, 1114141, 0, 0, 1179677, 0, 0, 983070, 0, 0, 1048606, 0, 0, 1114142, 0, 0, 1179678, 0, 0, 983071, 0, 0, 1048607, 0, 0, 1114143, 0, 0, 1179679, 0, 0, 22, 0, 0, 65558, 0, 0, 131094, 0, 0, 196630, 0, 0, 262166, 0, 0, 327702, 0, 0, 393238, 0, 0, 458774, 0, 0, 524310, 0, 0, 589846, 0, 0, 655382, 0, 0, 720918, 0, 0, 786454, 0, 0, 851990, 0, 0, 917526, 0, 0, 23, 0, 0, 65559, 0, 0, 131095, 0, 0, 196631, 0, 0, 262167, 0, 0, 327703, 0, 0, 393239, 0, 0, 458775, 0, 0, 524311, 0, 0, 589847, 0, 0, 655383, 0, 0, 720919, 0, 0, 786455, 0, 0, 851991, 0, 0, 917527, 0, 0, 24, 0, 0, 65560, 0, 0, 131096, 0, 0, 196632, 0, 0, 262168, 0, 0, 327704, 0, 0, 393240, 0, 0, 458776, 0, 0, 524312, 0, 0, 589848, 0, 0, 655384, 0, 0, 720920, 0, 0, 786456, 0, 0, 851992, 0, 0, 917528, 0, 0, 25, 0, 0, 65561, 0, 0, 131097, 0, 0, 196633, 0, 0, 262169, 0, 0, 327705, 0, 0, 393241, 0, 0, 458777, 0, 0, 524313, 0, 0, 589849, 0, 0, 655385, 0, 0, 720921, 0, 0, 786457, 0, 0, 851993, 0, 0, 917529, 0, 0, 26, 0, 0, 65562, 0, 0, 131098, 0, 0, 196634, 0, 0, 262170, 0, 0, 327706, 0, 0, 393242, 0, 0, 458778, 0, 0, 524314, 0, 0, 589850, 0, 0, 655386, 0, 0, 720922, 0, 0, 786458, 0, 0, 851994, 0, 0, 917530, 0, 0, 27, 0, 0, 65563, 0, 0, 131099, 0, 0, 196635, 0, 0, 262171, 0, 0, 327707, 0, 0, 393243, 0, 0, 458779, 0, 0, 524315, 0, 0, 589851, 0, 0, 655387, 0, 0, 720923, 0, 0, 786459, 0, 0, 851995, 0, 0, 917531, 0, 0, 28, 0, 0, 65564, 0, 0, 131100, 0, 0, 196636, 0, 0, 262172, 0, 0, 327708, 0, 0, 393244, 0, 0, 458780, 0, 0, 524316, 0, 0, 589852, 0, 0, 655388, 0, 0, 720924, 0, 0, 786460, 0, 0, 851996, 0, 0, 917532, 0, 0, 29, 0, 0, 65565, 0, 0, 131101, 0, 0, 196637, 0, 0, 262173, 0, 0, 327709, 0, 0, 393245, 0, 0, 458781, 0, 0, 524317, 0, 0, 589853, 0, 0, 655389, 0, 0, 720925, 0, 0, 786461, 0, 0, 851997, 0, 0, 917533, 0, 0, 30, 0, 0, 65566, 0, 0, 131102, 0, 0, 196638, 0, 0, 262174, 0, 0, 327710, 0, 0, 393246, 0, 0, 458782, 0, 0, 524318, 0, 0, 589854, 0, 0, 655390, 0, 0, 720926, 0, 0, 786462, 0, 0, 851998, 0, 0, 917534, 0, 0, 31, 0, 0, 65567, 0, 0, 131103, 0, 0, 196639, 0, 0, 262175, 0, 0, 327711, 0, 0, 393247, 0, 0, 458783, 0, 0, 524319, 0, 0, 589855, 0, 0, 655391, 0, 0, 720927, 0, 0, 786463, 0, 0, 851999, 0, 0, 917535, 0, 0, 32, 0, 0, 65568, 0, 0, 131104, 0, 0, 196640, 0, 0, 262176, 0, 0, 327712, 0, 0, 393248, 0, 0, 458784, 0, 0, 524320, 0, 0, 33, 0, 0, 65569, 0, 0, 131105, 0, 0, 196641, 0, 0, 262177, 0, 0, 327713, 0, 0, 393249, 0, 0, 458785, 0, 0, 524321, 0, 0, 589856, 0, 0, 655392, 0, 0, 720928, 0, 0, 786464, 0, 0, 852000, 0, 0, 917536, 0, 0, 983072, 0, 0, 1048608, 0, 0, 1114144, 0, 0, 1179680, 0, 0, 589857, 0, 0, 655393, 0, 0, 720929, 0, 0, 786465, 0, 0, 852001, 0, 0, 917537, 0, 0, 983073, 0, 0, 1048609, 0, 0, 1114145, 0, 0, 1179681, 0, 0, 34, 0, 0, 65570, 0, 0, 131106, 0, 0, 196642, 0, 0, 262178, 0, 0, 327714, 0, 0, 393250, 0, 0, 458786, 0, 0, 524322, 0, 0, 589858, 0, 0, 655394, 0, 0, 720930, 0, 0, 786466, 0, 0, 852002, 0, 0, 917538, 0, 0, 983074, 0, 0, 1048610, 0, 0, 1114146, 0, 0, 1179682, 0, 0, 1245183, 0, 0, 1179647, 0, 0, 1114111, 0, 0, 1048575, 0, 0, 983039, 0, 0, 917503, 0, 0, 851967, 0, 0, 786431, 0, 0, 720895, 0, 0, 655359, 0, 0, 589823, 0, 0, 524287, 0, 0, 458751, 0, 0, 393215, 0, 0, 327679, 0, 0, 262143, 0, 0, 196607, 0, 0, 131071, 0, 0, 65535, 0, 0, -1, 0, 0, -65536, 0, 0, -65535, 0, 0, -65534, 0, 0, -65533, 0, 0, -65532, 0, 0, -65531, 0, 0, -65530, 0, 0, -65529, 0, 0, -65528, 0, 0, -65527, 0, 0, -65526, 0, 0, -65525, 0, 0, -65524, 0, 0, -65523, 0, 0, -65522, 0, 0, -65521, 0, 0, -65520, 0, 0, -65519, 0, 0, -65518, 0, 0, -65517, 0, 0, -65516, 0, 0, -65515, 0, 0, -65514, 0, 0, -65513, 0, 0, -65512, 0, 0, -65511, 0, 0, -65510, 0, 0, -65509, 0, 0, -65508, 0, 0, -65507, 0, 0, -65506, 0, 0, -65505, 0, 0, -65504, 0, 0, -65503, 0, 0, -65502, 0, 0) +layer_1/name = "Castle" +layer_1/tile_data = PackedInt32Array(589840, 131072, 6, 655376, 131072, 7, 720912, 131072, 8, 786448, 131072, 9, 851984, 131072, 10, 589841, 196608, 6, 655377, 196608, 7, 720913, 196608, 8, 851985, 196608, 4, 589842, 262144, 6, 655378, 262144, 7, 720914, 262144, 8, 786450, 262144, 9, 851986, 65536, 0, 589843, 327680, 6, 655379, 327680, 7, 720915, 327680, 8, 786451, 262144, 4, 851987, 196608, 4, 589844, 393216, 6, 655380, 196608, 4, 720916, 262144, 8, 786452, 196608, 4, 851988, 262144, 4, 524310, 458752, 1, 589846, 458752, 2, 655382, 196608, 4, 720918, 720896, 4, 786454, 196608, 4, 851990, 458752, 6, 458775, 524288, 0, 524311, 524288, 1, 589847, 524288, 2, 655383, 524288, 3, 720919, 720896, 4, 786455, 720896, 4, 851991, 524288, 6, 458776, 589824, 0, 524312, 589824, 1, 589848, 589824, 2, 655384, 589824, 3, 720920, 589824, 4, 786456, 589824, 5, 851992, 589824, 6, 458777, 655360, 0, 524313, 655360, 1, 589849, 655360, 2, 655385, 655360, 3, 720921, 655360, 4, 786457, 655360, 5, 851993, 655360, 6, 458778, 720896, 0, 524314, 720896, 1, 589850, 720896, 2, 655386, 720896, 3, 720922, 720896, 4, 786458, 720896, 5, 851994, 720896, 6, 458779, 786432, 0, 524315, 786432, 1, 589851, 786432, 2, 655387, 786432, 3, 720923, 786432, 4, 786459, 786432, 5, 851995, 786432, 6, 458780, 851968, 0, 524316, 851968, 1, 589852, 851968, 2, 655388, 851968, 3, 720924, 851968, 4, 786460, 851968, 5, 851996, 851968, 6, 524317, 917504, 1, 589853, 917504, 2, 655389, 917504, 3, 720925, 917504, 4, 786461, 917504, 5, 851997, 917504, 6, 917527, 524288, 7, 917528, 589824, 7, 917529, 655360, 7, 917530, 720896, 7, 917531, 786432, 7, 917532, 851968, 7, 786453, 196608, 4, 655381, 196608, 4, 786449, 262144, 8, 720917, 262144, 0, 786436, 262144, 8, 851973, 262144, 8, 917509, 262144, 8, 786437, 262144, 8, 851972, 262144, 8, 917508, 262144, 8, 983044, 262144, 0, 983045, 655360, 4, 1048581, 655360, 4, 1048580, 655360, 4, 1114116, 655360, 4, 1114117, 655360, 4, 720901, 65536, 0, 327692, 262144, 4, 262156, 262144, 4, 196620, 262144, 4, 131084, 262144, 4, 131085, 262144, 4, 131086, 262144, 4, 131087, 262144, 4, 131088, 262144, 4, 196624, 262144, 4, 262160, 262144, 4, 327696, 262144, 4, 393232, 262144, 4, 393228, 262144, 4, 131105, 196608, 4, 196641, 196608, 4, 131102, 196608, 4, 196638, 196608, 4, 262174, 196608, 4, 262177, 196608, 4, 327710, 196608, 4, 327711, 196608, 4, 327712, 196608, 4, 327713, 196608, 4, 131104, 196608, 4, 131103, 196608, 4, 851978, 65536, 0, 917514, 262144, 0, 983050, 655360, 3) + +[node name="MarkerFrom" parent="." instance=ExtResource("3_iwmvr")] + +[node name="MarkerTo" parent="." instance=ExtResource("3_iwmvr")] + +[node name="PathLine" type="Line2D" parent="."] +width = 2.0 + +[node name="Units" type="Node2D" parent="."] + +[node name="Unit1" parent="Units" instance=ExtResource("4_rc8be")] +position = Vector2(256, 192) + +[node name="Unit2" parent="Units" instance=ExtResource("4_rc8be")] +position = Vector2(224, 224) + +[node name="Unit3" parent="Units" instance=ExtResource("4_rc8be")] +position = Vector2(576, 512) + +[node name="Unit4" parent="Units" instance=ExtResource("4_rc8be")] +position = Vector2(576, 544) + +[node name="Unit10" parent="Units" instance=ExtResource("4_rc8be")] +position = Vector2(640, 96) + +[node name="Unit11" parent="Units" instance=ExtResource("4_rc8be")] +position = Vector2(672, 96) + +[node name="Unit12" parent="Units" instance=ExtResource("4_rc8be")] +position = Vector2(608, 96) + +[node name="Unit13" parent="Units" instance=ExtResource("4_rc8be")] +position = Vector2(640, 64) + +[node name="Unit14" parent="Units" instance=ExtResource("4_rc8be")] +position = Vector2(32, 288) + +[node name="Unit15" parent="Units" instance=ExtResource("4_rc8be")] +position = Vector2(64, 288) + +[node name="Unit16" parent="Units" instance=ExtResource("4_rc8be")] +position = Vector2(0, 288) + +[node name="Unit17" parent="Units" instance=ExtResource("4_rc8be")] +position = Vector2(32, 256) + +[node name="Unit" parent="Units" instance=ExtResource("4_rc8be")] +position = Vector2(32, 320) + +[node name="CheckBox" type="CheckBox" parent="."] +offset_left = 25.0 +offset_top = 3.0 +offset_right = 164.0 +offset_bottom = 34.0 +focus_mode = 0 +text = "Return closest" + +[node name="Label" type="Label" parent="."] +offset_left = 27.0 +offset_top = 39.0 +offset_right = 117.0 +offset_bottom = 88.0 +text = "Red - Start (RMB) +Green - End (LMB) +" + +[connection signal="pressed" from="CheckBox" to="." method="_on_check_box_pressed"] diff --git a/demo/markers/marker.png b/demo/markers/marker.png new file mode 100644 index 0000000..bac1cf7 Binary files /dev/null and b/demo/markers/marker.png differ diff --git a/demo/markers/marker.png.import b/demo/markers/marker.png.import new file mode 100644 index 0000000..40786a9 --- /dev/null +++ b/demo/markers/marker.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ydnd8d7pbpct" +path="res://.godot/imported/marker.png-302bb6fffff2bb75ddac5872ea46d55a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://markers/marker.png" +dest_files=["res://.godot/imported/marker.png-302bb6fffff2bb75ddac5872ea46d55a.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 diff --git a/demo/markers/marker.tscn b/demo/markers/marker.tscn new file mode 100644 index 0000000..308fa54 --- /dev/null +++ b/demo/markers/marker.tscn @@ -0,0 +1,9 @@ +[gd_scene load_steps=2 format=3 uid="uid://cnrhrho63n4n2"] + +[ext_resource type="Texture2D" uid="uid://ydnd8d7pbpct" path="res://markers/marker.png" id="1_mefdn"] + +[node name="Marker" type="Node2D"] + +[node name="Sprite2D" type="Sprite2D" parent="."] +texture = ExtResource("1_mefdn") +offset = Vector2(16, 16) diff --git a/demo/markers/unit.png b/demo/markers/unit.png new file mode 100644 index 0000000..f2ab971 Binary files /dev/null and b/demo/markers/unit.png differ diff --git a/demo/markers/unit.png.import b/demo/markers/unit.png.import new file mode 100644 index 0000000..2b3025f --- /dev/null +++ b/demo/markers/unit.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b6j8es5qgtv05" +path="res://.godot/imported/unit.png-1fe68df64273b07deeeaa2e1953638b5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://markers/unit.png" +dest_files=["res://.godot/imported/unit.png-1fe68df64273b07deeeaa2e1953638b5.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 diff --git a/demo/markers/unit.tscn b/demo/markers/unit.tscn new file mode 100644 index 0000000..454a496 --- /dev/null +++ b/demo/markers/unit.tscn @@ -0,0 +1,9 @@ +[gd_scene load_steps=2 format=3 uid="uid://cj34xrleexqf6"] + +[ext_resource type="Texture2D" uid="uid://b6j8es5qgtv05" path="res://markers/unit.png" id="1_qutcq"] + +[node name="Unit" type="Node2D" groups=["unit"]] + +[node name="Sprite2D" type="Sprite2D" parent="."] +position = Vector2(16, 16) +texture = ExtResource("1_qutcq") diff --git a/demo/project.godot b/demo/project.godot new file mode 100644 index 0000000..f266208 --- /dev/null +++ b/demo/project.godot @@ -0,0 +1,20 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=5 + +[application] + +config/name="MultilevelAStarTest" +run/main_scene="res://main.tscn" +config/features=PackedStringArray("4.2", "Forward Plus") +config/icon="res://icon.svg" + +[display] + +window/stretch/mode="canvas_items" diff --git a/demo/tiles/socerb.png b/demo/tiles/socerb.png new file mode 100644 index 0000000..4373083 Binary files /dev/null and b/demo/tiles/socerb.png differ diff --git a/demo/tiles/socerb.png.import b/demo/tiles/socerb.png.import new file mode 100644 index 0000000..8bd4dac --- /dev/null +++ b/demo/tiles/socerb.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dh20x6lnm6ly8" +path="res://.godot/imported/socerb.png-80780b522a349cb35f220b47d0cdac2c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://tiles/socerb.png" +dest_files=["res://.godot/imported/socerb.png-80780b522a349cb35f220b47d0cdac2c.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 diff --git a/demo/tiles/socerb.tres b/demo/tiles/socerb.tres new file mode 100644 index 0000000..54d0478 --- /dev/null +++ b/demo/tiles/socerb.tres @@ -0,0 +1,204 @@ +[gd_resource type="TileSet" load_steps=3 format=3 uid="uid://dsc2e3ohtmv01"] + +[ext_resource type="Texture2D" uid="uid://dh20x6lnm6ly8" path="res://tiles/socerb.png" id="1_e53on"] + +[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_dokfe"] +texture = ExtResource("1_e53on") +texture_region_size = Vector2i(32, 32) +0:0/0 = 0 +0:0/0/custom_data_0 = 1 +1:0/0 = 0 +1:0/0/custom_data_0 = -1 +2:0/0 = 0 +2:0/0/custom_data_0 = -1 +3:0/0 = 0 +3:0/0/custom_data_0 = -1 +4:0/0 = 0 +4:0/0/custom_data_0 = -2 +8:0/0 = 0 +9:0/0 = 0 +10:0/0 = 0 +11:0/0 = 0 +12:0/0 = 0 +13:0/0 = 0 +0:1/0 = 0 +0:1/0/custom_data_0 = 1 +1:1/0 = 0 +1:1/0/custom_data_0 = 1 +2:1/0 = 0 +3:1/0 = 0 +4:1/0 = 0 +5:1/0 = 0 +6:1/0 = 0 +7:1/0 = 0 +8:1/0 = 0 +9:1/0 = 0 +9:1/0/custom_data_0 = 3 +10:1/0 = 0 +10:1/0/custom_data_0 = 3 +11:1/0 = 0 +11:1/0/custom_data_0 = 3 +12:1/0 = 0 +12:1/0/custom_data_0 = 3 +13:1/0 = 0 +14:1/0 = 0 +0:2/0 = 0 +0:2/0/custom_data_0 = 1 +1:2/0 = 0 +1:2/0/custom_data_0 = 1 +2:2/0 = 0 +3:2/0 = 0 +4:2/0 = 0 +5:2/0 = 0 +6:2/0 = 0 +7:2/0 = 0 +8:2/0 = 0 +8:2/0/custom_data_0 = 3 +9:2/0 = 0 +9:2/0/custom_data_0 = 3 +10:2/0 = 0 +10:2/0/custom_data_0 = 3 +11:2/0 = 0 +11:2/0/custom_data_0 = 3 +12:2/0 = 0 +12:2/0/custom_data_0 = 3 +13:2/0 = 0 +13:2/0/custom_data_0 = 3 +14:2/0 = 0 +0:3/0 = 0 +0:3/0/custom_data_0 = 1 +1:3/0 = 0 +1:3/0/custom_data_0 = 1 +2:3/0 = 0 +3:3/0 = 0 +3:3/0/custom_data_0 = 1 +4:3/0 = 0 +4:3/0/custom_data_0 = 1 +5:3/0 = 0 +5:3/0/custom_data_0 = 1 +6:3/0 = 0 +7:3/0 = 0 +8:3/0 = 0 +8:3/0/custom_data_0 = 3 +9:3/0 = 0 +9:3/0/custom_data_0 = 3 +10:3/0 = 0 +10:3/0/custom_data_0 = 3 +11:3/0 = 0 +11:3/0/custom_data_0 = 3 +12:3/0 = 0 +12:3/0/custom_data_0 = 3 +13:3/0 = 0 +13:3/0/custom_data_0 = 3 +14:3/0 = 0 +1:4/0 = 0 +2:4/0 = 0 +3:4/0 = 0 +4:4/0 = 0 +5:4/0 = 0 +5:4/0/custom_data_0 = 1 +6:4/0 = 0 +7:4/0 = 0 +8:4/0 = 0 +8:4/0/custom_data_0 = 3 +9:4/0 = 0 +9:4/0/custom_data_0 = 3 +10:4/0 = 0 +10:4/0/custom_data_0 = 3 +11:4/0 = 0 +11:4/0/custom_data_0 = 3 +12:4/0 = 0 +12:4/0/custom_data_0 = 3 +13:4/0 = 0 +13:4/0/custom_data_0 = 3 +14:4/0 = 0 +2:5/0 = 0 +3:5/0 = 0 +4:5/0 = 0 +5:5/0 = 0 +6:5/0 = 0 +7:5/0 = 0 +8:5/0 = 0 +8:5/0/custom_data_0 = 3 +9:5/0 = 0 +9:5/0/custom_data_0 = 3 +10:5/0 = 0 +10:5/0/custom_data_0 = 3 +11:5/0 = 0 +11:5/0/custom_data_0 = 3 +12:5/0 = 0 +12:5/0/custom_data_0 = 3 +13:5/0 = 0 +13:5/0/custom_data_0 = 3 +14:5/0 = 0 +2:6/0 = 0 +3:6/0 = 0 +4:6/0 = 0 +5:6/0 = 0 +6:6/0 = 0 +7:6/0 = 0 +8:6/0 = 0 +9:6/0 = 0 +9:6/0/custom_data_0 = 3 +10:6/0 = 0 +10:6/0/custom_data_0 = 3 +11:6/0 = 0 +11:6/0/custom_data_0 = 3 +12:6/0 = 0 +12:6/0/custom_data_0 = 3 +13:6/0 = 0 +14:6/0 = 0 +2:7/0 = 0 +3:7/0 = 0 +3:7/0/custom_data_0 = 2 +4:7/0 = 0 +4:7/0/custom_data_0 = 2 +5:7/0 = 0 +5:7/0/custom_data_0 = 2 +6:7/0 = 0 +8:7/0 = 0 +9:7/0 = 0 +10:7/0 = 0 +11:7/0 = 0 +12:7/0 = 0 +13:7/0 = 0 +2:8/0 = 0 +3:8/0 = 0 +3:8/0/custom_data_0 = 2 +4:8/0 = 0 +4:8/0/custom_data_0 = 2 +5:8/0 = 0 +5:8/0/custom_data_0 = 2 +6:8/0 = 0 +2:9/0 = 0 +3:9/0 = 0 +3:9/0/custom_data_0 = 2 +4:9/0 = 0 +4:9/0/custom_data_0 = 2 +5:9/0 = 0 +5:9/0/custom_data_0 = 2 +6:9/0 = 0 +2:10/0 = 0 +3:10/0 = 0 +4:10/0 = 0 +5:10/0 = 0 +6:10/0 = 0 +0:11/0 = 0 +0:12/0 = 0 +1:12/0 = 0 +2:12/0 = 0 +0:13/0 = 0 +1:13/0 = 0 +2:13/0 = 0 +0:14/0 = 0 +1:14/0 = 0 +2:14/0 = 0 +0:15/0 = 0 +1:15/0 = 0 +2:15/0 = 0 + +[resource] +tile_size = Vector2i(32, 32) +custom_data_layer_0/name = "type" +custom_data_layer_0/type = 2 +sources/0 = SubResource("TileSetAtlasSource_dokfe") diff --git a/godot-cpp b/godot-cpp new file mode 160000 index 0000000..b28098e --- /dev/null +++ b/godot-cpp @@ -0,0 +1 @@ +Subproject commit b28098e76b84e8831b8ac68d490f4bca44678b2a diff --git a/src/MultilevelAStarEx.cpp b/src/MultilevelAStarEx.cpp new file mode 100644 index 0000000..0d847e7 --- /dev/null +++ b/src/MultilevelAStarEx.cpp @@ -0,0 +1,346 @@ +#include "MultilevelAStarEx.h" + +#include +#include +#include + +#include +#include +#include + +#define TERRAIN(x, y) (_terrain[(x) + (y) * _width]) +#define UNITS(x, y) (_units[(x) + (y) * _width]) +#define NODES(x, y) (_nodes[(x) + (y) * _width]) + +using namespace godot; + +Node::Node() { } + +Node::Node(int x, int y) +{ + this->x = x; + this->y = y; + this->state = UNUSED; +} + +void Node::init(Node* parent, int distanceFromStart, const Vector2i &end) +{ + this->state = OPEN; + this->parent = parent; + this->distanceFromStart = distanceFromStart; + + int dx = abs(x - end.x); + int dy = abs(y - end.y); + this->distanceToEnd = (dx + dy) * 10; + + if ((dx == 0 || dx == 1) && (dy == 0 || dy == 1)) + { + this->distanceToEndForClosest = 10; + } + else + { + this->distanceToEndForClosest = this->distanceToEnd; + } +} + +int Node::total_cost() const +{ + return distanceFromStart + distanceToEnd; +} + +void MultilevelAStarEx::_bind_methods() +{ + ClassDB::bind_method(D_METHOD("init", "region"), &MultilevelAStarEx::init); + ClassDB::bind_method(D_METHOD("get_region"), &MultilevelAStarEx::get_region); + ClassDB::bind_method(D_METHOD("set_terrain", "cell", "type"), &MultilevelAStarEx::set_terrain); + ClassDB::bind_method(D_METHOD("get_terrain", "cell"), &MultilevelAStarEx::get_terrain); + ClassDB::bind_method(D_METHOD("set_unit", "cell", "blocked"), &MultilevelAStarEx::set_unit); + ClassDB::bind_method(D_METHOD("get_unit", "cell"), &MultilevelAStarEx::get_unit); + ClassDB::bind_method(D_METHOD("find_path", "from", "to", "return_closest"), &MultilevelAStarEx::find_path); + + BIND_ENUM_CONSTANT(STAIRS); + BIND_ENUM_CONSTANT(BLOCKED); + BIND_ENUM_CONSTANT(GROUND); +} + +MultilevelAStarEx::MultilevelAStarEx() +{ + //UtilityFunctions::print("Constructor."); + + _init = false; +} + +MultilevelAStarEx::~MultilevelAStarEx() +{ + //UtilityFunctions::print("Destructor."); +} + +void MultilevelAStarEx::init(const Rect2i ®ion) +{ + DEV_ASSERT(!_init); + + DEV_ASSERT(region.get_area() > 0); + + _region = region; + _width = region.get_size().width; + _height = region.get_size().height; + _trans = region.get_position(); + + _terrain.resize(_width * _height, BLOCKED); + _units.resize(_width * _height, false); + _nodes.resize(_width * _height); + + std::vector::iterator iter = _nodes.begin(); + for (int y = 0; y < _height; y++) + { + for (int x = 0; x < _width; x++) + { + *iter++ = Node(x, y); + } + } + + _init = true; +} + +Rect2i MultilevelAStarEx::get_region() const +{ + DEV_ASSERT(_init); + + return _region; +} + +void MultilevelAStarEx::set_terrain(const Vector2i &cell, TerrainType type) +{ + DEV_ASSERT(_init); + DEV_ASSERT(_region.has_point(cell)); + + Vector2i cell2 = cell - _trans; + TERRAIN(cell2.x, cell2.y) = type; +} + +MultilevelAStarEx::TerrainType MultilevelAStarEx::get_terrain(const Vector2i &cell) const +{ + DEV_ASSERT(_init); + DEV_ASSERT(_region.has_point(cell)); + + Vector2i cell2 = cell - _trans; + return TERRAIN(cell2.x, cell2.y); +} + +void MultilevelAStarEx::set_unit(const Vector2i &cell, bool blocked) +{ + DEV_ASSERT(_init); + DEV_ASSERT(_region.has_point(cell)); + + Vector2i cell2 = cell - _trans; + UNITS(cell2.x, cell2.y) = blocked; +} + +bool MultilevelAStarEx::get_unit(const Vector2i &cell) const +{ + DEV_ASSERT(_init); + DEV_ASSERT(_region.has_point(cell)); + + Vector2i cell2 = cell - _trans; + return UNITS(cell2.x, cell2.y); +} + +bool MultilevelAStarEx::can_move(const Node* current, int x, int y) const +{ + if (UNITS(x, y)) return false; + + TerrainType tc = TERRAIN(current->x, current->y); + TerrainType td = TERRAIN(x, y); + + if (td == BLOCKED) + { + return false; + } + else if (td == tc) + { + return true; + } + else if (td < 0 && tc > 0) // td is stairs + { + if (-td == tc || -td == tc - 1) return true; + } + else if (td > 0 && tc < 0) // tc is stairs + { + if (-tc == td || -tc == td - 1) return true; + } + else if (td < 0 && tc < 0) // both are stairs + { + return abs(td - tc) < 2; + } + + return false; +} + +TypedArray MultilevelAStarEx::generate_path(const Node* current) const +{ + TypedArray arr; + + while (current->parent != nullptr) + { + arr.insert(0, Vector2i(current->x, current->y) + _trans); + current = current->parent; + } + + return arr; +} + +Variant MultilevelAStarEx::find_path(const Vector2i &from, const Vector2i &to, const bool return_closest) +{ + DEV_ASSERT(_init); + + DEV_ASSERT(_region.has_point(from)); + DEV_ASSERT(_region.has_point(to)); + + Vector2i from2 = from - _trans; + Vector2i to2 = to - _trans; + + Variant result; + + std::vector open; + std::vector closed; + + open.reserve(_width * _height); + closed.reserve(_width * _height); + + Node* closest = &NODES(from2.x, from2.y); + closest->init(nullptr, 0, to2); + open.push_back(closest); + + auto process = [this, &open, &closed, &to2, &closest](Node* current, int x, int y, int distance) { + Node* node = &NODES(x, y); + if (node->state == Node::UNUSED) + { + node->init(current, current->distanceFromStart + distance, to2); + open.push_back(node); + } + else if (node->state == Node::OPEN) + { + if (current->distanceFromStart < node->parent->distanceFromStart) + { + node->parent = current; + node->distanceFromStart = current->distanceFromStart + distance; + } + } + + // find the closest cell + if (node->distanceToEndForClosest < closest->distanceToEndForClosest) + { + closest = node; + } + else if (node->distanceToEndForClosest == closest->distanceToEndForClosest) + { + if (node->distanceFromStart < closest->distanceFromStart) + { + closest = node; + } + } + }; + + while (open.size() > 0) + { + // find closest to destination + Node* current = open[0]; + for (Node* n : open) + { + if (n->total_cost() < current->total_cost()) + { + current = n; + } + } + + if (current->distanceToEnd == 0) + { + // found the path + result = Variant(generate_path(current)); + goto cleanup; + } + + // close it + current->state = Node::CLOSED; + open.erase(std::remove(open.begin(), open.end(), current), open.end()); + closed.push_back(current); + + // expand it + if (current->x - 1 >= 0) // left + { + if (can_move(current, current->x - 1, current->y)) + { + process(current, current->x - 1, current->y, 10); + } + } + if (current->x + 1 < _width) // right + { + if (can_move(current, current->x + 1, current->y)) + { + process(current, current->x + 1, current->y, 10); + } + } + if (current->y - 1 >= 0) // up + { + if (can_move(current, current->x, current->y - 1)) + { + process(current, current->x, current->y - 1, 10); + } + } + if (current->y + 1 < _height) // down + { + if (can_move(current, current->x, current->y + 1)) + { + process(current, current->x, current->y + 1, 10); + } + } + if ((current->x - 1 >= 0) && (current->y - 1 >= 0)) // top left + { + if (can_move(current, current->x - 1, current->y - 1)) + { + process(current, current->x - 1, current->y - 1, 14); + } + } + if ((current->x + 1 < _width) && (current->y - 1 >= 0)) // top right + { + if (can_move(current, current->x + 1, current->y - 1)) + { + process(current, current->x + 1, current->y - 1, 14); + } + } + if ((current->x - 1 >= 0) && (current->y + 1 < _height)) // bottom left + { + if (can_move(current, current->x - 1, current->y + 1)) + { + process(current, current->x - 1, current->y + 1, 14); + } + } + if ((current->x + 1 < _width) && (current->y + 1 < _height)) // bottom right + { + if (can_move(current, current->x + 1, current->y + 1)) + { + process(current, current->x + 1, current->y + 1, 14); + } + } + } + + // this is skipped if a path was found + if (return_closest) + { + // return path to closest + result = Variant(generate_path(closest)); + } + +cleanup: + // release the nodes + for (Node* node : open) + { + node->state = Node::UNUSED; + } + for (Node* node : closed) + { + node->state = Node::UNUSED; + } + + return result; +} diff --git a/src/MultilevelAStarEx.h b/src/MultilevelAStarEx.h new file mode 100644 index 0000000..e967744 --- /dev/null +++ b/src/MultilevelAStarEx.h @@ -0,0 +1,85 @@ +#ifndef MultilevelAStarEx_H +#define MultilevelAStarEx_H + +#include +#include +#include +#include + +#include + +namespace godot { + +class Node { + friend class MultilevelAStarEx; + +public: + enum NodeState + { + UNUSED, OPEN, CLOSED + }; + +private: + NodeState state; + int x, y; + + Node* parent; + int distanceFromStart; + int distanceToEnd; + + int distanceToEndForClosest; + + Node(int x, int y); + void init(Node* parent, int distanceFromStart, const Vector2i &end); + int total_cost() const; + +public: + Node(); +}; + +class MultilevelAStarEx : public RefCounted +{ + GDCLASS(MultilevelAStarEx, RefCounted) + +public: + enum TerrainType + { + STAIRS = -1, + BLOCKED = 0, + GROUND = 1, + }; + +private: + bool _init; + std::vector _terrain; + std::vector _units; + std::vector _nodes; + + Rect2i _region; + Vector2i _trans; + int _width, _height; + + bool can_move(const Node* current, int x, int y) const; + TypedArray generate_path(const Node* current) const; + +protected: + static void _bind_methods(); + +public: + MultilevelAStarEx(); + ~MultilevelAStarEx(); + + void init(const Rect2i ®ion); + Rect2i get_region() const; + void set_terrain(const Vector2i &cell, TerrainType type); + TerrainType get_terrain(const Vector2i &cell) const; + void set_unit(const Vector2i &cell, bool blocked); + bool get_unit(const Vector2i &cell) const; + Variant find_path(const Vector2i &from, const Vector2i &to, const bool return_closest); +}; + +} + +VARIANT_ENUM_CAST(MultilevelAStarEx::TerrainType); + +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..12e2b50 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,36 @@ +#include "MultilevelAStarEx.h" + +#include +#include +#include + +using namespace godot; + +void initialize_module(ModuleInitializationLevel p_level) +{ + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + + ClassDB::register_class(); +} + +void uninitialize_module(ModuleInitializationLevel p_level) +{ + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } +} + +extern "C" { +GDExtensionBool GDE_EXPORT my_astar_ext_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, const GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) +{ + godot::GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization); + + init_obj.register_initializer(initialize_module); + init_obj.register_terminator(uninitialize_module); + init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE); + + return init_obj.init(); +} +} \ No newline at end of file diff --git a/term.cmd b/term.cmd new file mode 100644 index 0000000..ccf03dc --- /dev/null +++ b/term.cmd @@ -0,0 +1,2 @@ +@set PATH=%PATH%;D:\Programs\scons +@cmd \ No newline at end of file