who the fuck knows
This commit is contained in:
parent
1c33ea2f59
commit
1da411cacd
31 changed files with 1372 additions and 78 deletions
207
addons/anim_player_refactor/lib/anim_player_refactor.gd
Normal file
207
addons/anim_player_refactor/lib/anim_player_refactor.gd
Normal file
|
|
@ -0,0 +1,207 @@
|
||||||
|
## Core utility class to handle all refactoring logic
|
||||||
|
|
||||||
|
const EditorUtil := preload("res://addons/anim_player_refactor/lib/editor_util.gd")
|
||||||
|
|
||||||
|
var _editor_plugin: EditorPlugin
|
||||||
|
var _undo_redo: EditorUndoRedoManager
|
||||||
|
|
||||||
|
func _init(editor_plugin: EditorPlugin) -> void:
|
||||||
|
_editor_plugin = editor_plugin
|
||||||
|
_undo_redo = editor_plugin.get_undo_redo()
|
||||||
|
|
||||||
|
# Nodes
|
||||||
|
func rename_node_path(anim_player: AnimationPlayer, old: NodePath, new: NodePath):
|
||||||
|
if old == new:
|
||||||
|
return
|
||||||
|
|
||||||
|
_undo_redo.create_action("Refactor node tracks", UndoRedo.MERGE_ALL, anim_player)
|
||||||
|
|
||||||
|
_foreach_animation(anim_player, func(animation: Animation):
|
||||||
|
for i in animation.get_track_count():
|
||||||
|
var path := animation.track_get_path(i)
|
||||||
|
var node_path := path.get_concatenated_names()
|
||||||
|
|
||||||
|
if node_path == old.get_concatenated_names():
|
||||||
|
var new_path := new.get_concatenated_names() + ":" + path.get_concatenated_subnames()
|
||||||
|
animation.track_set_path(i, NodePath(new_path))
|
||||||
|
|
||||||
|
_undo_redo.add_do_property(animation, "tracks/%d/path" % i, new_path)
|
||||||
|
_undo_redo.add_undo_property(animation, "tracks/%d/path" % i, path)
|
||||||
|
)
|
||||||
|
|
||||||
|
_undo_redo.commit_action()
|
||||||
|
|
||||||
|
|
||||||
|
func remove_node_path(anim_player: AnimationPlayer, node_path: NodePath):
|
||||||
|
_undo_redo.create_action("Remove node tracks", UndoRedo.MERGE_ALL, anim_player)
|
||||||
|
|
||||||
|
_foreach_animation_restore(anim_player, _undo_redo, func(animation: Animation):
|
||||||
|
var removed_tracks = 0
|
||||||
|
|
||||||
|
for i in range(animation.get_track_count() - 1, -1, -1):
|
||||||
|
var path = animation.track_get_path(i)
|
||||||
|
|
||||||
|
if NodePath(path.get_concatenated_names()) == node_path:
|
||||||
|
removed_tracks += 1
|
||||||
|
_undo_redo.add_do_method(animation, &'remove_track', i)
|
||||||
|
|
||||||
|
return removed_tracks
|
||||||
|
)
|
||||||
|
|
||||||
|
_undo_redo.commit_action()
|
||||||
|
|
||||||
|
|
||||||
|
# Tracks
|
||||||
|
func rename_track_path(anim_player: AnimationPlayer, old: NodePath, new: NodePath):
|
||||||
|
if old == new:
|
||||||
|
return
|
||||||
|
|
||||||
|
_undo_redo.create_action("Refactor track paths", UndoRedo.MERGE_ALL, anim_player)
|
||||||
|
|
||||||
|
_foreach_animation(anim_player, func(animation: Animation):
|
||||||
|
for i in animation.get_track_count():
|
||||||
|
var path = animation.track_get_path(i)
|
||||||
|
|
||||||
|
if path == old:
|
||||||
|
animation.track_set_path(i, new)
|
||||||
|
|
||||||
|
_undo_redo.add_do_property(animation, "tracks/%d/path" % i, new)
|
||||||
|
_undo_redo.add_undo_property(animation, "tracks/%d/path" % i, old)
|
||||||
|
)
|
||||||
|
|
||||||
|
_undo_redo.commit_action()
|
||||||
|
|
||||||
|
|
||||||
|
func remove_track_path(anim_player: AnimationPlayer, property_path: NodePath):
|
||||||
|
_undo_redo.create_action("Remove tracks", UndoRedo.MERGE_ALL, anim_player)
|
||||||
|
|
||||||
|
_foreach_animation_restore(anim_player, _undo_redo, func(animation: Animation):
|
||||||
|
var removed_tracks = 0
|
||||||
|
|
||||||
|
for i in range(animation.get_track_count() - 1, -1, -1):
|
||||||
|
var path = animation.track_get_path(i)
|
||||||
|
|
||||||
|
if path == property_path:
|
||||||
|
removed_tracks += 1
|
||||||
|
_undo_redo.add_do_method(animation, &'remove_track', i)
|
||||||
|
|
||||||
|
return removed_tracks
|
||||||
|
)
|
||||||
|
|
||||||
|
_undo_redo.commit_action()
|
||||||
|
|
||||||
|
# Method tracks
|
||||||
|
func rename_method(anim_player, old: NodePath, new: NodePath):
|
||||||
|
if old == new:
|
||||||
|
return
|
||||||
|
|
||||||
|
var node_path := NodePath(old.get_concatenated_names())
|
||||||
|
var old_method := old.get_concatenated_subnames()
|
||||||
|
var new_method := new.get_concatenated_subnames()
|
||||||
|
|
||||||
|
_undo_redo.create_action("Rename method keys", UndoRedo.MERGE_ALL, anim_player)
|
||||||
|
|
||||||
|
_foreach_animation(anim_player, func(animation: Animation):
|
||||||
|
for i in animation.get_track_count():
|
||||||
|
if (animation.track_get_type(i) == Animation.TYPE_METHOD and animation.track_get_path(i) == node_path):
|
||||||
|
for j in animation.track_get_key_count(i):
|
||||||
|
var name := animation.method_track_get_name(i, j)
|
||||||
|
if name == old_method:
|
||||||
|
var old_method_params := {
|
||||||
|
"method": old_method,
|
||||||
|
"args": animation.method_track_get_params(i, j)
|
||||||
|
}
|
||||||
|
|
||||||
|
var method_params := {
|
||||||
|
"method": new_method,
|
||||||
|
"args": animation.method_track_get_params(i, j)
|
||||||
|
}
|
||||||
|
|
||||||
|
_undo_redo.add_do_method(animation, &'track_set_key_value', i, j, method_params)
|
||||||
|
_undo_redo.add_undo_method(animation, &'track_set_key_value', i, j, old_method_params)
|
||||||
|
)
|
||||||
|
|
||||||
|
_undo_redo.commit_action()
|
||||||
|
|
||||||
|
|
||||||
|
func remove_method(anim_player: AnimationPlayer, method_path: NodePath):
|
||||||
|
_undo_redo.create_action("Remove method keys", UndoRedo.MERGE_ALL, anim_player)
|
||||||
|
|
||||||
|
_foreach_animation_restore(anim_player, _undo_redo, func(animation: Animation):
|
||||||
|
for i in animation.get_track_count():
|
||||||
|
if (
|
||||||
|
animation.track_get_type(i) == Animation.TYPE_METHOD
|
||||||
|
and StringName(animation.track_get_path(i)) == method_path.get_concatenated_names()
|
||||||
|
):
|
||||||
|
for j in range(animation.track_get_key_count(i) - 1, -1, -1):
|
||||||
|
var name := animation.method_track_get_name(i, j)
|
||||||
|
if name == method_path.get_concatenated_subnames():
|
||||||
|
_undo_redo.add_do_method(animation, &'track_remove_key', i, j)
|
||||||
|
return 0
|
||||||
|
)
|
||||||
|
|
||||||
|
_undo_redo.commit_action()
|
||||||
|
|
||||||
|
|
||||||
|
# Root
|
||||||
|
func change_root(anim_player: AnimationPlayer, new_path: NodePath):
|
||||||
|
var current_root: Node = anim_player.get_node(anim_player.root_node)
|
||||||
|
var new_root: Node = anim_player.get_node_or_null(new_path)
|
||||||
|
|
||||||
|
if new_root == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
_undo_redo.create_action("Change animation player root", UndoRedo.MERGE_ALL, anim_player)
|
||||||
|
|
||||||
|
_foreach_animation(anim_player, func(animation: Animation):
|
||||||
|
for i in animation.get_track_count():
|
||||||
|
var path := animation.track_get_path(i)
|
||||||
|
var node := current_root.get_node_or_null(NodePath(path.get_concatenated_names()))
|
||||||
|
|
||||||
|
if node == null:
|
||||||
|
push_warning("Invalid path: %s. Skipping root change." % path)
|
||||||
|
continue
|
||||||
|
|
||||||
|
var updated_path = str(new_root.get_path_to(node)) + ":" + path.get_concatenated_subnames()
|
||||||
|
|
||||||
|
_undo_redo.add_do_property(animation, "tracks/%d/path" % i, updated_path)
|
||||||
|
_undo_redo.add_undo_property(animation, "tracks/%d/path" % i, path)
|
||||||
|
)
|
||||||
|
|
||||||
|
_undo_redo.add_do_property(anim_player, "root_node", new_path)
|
||||||
|
_undo_redo.add_undo_property(anim_player, "root_node", anim_player.root_node)
|
||||||
|
|
||||||
|
_undo_redo.commit_action()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Helper methods
|
||||||
|
|
||||||
|
## Iterates over all animations in the animation player
|
||||||
|
static func _foreach_animation(anim_player: AnimationPlayer, callback: Callable):
|
||||||
|
for lib_name in anim_player.get_animation_library_list():
|
||||||
|
var lib := anim_player.get_animation_library(lib_name)
|
||||||
|
for animation_name in lib.get_animation_list():
|
||||||
|
var animation := lib.get_animation(animation_name)
|
||||||
|
callback.call(animation)
|
||||||
|
|
||||||
|
|
||||||
|
## Iterates over all animations in the animation player and adds a full revert to the undo stack
|
||||||
|
## Useful for do actions that remove tracks
|
||||||
|
static func _foreach_animation_restore(anim_player: AnimationPlayer, undo_redo: EditorUndoRedoManager, callback: Callable):
|
||||||
|
for lib_name in anim_player.get_animation_library_list():
|
||||||
|
var lib := anim_player.get_animation_library(lib_name)
|
||||||
|
for animation_name in lib.get_animation_list():
|
||||||
|
var animation := lib.get_animation(animation_name)
|
||||||
|
|
||||||
|
var old_anim := animation.duplicate(true)
|
||||||
|
|
||||||
|
var removed_tracked = callback.call(animation)
|
||||||
|
|
||||||
|
for i in range(animation.get_track_count() - 1 - removed_tracked, -1, -1):
|
||||||
|
undo_redo.add_undo_method(animation, &'remove_track', i)
|
||||||
|
|
||||||
|
for i in range(old_anim.get_track_count()):
|
||||||
|
undo_redo.add_undo_method(old_anim, &'copy_track', i, animation)
|
||||||
|
|
||||||
|
undo_redo.add_undo_reference(old_anim)
|
||||||
64
addons/anim_player_refactor/lib/editor_util.gd
Normal file
64
addons/anim_player_refactor/lib/editor_util.gd
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
# Utility class for parsing and hacking the editor
|
||||||
|
|
||||||
|
## Find menu button to add option to
|
||||||
|
static func find_animation_menu_button(node: Node) -> MenuButton:
|
||||||
|
var animation_editor := find_editor_control_with_class(node, "AnimationPlayerEditor")
|
||||||
|
if animation_editor:
|
||||||
|
return find_editor_control_with_class(
|
||||||
|
animation_editor,
|
||||||
|
"MenuButton",
|
||||||
|
func(node): return node.text == "Animation"
|
||||||
|
)
|
||||||
|
|
||||||
|
return null
|
||||||
|
|
||||||
|
|
||||||
|
## General utility to find a control in the editor using an iterative search
|
||||||
|
static func find_editor_control_with_class(
|
||||||
|
base: Control,
|
||||||
|
p_class_name: StringName,
|
||||||
|
condition := func(node: Node): return true
|
||||||
|
) -> Node:
|
||||||
|
if base.get_class() == p_class_name and condition.call(base):
|
||||||
|
return base
|
||||||
|
|
||||||
|
for child in base.get_children():
|
||||||
|
if not child is Control:
|
||||||
|
continue
|
||||||
|
|
||||||
|
var found = find_editor_control_with_class(child, p_class_name)
|
||||||
|
if found:
|
||||||
|
return found
|
||||||
|
|
||||||
|
return null
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Finds the active animation player (either pinned or selected)
|
||||||
|
static func find_active_anim_player(base_control: Control, scene_tree: Tree) -> AnimationPlayer:
|
||||||
|
var find_anim_player_recursive: Callable
|
||||||
|
|
||||||
|
var pin_icon := scene_tree.get_theme_icon("Pin", "EditorIcons")
|
||||||
|
|
||||||
|
var stack: Array[TreeItem] = []
|
||||||
|
stack.append(scene_tree.get_root())
|
||||||
|
|
||||||
|
while not stack.is_empty():
|
||||||
|
var current := stack.pop_back() as TreeItem
|
||||||
|
|
||||||
|
# Check for pin icon
|
||||||
|
for i in current.get_button_count(0):
|
||||||
|
if current.get_button(0, i) == pin_icon:
|
||||||
|
var node := base_control.get_node_or_null(current.get_metadata(0))
|
||||||
|
if node is AnimationPlayer:
|
||||||
|
return node
|
||||||
|
|
||||||
|
if current.is_selected(0):
|
||||||
|
var node := base_control.get_node_or_null(current.get_metadata(0))
|
||||||
|
if node is AnimationPlayer:
|
||||||
|
return node
|
||||||
|
|
||||||
|
for i in range(current.get_child_count() - 1, -1, -1):
|
||||||
|
stack.push_back(current.get_child(i))
|
||||||
|
|
||||||
|
return null
|
||||||
7
addons/anim_player_refactor/plugin.cfg
Normal file
7
addons/anim_player_refactor/plugin.cfg
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
[plugin]
|
||||||
|
|
||||||
|
name="Animation Player Refactor"
|
||||||
|
description="Refactoring tools for AnimationPlayer libraries. Adds \"Refactor\" menu option under AnimationPlayer > Animation."
|
||||||
|
author="poohcom1"
|
||||||
|
version="0.1.4"
|
||||||
|
script="plugin.gd"
|
||||||
144
addons/anim_player_refactor/plugin.gd
Normal file
144
addons/anim_player_refactor/plugin.gd
Normal file
|
|
@ -0,0 +1,144 @@
|
||||||
|
@tool
|
||||||
|
extends EditorPlugin
|
||||||
|
|
||||||
|
const RefactorDialogue := preload("scenes/refactor_dialogue/refactor_dialogue.gd")
|
||||||
|
|
||||||
|
const AnimPlayerInspectorButton := preload("scenes/inspector_button/inspector_button.gd")
|
||||||
|
|
||||||
|
const EditorUtil := preload("lib/editor_util.gd")
|
||||||
|
|
||||||
|
var activate_button: AnimPlayerInspectorButton
|
||||||
|
var refactor_dialogue: RefactorDialogue
|
||||||
|
|
||||||
|
var anim_menu_button: MenuButton
|
||||||
|
|
||||||
|
var _last_anim_player: AnimationPlayer
|
||||||
|
const SCENE_TREE_IDX := 0
|
||||||
|
var _scene_tree: Tree
|
||||||
|
|
||||||
|
func _enter_tree() -> void:
|
||||||
|
# Create dialogue
|
||||||
|
refactor_dialogue = load("res://addons/anim_player_refactor/scenes/refactor_dialogue/refactor_dialogue.tscn").instantiate()
|
||||||
|
get_editor_interface().get_base_control().add_child(refactor_dialogue)
|
||||||
|
refactor_dialogue.init(self)
|
||||||
|
# Create menu button
|
||||||
|
_add_refactor_option(func():
|
||||||
|
refactor_dialogue.popup_centered()
|
||||||
|
refactor_dialogue.reset_size()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func _exit_tree() -> void:
|
||||||
|
if refactor_dialogue and refactor_dialogue.is_inside_tree():
|
||||||
|
get_editor_interface().get_base_control().remove_child(refactor_dialogue)
|
||||||
|
refactor_dialogue.queue_free()
|
||||||
|
|
||||||
|
_remove_refactor_option()
|
||||||
|
|
||||||
|
|
||||||
|
func _handles(object: Object) -> bool:
|
||||||
|
if object is AnimationPlayer:
|
||||||
|
_last_anim_player = object
|
||||||
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
# Editor methods
|
||||||
|
func get_anim_player() -> AnimationPlayer:
|
||||||
|
# Check for pinned animation
|
||||||
|
if not _scene_tree:
|
||||||
|
var _scene_tree_editor = EditorUtil.find_editor_control_with_class(
|
||||||
|
get_editor_interface().get_base_control(),
|
||||||
|
"SceneTreeEditor"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not _scene_tree_editor:
|
||||||
|
push_error("[Animation Refactor] Could not find scene tree editor. Please report this.")
|
||||||
|
return null
|
||||||
|
|
||||||
|
_scene_tree = _scene_tree_editor.get_child(SCENE_TREE_IDX)
|
||||||
|
|
||||||
|
if not _scene_tree:
|
||||||
|
push_error("[Animation Refactor] Could not find scene tree editor. Please report this.")
|
||||||
|
return null
|
||||||
|
|
||||||
|
var found_anim := EditorUtil.find_active_anim_player(
|
||||||
|
get_editor_interface().get_base_control(),
|
||||||
|
_scene_tree
|
||||||
|
)
|
||||||
|
|
||||||
|
if found_anim:
|
||||||
|
return found_anim
|
||||||
|
|
||||||
|
# Get latest edited
|
||||||
|
return _last_anim_player
|
||||||
|
|
||||||
|
|
||||||
|
# Plugin buttons
|
||||||
|
|
||||||
|
const TOOL_REFACTOR := 999
|
||||||
|
const TOOL_ANIM_LIBRARY := 1
|
||||||
|
|
||||||
|
func _add_refactor_option(on_pressed: Callable):
|
||||||
|
var base_control := get_editor_interface().get_base_control()
|
||||||
|
if not anim_menu_button:
|
||||||
|
anim_menu_button = EditorUtil.find_animation_menu_button(base_control)
|
||||||
|
if not anim_menu_button:
|
||||||
|
push_error("Could not find Animation menu button. Please report this issue.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Remove item up to "Manage Animations..."
|
||||||
|
var menu_popup := anim_menu_button.get_popup()
|
||||||
|
var items := []
|
||||||
|
var count := menu_popup.item_count - 1
|
||||||
|
|
||||||
|
while count >= 0 and menu_popup.get_item_id(count) != TOOL_ANIM_LIBRARY:
|
||||||
|
if menu_popup.is_item_separator(count):
|
||||||
|
items.append({})
|
||||||
|
else:
|
||||||
|
items.append({
|
||||||
|
"shortcut": menu_popup.get_item_shortcut(count),
|
||||||
|
"id": menu_popup.get_item_id(count),
|
||||||
|
"icon": menu_popup.get_item_icon(count)
|
||||||
|
})
|
||||||
|
|
||||||
|
menu_popup.remove_item(count)
|
||||||
|
count -= 1
|
||||||
|
|
||||||
|
# Add refactor item
|
||||||
|
menu_popup.add_icon_item(
|
||||||
|
base_control.get_theme_icon(&"Reload", &"EditorIcons"),
|
||||||
|
"Refactor",
|
||||||
|
TOOL_REFACTOR,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Re-add items
|
||||||
|
for i in range(items.size() - 1, -1, -1):
|
||||||
|
var item: Dictionary = items[i]
|
||||||
|
|
||||||
|
if not item.is_empty():
|
||||||
|
menu_popup.add_shortcut(item.shortcut, item.id)
|
||||||
|
menu_popup.set_item_icon(menu_popup.get_item_index(item.id), item.icon)
|
||||||
|
else:
|
||||||
|
menu_popup.add_separator()
|
||||||
|
|
||||||
|
menu_popup.notification(NOTIFICATION_TRANSLATION_CHANGED)
|
||||||
|
|
||||||
|
menu_popup.id_pressed.connect(_on_menu_button_pressed)
|
||||||
|
|
||||||
|
|
||||||
|
func _remove_refactor_option():
|
||||||
|
if not anim_menu_button:
|
||||||
|
return
|
||||||
|
|
||||||
|
var base_control := get_editor_interface().get_base_control()
|
||||||
|
|
||||||
|
var menu_popup := anim_menu_button.get_popup()
|
||||||
|
menu_popup.remove_item(menu_popup.get_item_index(TOOL_REFACTOR))
|
||||||
|
|
||||||
|
menu_popup.id_pressed.disconnect(_on_menu_button_pressed)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_menu_button_pressed(id: int):
|
||||||
|
if id == TOOL_REFACTOR:
|
||||||
|
refactor_dialogue.popup_centered()
|
||||||
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
extends CodeEdit
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
code_completion_enabled = true
|
||||||
|
add_code_completion_option(CodeEdit.KIND_MEMBER, "Test", "test")
|
||||||
|
add_code_completion_option(CodeEdit.KIND_MEMBER, "Boo", "boo")
|
||||||
|
code_completion_prefixes = ["t", "b"]
|
||||||
|
|
||||||
|
code_completion_requested.connect(func():
|
||||||
|
add_code_completion_option(CodeEdit.KIND_MEMBER, "Test", "test")
|
||||||
|
add_code_completion_option(CodeEdit.KIND_MEMBER, "Boo", "boo")
|
||||||
|
update_code_completion_options(true)
|
||||||
|
)
|
||||||
|
|
||||||
|
text_changed.connect(func(): request_code_completion(true))
|
||||||
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
## Autocomplete Class
|
||||||
|
extends OptionButton
|
||||||
|
|
||||||
|
## LineEdit.text_change_rejected
|
||||||
|
signal text_change_rejected(rejected_substring: String)
|
||||||
|
## LineEdit.text_changed
|
||||||
|
signal text_changed(new_text: String)
|
||||||
|
## LineEdit.text_submitted
|
||||||
|
signal text_submitted(new_text: String)
|
||||||
|
|
||||||
|
## LineEdit component
|
||||||
|
var edit: LineEdit = LineEdit.new()
|
||||||
|
|
||||||
|
@export var get_autocomplete_options: Callable = func(text: String): return []
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
focus_mode = Control.FOCUS_NONE
|
||||||
|
edit.custom_minimum_size = size
|
||||||
|
get_popup().unfocusable = true
|
||||||
|
|
||||||
|
add_child(edit)
|
||||||
|
edit.reset_size()
|
||||||
|
|
||||||
|
edit.text_change_rejected.connect(func(arg): text_change_rejected.emit(arg))
|
||||||
|
edit.text_changed.connect(func(arg): text_changed.emit(arg))
|
||||||
|
edit.text_submitted.connect(func(arg): text_submitted.emit(arg))
|
||||||
|
|
||||||
|
edit.text_changed.connect(_update_options)
|
||||||
|
|
||||||
|
edit.focus_entered.connect(_update_options)
|
||||||
|
edit.focus_exited.connect(clear)
|
||||||
|
|
||||||
|
get_autocomplete_options = func(text: String):
|
||||||
|
return [
|
||||||
|
"test",
|
||||||
|
"ashina",
|
||||||
|
"hello"
|
||||||
|
].filter(func(el: String): return el.contains(text))
|
||||||
|
|
||||||
|
func _update_options(text: String = edit.text):
|
||||||
|
clear()
|
||||||
|
var options = get_autocomplete_options.call(text)
|
||||||
|
|
||||||
|
for option in options:
|
||||||
|
if typeof(option) == TYPE_STRING:
|
||||||
|
add_item(option)
|
||||||
|
|
||||||
|
show_popup()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
extends EditorInspectorPlugin
|
||||||
|
signal button_clicked
|
||||||
|
|
||||||
|
var button: Button
|
||||||
|
var button_text: String
|
||||||
|
|
||||||
|
func _init(text: String) -> void:
|
||||||
|
button_text = text
|
||||||
|
|
||||||
|
func _can_handle(object: Object) -> bool:
|
||||||
|
return object is AnimationPlayer
|
||||||
|
|
||||||
|
func _parse_end(object: Object) -> void:
|
||||||
|
button = Button.new()
|
||||||
|
button.text = button_text
|
||||||
|
button.pressed.connect(func(): button_clicked.emit())
|
||||||
|
|
||||||
|
var margins := MarginContainer.new()
|
||||||
|
margins.add_theme_constant_override("margin_top", 8)
|
||||||
|
margins.add_theme_constant_override("margin_left", 16)
|
||||||
|
margins.add_theme_constant_override("margin_bottom", 8)
|
||||||
|
margins.add_theme_constant_override("margin_right", 16)
|
||||||
|
margins.add_child(button)
|
||||||
|
|
||||||
|
var container = VBoxContainer.new()
|
||||||
|
container.add_theme_constant_override("separation", 0)
|
||||||
|
container.add_child(HSeparator.new())
|
||||||
|
container.add_child(margins)
|
||||||
|
|
||||||
|
var container_margins := MarginContainer.new()
|
||||||
|
container_margins.add_theme_constant_override("margin_top", 8)
|
||||||
|
container_margins.add_theme_constant_override("margin_left", 4)
|
||||||
|
container_margins.add_theme_constant_override("margin_bottom", 8)
|
||||||
|
container_margins.add_theme_constant_override("margin_right", 4)
|
||||||
|
container_margins.add_child(container)
|
||||||
|
|
||||||
|
add_custom_control(container_margins)
|
||||||
|
|
@ -0,0 +1,176 @@
|
||||||
|
@tool
|
||||||
|
extends Tree
|
||||||
|
|
||||||
|
signal rendered
|
||||||
|
|
||||||
|
const EditInfo := preload("edit_info.gd")
|
||||||
|
|
||||||
|
@export var edittable_items := false
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
reset_size()
|
||||||
|
|
||||||
|
|
||||||
|
func render(editor_plugin: EditorPlugin, anim_player: AnimationPlayer) -> void:
|
||||||
|
clear()
|
||||||
|
|
||||||
|
# Get paths
|
||||||
|
var animations = anim_player.get_animation_list()
|
||||||
|
var root_node := anim_player.get_node(anim_player.root_node)
|
||||||
|
|
||||||
|
var track_paths := {} # Dictionary[NodePath, Dictionary[NodePath, EditInfo]]
|
||||||
|
|
||||||
|
# Get EditInfo data
|
||||||
|
for anim_name in animations:
|
||||||
|
var animation := anim_player.get_animation(anim_name)
|
||||||
|
|
||||||
|
for i in animation.get_track_count():
|
||||||
|
var path := animation.track_get_path(i)
|
||||||
|
var type := animation.track_get_type(i)
|
||||||
|
|
||||||
|
var node_path := NodePath(path.get_concatenated_names())
|
||||||
|
var property_path := path.get_concatenated_subnames()
|
||||||
|
var node := root_node.get_node_or_null(node_path)
|
||||||
|
|
||||||
|
var edit_infos: Array[EditInfo] = []
|
||||||
|
|
||||||
|
if not node_path in track_paths:
|
||||||
|
track_paths[node_path] = {}
|
||||||
|
match type:
|
||||||
|
Animation.TYPE_METHOD:
|
||||||
|
for j in animation.track_get_key_count(i):
|
||||||
|
var method_path = NodePath(
|
||||||
|
(
|
||||||
|
path.get_concatenated_names()
|
||||||
|
+ ":"
|
||||||
|
+ animation.method_track_get_name(i, j)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
var edit_info = EditInfo.new(
|
||||||
|
EditInfo.Type.METHOD_TRACK, method_path, node_path, node, [anim_name]
|
||||||
|
)
|
||||||
|
|
||||||
|
edit_infos.append(edit_info)
|
||||||
|
_:
|
||||||
|
if not property_path.is_empty():
|
||||||
|
var edit_info = EditInfo.new(
|
||||||
|
EditInfo.Type.VALUE_TRACK, path, node_path, node, [anim_name]
|
||||||
|
)
|
||||||
|
|
||||||
|
edit_infos.append(edit_info)
|
||||||
|
|
||||||
|
# Combine
|
||||||
|
for info in edit_infos:
|
||||||
|
if not StringName(info.path) in track_paths[node_path]:
|
||||||
|
track_paths[node_path][StringName(info.path)] = info
|
||||||
|
else:
|
||||||
|
for name in info.animation_names:
|
||||||
|
if name in track_paths[node_path][StringName(info.path)].animation_names: continue
|
||||||
|
track_paths[node_path][StringName(info.path)].animation_names.append(name)
|
||||||
|
|
||||||
|
# Sort
|
||||||
|
var paths := track_paths.keys()
|
||||||
|
paths.sort()
|
||||||
|
|
||||||
|
var tree_root: TreeItem = create_item()
|
||||||
|
hide_root = true
|
||||||
|
|
||||||
|
# Get icons
|
||||||
|
var gui := editor_plugin.get_editor_interface().get_base_control()
|
||||||
|
|
||||||
|
# Render
|
||||||
|
for path in paths:
|
||||||
|
var node := root_node.get_node_or_null(path)
|
||||||
|
var icon := gui.get_theme_icon(node.get_class() if node != null else "", "EditorIcons")
|
||||||
|
|
||||||
|
var path_item = create_item(tree_root)
|
||||||
|
path_item.set_editable(0, edittable_items)
|
||||||
|
if edittable_items:
|
||||||
|
path_item.set_text(0, path)
|
||||||
|
if path.get_concatenated_names() == ".." and node:
|
||||||
|
path_item.set_suffix(0, "(" + node.name + ")")
|
||||||
|
else:
|
||||||
|
path_item.set_text(0, node.name if node else path)
|
||||||
|
path_item.set_icon(0, icon)
|
||||||
|
path_item.set_metadata(0, EditInfo.new(EditInfo.Type.NODE, path, path, node, []))
|
||||||
|
path_item.add_button(0, gui.get_theme_icon("Edit", "EditorIcons"))
|
||||||
|
path_item.add_button(0, gui.get_theme_icon("Remove", "EditorIcons"))
|
||||||
|
|
||||||
|
var property_paths: Array = track_paths[path].keys()
|
||||||
|
property_paths.sort()
|
||||||
|
|
||||||
|
for property_path in property_paths:
|
||||||
|
var info: EditInfo = track_paths[path][property_path]
|
||||||
|
var edit_type = EditInfo.Type.VALUE_TRACK
|
||||||
|
var icon_type = "KeyValue"
|
||||||
|
var invalid = false
|
||||||
|
var property := info.path.get_concatenated_subnames()
|
||||||
|
if node == null:
|
||||||
|
invalid = true
|
||||||
|
icon_type = ""
|
||||||
|
elif node.has_method(StringName(property)):
|
||||||
|
icon_type = "KeyCall"
|
||||||
|
elif str(info.path) in node or node.get_indexed(NodePath(property)) != null:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
invalid = true
|
||||||
|
icon_type = ""
|
||||||
|
|
||||||
|
var property_item = create_item(path_item)
|
||||||
|
property_item.set_editable(0, edittable_items)
|
||||||
|
property_item.set_text(0, property)
|
||||||
|
property_item.set_icon(0, gui.get_theme_icon(icon_type, "EditorIcons"))
|
||||||
|
property_item.set_metadata(0, info)
|
||||||
|
property_item.add_button(0, gui.get_theme_icon("Edit", "EditorIcons"))
|
||||||
|
property_item.add_button(0, gui.get_theme_icon("Remove", "EditorIcons"))
|
||||||
|
|
||||||
|
if invalid:
|
||||||
|
property_item.set_custom_color(0, Color.RED)
|
||||||
|
property_item.set_tooltip_text(0, "Possibly invalid value: %s" % info.path)
|
||||||
|
rendered.emit()
|
||||||
|
|
||||||
|
|
||||||
|
func set_filter(filter: String):
|
||||||
|
var item_stack := []
|
||||||
|
var visited := []
|
||||||
|
|
||||||
|
item_stack.append(get_root())
|
||||||
|
|
||||||
|
# Post-order traversal
|
||||||
|
while not item_stack.is_empty():
|
||||||
|
var current: TreeItem = item_stack[item_stack.size() - 1]
|
||||||
|
var children = current.get_children() if current else []
|
||||||
|
|
||||||
|
var children_all_visited := true
|
||||||
|
var child_visible := false
|
||||||
|
|
||||||
|
for child in children:
|
||||||
|
children_all_visited = children_all_visited and child in visited
|
||||||
|
child_visible = child_visible or child.visible
|
||||||
|
|
||||||
|
if children_all_visited:
|
||||||
|
item_stack.pop_back()
|
||||||
|
if current:
|
||||||
|
if current == get_root() or filter.is_empty() or child_visible:
|
||||||
|
current.visible = true
|
||||||
|
else:
|
||||||
|
current.visible = current.get_text(0).to_lower().contains(filter.to_lower())
|
||||||
|
visited.append(current)
|
||||||
|
else:
|
||||||
|
item_stack += children
|
||||||
|
|
||||||
|
|
||||||
|
## Class to cache heirarchy of nodes
|
||||||
|
## Unused
|
||||||
|
class TreeNode:
|
||||||
|
var node: Node
|
||||||
|
var path: String
|
||||||
|
var children: Dictionary
|
||||||
|
var parent: TreeNode
|
||||||
|
|
||||||
|
func debug(level = 0):
|
||||||
|
print(" - ".repeat(level) + node.name)
|
||||||
|
for name in children:
|
||||||
|
children[name].debug(level + 1)
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
## Data class for storing information on tracks
|
||||||
|
extends Object
|
||||||
|
|
||||||
|
enum Type { VALUE_TRACK, METHOD_TRACK, NODE }
|
||||||
|
|
||||||
|
## Type of info being edited
|
||||||
|
var type: Type
|
||||||
|
|
||||||
|
## Full path to property. Same as node_path if type is NODE
|
||||||
|
var path: NodePath
|
||||||
|
|
||||||
|
## Full path to node
|
||||||
|
var node_path: NodePath
|
||||||
|
|
||||||
|
## Cached node
|
||||||
|
var node: Node
|
||||||
|
|
||||||
|
## Animations the track is used in
|
||||||
|
var animation_names: Array[String] = []
|
||||||
|
|
||||||
|
func _init(type: Type, path: NodePath, node_path: NodePath, node: Node, animation_names: Array[String]) -> void:
|
||||||
|
self.type = type
|
||||||
|
self.path = path
|
||||||
|
self.node = node
|
||||||
|
self.node_path = node_path
|
||||||
|
self.animation_names = animation_names
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
@tool
|
||||||
|
extends Tree
|
||||||
|
|
||||||
|
var _editor_plugin: EditorPlugin
|
||||||
|
var _gui: Control
|
||||||
|
|
||||||
|
func init(editor_plugin: EditorPlugin):
|
||||||
|
_editor_plugin = editor_plugin
|
||||||
|
_gui = editor_plugin.get_editor_interface().get_base_control()
|
||||||
|
|
||||||
|
func render(anim_player: AnimationPlayer):
|
||||||
|
clear()
|
||||||
|
|
||||||
|
_create_items(null, anim_player, anim_player.owner)
|
||||||
|
|
||||||
|
|
||||||
|
func _create_items(parent: TreeItem, anim_player: AnimationPlayer, node: Node):
|
||||||
|
var icon := _gui.get_theme_icon(node.get_class(), "EditorIcons")
|
||||||
|
|
||||||
|
var item := create_item(parent)
|
||||||
|
item.set_text(0, node.name)
|
||||||
|
item.set_icon(0, icon)
|
||||||
|
item.set_metadata(0, anim_player.get_path_to(node))
|
||||||
|
|
||||||
|
if anim_player.get_path_to(node) == anim_player.root_node:
|
||||||
|
item.select(0)
|
||||||
|
scroll_to_item(item)
|
||||||
|
|
||||||
|
for child in node.get_children():
|
||||||
|
_create_items(item, anim_player, child)
|
||||||
|
|
@ -0,0 +1,235 @@
|
||||||
|
@tool
|
||||||
|
extends AcceptDialog
|
||||||
|
|
||||||
|
const CustomEditorPlugin := preload("res://addons/anim_player_refactor/plugin.gd")
|
||||||
|
const EditorUtil := preload("res://addons/anim_player_refactor/lib/editor_util.gd")
|
||||||
|
|
||||||
|
const AnimPlayerRefactor = preload("res://addons/anim_player_refactor/lib/anim_player_refactor.gd")
|
||||||
|
const AnimPlayerTree := preload("components/anim_player_tree.gd")
|
||||||
|
const EditInfo := preload("components/edit_info.gd")
|
||||||
|
|
||||||
|
const NodeSelect := preload("components/node_select.gd")
|
||||||
|
|
||||||
|
var _editor_plugin: CustomEditorPlugin
|
||||||
|
var _editor_interface: EditorInterface
|
||||||
|
var _anim_player_refactor: AnimPlayerRefactor
|
||||||
|
var _anim_player: AnimationPlayer
|
||||||
|
|
||||||
|
@onready var anim_player_tree: AnimPlayerTree = $%AnimPlayerTree
|
||||||
|
|
||||||
|
@onready var change_root: Button = $%ChangeRoot
|
||||||
|
|
||||||
|
@onready var edit_dialogue: ConfirmationDialog = $%EditDialogue
|
||||||
|
@onready var edit_dialogue_input: LineEdit = $%EditInput
|
||||||
|
@onready var edit_dialogue_button: Button = $%EditDialogueButton # Just for pretty icon display
|
||||||
|
@onready var edit_full_path_toggle: CheckButton = $%EditFullPathToggle
|
||||||
|
@onready var edit_anim_list: Label = $%EditAnimationList
|
||||||
|
|
||||||
|
@onready var node_select_dialogue: ConfirmationDialog = $%NodeSelectDialogue
|
||||||
|
@onready var node_select: NodeSelect = $%NodeSelect
|
||||||
|
|
||||||
|
@onready var confirmation_dialogue: ConfirmationDialog = $%ConfirmationDialog
|
||||||
|
|
||||||
|
|
||||||
|
var is_full_path: bool:
|
||||||
|
set(val): edit_full_path_toggle.button_pressed = val
|
||||||
|
get: return edit_full_path_toggle.button_pressed
|
||||||
|
|
||||||
|
|
||||||
|
func init(editor_plugin: CustomEditorPlugin) -> void:
|
||||||
|
_editor_plugin = editor_plugin
|
||||||
|
_editor_interface = editor_plugin.get_editor_interface()
|
||||||
|
_anim_player_refactor = AnimPlayerRefactor.new(_editor_plugin)
|
||||||
|
node_select.init(_editor_plugin)
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
wrap_controls = true
|
||||||
|
about_to_popup.connect(render)
|
||||||
|
|
||||||
|
|
||||||
|
func render():
|
||||||
|
_anim_player = _editor_plugin.get_anim_player()
|
||||||
|
|
||||||
|
if not _anim_player or not _anim_player is AnimationPlayer:
|
||||||
|
push_error("AnimationPlayer is null or invalid")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Render track tree
|
||||||
|
anim_player_tree.render(_editor_plugin, _anim_player)
|
||||||
|
|
||||||
|
# Render root node button
|
||||||
|
var root_node: Node = _anim_player.get_node(_anim_player.root_node)
|
||||||
|
var node_path := str(_anim_player.owner.get_path_to(root_node))
|
||||||
|
if node_path == ".":
|
||||||
|
node_path = _anim_player.owner.name
|
||||||
|
else:
|
||||||
|
node_path = _anim_player.owner.name + "/" + node_path
|
||||||
|
|
||||||
|
change_root.text = "%s (Change)" % node_path
|
||||||
|
change_root.icon = _editor_interface.get_base_control().get_theme_icon(
|
||||||
|
root_node.get_class(), "EditorIcons"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Rename
|
||||||
|
enum Action { Rename, Delete }
|
||||||
|
var _current_info: EditInfo
|
||||||
|
|
||||||
|
func _on_tree_activated():
|
||||||
|
_current_info = anim_player_tree.get_selected().get_metadata(0)
|
||||||
|
_on_action(Action.Rename)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_tree_button_clicked(item: TreeItem, column: int, id: int, mouse_button_index: int):
|
||||||
|
_current_info = item.get_metadata(column)
|
||||||
|
if id == 0:
|
||||||
|
_on_action(Action.Rename)
|
||||||
|
elif id == 1:
|
||||||
|
_on_action(Action.Delete)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_action(action: Action):
|
||||||
|
if action == Action.Rename:
|
||||||
|
_render_edit_dialogue()
|
||||||
|
edit_dialogue.popup_centered()
|
||||||
|
edit_dialogue_input.grab_focus()
|
||||||
|
edit_dialogue_input.caret_column = edit_dialogue_input.text.length()
|
||||||
|
elif action == Action.Delete:
|
||||||
|
var track_path = _current_info.path
|
||||||
|
var anim_player = _editor_plugin.get_anim_player()
|
||||||
|
var node = anim_player\
|
||||||
|
.get_node(anim_player.root_node)\
|
||||||
|
.get_node_or_null(_current_info.path)
|
||||||
|
|
||||||
|
if node:
|
||||||
|
track_path = node.name
|
||||||
|
var property := _current_info.path.get_concatenated_subnames()
|
||||||
|
if not property.is_empty():
|
||||||
|
track_path += ":" + property
|
||||||
|
|
||||||
|
var msg = 'Delete all tracks with the path "%s"?' % track_path
|
||||||
|
|
||||||
|
if _current_info.type == EditInfo.Type.NODE:
|
||||||
|
msg = 'Delete tracks belonging to the node "%s"?' % track_path
|
||||||
|
|
||||||
|
_show_confirmation(msg, _remove)
|
||||||
|
|
||||||
|
|
||||||
|
func _render_edit_dialogue():
|
||||||
|
var info := _current_info
|
||||||
|
|
||||||
|
if info.type == EditInfo.Type.METHOD_TRACK:
|
||||||
|
is_full_path = false
|
||||||
|
edit_full_path_toggle.disabled = true
|
||||||
|
edit_full_path_toggle.visible = false
|
||||||
|
else:
|
||||||
|
edit_full_path_toggle.disabled = false
|
||||||
|
edit_full_path_toggle.visible = true
|
||||||
|
|
||||||
|
if is_full_path:
|
||||||
|
edit_dialogue_input.text = info.path
|
||||||
|
else:
|
||||||
|
if info.type == EditInfo.Type.NODE:
|
||||||
|
edit_dialogue.title = "Rename node"
|
||||||
|
edit_dialogue_input.text = info.path.get_name(info.path.get_name_count() - 1)
|
||||||
|
elif info.type == EditInfo.Type.VALUE_TRACK:
|
||||||
|
edit_dialogue.title = "Rename Value"
|
||||||
|
edit_dialogue_input.text = info.path.get_concatenated_subnames()
|
||||||
|
elif info.type == EditInfo.Type.METHOD_TRACK:
|
||||||
|
edit_dialogue.title = "Rename method"
|
||||||
|
edit_dialogue_input.text = info.path.get_concatenated_subnames()
|
||||||
|
edit_dialogue_button.text = info.node_path
|
||||||
|
if str(info.node_path) in [".", ".."] and info.node:
|
||||||
|
# Show name for relatives paths
|
||||||
|
edit_dialogue_button.text = info.node.name
|
||||||
|
if info.node:
|
||||||
|
# Show icon
|
||||||
|
edit_dialogue_button.icon = _editor_interface.get_base_control().get_theme_icon(
|
||||||
|
info.node.get_class(), "EditorIcons"
|
||||||
|
)
|
||||||
|
edit_anim_list.text = ""
|
||||||
|
for name in _current_info.animation_names:
|
||||||
|
edit_anim_list.text += " • " + name + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
## Toggle full path and re-render edit dialogue
|
||||||
|
func _on_full_path_toggled(pressed: bool):
|
||||||
|
_render_edit_dialogue()
|
||||||
|
|
||||||
|
|
||||||
|
## Callback on rename
|
||||||
|
func _on_rename_confirmed(_arg0 = null):
|
||||||
|
var new := edit_dialogue_input.text
|
||||||
|
|
||||||
|
edit_dialogue.hide()
|
||||||
|
if not _anim_player or not _anim_player is AnimationPlayer:
|
||||||
|
push_error("AnimationPlayer is null or invalid")
|
||||||
|
return
|
||||||
|
|
||||||
|
if new.is_empty():
|
||||||
|
return
|
||||||
|
|
||||||
|
var info: EditInfo = _current_info
|
||||||
|
if info.type == EditInfo.Type.NODE:
|
||||||
|
var old := info.path
|
||||||
|
var new_path = new
|
||||||
|
if not is_full_path:
|
||||||
|
new_path = ""
|
||||||
|
for i in range(info.path.get_name_count() - 1):
|
||||||
|
new_path += info.path.get_name(i) + "/"
|
||||||
|
new_path += new
|
||||||
|
_anim_player_refactor.rename_node_path(_anim_player, old, NodePath(new))
|
||||||
|
elif info.type == EditInfo.Type.VALUE_TRACK:
|
||||||
|
var old_path := info.path
|
||||||
|
var new_path := NodePath(new)
|
||||||
|
if not is_full_path:
|
||||||
|
new_path = info.node_path.get_concatenated_names() + ":" + new
|
||||||
|
_anim_player_refactor.rename_track_path(_anim_player, old_path, new_path)
|
||||||
|
elif info.type == EditInfo.Type.METHOD_TRACK:
|
||||||
|
var old_method := info.path
|
||||||
|
var new_method := NodePath(
|
||||||
|
info.path.get_concatenated_names() + ":" + new
|
||||||
|
)
|
||||||
|
_anim_player_refactor.rename_method(_anim_player, old_method, new_method)
|
||||||
|
await get_tree().create_timer(0.1).timeout
|
||||||
|
render()
|
||||||
|
|
||||||
|
|
||||||
|
func _remove():
|
||||||
|
var info: EditInfo = _current_info
|
||||||
|
match info.type:
|
||||||
|
EditInfo.Type.NODE:
|
||||||
|
_anim_player_refactor.remove_node_path(_anim_player, info.node_path)
|
||||||
|
EditInfo.Type.VALUE_TRACK:
|
||||||
|
_anim_player_refactor.remove_track_path(_anim_player, info.path)
|
||||||
|
EditInfo.Type.METHOD_TRACK:
|
||||||
|
_anim_player_refactor.remove_method(_anim_player, info.path)
|
||||||
|
await get_tree().create_timer(0.1).timeout
|
||||||
|
render()
|
||||||
|
|
||||||
|
|
||||||
|
# Change root
|
||||||
|
func _on_change_root_pressed():
|
||||||
|
node_select_dialogue.popup_centered()
|
||||||
|
node_select.render(_editor_plugin.get_anim_player())
|
||||||
|
|
||||||
|
|
||||||
|
func _on_node_select_confirmed():
|
||||||
|
var path: NodePath = node_select.get_selected().get_metadata(0)
|
||||||
|
|
||||||
|
_anim_player_refactor.change_root(_editor_plugin.get_anim_player(), path)
|
||||||
|
|
||||||
|
await get_tree().create_timer(0.1).timeout
|
||||||
|
render()
|
||||||
|
|
||||||
|
|
||||||
|
# Confirmation
|
||||||
|
func _show_confirmation(text: String, on_confirmed: Callable):
|
||||||
|
for c in confirmation_dialogue.confirmed.get_connections():
|
||||||
|
confirmation_dialogue.confirmed.disconnect(c.callable)
|
||||||
|
|
||||||
|
confirmation_dialogue.confirmed.connect(on_confirmed, CONNECT_ONE_SHOT)
|
||||||
|
confirmation_dialogue.popup_centered()
|
||||||
|
confirmation_dialogue.dialog_text = text
|
||||||
|
|
||||||
|
|
@ -0,0 +1,157 @@
|
||||||
|
[gd_scene load_steps=4 format=3 uid="uid://cyfxysds8uhnx"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://addons/anim_player_refactor/scenes/refactor_dialogue/refactor_dialogue.gd" id="1_nkqdl"]
|
||||||
|
[ext_resource type="Script" path="res://addons/anim_player_refactor/scenes/refactor_dialogue/components/anim_player_tree.gd" id="2_7pqfs"]
|
||||||
|
[ext_resource type="Script" path="res://addons/anim_player_refactor/scenes/refactor_dialogue/components/node_select.gd" id="3_87x4i"]
|
||||||
|
|
||||||
|
[node name="RefactorDialogue" type="AcceptDialog"]
|
||||||
|
title = "Refactor Animations"
|
||||||
|
size = Vector2i(400, 599)
|
||||||
|
ok_button_text = "Close"
|
||||||
|
script = ExtResource("1_nkqdl")
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||||
|
offset_left = 8.0
|
||||||
|
offset_top = 8.0
|
||||||
|
offset_right = 392.0
|
||||||
|
offset_bottom = 550.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 3
|
||||||
|
theme_override_constants/separation = 8
|
||||||
|
|
||||||
|
[node name="TreeContainer" type="VBoxContainer" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="VBoxContainer/TreeContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Properties:"
|
||||||
|
|
||||||
|
[node name="FilterInput" type="LineEdit" parent="VBoxContainer/TreeContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
placeholder_text = "Filter..."
|
||||||
|
caret_blink = true
|
||||||
|
caret_blink_interval = 0.5
|
||||||
|
|
||||||
|
[node name="AnimPlayerTree" type="Tree" parent="VBoxContainer/TreeContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(300, 400)
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 3
|
||||||
|
hide_root = true
|
||||||
|
scroll_horizontal_enabled = false
|
||||||
|
script = ExtResource("2_7pqfs")
|
||||||
|
|
||||||
|
[node name="RootNodeContainer" type="VBoxContainer" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="VBoxContainer/RootNodeContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Root Node"
|
||||||
|
|
||||||
|
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/RootNodeContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="ChangeRoot" type="Button" parent="VBoxContainer/RootNodeContainer/HBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
text = "Change Root"
|
||||||
|
|
||||||
|
[node name="EditDialogue" type="ConfirmationDialog" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
title = "Renaming"
|
||||||
|
position = Vector2i(0, 36)
|
||||||
|
size = Vector2i(230, 239)
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="EditDialogue"]
|
||||||
|
offset_left = 8.0
|
||||||
|
offset_top = 8.0
|
||||||
|
offset_right = 222.0
|
||||||
|
offset_bottom = 190.0
|
||||||
|
|
||||||
|
[node name="HBoxContainer" type="HBoxContainer" parent="EditDialogue/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="EditDialogueButton" type="Button" parent="EditDialogue/VBoxContainer/HBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
focus_mode = 0
|
||||||
|
|
||||||
|
[node name="EditInput" type="LineEdit" parent="EditDialogue/VBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 0
|
||||||
|
|
||||||
|
[node name="HBoxContainer2" type="HBoxContainer" parent="EditDialogue/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="EditDialogue/VBoxContainer/HBoxContainer2"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Used in:"
|
||||||
|
|
||||||
|
[node name="EditFullPathToggle" type="CheckButton" parent="EditDialogue/VBoxContainer/HBoxContainer2"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 10
|
||||||
|
text = "Edit full path"
|
||||||
|
|
||||||
|
[node name="MarginContainer" type="MarginContainer" parent="EditDialogue/VBoxContainer"]
|
||||||
|
custom_minimum_size = Vector2(0, 100)
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="ColorRect" type="ColorRect" parent="EditDialogue/VBoxContainer/MarginContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 3
|
||||||
|
color = Color(0, 0, 0, 0.211765)
|
||||||
|
|
||||||
|
[node name="ScrollContainer" type="ScrollContainer" parent="EditDialogue/VBoxContainer/MarginContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 3
|
||||||
|
horizontal_scroll_mode = 0
|
||||||
|
|
||||||
|
[node name="MarginContainer" type="MarginContainer" parent="EditDialogue/VBoxContainer/MarginContainer/ScrollContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/margin_left = 2
|
||||||
|
theme_override_constants/margin_top = 2
|
||||||
|
theme_override_constants/margin_right = 2
|
||||||
|
theme_override_constants/margin_bottom = 2
|
||||||
|
|
||||||
|
[node name="EditAnimationList" type="Label" parent="EditDialogue/VBoxContainer/MarginContainer/ScrollContainer/MarginContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Test
|
||||||
|
Test 2"
|
||||||
|
|
||||||
|
[node name="NodeSelectDialogue" type="ConfirmationDialog" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
title = "Select a node..."
|
||||||
|
size = Vector2i(616, 557)
|
||||||
|
ok_button_text = "Change"
|
||||||
|
|
||||||
|
[node name="NodeSelect" type="Tree" parent="NodeSelectDialogue"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(600, 500)
|
||||||
|
offset_left = 8.0
|
||||||
|
offset_top = 8.0
|
||||||
|
offset_right = 608.0
|
||||||
|
offset_bottom = 508.0
|
||||||
|
scroll_horizontal_enabled = false
|
||||||
|
script = ExtResource("3_87x4i")
|
||||||
|
|
||||||
|
[node name="ConfirmationDialog" type="ConfirmationDialog" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
size = Vector2i(300, 200)
|
||||||
|
ok_button_text = "Delete"
|
||||||
|
dialog_autowrap = true
|
||||||
|
|
||||||
|
[connection signal="about_to_popup" from="." to="VBoxContainer/TreeContainer/FilterInput" method="clear"]
|
||||||
|
[connection signal="text_changed" from="VBoxContainer/TreeContainer/FilterInput" to="VBoxContainer/TreeContainer/AnimPlayerTree" method="set_filter"]
|
||||||
|
[connection signal="button_clicked" from="VBoxContainer/TreeContainer/AnimPlayerTree" to="." method="_on_tree_button_clicked"]
|
||||||
|
[connection signal="item_activated" from="VBoxContainer/TreeContainer/AnimPlayerTree" to="." method="_on_tree_activated"]
|
||||||
|
[connection signal="rendered" from="VBoxContainer/TreeContainer/AnimPlayerTree" to="VBoxContainer/TreeContainer/FilterInput" method="clear"]
|
||||||
|
[connection signal="pressed" from="VBoxContainer/RootNodeContainer/HBoxContainer/ChangeRoot" to="." method="_on_change_root_pressed"]
|
||||||
|
[connection signal="confirmed" from="EditDialogue" to="." method="_on_rename_confirmed"]
|
||||||
|
[connection signal="text_submitted" from="EditDialogue/VBoxContainer/EditInput" to="." method="_on_rename_confirmed"]
|
||||||
|
[connection signal="toggled" from="EditDialogue/VBoxContainer/HBoxContainer2/EditFullPathToggle" to="." method="_on_full_path_toggled"]
|
||||||
|
[connection signal="confirmed" from="NodeSelectDialogue" to="." method="_on_node_select_confirmed"]
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
[gd_scene load_steps=14 format=3 uid="uid://deek6uv574xas"]
|
[gd_scene load_steps=18 format=3 uid="uid://deek6uv574xas"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://entities/scripts/bee.gd" id="1_pnu7x"]
|
[ext_resource type="Script" path="res://entities/scripts/bee.gd" id="1_pnu7x"]
|
||||||
[ext_resource type="Script" path="res://entities/scripts/finite_state_machine.gd" id="1_t3s5d"]
|
[ext_resource type="Script" path="res://entities/scripts/finite_state_machine.gd" id="1_t3s5d"]
|
||||||
|
|
@ -8,23 +8,25 @@
|
||||||
[ext_resource type="Script" path="res://entities/bee/states/bee_travelling.gd" id="5_qtx0r"]
|
[ext_resource type="Script" path="res://entities/bee/states/bee_travelling.gd" id="5_qtx0r"]
|
||||||
[ext_resource type="Script" path="res://entities/bee/states/bee_sleeping.gd" id="7_6qlbu"]
|
[ext_resource type="Script" path="res://entities/bee/states/bee_sleeping.gd" id="7_6qlbu"]
|
||||||
[ext_resource type="Script" path="res://entities/bee/states/bee_returning.gd" id="8_dptvu"]
|
[ext_resource type="Script" path="res://entities/bee/states/bee_returning.gd" id="8_dptvu"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://ch3qalaaky8ng" path="res://resources/textures/bee_body.png" id="10_yi42o"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://bsskcrayofs8n" path="res://resources/textures/bee_wings.png" id="11_utbwk"]
|
||||||
|
|
||||||
[sub_resource type="Animation" id="Animation_iys4n"]
|
[sub_resource type="Animation" id="Animation_iys4n"]
|
||||||
resource_name = "Flying"
|
resource_name = "Flying"
|
||||||
length = 5.0
|
length = 5.0
|
||||||
loop_mode = 1
|
loop_mode = 1
|
||||||
step = 0.5
|
step = 0.25
|
||||||
tracks/0/type = "value"
|
tracks/0/type = "value"
|
||||||
tracks/0/imported = false
|
tracks/0/imported = false
|
||||||
tracks/0/enabled = true
|
tracks/0/enabled = true
|
||||||
tracks/0/path = NodePath("Polygon2D:position")
|
tracks/0/path = NodePath("BeeBody:position")
|
||||||
tracks/0/interp = 1
|
tracks/0/interp = 1
|
||||||
tracks/0/loop_wrap = true
|
tracks/0/loop_wrap = true
|
||||||
tracks/0/keys = {
|
tracks/0/keys = {
|
||||||
"times": PackedFloat32Array(0, 1.5, 2.5, 3.5, 5),
|
"times": PackedFloat32Array(0, 1, 2, 3, 4, 5),
|
||||||
"transitions": PackedFloat32Array(1, 1, 1, 1, 1),
|
"transitions": PackedFloat32Array(-2, -2, -2, -2, -2, -2),
|
||||||
"update": 0,
|
"update": 0,
|
||||||
"values": [Vector2(0, 0), Vector2(0, 10), Vector2(0, -10), Vector2(0, 10), Vector2(0, 0)]
|
"values": [Vector2(0, 0), Vector2(0, 10), Vector2(0, 5), Vector2(0, -5), Vector2(0, 10), Vector2(0, 0)]
|
||||||
}
|
}
|
||||||
|
|
||||||
[sub_resource type="Animation" id="Animation_t75ra"]
|
[sub_resource type="Animation" id="Animation_t75ra"]
|
||||||
|
|
@ -32,18 +34,6 @@ resource_name = "Idle"
|
||||||
|
|
||||||
[sub_resource type="Animation" id="Animation_0encb"]
|
[sub_resource type="Animation" id="Animation_0encb"]
|
||||||
length = 0.001
|
length = 0.001
|
||||||
tracks/0/type = "value"
|
|
||||||
tracks/0/imported = false
|
|
||||||
tracks/0/enabled = true
|
|
||||||
tracks/0/path = NodePath("Polygon2D:position")
|
|
||||||
tracks/0/interp = 1
|
|
||||||
tracks/0/loop_wrap = true
|
|
||||||
tracks/0/keys = {
|
|
||||||
"times": PackedFloat32Array(0),
|
|
||||||
"transitions": PackedFloat32Array(1),
|
|
||||||
"update": 0,
|
|
||||||
"values": [Vector2(0, 0)]
|
|
||||||
}
|
|
||||||
|
|
||||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_m27po"]
|
[sub_resource type="AnimationLibrary" id="AnimationLibrary_m27po"]
|
||||||
_data = {
|
_data = {
|
||||||
|
|
@ -52,6 +42,29 @@ _data = {
|
||||||
"RESET": SubResource("Animation_0encb")
|
"RESET": SubResource("Animation_0encb")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[sub_resource type="Animation" id="Animation_muxdj"]
|
||||||
|
resource_name = "Fly"
|
||||||
|
length = 0.5
|
||||||
|
loop_mode = 1
|
||||||
|
step = 0.05
|
||||||
|
tracks/0/type = "value"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath("BeeBody/BeeWings:scale")
|
||||||
|
tracks/0/interp = 1
|
||||||
|
tracks/0/loop_wrap = false
|
||||||
|
tracks/0/keys = {
|
||||||
|
"times": PackedFloat32Array(0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45),
|
||||||
|
"transitions": PackedFloat32Array(-2, -2, -2, -2, -2, -2, -2, -2, -2, -2),
|
||||||
|
"update": 0,
|
||||||
|
"values": [Vector2(1, 1), Vector2(1, 0.1), Vector2(1, 1), Vector2(1, 0.1), Vector2(1, 1), Vector2(1, 0.1), Vector2(1, 1), Vector2(1, 0.1), Vector2(1, 1), Vector2(1, 0.1)]
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="AnimationLibrary" id="AnimationLibrary_yvewf"]
|
||||||
|
_data = {
|
||||||
|
"Fly": SubResource("Animation_muxdj")
|
||||||
|
}
|
||||||
|
|
||||||
[sub_resource type="CircleShape2D" id="CircleShape2D_86nxf"]
|
[sub_resource type="CircleShape2D" id="CircleShape2D_86nxf"]
|
||||||
radius = 22.0907
|
radius = 22.0907
|
||||||
|
|
||||||
|
|
@ -60,11 +73,16 @@ z_index = 99
|
||||||
collision_mask = 0
|
collision_mask = 0
|
||||||
script = ExtResource("1_pnu7x")
|
script = ExtResource("1_pnu7x")
|
||||||
|
|
||||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
|
[node name="BeePositionAnimation" type="AnimationPlayer" parent="."]
|
||||||
libraries = {
|
libraries = {
|
||||||
"": SubResource("AnimationLibrary_m27po")
|
"": SubResource("AnimationLibrary_m27po")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[node name="WingAnimation" type="AnimationPlayer" parent="."]
|
||||||
|
libraries = {
|
||||||
|
"": SubResource("AnimationLibrary_yvewf")
|
||||||
|
}
|
||||||
|
|
||||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||||
light_mask = 0
|
light_mask = 0
|
||||||
shape = SubResource("CircleShape2D_86nxf")
|
shape = SubResource("CircleShape2D_86nxf")
|
||||||
|
|
@ -97,52 +115,21 @@ script = ExtResource("7_6qlbu")
|
||||||
[node name="Returning" type="Node" parent="StateMachine"]
|
[node name="Returning" type="Node" parent="StateMachine"]
|
||||||
script = ExtResource("8_dptvu")
|
script = ExtResource("8_dptvu")
|
||||||
|
|
||||||
[node name="Polygon2D" type="Polygon2D" parent="."]
|
[node name="BeeBody" type="Sprite2D" parent="."]
|
||||||
scale = Vector2(0.152885, 0.15978)
|
scale = Vector2(0.1, 0.1)
|
||||||
color = Color(1, 1, 0.0745098, 1)
|
texture = ExtResource("10_yi42o")
|
||||||
polygon = PackedVector2Array(-18, -11, -6, -21, 17, -19, 23, 1, 3, 12, -18, 7)
|
|
||||||
|
|
||||||
[node name="CPUParticles2D" type="CPUParticles2D" parent="Polygon2D"]
|
[node name="BeeWings" type="Sprite2D" parent="BeeBody"]
|
||||||
position = Vector2(0, 2.46663)
|
scale = Vector2(1, 0.1)
|
||||||
|
texture = ExtResource("11_utbwk")
|
||||||
|
|
||||||
|
[node name="CPUParticles2D" type="CPUParticles2D" parent="BeeBody"]
|
||||||
|
position = Vector2(0, 3.94118)
|
||||||
|
scale = Vector2(1.52885, 1.5978)
|
||||||
lifetime_randomness = 0.33
|
lifetime_randomness = 0.33
|
||||||
gravity = Vector2(0, 0)
|
gravity = Vector2(0, 0)
|
||||||
linear_accel_min = 5.0
|
linear_accel_min = 5.0
|
||||||
linear_accel_max = 10.0
|
linear_accel_max = 10.0
|
||||||
|
|
||||||
[node name="Polygon2D" type="Polygon2D" parent="Polygon2D"]
|
|
||||||
position = Vector2(-13.0817, -6.25862)
|
|
||||||
scale = Vector2(0.5, 0.5)
|
|
||||||
color = Color(0, 0, 0, 1)
|
|
||||||
offset = Vector2(-9.53674e-07, -9.53674e-07)
|
|
||||||
polygon = PackedVector2Array(32.7043, -12.5172, 39.2451, -18.7759, 45.786, -12.5172, 39.2451, -6.25862)
|
|
||||||
|
|
||||||
[node name="Polygon2D5" type="Polygon2D" parent="Polygon2D"]
|
|
||||||
position = Vector2(-13.0817, 18.7759)
|
|
||||||
scale = Vector2(0.5, 0.5)
|
|
||||||
color = Color(0, 0, 0, 1)
|
|
||||||
offset = Vector2(-9.53674e-07, -9.53674e-07)
|
|
||||||
polygon = PackedVector2Array(32.7043, -12.5172, 39.2451, -18.7759, 45.786, -12.5172, 39.2451, -6.25862)
|
|
||||||
|
|
||||||
[node name="Polygon2D4" type="Polygon2D" parent="Polygon2D"]
|
|
||||||
position = Vector2(-26.1634, 18.7759)
|
|
||||||
scale = Vector2(0.5, 0.5)
|
|
||||||
color = Color(0, 0, 0, 1)
|
|
||||||
offset = Vector2(-9.53674e-07, -9.53674e-07)
|
|
||||||
polygon = PackedVector2Array(32.7043, -12.5172, 39.2451, -18.7759, 45.786, -12.5172, 39.2451, -6.25862)
|
|
||||||
|
|
||||||
[node name="Polygon2D3" type="Polygon2D" parent="Polygon2D"]
|
|
||||||
position = Vector2(-26.1634, -6.25862)
|
|
||||||
scale = Vector2(0.5, 0.5)
|
|
||||||
color = Color(0.30032, 0.200213, 0.0690995, 1)
|
|
||||||
offset = Vector2(-9.53674e-07, -9.53674e-07)
|
|
||||||
polygon = PackedVector2Array(32.7043, -12.5172, 39.2451, -18.7759, 78.4903, 12.5172, 65.4086, 25.0345)
|
|
||||||
|
|
||||||
[node name="Polygon2D2" type="Polygon2D" parent="Polygon2D"]
|
|
||||||
position = Vector2(-6.54086, 0)
|
|
||||||
scale = Vector2(0.5, 0.5)
|
|
||||||
color = Color(0, 0, 0, 1)
|
|
||||||
offset = Vector2(-9.53674e-07, -9.53674e-07)
|
|
||||||
polygon = PackedVector2Array(32.7043, -12.5172, 39.2451, -18.7759, 45.786, -12.5172, 39.2451, -6.25862)
|
|
||||||
|
|
||||||
[connection signal="area_entered" from="HitBox" to="HitBox" method="_on_area_entered"]
|
[connection signal="area_entered" from="HitBox" to="HitBox" method="_on_area_entered"]
|
||||||
[connection signal="area_exited" from="HitBox" to="HitBox" method="_on_area_exited"]
|
[connection signal="area_exited" from="HitBox" to="HitBox" method="_on_area_exited"]
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,17 @@ class_name BeeGathering
|
||||||
|
|
||||||
var time_at_patch : float = 0.0
|
var time_at_patch : float = 0.0
|
||||||
|
|
||||||
|
var target : Vector2 = Vector2.ZERO
|
||||||
|
|
||||||
func enter(_msg := {}):
|
func enter(_msg := {}):
|
||||||
bee.just_gathering = true
|
bee.just_gathering = true
|
||||||
|
|
||||||
Log.pr("Gathering now...")
|
Log.pr("Gathering now...")
|
||||||
|
|
||||||
|
randomize()
|
||||||
|
target = bee.get_global_position() + Vector2(randi_range(-100, 100), randi_range(-100, 100))
|
||||||
|
|
||||||
|
|
||||||
#animator.play("Idle")
|
#animator.play("Idle")
|
||||||
|
|
||||||
#if !bee.in_range_of_flowers:
|
#if !bee.in_range_of_flowers:
|
||||||
|
|
@ -30,3 +37,9 @@ func update(_delta : float):
|
||||||
else:
|
else:
|
||||||
state_transition.emit(self, "Idle")
|
state_transition.emit(self, "Idle")
|
||||||
|
|
||||||
|
func physics_update(delta : float) -> void:
|
||||||
|
if target:
|
||||||
|
if bee.position.distance_to(target) > 2:
|
||||||
|
bee.velocity = (target - bee.position).normalized() * bee.speed / 2 * delta
|
||||||
|
bee.move_and_collide(bee.velocity)
|
||||||
|
bee.look_at(target)
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,25 @@ class_name BeeIdle
|
||||||
|
|
||||||
var idle_time : float = 0.0
|
var idle_time : float = 0.0
|
||||||
|
|
||||||
|
var target : Vector2 = Vector2.ZERO
|
||||||
|
|
||||||
|
var acquire_new_target : bool = false
|
||||||
|
|
||||||
|
|
||||||
func enter(_msg := {}):
|
func enter(_msg := {}):
|
||||||
#animator.play("Idle")
|
if acquire_new_target:
|
||||||
pass
|
target = bee.get_global_position() + Vector2(randi_range(-60, 60), randi_range(-60, 60))
|
||||||
|
|
||||||
|
func exit():
|
||||||
|
acquire_new_target = true
|
||||||
|
|
||||||
func update(delta : float):
|
func update(delta : float):
|
||||||
|
|
||||||
|
if target == Vector2.ZERO:
|
||||||
|
randomize()
|
||||||
|
target = bee.get_global_position() + Vector2(randi_range(-60, 60), randi_range(-60, 60))
|
||||||
|
|
||||||
|
|
||||||
idle_time += delta
|
idle_time += delta
|
||||||
|
|
||||||
if idle_time > 2.0:
|
if idle_time > 2.0:
|
||||||
|
|
@ -18,6 +31,14 @@ func update(delta : float):
|
||||||
idle_time = 0.0
|
idle_time = 0.0
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
func physics_update(delta : float) -> void:
|
||||||
|
if target:
|
||||||
|
if bee.position.distance_to(target) > 3:
|
||||||
|
|
||||||
|
bee.velocity = (target - bee.position).normalized() * bee.speed / 2 * delta
|
||||||
|
bee.move_and_collide(bee.velocity)
|
||||||
|
bee.look_at(target)
|
||||||
|
|
||||||
func find_something_to_do():
|
func find_something_to_do():
|
||||||
if bee.nectar > 0:
|
if bee.nectar > 0:
|
||||||
Log.pr("I have pollen, time to move..")
|
Log.pr("I have pollen, time to move..")
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,13 @@ class_name BeeReturning
|
||||||
|
|
||||||
func enter(_msg := {}):
|
func enter(_msg := {}):
|
||||||
Log.pr("Returning to the hive")
|
Log.pr("Returning to the hive")
|
||||||
bee.animation_player.play("Flying")
|
bee.bee_position_animation.play("Flying")
|
||||||
|
|
||||||
func update(delta : float) -> void:
|
func update(_delta : float) -> void:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
func physics_update(delta : float) -> void:
|
||||||
if target:
|
if target:
|
||||||
if bee.position.distance_to(target.position) > 3:
|
if bee.position.distance_to(target.position) > 3:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,15 @@
|
||||||
extends State
|
extends State
|
||||||
class_name BeeSleeping
|
class_name BeeSleeping
|
||||||
|
|
||||||
@onready var bee = get_parent().get_parent() as Bee # I think this is bad but I dont care it works
|
@onready var bee : Bee = get_parent().get_parent() as Bee # I think this is bad but I dont care it works
|
||||||
|
|
||||||
var time_at_patch : float = 0.0
|
var time_at_patch : float = 0.0
|
||||||
|
|
||||||
func enter(_msg := {}):
|
func enter(_msg := {}) -> void:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
func update(_delta):
|
func update(_delta) -> void:
|
||||||
|
pass
|
||||||
|
|
||||||
|
func physics_update(_delta : float) -> void:
|
||||||
pass
|
pass
|
||||||
|
|
@ -6,6 +6,7 @@ class_name BeeTravelling
|
||||||
@onready var bee = get_parent().get_parent() as Bee # I think this is bad but I dont care it works
|
@onready var bee = get_parent().get_parent() as Bee # I think this is bad but I dont care it works
|
||||||
|
|
||||||
var return_to_hive : bool = false
|
var return_to_hive : bool = false
|
||||||
|
var moving_to : Vector2 = Vector2(0,0)
|
||||||
|
|
||||||
func enter(_msg := {}):
|
func enter(_msg := {}):
|
||||||
return_to_hive = false
|
return_to_hive = false
|
||||||
|
|
@ -23,20 +24,22 @@ func enter(_msg := {}):
|
||||||
# If we have no target, we are returning to the hive
|
# If we have no target, we are returning to the hive
|
||||||
if !target:
|
if !target:
|
||||||
return_to_hive = true
|
return_to_hive = true
|
||||||
|
else:
|
||||||
|
moving_to = target.get_global_position()
|
||||||
|
|
||||||
bee.animation_player.play("Flying")
|
bee.bee_position_animation.play("Flying")
|
||||||
|
|
||||||
|
|
||||||
func update(delta : float) -> void:
|
func update(_delta : float) -> void:
|
||||||
|
|
||||||
if return_to_hive:
|
if return_to_hive:
|
||||||
state_transition.emit(self, "Returning")
|
state_transition.emit(self, "Returning")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
func physics_update(delta : float) -> void:
|
||||||
if target:
|
if target:
|
||||||
if bee.position.distance_to(target.position) > 3:
|
if bee.position.distance_to(target.position) > 3:
|
||||||
|
|
||||||
bee.velocity = (target.get_global_position() - bee.position).normalized() * bee.speed * delta
|
bee.velocity = (moving_to - bee.position).normalized() * bee.speed * delta
|
||||||
bee.move_and_collide(bee.velocity)
|
bee.move_and_collide(bee.velocity)
|
||||||
bee.look_at(target.position)
|
bee.look_at(target.position)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@ class_name Bee
|
||||||
|
|
||||||
@onready var fsm = $StateMachine as FiniteStateMachine
|
@onready var fsm = $StateMachine as FiniteStateMachine
|
||||||
@onready var drone_manager = get_tree().get_first_node_in_group("dronemanager") as DroneManager
|
@onready var drone_manager = get_tree().get_first_node_in_group("dronemanager") as DroneManager
|
||||||
@onready var animation_player = $AnimationPlayer as AnimationPlayer
|
@onready var bee_position_animation = $BeePositionAnimation as AnimationPlayer
|
||||||
|
@onready var bee_wing_animation = $WingAnimation as AnimationPlayer
|
||||||
|
|
||||||
@export var nectar : int = 0
|
@export var nectar : int = 0
|
||||||
@export var speed : int = 30
|
@export var speed : int = 30
|
||||||
|
|
@ -16,6 +17,7 @@ var just_gathering : bool = false # Used to check if the bee has just been gathe
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
speed = randi_range(35,55) # Randomise the bee speed a bit
|
speed = randi_range(35,55) # Randomise the bee speed a bit
|
||||||
|
bee_wing_animation.play("Fly")
|
||||||
|
|
||||||
func get_current_director():
|
func get_current_director():
|
||||||
return drone_manager.get_director(latest_target_director)
|
return drone_manager.get_director(latest_target_director)
|
||||||
|
|
@ -51,10 +53,11 @@ func get_next_target():
|
||||||
return null
|
return null
|
||||||
|
|
||||||
func deposit_nectar():
|
func deposit_nectar():
|
||||||
GameState.add_nectar()
|
if nectar > 0:
|
||||||
nectar = 0
|
GameState.add_nectar()
|
||||||
latest_target_director = 0
|
nectar = 0
|
||||||
just_gathering = false
|
latest_target_director = 0
|
||||||
|
just_gathering = false
|
||||||
|
|
||||||
func die():
|
func die():
|
||||||
# Move to the death state
|
# Move to the death state
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,10 @@ func _process(delta):
|
||||||
if current_state:
|
if current_state:
|
||||||
current_state.update(delta)
|
current_state.update(delta)
|
||||||
|
|
||||||
|
func _physics_process(delta):
|
||||||
|
if current_state:
|
||||||
|
current_state.physics_update(delta)
|
||||||
|
|
||||||
# Use force_change_state cautiously, it immediately switches to a state regardless of any transitions.
|
# Use force_change_state cautiously, it immediately switches to a state regardless of any transitions.
|
||||||
# This is used to force us into a 'death state' when killed
|
# This is used to force us into a 'death state' when killed
|
||||||
func force_change_state(new_state : String):
|
func force_change_state(new_state : String):
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ GameState="*res://utility/game_state.gd"
|
||||||
|
|
||||||
window/size/viewport_width=1280
|
window/size/viewport_width=1280
|
||||||
window/size/viewport_height=720
|
window/size/viewport_height=720
|
||||||
|
window/vsync/vsync_mode=0
|
||||||
|
|
||||||
[editor_plugins]
|
[editor_plugins]
|
||||||
|
|
||||||
|
|
@ -37,3 +38,7 @@ theme/custom="res://resources/theme/game_theme.tres"
|
||||||
2d_physics/layer_1="bees"
|
2d_physics/layer_1="bees"
|
||||||
2d_physics/layer_2="hazards"
|
2d_physics/layer_2="hazards"
|
||||||
2d_physics/layer_3="flowers"
|
2d_physics/layer_3="flowers"
|
||||||
|
|
||||||
|
[physics]
|
||||||
|
|
||||||
|
2d/run_on_separate_thread=true
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
BIN
resources/textures/bee.png
Normal file
BIN
resources/textures/bee.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 401 B |
34
resources/textures/bee.png.import
Normal file
34
resources/textures/bee.png.import
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bmy5d0vl0l2bj"
|
||||||
|
path="res://.godot/imported/bee.png-e6e2f710a80ac28411d91cb428bfbb46.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://resources/textures/bee.png"
|
||||||
|
dest_files=["res://.godot/imported/bee.png-e6e2f710a80ac28411d91cb428bfbb46.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
|
||||||
BIN
resources/textures/bee.png~
Normal file
BIN
resources/textures/bee.png~
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
BIN
resources/textures/bee_body.png
Normal file
BIN
resources/textures/bee_body.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.7 KiB |
34
resources/textures/bee_body.png.import
Normal file
34
resources/textures/bee_body.png.import
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://ch3qalaaky8ng"
|
||||||
|
path="res://.godot/imported/bee_body.png-a901a812be76582d296d2da284fea011.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://resources/textures/bee_body.png"
|
||||||
|
dest_files=["res://.godot/imported/bee_body.png-a901a812be76582d296d2da284fea011.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
|
||||||
BIN
resources/textures/bee_wings.png
Normal file
BIN
resources/textures/bee_wings.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.5 KiB |
34
resources/textures/bee_wings.png.import
Normal file
34
resources/textures/bee_wings.png.import
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bsskcrayofs8n"
|
||||||
|
path="res://.godot/imported/bee_wings.png-40259da7bb67a8bea5d5368d118220ff.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://resources/textures/bee_wings.png"
|
||||||
|
dest_files=["res://.godot/imported/bee_wings.png-40259da7bb67a8bea5d5368d118220ff.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
|
||||||
|
|
@ -8,7 +8,7 @@ var bee = preload("res://entities/Bee.tscn")
|
||||||
@onready var small_bee_sound = get_node("BeeSound")
|
@onready var small_bee_sound = get_node("BeeSound")
|
||||||
|
|
||||||
var bee_count = 0
|
var bee_count = 0
|
||||||
var max_bees = 10
|
var max_bees = 100
|
||||||
var spawn_interval = 0.5
|
var spawn_interval = 0.5
|
||||||
var spawn_timer = 0.0
|
var spawn_timer = 0.0
|
||||||
var bee_sound_timer = 0.0
|
var bee_sound_timer = 0.0
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue