First commit 🎉

This commit is contained in:
Tony Bark 2025-07-17 01:49:18 -04:00
commit 43ea213f9b
728 changed files with 37080 additions and 0 deletions

View file

@ -0,0 +1,141 @@
@tool
@icon('res://addons/popochiu/icons/walkable_area.png')
class_name PopochiuWalkableArea
extends Node2D
## The areas where characters can move.
##
## The area is defined by a [NavigationRegion2D].
## The identifier of the object used in scripts.
@export var script_name := ''
## Can be used to show the name of the area to players.
@export var description := ''
## Whether the area is or not enabled.
@export var enabled := true : set = _set_enabled
## Stores the outlines to assign to the [b]NavigationRegion2D/NavigationPolygon[/b] child during
## runtime. This is used by [PopochiuRoom] to store the info in its [code].tscn[/code].
@export var interaction_polygon := []
## Stores the position to assign to the [b]NavigationRegion2D/NavigationPolygon[/b] child during
## runtime. This is used by [PopochiuRoom] to store the info in its [code].tscn[/code].
@export var interaction_polygon_position := Vector2.ZERO
# TODO: If walkable is false, characters should not be able to walk through this.
#@export var walkable := true
# TODO: Make the value of the tint property to modify the modulate color of the polygon (or the
# modulate of the node itself).
#@export var tint := Color.WHITE
# TODO: Make the scale of the character change depending checked where it is placed in
# this walkable area.
#@export var scale_top := 1.0
#@export var scale_bottom := 1.0
## Property used by [PopochiuRoom]s to activate the map of this area in the [NavigationServer2D].
var map_rid: RID
## Used to assign a map in the [NavigationServer2D] to the region RID of the [b]$Perimeter[/b]
## child.
var rid: RID
#region Godot ######################################################################################
func _ready() -> void:
add_to_group('walkable_areas')
if Engine.is_editor_hint():
# Ignore assigning the polygon when:
if (
get_node_or_null("Perimeter") == null # there is no NavigationArea2D node
or not get_parent() is Node2D # editing it in the .tscn file of the object directly
):
return
# Add interaction polygon to the proper group
get_node("Perimeter").add_to_group(
PopochiuEditorHelper.POPOCHIU_OBJECT_POLYGON_GROUP
)
# Take the reference to the navigation polygon
var navpoly: NavigationPolygon = get_node("Perimeter").navigation_polygon
if interaction_polygon.is_empty():
# Save all the NavigationPolygon outlines in the local variable
for idx in range(0, navpoly.get_outline_count()):
interaction_polygon.append(navpoly.get_outline(idx))
# Save the NavigationRegion2D position
interaction_polygon_position = get_node("Perimeter").position
else:
clear_and_bake(navpoly)
# If we are in the editor, we're done
return
# When the game is running...
# Update the node's polygon when:
if (
get_node_or_null("Perimeter") # there is an Perimeter node
):
# Take the reference to the navigation polygon
var navpoly: NavigationPolygon = get_node("Perimeter").navigation_polygon
clear_and_bake(navpoly)
# Map the necessary resources
map_rid = NavigationServer2D.get_maps()[0]
rid = ($Perimeter as NavigationRegion2D).get_region_rid()
NavigationServer2D.region_set_map(rid, map_rid)
func _notification(event: int) -> void:
if event == NOTIFICATION_EDITOR_PRE_SAVE:
map_navigation_polygon(get_node("Perimeter"))
# Saving the scene is necessary to make the changes permanent.
# If you remove this the character won't be able to walk in the area.
PopochiuEditorHelper.pack_scene(self)
func _exit_tree():
if Engine.is_editor_hint(): return
NavigationServer2D.map_set_active(map_rid, false)
#endregion
#region Public #####################################################################################
## Maps the outlines in [param perimeter] to the [member interaction_polygon] property and also
## stores its position in [member interaction_polygon_position].
func map_navigation_polygon(perimeter: NavigationRegion2D) -> void:
# Take the reference to the navigation polygon
var navpoly: NavigationPolygon = perimeter.navigation_polygon
if not navpoly or not is_instance_valid(navpoly):
return
interaction_polygon.clear()
# Save all the NavigationPolygon outlines in the local variable
for idx in range(0, navpoly.get_outline_count()):
interaction_polygon.append(navpoly.get_outline(idx))
# Save the NavigationRegion2D position
interaction_polygon_position = perimeter.position
## Populates [param navpoly] with all the outlines and bakes it back.
func clear_and_bake(navpoly: NavigationPolygon) -> void:
navpoly.clear_outlines()
for outline in interaction_polygon:
navpoly.add_outline(outline)
NavigationServer2D.bake_from_source_geometry_data(
navpoly, NavigationMeshSourceGeometryData2D.new()
)
# Restore the NavigationRegion2D position
get_node("Perimeter").position = interaction_polygon_position
#endregion
#region SetGet #####################################################################################
func _set_enabled(value: bool) -> void:
enabled = value
notify_property_list_changed()
#endregion
#region Private ####################################################################################
#endregion