Moved to a floodfill algorithm, and put it all in a GDNative C++ class.

This commit is contained in:
Francois Belair 2019-10-03 16:07:54 -04:00
commit f92db19323
12 changed files with 258 additions and 518 deletions

353
Native/.gitignore vendored
View file

@ -1,353 +0,0 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/

View file

@ -1,25 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29230.47
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Heatmap", "Heatmap.vcxproj", "{95F50422-B0D5-44A4-8A83-3B56BFC6B7B0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{95F50422-B0D5-44A4-8A83-3B56BFC6B7B0}.Debug|x64.ActiveCfg = Debug|x64
{95F50422-B0D5-44A4-8A83-3B56BFC6B7B0}.Debug|x64.Build.0 = Debug|x64
{95F50422-B0D5-44A4-8A83-3B56BFC6B7B0}.Release|x64.ActiveCfg = Release|x64
{95F50422-B0D5-44A4-8A83-3B56BFC6B7B0}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6B60736E-491D-46DB-B927-593F9A8CEDF2}
EndGlobalSection
EndGlobal

View file

@ -1,110 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Heatmap.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="gdlibrary.cpp" />
<ClCompile Include="Heatmap.cpp" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{95F50422-B0D5-44A4-8A83-3B56BFC6B7B0}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>Heatmap</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>E:\Projects\Games\GDQuest\GDNative\godot-cpp\include;E:\Projects\Games\GDQuest\GDNative\godot-cpp\include\core;E:\Projects\Games\GDQuest\GDNative\godot-cpp\include\gen;E:\Projects\Games\GDQuest\GDNative\godot-cpp\godot_headers;$(IncludePath)</IncludePath>
<TargetName>libheatmap</TargetName>
<LibraryPath>E:\Projects\Games\GDQuest\GDNative\godot-cpp\bin;$(LibraryPath)</LibraryPath>
<OutDir>..\game\assets\libraries\win64\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>E:\Projects\Games\GDQuest\GDNative\godot-cpp\include;E:\Projects\Games\GDQuest\GDNative\godot-cpp\include\core;E:\Projects\Games\GDQuest\GDNative\godot-cpp\include\gen;E:\Projects\Games\GDQuest\GDNative\godot-cpp\godot_headers;$(IncludePath)</IncludePath>
<LibraryPath>E:\Projects\Games\GDQuest\GDNative\godot-cpp\bin;$(LibraryPath)</LibraryPath>
<OutDir>..\game\assets\libraries\win64\</OutDir>
<TargetName>libheatmap</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;HEATMAP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>
</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalDependencies>libgodot-cpp.windows.debug.64.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;HEATMAP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>
</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalDependencies>libgodot-cpp.windows.release.64.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -1,30 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Heatmap.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="gdlibrary.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Heatmap.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View file

@ -7,8 +7,12 @@ reloadable=true
[entry]
OSX.64="res://assets/libraries/osx/libheatmap.dylib"
Windows.64="res://assets/libraries/win64/libheatmap.dll"
X11.64="res://assets/libraries/x11/libheatmap.so"
[dependencies]
OSX.64=[ ]
Windows.64=[ ]
X11.64=[ ]

View file

