First commit 🎉
This commit is contained in:
commit
43ea213f9b
728 changed files with 37080 additions and 0 deletions
274
addons/popochiu/editor/gizmos/gizmo2d.gd
Normal file
274
addons/popochiu/editor/gizmos/gizmo2d.gd
Normal file
|
@ -0,0 +1,274 @@
|
|||
@tool
|
||||
class_name Gizmo2D
|
||||
extends RefCounted
|
||||
|
||||
# Gizmo types
|
||||
enum {
|
||||
GIZMO_POS, # square marker that represents (x,y) coordinates
|
||||
GIZMO_HPOS, # vertical line that represents a horizontal coordinate
|
||||
GIZMO_VPOS # horizontal line that represents a vertical coordinate
|
||||
}
|
||||
|
||||
# Public vars
|
||||
# Convenience accessors
|
||||
var target_node: Node2D:
|
||||
set = set_target_node,
|
||||
get = get_target_node
|
||||
var target_property: String:
|
||||
set = set_target_property,
|
||||
get = get_target_property
|
||||
var position:
|
||||
get = get_position
|
||||
# Behavior flags
|
||||
var show_connector: bool = true # Show gizmo-to-node connectors
|
||||
var show_outlines: bool = true
|
||||
var show_target_name: bool = true # Show target node name
|
||||
var visible: bool = true # Gizmo visibility
|
||||
|
||||
# Private vars
|
||||
# Context
|
||||
var _type: int
|
||||
var _target_node: Node2D
|
||||
var _target_property: String
|
||||
# Appearance
|
||||
var _size: Vector2 # Gizmo width and height
|
||||
var _color: Color # Gizmo color
|
||||
var _label: String # A label to be painted near the Gizmo
|
||||
var _font: Font # Label font
|
||||
var _font_size: int # Label font size
|
||||
# State
|
||||
var _handle: Rect2 # Gizmo handle
|
||||
var _current_position: Vector2 # The position the gizmo is representing in every moment
|
||||
var _current_color: Color
|
||||
var _is_grabbed: bool = false # Gizmo is moving
|
||||
var _grab_center_pos: Vector2 # Starting center position when grabbing
|
||||
var _grab_mouse_pos: Vector2 # Starting mouse position when grabbing
|
||||
|
||||
|
||||
#region Virtual ####################################################################################
|
||||
|
||||
func _init(
|
||||
node: Node,
|
||||
property: String,
|
||||
label: String,
|
||||
type: int,
|
||||
):
|
||||
_target_node = node
|
||||
_target_property = property
|
||||
_type = type
|
||||
_label = label
|
||||
|
||||
set_theme(
|
||||
Color.AQUA,
|
||||
24,
|
||||
EditorInterface.get_editor_theme().default_font,
|
||||
EditorInterface.get_editor_theme().default_font_size
|
||||
)
|
||||
|
||||
_current_color = _color
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region SetGet #####################################################################################
|
||||
|
||||
func set_theme(
|
||||
color: Color,
|
||||
size: int,
|
||||
font: Font,
|
||||
font_size: int
|
||||
):
|
||||
_color = color
|
||||
_size = Vector2(size, size)
|
||||
_font = font
|
||||
_font_size = font_size
|
||||
|
||||
func set_target_node(node: Node2D):
|
||||
_target_node = node
|
||||
|
||||
func get_target_node() -> Node2D:
|
||||
return _target_node
|
||||
|
||||
func set_target_property(property: String):
|
||||
_target_property = property
|
||||
|
||||
func get_target_property() -> String:
|
||||
if _target_property:
|
||||
return _target_property
|
||||
return ""
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private ####################################################################################
|
||||
|
||||
func _draw_outlines(viewport: Control):
|
||||
viewport.draw_rect(
|
||||
_handle,
|
||||
Color.BLACK, false, 4
|
||||
)
|
||||
|
||||
viewport.draw_string_outline(
|
||||
_font,
|
||||
_handle.position + Vector2(0, _size.y + 2 + _font.get_ascent(_font_size)),
|
||||
_label, HORIZONTAL_ALIGNMENT_CENTER,
|
||||
- 1,
|
||||
_font_size,
|
||||
6,
|
||||
Color.BLACK
|
||||
)
|
||||
|
||||
if show_target_name:
|
||||
viewport.draw_string_outline(
|
||||
_font,
|
||||
_handle.position + Vector2(0, -_font.get_descent(_font_size)),
|
||||
_target_node.name,
|
||||
HORIZONTAL_ALIGNMENT_CENTER,
|
||||
- 1,
|
||||
_font_size,
|
||||
6,
|
||||
Color.BLACK
|
||||
)
|
||||
|
||||
func _draw_gizmo(viewport: Control):
|
||||
|
||||
# Draw the handle (on top of the line, if it's present)
|
||||
viewport.draw_rect(
|
||||
_handle,
|
||||
_current_color
|
||||
)
|
||||
|
||||
# Draw gizmo-to-node connector, if active
|
||||
if show_connector:
|
||||
viewport.draw_dashed_line(
|
||||
(_target_node.get_viewport_transform() * _target_node.get_global_transform()).origin,
|
||||
_handle.get_center(),
|
||||
_current_color.darkened(0.2),
|
||||
2,
|
||||
4
|
||||
)
|
||||
viewport.draw_circle(
|
||||
_handle.get_center(),
|
||||
3,
|
||||
_current_color.darkened(0.2)
|
||||
)
|
||||
|
||||
# Draw the label, if it's set and non empty
|
||||
if _label:
|
||||
viewport.draw_string(
|
||||
_font,
|
||||
_handle.position + Vector2(0, _size.y + 2 + _font.get_ascent(_font_size)),
|
||||
_label, HORIZONTAL_ALIGNMENT_CENTER,
|
||||
- 1,
|
||||
_font_size,
|
||||
_current_color
|
||||
)
|
||||
|
||||
if show_target_name:
|
||||
viewport.draw_string(
|
||||
_font,
|
||||
_handle.position + Vector2(0, -_font.get_descent(_font_size)),
|
||||
_target_node.name,
|
||||
HORIZONTAL_ALIGNMENT_CENTER,
|
||||
- 1,
|
||||
_font_size,
|
||||
_current_color
|
||||
)
|
||||
|
||||
func _can_draw():
|
||||
return (visible and _target_node != null and _target_node.is_visible_in_tree())
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public #####################################################################################
|
||||
|
||||
func draw(viewport: Control, coord: Variant) -> void:
|
||||
# Handmade coordinates type overloading
|
||||
if not (coord is Vector2 or coord is int):
|
||||
return
|
||||
# Check if the gizmo can be drawn
|
||||
if not _can_draw():
|
||||
return
|
||||
|
||||
# Coordinates normalization (to vector) for horizontal or vertical gizmos
|
||||
# Both axis are set to the same value, then ignore one or the other
|
||||
# depending on the gizmo type
|
||||
if coord is int:
|
||||
coord = Vector2(coord, coord)
|
||||
|
||||
# Calculate the GLOBAL coordinates of the center of the square handle
|
||||
# This only takes into account the node offset discarding its transform basis
|
||||
# (representing rotation, skew and scale) then it applies the viewport transform
|
||||
# to take into account the zoom level
|
||||
var center = _target_node.get_viewport_transform() * (_target_node.get_global_transform().origin + Vector2(coord))
|
||||
|
||||
# Set handle color
|
||||
_current_color = _color
|
||||
# Highlight handle if held by the mouse click
|
||||
if _is_grabbed:
|
||||
_current_color = _color.lightened(0.5)
|
||||
|
||||
# Draw an horizontal or vertical line if the gizmo is one-dimensional
|
||||
match _type:
|
||||
GIZMO_VPOS:
|
||||
var viewport_width = EditorInterface.get_editor_viewport_2d().size.x
|
||||
center.x = viewport_width / 2
|
||||
viewport.draw_line(
|
||||
Vector2(0, center.y),
|
||||
Vector2(viewport_width, center.y),
|
||||
_current_color,
|
||||
2
|
||||
)
|
||||
GIZMO_HPOS:
|
||||
var viewport_height = EditorInterface.get_editor_viewport_2d().size.y
|
||||
center.y = viewport_height / 2
|
||||
viewport.draw_line(
|
||||
Vector2(center.x, 0),
|
||||
Vector2(center.x, viewport_height),
|
||||
_current_color,
|
||||
2
|
||||
)
|
||||
|
||||
# Initialize the handle in the right position
|
||||
_handle = Rect2(center - _size / 2, _size)
|
||||
|
||||
if show_outlines:
|
||||
_draw_outlines(viewport)
|
||||
|
||||
_draw_gizmo(viewport)
|
||||
|
||||
func drag_to(pos: Vector2):
|
||||
# Distance between the mouse position and the gizmo center
|
||||
var d = _grab_center_pos - _grab_mouse_pos
|
||||
# Gizmo center position in global coordinates
|
||||
var current_gizmo_pos = pos + d
|
||||
# Distance between gizmo center position in 2D world node coordinates and
|
||||
# node position ignoring its transform basis (representing rotation, skew and scale)
|
||||
_current_position = _target_node.get_viewport_transform().affine_inverse() * current_gizmo_pos - (target_node.get_global_transform().origin)
|
||||
|
||||
func release():
|
||||
_is_grabbed = false
|
||||
|
||||
func grab(pos: Vector2):
|
||||
_is_grabbed = true
|
||||
_grab_mouse_pos = pos
|
||||
_grab_center_pos = _handle.get_center()
|
||||
|
||||
func cancel():
|
||||
_is_grabbed = false
|
||||
|
||||
func has_point(pos: Vector2):
|
||||
return visible and _handle.abs().has_point(pos)
|
||||
|
||||
func get_position():
|
||||
match _type:
|
||||
GIZMO_POS:
|
||||
return _current_position
|
||||
GIZMO_HPOS:
|
||||
return _current_position.x
|
||||
GIZMO_VPOS:
|
||||
return _current_position.y
|
||||
|
||||
|
||||
#endregion
|
1
addons/popochiu/editor/gizmos/gizmo2d.gd.uid
Normal file
1
addons/popochiu/editor/gizmos/gizmo2d.gd.uid
Normal file
|
@ -0,0 +1 @@
|
|||
uid://71g54gbvyv7l
|
278
addons/popochiu/editor/gizmos/gizmo_clickable_plugin.gd
Normal file
278
addons/popochiu/editor/gizmos/gizmo_clickable_plugin.gd
Normal file
|
@ -0,0 +1,278 @@
|
|||
@tool
|
||||
class_name PopochiuGizmoClickablePlugin
|
||||
extends EditorPlugin
|
||||
|
||||
# TODO: move these out of the plugin and into Popochiu (enums) or PopochiuClickable
|
||||
enum {
|
||||
WALK_TO_POINT,
|
||||
LOOK_AT_POINT,
|
||||
BASELINE,
|
||||
DIALOG_POS
|
||||
}
|
||||
|
||||
# Private vars
|
||||
# State
|
||||
var _target_node: Node2D
|
||||
var _undo: EditorUndoRedoManager
|
||||
var _gizmos: Array
|
||||
var _active_gizmos: Array
|
||||
var _grabbed_gizmo: Gizmo2D
|
||||
|
||||
|
||||
#region Godot ######################################################################################
|
||||
|
||||
func _enter_tree() -> void:
|
||||
# TODO: remove the following 2 lines when the plugin is connected to the appropriate signal
|
||||
# e.g. popochiu_ready
|
||||
PopochiuEditorConfig.initialize_editor_settings()
|
||||
PopochiuConfig.initialize_project_settings()
|
||||
|
||||
# Initialization of the plugin goes here.
|
||||
_undo = get_undo_redo()
|
||||
_gizmos.insert(WALK_TO_POINT, _init_popochiu_gizmo(WALK_TO_POINT))
|
||||
_gizmos.insert(LOOK_AT_POINT, _init_popochiu_gizmo(LOOK_AT_POINT))
|
||||
_gizmos.insert(BASELINE, _init_popochiu_gizmo(BASELINE))
|
||||
_gizmos.insert(DIALOG_POS, _init_popochiu_gizmo(DIALOG_POS))
|
||||
|
||||
EditorInterface.get_editor_settings().settings_changed.connect(_on_gizmo_settings_changed)
|
||||
PopochiuEditorHelper.signal_bus.gizmo_visibility_changed.connect(_on_gizmo_visibility_changed)
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Virtual ####################################################################################
|
||||
|
||||
func _edit(object: Object) -> void:
|
||||
if object == null or object.get_class() == "EditorDebuggerRemoteObject":
|
||||
return
|
||||
|
||||
_target_node = object
|
||||
_active_gizmos.clear()
|
||||
|
||||
if EditorInterface.get_edited_scene_root() is PopochiuCharacter:
|
||||
_active_gizmos.append(_gizmos[DIALOG_POS])
|
||||
elif EditorInterface.get_edited_scene_root() is PopochiuRoom:
|
||||
_active_gizmos.append(_gizmos[WALK_TO_POINT])
|
||||
_active_gizmos.append(_gizmos[LOOK_AT_POINT])
|
||||
_active_gizmos.append(_gizmos[BASELINE])
|
||||
|
||||
for gizmo in _active_gizmos:
|
||||
gizmo.set_target_node(_target_node)
|
||||
|
||||
if not EditorInterface.get_inspector().property_edited.is_connected(_on_property_changed):
|
||||
EditorInterface.get_inspector().property_edited.connect(_on_property_changed)
|
||||
update_overlays()
|
||||
|
||||
|
||||
func _forward_canvas_draw_over_viewport(viewport_control: Control) -> void:
|
||||
for gizmo in _active_gizmos:
|
||||
gizmo.draw(viewport_control, _target_node.get(gizmo.target_property))
|
||||
|
||||
|
||||
func _handles(object: Object) -> bool:
|
||||
return object is PopochiuClickable
|
||||
|
||||
|
||||
func _forward_canvas_gui_input(event: InputEvent) -> bool:
|
||||
if not _target_node or not _target_node.is_visible_in_tree():
|
||||
return false
|
||||
|
||||
# For left mouse buttons, try to grab or release, depending on state
|
||||
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
|
||||
# Grab
|
||||
if not _grabbed_gizmo and event.is_pressed():
|
||||
return _try_grab_gizmo(event)
|
||||
# Release
|
||||
elif _grabbed_gizmo and event.is_released():
|
||||
return _release_gizmo(event)
|
||||
|
||||
# For mouse movement, drag the grabbed gizmo
|
||||
if event is InputEventMouseMotion:
|
||||
return _drag_gizmo(event)
|
||||
|
||||
# For ESC key or comparable events, cancel the dragging if in place
|
||||
if event.is_action_pressed("ui_cancel"):
|
||||
return _cancel_dragging_gizmo(event)
|
||||
|
||||
## Nothing to handle outside the cases above
|
||||
return false
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private ####################################################################################
|
||||
|
||||
func _on_property_changed(property: String):
|
||||
update_overlays()
|
||||
|
||||
|
||||
func _on_gizmo_settings_changed() -> void:
|
||||
var gizmo_id = 0
|
||||
var default_font = EditorInterface.get_editor_theme().default_font
|
||||
|
||||
for gizmo in _gizmos:
|
||||
match gizmo_id:
|
||||
WALK_TO_POINT:
|
||||
gizmo.set_theme(
|
||||
PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_WALK_TO_POINT_COLOR),
|
||||
PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_HANDLER_SIZE),
|
||||
default_font,
|
||||
PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_FONT_SIZE)
|
||||
)
|
||||
LOOK_AT_POINT:
|
||||
gizmo.set_theme(
|
||||
PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_LOOK_AT_POINT_COLOR),
|
||||
PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_HANDLER_SIZE),
|
||||
default_font,
|
||||
PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_FONT_SIZE)
|
||||
)
|
||||
BASELINE:
|
||||
gizmo.set_theme(
|
||||
PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_BASELINE_COLOR),
|
||||
PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_HANDLER_SIZE),
|
||||
default_font,
|
||||
PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_FONT_SIZE)
|
||||
)
|
||||
DIALOG_POS:
|
||||
gizmo.set_theme(
|
||||
PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_DIALOG_POS_COLOR),
|
||||
PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_HANDLER_SIZE),
|
||||
default_font,
|
||||
PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_FONT_SIZE)
|
||||
)
|
||||
|
||||
gizmo.show_connector = PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_SHOW_CONNECTORS)
|
||||
gizmo.show_outlines = PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_SHOW_OUTLINE)
|
||||
gizmo.show_target_name = PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_SHOW_NODE_NAME)
|
||||
gizmo_id += 1
|
||||
|
||||
update_overlays()
|
||||
|
||||
|
||||
func _on_gizmo_visibility_changed(gizmo_id:int, visibility:bool):
|
||||
if gizmo_id < _gizmos.size():
|
||||
_gizmos[gizmo_id].visible = visibility
|
||||
update_overlays()
|
||||
|
||||
func _update_properties():
|
||||
if _grabbed_gizmo and _grabbed_gizmo.target_property:
|
||||
_target_node.set(
|
||||
_grabbed_gizmo.target_property,
|
||||
_grabbed_gizmo.get_position()
|
||||
)
|
||||
|
||||
|
||||
func _init_popochiu_gizmo(gizmo_id: int) -> Gizmo2D:
|
||||
var gizmo: Gizmo2D
|
||||
var default_font = EditorInterface.get_editor_theme().default_font
|
||||
|
||||
match gizmo_id:
|
||||
WALK_TO_POINT:
|
||||
gizmo = Gizmo2D.new(_target_node, "walk_to_point", "Walk To Point", Gizmo2D.GIZMO_POS)
|
||||
gizmo.set_theme(
|
||||
PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_WALK_TO_POINT_COLOR),
|
||||
PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_HANDLER_SIZE),
|
||||
default_font,
|
||||
PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_FONT_SIZE)
|
||||
)
|
||||
LOOK_AT_POINT:
|
||||
gizmo = Gizmo2D.new(_target_node, "look_at_point", "Look At Point", Gizmo2D.GIZMO_POS)
|
||||
gizmo.set_theme(
|
||||
PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_LOOK_AT_POINT_COLOR),
|
||||
PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_HANDLER_SIZE),
|
||||
default_font,
|
||||
PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_FONT_SIZE)
|
||||
)
|
||||
BASELINE:
|
||||
gizmo = Gizmo2D.new(_target_node, "baseline", "Baseline", Gizmo2D.GIZMO_VPOS)
|
||||
gizmo.set_theme(
|
||||
PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_BASELINE_COLOR),
|
||||
PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_HANDLER_SIZE),
|
||||
default_font,
|
||||
PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_FONT_SIZE)
|
||||
)
|
||||
DIALOG_POS:
|
||||
gizmo = Gizmo2D.new(_target_node, "dialog_pos", "Dialog Position", Gizmo2D.GIZMO_POS)
|
||||
gizmo.set_theme(
|
||||
PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_DIALOG_POS_COLOR),
|
||||
PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_HANDLER_SIZE),
|
||||
default_font,
|
||||
PopochiuEditorConfig.get_editor_setting(PopochiuEditorConfig.GIZMOS_FONT_SIZE)
|
||||
)
|
||||
return gizmo
|
||||
|
||||
|
||||
func _try_grab_gizmo(event: InputEventMouseButton) -> bool:
|
||||
# Check if the mouse click happened on a gizmo
|
||||
# The order is reversed to the topmost gizmo
|
||||
# (the last been drawn) is selected
|
||||
for i in range(_active_gizmos.size() - 1, -1, -1):
|
||||
if not _active_gizmos[i].has_point(event.position):
|
||||
continue
|
||||
_grabbed_gizmo = _active_gizmos[i]
|
||||
break
|
||||
|
||||
# If user clicked on no gizmos
|
||||
# ignore the event
|
||||
if not _grabbed_gizmo:
|
||||
return false
|
||||
|
||||
# hold the gizmo with the mouse
|
||||
_grabbed_gizmo.grab(event.position)
|
||||
_undo.create_action("Move gizmo")
|
||||
_undo.add_undo_property(
|
||||
_grabbed_gizmo.target_node,
|
||||
_grabbed_gizmo.target_property,
|
||||
_grabbed_gizmo.target_node.get(_grabbed_gizmo.target_property)
|
||||
)
|
||||
update_overlays()
|
||||
return true
|
||||
|
||||
|
||||
func _release_gizmo(event: InputEvent) -> bool:
|
||||
# If there is no gizmo to release
|
||||
# ignore the event
|
||||
if not _grabbed_gizmo:
|
||||
return false
|
||||
|
||||
_grabbed_gizmo.release()
|
||||
_undo.add_do_property(
|
||||
_grabbed_gizmo.target_node,
|
||||
_grabbed_gizmo.target_property,
|
||||
_grabbed_gizmo.target_node.get(_grabbed_gizmo.target_property)
|
||||
)
|
||||
_undo.commit_action()
|
||||
update_overlays()
|
||||
_grabbed_gizmo = null
|
||||
return true
|
||||
|
||||
|
||||
func _drag_gizmo(event: InputEvent) -> bool:
|
||||
# If no gizmo to drag
|
||||
# ignore the event
|
||||
if not _grabbed_gizmo:
|
||||
return false
|
||||
|
||||
# Drag the gizmo
|
||||
_grabbed_gizmo.drag_to(event.position)
|
||||
_update_properties()
|
||||
update_overlays()
|
||||
return true
|
||||
|
||||
|
||||
func _cancel_dragging_gizmo(event: InputEvent) -> bool:
|
||||
# If ESC/Cancel happens but we're not dragging
|
||||
# ignore the event
|
||||
if not _grabbed_gizmo:
|
||||
return false
|
||||
|
||||
# Cancel the action
|
||||
_grabbed_gizmo.cancel()
|
||||
_undo.commit_action()
|
||||
_undo.get_history_undo_redo(_undo.get_object_history_id(_grabbed_gizmo.target_node)).undo()
|
||||
update_overlays()
|
||||
_grabbed_gizmo = null
|
||||
return true
|
||||
|
||||
|
||||
#endregion
|
|
@ -0,0 +1 @@
|
|||
uid://1t0c81s6wd7c
|
7
addons/popochiu/editor/gizmos/plugin.cfg
Normal file
7
addons/popochiu/editor/gizmos/plugin.cfg
Normal file
|
@ -0,0 +1,7 @@
|
|||
[plugin]
|
||||
|
||||
name="PopochiuGizmoClickable"
|
||||
description="Provides viewport-drawn interactive 2D gizmos to Popochiu objects in the editor."
|
||||
author="Carenalgas Dev Team"
|
||||
version="2.0"
|
||||
script="gizmo_clickable_plugin.gd"
|
Loading…
Add table
Add a link
Reference in a new issue