maxgame/addons/popochiu/engine/objects/region/popochiu_region.gd
2025-07-17 01:49:18 -04:00

181 lines
5.8 KiB
GDScript

@tool
@icon('res://addons/popochiu/icons/region.png')
class_name PopochiuRegion
extends Area2D
## Used to handle events when a character walks inside or outside of it. Can also be used to scale
## characters while they walk through the region's polygon.
##
## By default, can be used to apply a tint to characters when they enter or leave the region.
## 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 region is or not enabled.
@export var enabled := true : set = _set_enabled
## The [Color] to apply to the character that enters this region.
@export var tint := Color.WHITE
## Whether the region will scale the character while it moves through it.
@export var scaling :bool = false
## The scale to apply to the character inside the region when it moves to the top ([code]y[/code])
## of it.
@export var scale_top :float = 1.0
## The scale to apply to the character inside the region when it moves to the bottom
## ([code]y[/code]) of it.
@export var scale_bottom :float = 1.0
## Stores the vertices to assign to the [b]InteractionPolygon[/b] child during runtime. This is used
## by [PopochiuRoom] to store the info in its [code].tscn[/code].
@export var interaction_polygon := PackedVector2Array()
## Stores the position to assign to the [b]InteractionPolygon[/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
#region Godot ######################################################################################
func _ready() -> void:
add_to_group("regions")
area_entered.connect(_check_area.bind(true))
area_exited.connect(_check_area.bind(false))
area_shape_entered.connect(_check_scaling.bind(true))
area_shape_exited.connect(_check_scaling.bind(false))
if Engine.is_editor_hint():
hide_helpers()
# Ignore assigning the polygon when:
if (
get_node_or_null("InteractionPolygon") == null # there is no InteractionPolygon 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("InteractionPolygon").add_to_group(
PopochiuEditorHelper.POPOCHIU_OBJECT_POLYGON_GROUP
)
if interaction_polygon.is_empty():
interaction_polygon = get_node("InteractionPolygon").polygon
interaction_polygon_position = get_node("InteractionPolygon").position
else:
get_node("InteractionPolygon").polygon = interaction_polygon
get_node("InteractionPolygon").position = interaction_polygon_position
# 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("InteractionPolygon") # there is an InteractionPolygon node
):
get_node("InteractionPolygon").polygon = interaction_polygon
get_node("InteractionPolygon").position = interaction_polygon_position
func _notification(event: int) -> void:
if event == NOTIFICATION_EDITOR_PRE_SAVE:
interaction_polygon = get_node("InteractionPolygon").polygon
interaction_polygon_position = get_node("InteractionPolygon").position
#endregion
#region Virtual ####################################################################################
## Called when a [param chr] enters this region.
## [i]Virtual[/i].
func _on_character_entered(chr: PopochiuCharacter) -> void:
pass
## Called when a [param chr] leaves this region.
## [i]Virtual[/i].
func _on_character_exited(chr: PopochiuCharacter) -> void:
pass
#endregion
#region SetGet #####################################################################################
func _set_enabled(value: bool) -> void:
enabled = value
monitoring = value
notify_property_list_changed()
#endregion
#region Private ####################################################################################
func _check_area(area: Area2D, entered: bool) -> void:
if not area is PopochiuCharacter: return
if entered:
_on_character_entered(area)
else:
_on_character_exited(area)
func _check_scaling(
area_rid: RID, area: Area2D, area_shape_index: int, local_shape_index: int, entered: bool
):
if not (
area is PopochiuCharacter
and area.get_node_or_null("ScalingPolygon")
and area_shape_index == area.get_node("ScalingPolygon").get_index()
):
return
if not entered:
_clear_scaling_region(area)
return
if scaling:
_update_scaling_region(area)
area.update_scale()
func _update_scaling_region(chr: PopochiuCharacter) -> void:
var polygon_y_array = []
for x in get_node("InteractionPolygon").get_polygon():
polygon_y_array.append(x.y)
chr.on_scaling_region= {
"region_description": self.description,
"scale_top": self.scale_top,
"scale_bottom": self.scale_bottom,
"scale_max": [self.scale_top, self.scale_bottom].max(),
"scale_min": [self.scale_top, self.scale_bottom].min(),
"polygon_top_y": (
polygon_y_array.min()+self.position.y+get_node("InteractionPolygon").position.y
if self.position
else ""
),
"polygon_bottom_y": (
polygon_y_array.max()+self.position.y+get_node("InteractionPolygon").position.y
if self.position
else ""),
}
func _clear_scaling_region(chr: PopochiuCharacter) -> void:
if chr.on_scaling_region and chr.on_scaling_region["region_description"] == self.description:
chr.on_scaling_region = {}
#endregion
#region Public #####################################################################################
## Used by the plugin to hide the visual helpers that show the [member baseline] and
## [member walk_to_point] in the 2D Canvas Editor when this node is unselected in the Scene panel.
func hide_helpers() -> void:
# TODO: visibility logic for gizmos
if get_node_or_null("InteractionPolygon"):
$InteractionPolygon.hide()
#endregion