who the fuck knows

This commit is contained in:
Dan 2024-05-08 17:06:15 +01:00
parent 1c33ea2f59
commit 1da411cacd
31 changed files with 1372 additions and 78 deletions

View 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)

View 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

View 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"

View 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()

View file

@ -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))

View file

@ -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()

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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"]

View file

@ -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/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_sleeping.gd" id="7_6qlbu"]
[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"]
resource_name = "Flying"
length = 5.0
loop_mode = 1
step = 0.5
step = 0.25
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Polygon2D:position")
tracks/0/path = NodePath("BeeBody:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 1.5, 2.5, 3.5, 5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1),
"times": PackedFloat32Array(0, 1, 2, 3, 4, 5),
"transitions": PackedFloat32Array(-2, -2, -2, -2, -2, -2),
"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"]
@ -32,18 +34,6 @@ resource_name = "Idle"
[sub_resource type="Animation" id="Animation_0encb"]
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"]
_data = {
@ -52,6 +42,29 @@ _data = {
"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"]
radius = 22.0907
@ -60,11 +73,16 @@ z_index = 99
collision_mask = 0
script = ExtResource("1_pnu7x")
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
[node name="BeePositionAnimation" type="AnimationPlayer" parent="."]
libraries = {
"": SubResource("AnimationLibrary_m27po")
}
[node name="WingAnimation" type="AnimationPlayer" parent="."]
libraries = {
"": SubResource("AnimationLibrary_yvewf")
}
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
light_mask = 0
shape = SubResource("CircleShape2D_86nxf")
@ -97,52 +115,21 @@ script = ExtResource("7_6qlbu")
[node name="Returning" type="Node" parent="StateMachine"]
script = ExtResource("8_dptvu")
[node name="Polygon2D" type="Polygon2D" parent="."]
scale = Vector2(0.152885, 0.15978)
color = Color(1, 1, 0.0745098, 1)
polygon = PackedVector2Array(-18, -11, -6, -21, 17, -19, 23, 1, 3, 12, -18, 7)
[node name="BeeBody" type="Sprite2D" parent="."]
scale = Vector2(0.1, 0.1)
texture = ExtResource("10_yi42o")
[node name="CPUParticles2D" type="CPUParticles2D" parent="Polygon2D"]
position = Vector2(0, 2.46663)
[node name="BeeWings" type="Sprite2D" parent="BeeBody"]
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
gravity = Vector2(0, 0)
linear_accel_min = 5.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_exited" from="HitBox" to="HitBox" method="_on_area_exited"]

View file

@ -6,10 +6,17 @@ class_name BeeGathering
var time_at_patch : float = 0.0
var target : Vector2 = Vector2.ZERO
func enter(_msg := {}):
bee.just_gathering = true
Log.pr("Gathering now...")
randomize()
target = bee.get_global_position() + Vector2(randi_range(-100, 100), randi_range(-100, 100))
#animator.play("Idle")
#if !bee.in_range_of_flowers:
@ -30,3 +37,9 @@ func update(_delta : float):
else:
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)

View file

@ -5,12 +5,25 @@ class_name BeeIdle
var idle_time : float = 0.0
var target : Vector2 = Vector2.ZERO
var acquire_new_target : bool = false
func enter(_msg := {}):
#animator.play("Idle")
pass
if acquire_new_target:
target = bee.get_global_position() + Vector2(randi_range(-60, 60), randi_range(-60, 60))
func exit():
acquire_new_target = true
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
if idle_time > 2.0:
@ -18,6 +31,14 @@ func update(delta : float):
idle_time = 0.0
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():
if bee.nectar > 0:
Log.pr("I have pollen, time to move..")

View file

@ -6,10 +6,13 @@ class_name BeeReturning
func enter(_msg := {}):
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 bee.position.distance_to(target.position) > 3:

View file

@ -1,12 +1,15 @@
extends State
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
func enter(_msg := {}):
func enter(_msg := {}) -> void:
pass
func update(_delta):
func update(_delta) -> void:
pass
func physics_update(_delta : float) -> void:
pass

View file

@ -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
var return_to_hive : bool = false
var moving_to : Vector2 = Vector2(0,0)
func enter(_msg := {}):
return_to_hive = false
@ -23,20 +24,22 @@ func enter(_msg := {}):
# If we have no target, we are returning to the hive
if !target:
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:
state_transition.emit(self, "Returning")
return
func physics_update(delta : float) -> void:
if target:
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.look_at(target.position)

View file

@ -3,7 +3,8 @@ class_name Bee
@onready var fsm = $StateMachine as FiniteStateMachine
@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 speed : int = 30
@ -16,6 +17,7 @@ var just_gathering : bool = false # Used to check if the bee has just been gathe
func _ready():
speed = randi_range(35,55) # Randomise the bee speed a bit
bee_wing_animation.play("Fly")
func get_current_director():
return drone_manager.get_director(latest_target_director)
@ -51,6 +53,7 @@ func get_next_target():
return null
func deposit_nectar():
if nectar > 0:
GameState.add_nectar()
nectar = 0
latest_target_director = 0

View file

@ -24,6 +24,10 @@ func _process(delta):
if current_state:
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.
# This is used to force us into a 'death state' when killed
func force_change_state(new_state : String):

View file

@ -23,6 +23,7 @@ GameState="*res://utility/game_state.gd"
window/size/viewport_width=1280
window/size/viewport_height=720
window/vsync/vsync_mode=0
[editor_plugins]
@ -37,3 +38,7 @@ theme/custom="res://resources/theme/game_theme.tres"
2d_physics/layer_1="bees"
2d_physics/layer_2="hazards"
2d_physics/layer_3="flowers"
[physics]
2d/run_on_separate_thread=true

BIN
resources/textures/bee.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 B

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

View 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

View file

@ -8,7 +8,7 @@ var bee = preload("res://entities/Bee.tscn")
@onready var small_bee_sound = get_node("BeeSound")
var bee_count = 0
var max_bees = 10
var max_bees = 100
var spawn_interval = 0.5
var spawn_timer = 0.0
var bee_sound_timer = 0.0