@ -64,6 +64,11 @@ _global_script_classes=[ {
"language": "GDScript",
"path": "res://src/AI/Steering/Behaviors/Individual/FollowHeatmapBehavior2D.gd"
}, {
"base": "CanvasItem",
"class": "HeatmapGD",
"language": "GDScript",
"path": "res://src/AI/Heatmap.gd"
}, {
"base": "Reference",
"class": "Hit",
"language": "GDScript",
@ -84,6 +89,11 @@ _global_script_classes=[ {
"language": "GDScript",
"path": "res://src/AI/Steering/Behaviors/Individual/InterceptBehavior2D.gd"
}, {
"base": "Reference",
"class": "Pathfinder",
"language": "GDScript",
"path": "res://src/AI/Pathfinder.gd"
}, {
"base": "KinematicBody2D",
"class": "Player",
"language": "GDScript",
@ -146,10 +156,12 @@ _global_script_class_icons={
"FleeBehavior2D": "",
"FloorDetector": "",
"FollowHeatmapBehavior2D": "",
"HeatmapGD": "",
"Hit": "",
"Hook": "res://assets/icons/icon_hook.svg",
"HookTarget": "",
"InterceptBehavior2D": "",
"Pathfinder": "",
"Player": "",
"PrioritySteering2D": "",
"SchedulableJob": "",

155
game/src/AI/Heatmap.gd Normal file
View file

@ -0,0 +1,155 @@
extends CanvasItem
class_name HeatmapGD
"""
GDScript based solution to generate a heatmap that points from all available tiles,
to the player's location. The heatmap updating itself happens in a thread to keep
the game from skipping.
"""
onready var _grid: TileMap = get_node(pathfinding_tilemap)
export var pathfinding_tilemap: = NodePath()
export var font: Font
export var draw_debug: bool = true
var _pathfinder: = Pathfinder.new()
var _map_limits: Rect2
var _cells_heat: Array = []
var _cells_heat_cache: Array
var _last_player_cell_position: = Vector2(INF, INF)
var _mutex: = Mutex.new()
var _thread: = Thread.new()
var _finished_updating: = false
var _updating: = false
var _x_min: float
var _x_max: float
var _y_min: float
var _y_max: float
func _ready() -> void:
_map_limits = _grid.get_used_rect()
_pathfinder.initialize(_grid, range(4,14))
var highest_index: = calculate_point_index(_map_limits.size - _map_limits.position)
_cells_heat.resize(highest_index)
_cells_heat_cache = [] + _cells_heat
_x_min = _map_limits.position.x
_y_min = _map_limits.position.y
_x_max = _map_limits.size.x - _map_limits.position.x
_y_max = _map_limits.size.y - _map_limits.position.y
Events.connect("player_moved", self, "_on_Events_player_moved")
func _draw() -> void:
if not draw_debug or not font:
return
for y in range(_y_min, _y_max):
for x in range(_x_min, _x_max):
var point: = Vector2(x, y)
var cell_index: = calculate_point_index(point)
var heat: int = _cells_heat[cell_index]
draw_string(font, _grid.map_to_world(point), str(heat))
func best_direction_for(location: Vector2, is_world_location: bool = true) -> Vector2:
var point: = _grid.world_to_map(location) if is_world_location else location
var cell_index: = calculate_point_index(point)
var best_neighbour: = point
var best_heat: int = _cells_heat[cell_index]
if not _is_out_of_bounds(point):
for y in range(0, 3):
for x in range(0, 3):
var point_relative: = Vector2(point.x + x - 1, point.y + y - 1)
if point_relative == point or _is_out_of_bounds(point_relative):
continue
var point_relative_index: = calculate_point_index(point_relative)
if point_relative_index >= 0 and point_relative_index < _cells_heat.size():
var heat: int = _cells_heat[point_relative_index]
if heat and heat < best_heat:
best_heat = heat
best_neighbour = point_relative
var world_neighbour: = _grid.map_to_world(best_neighbour)
var world_location: = _grid.map_to_world(location) if not is_world_location else location
return (world_neighbour - world_location).normalized()
func calculate_point_index(point : Vector2) -> int:
point -= _map_limits.position
return int(point.x + _map_limits.size.x * point.y)
func calculate_point_index_for_world_position(world_position: Vector2) -> int:
return calculate_point_index(_grid.world_to_map(world_position))
func _refresh_cells_heat(player_cell_position: Vector2) -> void:
for y in range(_y_min, _y_max):
for x in range(_x_min, _x_max):
var point: = Vector2(x,y)
var cell_index: int = calculate_point_index(point)
var path: Array = _pathfinder.find_path(point, player_cell_position)
if path.size() == 0:
continue
var heat: int = path.size()
_cells_heat_cache[cell_index] = heat
_mutex.lock()
_finished_updating = true
_mutex.unlock()
func _is_out_of_bounds(player_cell_position: Vector2) -> bool:
return (player_cell_position.x < _x_min
or player_cell_position.y < _y_min
or player_cell_position.x > _x_max
or player_cell_position.y > _y_max)
func _on_Events_player_moved(player: Player) -> void:
if _updating:
return
var player_cell_position: Vector2 = _grid.world_to_map(player.global_position)
var out_of_bounds: = _is_out_of_bounds(player_cell_position)
if (not out_of_bounds
and (player_cell_position.x != _last_player_cell_position.x
or player_cell_position.y != _last_player_cell_position.y)):
_updating = true
_finished_updating = false
_thread.start(self, "_refresh_cells_heat", player_cell_position)
while true:
var locked: = _mutex.try_lock()
if locked == OK and _finished_updating:
_mutex.unlock()
break
_mutex.unlock()
yield(get_tree(), "idle_frame")
_thread.wait_to_finish()
_cells_heat = [] + _cells_heat_cache
_last_player_cell_position = player_cell_position
_updating = false
update()

86
game/src/AI/Pathfinder.gd Normal file
View file

@ -0,0 +1,86 @@
"""
Finds the path between two points using AStar, in grid coordinates
Code by razcore as part of the GDQuest OpenRPG project:
https://github.com/GDquest/godot-open-rpg
It's been modified and extended a little to not allow diagonals, and to allow
tiles that lie on the negative side of the Tilemap planes.
"""
class_name Pathfinder
var astar : AStar = AStar.new()
var _obstacles : Array
var _map_size : Rect2
var _x_min: float
var _x_max: float
var _y_min: float
var _y_max: float
func initialize(grid : TileMap, obstacle_tile_ids : Array) -> void:
"""
Initializes the AStar node: finds all walkable cells
and connects all walkable paths
"""
# Initialize map size and obstacles array
_map_size = grid.get_used_rect()
_x_min = _map_size.position.x
_x_max = _map_size.size.x - _map_size.position.x
_y_min = _map_size.position.y
_y_max = _map_size.size.y - _map_size.position.y
for id in obstacle_tile_ids:
var occupied_cells = (grid as TileMap).get_used_cells_by_id(id)
for cell in occupied_cells:
_obstacles.append(cell)
# Find all walkable cells and store them in an array
var points_array : = []
for y in range(_y_min, _y_max):
for x in range(_x_min, _x_max):
var point = Vector2(x, y)
if point in _obstacles:
continue
points_array.append(point)
var point_index = calculate_point_index(point)
astar.add_point(point_index, Vector3(point.x, point.y, 0))
# Loop through all walkable cells and their neighbors
# to connect the points
for point in points_array:
var point_index = calculate_point_index(point)
for y in range(0, 3):
for x in range(0, 3):
var point_relative: = Vector2(point.x + x - 1, point.y + y - 1)
#only connect south-north and west-east, no diagonals
if point_relative.x != point.x and point_relative.y != point.y:
continue
var point_relative_index: = calculate_point_index(point_relative)
if (point_relative != point and not is_outside_map_bounds(point_relative)
and astar.has_point(point_relative_index)):
astar.connect_points(point_index, point_relative_index)
func is_outside_map_bounds(point : Vector2) -> bool:
return (point.x < _x_min
or point.y < _y_min
or point.x >= _x_max
or point.y >= _y_max)
func calculate_point_index(point : Vector2) -> int:
point -= _map_size.position
return int(point.x + _map_size.size.x * point.y)
func find_path(start : Vector2, end : Vector2) -> PoolVector3Array:
"""
Returns an array of cells that connect the start and end positions
in grid coordinates
"""
var start_index = calculate_point_index(start)
var end_index = calculate_point_index(end)
return astar.get_point_path(start_index, end_index)

View file

View file

@ -4,6 +4,7 @@
#include <Viewport.hpp>
#include <deque>
#include <TileSet.hpp>
#include <algorithm>
namespace godot {
inline float lerp(const float& a, const float& b, const float& t) {