Removed state machine for behavior trees
- Added Font Awesome Support
201
LICENSE.md
Normal file
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
BIN
addons/SpritesheetGenerator/Checker.png
Normal file
After Width: | Height: | Size: 913 B |
|
@ -2,16 +2,16 @@
|
|||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://msu07hn5ewo5"
|
||||
path="res://.godot/imported/state.png-fa3dd722682a28f890f138dcc6e162af.ctex"
|
||||
uid="uid://bnkl8rujlgv0h"
|
||||
path="res://.godot/imported/Checker.png-95b82ca4c05ab143e1e16c56d598421b.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/simple-state/icons/state.png"
|
||||
dest_files=["res://.godot/imported/state.png-fa3dd722682a28f890f138dcc6e162af.ctex"]
|
||||
source_file="res://addons/SpritesheetGenerator/Checker.png"
|
||||
dest_files=["res://.godot/imported/Checker.png-95b82ca4c05ab143e1e16c56d598421b.ctex"]
|
||||
|
||||
[params]
|
||||
|
13
addons/SpritesheetGenerator/SpriteSheetGenerator.gd
Normal file
|
@ -0,0 +1,13 @@
|
|||
@tool
|
||||
extends EditorPlugin
|
||||
|
||||
func _enter_tree() -> void:
|
||||
add_tool_menu_item("Open Spritesheet Generator", run_generator)
|
||||
get_editor_interface().get_command_palette().add_command("Open Spritesheet Generator", "addons/open_spritesheet_generator", run_generator)
|
||||
|
||||
func _exit_tree() -> void:
|
||||
remove_tool_menu_item("Open Spritesheet Generator")
|
||||
get_editor_interface().get_command_palette().remove_command("addons/open_spritesheet_generator")
|
||||
|
||||
func run_generator():
|
||||
get_editor_interface().play_custom_scene("res://addons/SpritesheetGenerator/SpritesheetGenerator.tscn")
|
77
addons/SpritesheetGenerator/SpritesheetFrame.tscn
Normal file
|
@ -0,0 +1,77 @@
|
|||
[gd_scene load_steps=3 format=3 uid="uid://cd5wndu01c1sn"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="2"]
|
||||
resource_local_to_scene = true
|
||||
bg_color = Color(0, 0.501961, 0.501961, 1)
|
||||
|
||||
[sub_resource type="GDScript" id="3"]
|
||||
resource_name = "Prefab"
|
||||
script/source = "extends PanelContainer
|
||||
|
||||
var odd: Vector2
|
||||
|
||||
func set_frame_margin(margin: Vector2):
|
||||
$MarginContainer.add_theme_constant_override(&\"margin_left\", margin.x)
|
||||
$MarginContainer.add_theme_constant_override(&\"margin_top\", margin.y)
|
||||
|
||||
margin += odd
|
||||
|
||||
$MarginContainer.add_theme_constant_override(&\"margin_right\", margin.x)
|
||||
$MarginContainer.add_theme_constant_override(&\"margin_bottom\", margin.y)
|
||||
|
||||
func set_texture(texture: Texture2D):
|
||||
%TextureRect.texture = texture
|
||||
odd = Vector2(int(get_texture_size().x) % 2, int(get_texture_size().y) % 2)
|
||||
|
||||
func get_texture_size() -> Vector2:
|
||||
return %TextureRect.texture.get_size()
|
||||
|
||||
func get_position2() -> Vector2:
|
||||
return position + %TextureRect.position
|
||||
|
||||
func get_texture_data() -> Image:
|
||||
return %TextureRect.texture.get_image()
|
||||
|
||||
func set_display_background(display: bool):
|
||||
get_theme_stylebox(&\"panel\").draw_center = display
|
||||
|
||||
func set_background_color(color: Color):
|
||||
get_theme_stylebox(&\"panel\").bg_color = color
|
||||
|
||||
func _get_drag_data(p: Vector2):
|
||||
var preview = TextureRect.new()
|
||||
preview.texture = %TextureRect.texture
|
||||
preview.ignore_texture_size = true
|
||||
preview.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
preview.size = Vector2(64, 64)
|
||||
set_drag_preview(preview)
|
||||
return {type = \"SpritesheetFrame\", node = self}
|
||||
|
||||
func _can_drop_data(p: Vector2, data) -> bool:
|
||||
return data is Dictionary and data.get(\"type\", \"\") == \"SpritesheetFrame\"
|
||||
|
||||
func _drop_data(p: Vector2, data) -> void:
|
||||
var index = get_index()
|
||||
get_parent().move_child(self, data.node.get_index())
|
||||
get_parent().move_child(data.node, index)
|
||||
get_tree().current_scene.refresh_grid()
|
||||
|
||||
func _gui_input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseButton:
|
||||
if event.pressed and event.button_index == MOUSE_BUTTON_RIGHT:
|
||||
get_tree().current_scene.remove_frame.call_deferred(self)
|
||||
"
|
||||
|
||||
[node name="FramePrefab" type="PanelContainer" groups=["frame"]]
|
||||
theme_override_styles/panel = SubResource("2")
|
||||
script = SubResource("3")
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="."]
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="TextureRect" type="TextureRect" parent="MarginContainer"]
|
||||
unique_name_in_owner = true
|
||||
texture_filter = 1
|
||||
layout_mode = 2
|
||||
stretch_mode = 4
|
714
addons/SpritesheetGenerator/SpritesheetGenerator.tscn
Normal file
|
@ -0,0 +1,714 @@
|
|||
[gd_scene load_steps=5 format=3 uid="uid://bf3b0i8scthbm"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://bnkl8rujlgv0h" path="res://addons/SpritesheetGenerator/Checker.png" id="1_hs1uu"]
|
||||
|
||||
[sub_resource type="GDScript" id="1"]
|
||||
resource_name = "Generator"
|
||||
script/source = "extends Control
|
||||
|
||||
const SUPPORTED_FORMATS: PackedStringArray = [\"bmp\", \"dds\", \"exr\", \"hdr\", \"jpg\", \"jpeg\", \"png\", \"tga\", \"svg\", \"svgz\", \"webp\"]
|
||||
|
||||
@onready var grid := %GridContainer
|
||||
|
||||
var file_list: Array
|
||||
var image_list: Array
|
||||
var texture_list: Array
|
||||
|
||||
var images_to_process: Array
|
||||
var images_to_texturize: Array
|
||||
var first_time := true
|
||||
var image_count: int
|
||||
var output_path: String
|
||||
|
||||
var auto := true
|
||||
var margin := Vector2.ONE
|
||||
|
||||
var pan_origin: Vector2
|
||||
var pan_start: Vector2
|
||||
|
||||
signal images_processed
|
||||
|
||||
func _enter_tree() -> void:
|
||||
$SplitDialog.hide()
|
||||
$StashDialog.hide()
|
||||
|
||||
func _ready():
|
||||
$Status.text = $Status.text % \", \".join(SUPPORTED_FORMATS)
|
||||
|
||||
get_viewport().files_dropped.connect(load_files)
|
||||
grid.minimum_size_changed.connect(refresh_background)
|
||||
set_process(false)
|
||||
|
||||
func refresh_background():
|
||||
%Background.custom_minimum_size = grid.get_minimum_size()
|
||||
|
||||
func load_files(files: PackedStringArray):
|
||||
file_list.clear()
|
||||
image_list.clear()
|
||||
|
||||
%CustomName.text = \"\"
|
||||
%Reload.disabled = false
|
||||
%SavePNG.disabled = false
|
||||
|
||||
if files.size() == 1 and not FileAccess.file_exists(files[0]):
|
||||
var dir := DirAccess.open(files[0])
|
||||
if not dir:
|
||||
show_error(\"Can't open directory.\")
|
||||
return
|
||||
|
||||
for file in dir.get_files():
|
||||
if file.get_extension() in SUPPORTED_FORMATS:
|
||||
file_list.append(str(dir.get_current_dir().path_join(file)))
|
||||
else:
|
||||
var wrong_count: int
|
||||
for file in files:
|
||||
if file.get_extension() in SUPPORTED_FORMATS:
|
||||
file_list.append(file)
|
||||
else:
|
||||
wrong_count += 1
|
||||
|
||||
if wrong_count > 0:
|
||||
show_error(\"Skipped %s file(s) with unsupported extension.\" % wrong_count)
|
||||
|
||||
if file_list.is_empty():
|
||||
show_error(\"No valid files or directories to process.\")
|
||||
return
|
||||
|
||||
load_images()
|
||||
|
||||
func load_images():
|
||||
texture_list.clear()
|
||||
|
||||
for image in grid.get_children():
|
||||
image.free()
|
||||
|
||||
for image in %StashImages.get_children():
|
||||
image.free()
|
||||
update_stash()
|
||||
|
||||
var size_map: Dictionary
|
||||
|
||||
if not file_list.is_empty():
|
||||
image_list = file_list.map(func(file: String):
|
||||
var image := Image.load_from_file(file)
|
||||
if image:
|
||||
image.set_meta(&\"path\", file)
|
||||
return image)
|
||||
|
||||
for image in image_list:
|
||||
if not image:
|
||||
continue
|
||||
|
||||
if not image.get_size() in size_map:
|
||||
size_map[image.get_size()] = []
|
||||
size_map[image.get_size()].append(image)
|
||||
|
||||
var output_name: String
|
||||
var most_common_size: Vector2i
|
||||
var most_common_count: int
|
||||
|
||||
for size in size_map:
|
||||
if size_map[size].size() > most_common_count:
|
||||
most_common_size = size
|
||||
most_common_count = size_map[size].size()
|
||||
|
||||
for image in size_map[most_common_size]:
|
||||
if output_path.is_empty():
|
||||
var path: String = image.get_meta(&\"path\", \"\")
|
||||
output_path = path.get_base_dir()
|
||||
output_name = path.get_base_dir().get_file()
|
||||
|
||||
images_to_process.append(image)
|
||||
size_map.clear()
|
||||
|
||||
if not output_name.is_empty() and %CustomName.text.is_empty():
|
||||
%CustomName.text = output_name
|
||||
update_save_button()
|
||||
|
||||
if images_to_process.size() < file_list.size():
|
||||
show_error(\"Rejected %s image(s) due to size mismatch.\" % (file_list.size() - images_to_process.size()))
|
||||
|
||||
if images_to_process.size() == 1:
|
||||
if file_list.size() > 1:
|
||||
images_to_process.clear()
|
||||
show_error(\"Only one dropped image was valid.\")
|
||||
else:
|
||||
%SplitPreview.texture = ImageTexture.create_from_image(images_to_process[0])
|
||||
$SplitDialog.reset_size()
|
||||
$SplitDialog.popup_centered()
|
||||
|
||||
return
|
||||
|
||||
$Status.show()
|
||||
%CenterContainer.hide()
|
||||
|
||||
image_count = images_to_process.size()
|
||||
%Columns.max_value = image_count
|
||||
|
||||
threshold = %Threshold.value
|
||||
min_x = 9999999
|
||||
min_y = 9999999
|
||||
max_x = -9999999
|
||||
max_y = -9999999
|
||||
|
||||
set_process(true)
|
||||
|
||||
await images_processed
|
||||
|
||||
for texture in texture_list:
|
||||
add_frame(texture)
|
||||
|
||||
toggle_auto(auto)
|
||||
refresh_margin()
|
||||
|
||||
$Status.hide()
|
||||
%CenterContainer.show()
|
||||
|
||||
var threshold: float
|
||||
var min_x: int
|
||||
var min_y: int
|
||||
var max_x: int
|
||||
var max_y: int
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if not images_to_process.is_empty():
|
||||
var image: Image = images_to_process.pop_front()
|
||||
$Status.text = str(\"Preprocessing image \", image_count - images_to_process.size(), \"/\", image_count)
|
||||
|
||||
for x in image.get_width():
|
||||
for y in image.get_height():
|
||||
if image.get_pixel(x, y).a >= threshold:
|
||||
min_x = mini(min_x, x)
|
||||
min_y = mini(min_y, y)
|
||||
max_x = maxi(max_x, x)
|
||||
max_y = maxi(max_y, y)
|
||||
|
||||
images_to_texturize.append(image)
|
||||
elif not images_to_texturize.is_empty():
|
||||
var rect := Rect2i(min_x, min_y, max_x - min_x + 1, max_y - min_y + 1)
|
||||
var image: Image = images_to_texturize.pop_front()
|
||||
$Status.text = str(\"Creating texture \", image_count - images_to_texturize.size(), \"/\", image_count)
|
||||
|
||||
var true_image := Image.create(rect.size.x, rect.size.y, false, image.get_format())
|
||||
true_image.blit_rect(image, rect, Vector2())
|
||||
|
||||
var texture := ImageTexture.create_from_image(true_image)
|
||||
texture_list.append(texture)
|
||||
|
||||
if images_to_texturize.is_empty():
|
||||
set_process(false)
|
||||
images_processed.emit()
|
||||
if first_time:
|
||||
recenter()
|
||||
first_time = false
|
||||
|
||||
func toggle_grid(show: bool) -> void:
|
||||
get_tree().call_group(&\"frame\", &\"set_display_background\", show)
|
||||
|
||||
func toggle_auto(button_pressed: bool) -> void:
|
||||
%Columns.editable = not button_pressed
|
||||
auto = button_pressed
|
||||
|
||||
if button_pressed:
|
||||
var best: int
|
||||
var best_score = -9999999
|
||||
|
||||
for i in range(1, image_count + 1):
|
||||
var cols = i
|
||||
var rows = ceili(image_count / float(i))
|
||||
|
||||
var score = image_count - cols * rows - maxi(cols, rows) - rows
|
||||
if score > best_score:
|
||||
best = i
|
||||
best_score = score
|
||||
|
||||
grid.columns = best
|
||||
else:
|
||||
grid.columns = %Columns.value
|
||||
refresh_grid()
|
||||
|
||||
func hmargin_changed(value: float) -> void:
|
||||
margin.x = value
|
||||
refresh_margin()
|
||||
|
||||
func vmargin_changed(value: float) -> void:
|
||||
margin.y = value
|
||||
refresh_margin()
|
||||
|
||||
func refresh_margin():
|
||||
get_tree().call_group(&\"frame\", &\"set_frame_margin\", margin)
|
||||
|
||||
func columns_changed(value: float) -> void:
|
||||
grid.columns = value
|
||||
refresh_grid()
|
||||
|
||||
func refresh_grid():
|
||||
var coord: Vector2
|
||||
var dark = false
|
||||
|
||||
for rect in grid.get_children():
|
||||
rect.set_background_color(Color(0, 0, 0, 0.2 if dark else 0.1))
|
||||
dark = not dark
|
||||
coord.x += 1
|
||||
|
||||
if coord.x == grid.columns:
|
||||
coord.x = 0
|
||||
coord.y += 1
|
||||
dark = int(coord.y) % 2 == 1
|
||||
|
||||
func save_png() -> void:
|
||||
var image_size: Vector2 = grid.get_child(0).get_minimum_size()
|
||||
|
||||
var image := Image.create(image_size.x * grid.columns, image_size.y * (ceil(grid.get_child_count() / float(grid.columns))), false, Image.FORMAT_RGBA8)
|
||||
|
||||
for rect in grid.get_children():
|
||||
image.blit_rect(rect.get_texture_data(), Rect2(Vector2(), image_size), rect.get_position2())
|
||||
|
||||
image.save_png(output_path.path_join(%CustomName.text) + \".png\")
|
||||
|
||||
func show_error(text: String):
|
||||
if not %Error.visible:
|
||||
%Error.show()
|
||||
else:
|
||||
%Error.text += \"\\n\"
|
||||
%Error.text += text
|
||||
%Timer.start()
|
||||
|
||||
func error_hidden() -> void:
|
||||
%Error.text = \"\"
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseButton:
|
||||
var cc: Control = %CenterContainer
|
||||
|
||||
if event.button_index == MOUSE_BUTTON_MIDDLE:
|
||||
if event.pressed:
|
||||
pan_origin = get_local_mouse_position()
|
||||
pan_start = cc.position
|
||||
else:
|
||||
pan_origin = Vector2()
|
||||
|
||||
if event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
|
||||
var lm = cc.get_local_mouse_position()
|
||||
cc.scale -= Vector2.ONE * 0.05
|
||||
if cc.scale.x <= 0:
|
||||
cc.scale = Vector2.ONE * 0.05
|
||||
|
||||
cc.position -= (lm - cc.get_local_mouse_position()) * cc.scale
|
||||
elif event.button_index == MOUSE_BUTTON_WHEEL_UP:
|
||||
var lm = cc.get_local_mouse_position()
|
||||
cc.scale += Vector2.ONE * 0.05
|
||||
cc.position -= (lm - cc.get_local_mouse_position()) * cc.scale
|
||||
|
||||
if event is InputEventMouseMotion:
|
||||
if pan_origin != Vector2():
|
||||
%CenterContainer.position = pan_start + (get_local_mouse_position() - pan_origin)
|
||||
|
||||
func recenter() -> void:
|
||||
%CenterContainer.position = get_viewport().size / 2 - Vector2i(%CenterContainer.size) / 2
|
||||
%CenterContainer.scale = Vector2.ONE
|
||||
|
||||
func update_split_preview():
|
||||
%SplitPreview.queue_redraw()
|
||||
|
||||
func draw_split_preview() -> void:
|
||||
var preview: TextureRect = %SplitPreview
|
||||
var frame_count := Vector2(%SplitX.value, %SplitY.value)
|
||||
var frame_size := preview.size / frame_count
|
||||
|
||||
for x in range(1, frame_count.x):
|
||||
for y in int(frame_count.y):
|
||||
preview.draw_line(frame_size * Vector2(x, y), frame_size * Vector2(x, y + 1), Color.WHITE)
|
||||
preview.draw_line(frame_size * Vector2(x, y) + Vector2.RIGHT, frame_size * Vector2(x, y + 1) + Vector2.RIGHT, Color.BLACK)
|
||||
|
||||
for y in range(1, frame_count.y):
|
||||
for x in int(frame_count.x):
|
||||
preview.draw_line(frame_size * Vector2(x, y), frame_size * Vector2(x + 1, y), Color.WHITE)
|
||||
preview.draw_line(frame_size * Vector2(x, y) + Vector2.DOWN, frame_size * Vector2(x + 1, y) + Vector2.DOWN, Color.BLACK)
|
||||
|
||||
func split_spritesheet() -> void:
|
||||
file_list.clear()
|
||||
image_list.clear()
|
||||
|
||||
var image: Image = images_to_process[0]
|
||||
var sub_image_size := image.get_size() / Vector2i(%SplitX.value, %SplitY.value)
|
||||
|
||||
for y in %SplitY.value:
|
||||
for x in %SplitX.value:
|
||||
image_list.append(image.get_region(Rect2i(Vector2i(x, y) * sub_image_size, sub_image_size)))
|
||||
|
||||
images_to_process.clear()
|
||||
load_images()
|
||||
|
||||
func remove_frame(frame):
|
||||
var image: Image = frame.get_texture_data()
|
||||
var texture := ImageTexture.create_from_image(image)
|
||||
|
||||
var button := TextureButton.new()
|
||||
button.texture_normal = texture
|
||||
button.custom_minimum_size = Vector2(128, 128)
|
||||
button.stretch_mode = TextureButton.STRETCH_KEEP_ASPECT_CENTERED
|
||||
button.ignore_texture_size = true
|
||||
button.pressed.connect(re_add_image.bind(button), CONNECT_DEFERRED)
|
||||
%StashImages.add_child(button)
|
||||
|
||||
var ref := ReferenceRect.new()
|
||||
button.add_child(ref)
|
||||
ref.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||
ref.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
ref.editor_only = false
|
||||
|
||||
frame.free()
|
||||
refresh_grid()
|
||||
update_stash()
|
||||
|
||||
func update_stash():
|
||||
%Stash.disabled = %StashImages.get_child_count() == 0
|
||||
|
||||
func re_add_image(tb: TextureButton):
|
||||
add_frame(tb.texture_normal)
|
||||
tb.free()
|
||||
refresh_grid()
|
||||
update_stash()
|
||||
|
||||
if %Stash.disabled:
|
||||
$StashDialog.hide()
|
||||
|
||||
func add_frame(texture: Texture2D):
|
||||
var rect := preload(\"res://addons/SpritesheetGenerator/SpritesheetFrame.tscn\").instantiate()
|
||||
rect.set_texture(texture)
|
||||
rect.set_display_background(%DisplayGrid.button_pressed)
|
||||
rect.set_frame_margin(margin)
|
||||
grid.add_child(rect)
|
||||
|
||||
func update_save_button() -> void:
|
||||
%SavePNG.disabled = %CustomName.text.is_empty()
|
||||
"
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="5"]
|
||||
content_margin_left = 20.0
|
||||
content_margin_top = 20.0
|
||||
content_margin_right = 20.0
|
||||
content_margin_bottom = 20.0
|
||||
bg_color = Color(0, 0, 0, 0.25098)
|
||||
|
||||
[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_kjgn5"]
|
||||
texture = ExtResource("1_hs1uu")
|
||||
axis_stretch_horizontal = 1
|
||||
axis_stretch_vertical = 1
|
||||
|
||||
[node name="Main" type="HBoxContainer"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
script = SubResource("1")
|
||||
|
||||
[node name="MarginContainer" type="PanelContainer" parent="."]
|
||||
layout_mode = 2
|
||||
theme_override_styles/panel = SubResource("5")
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 10
|
||||
|
||||
[node name="Label5" type="Label" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Alpha Threshold"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Threshold" type="SpinBox" parent="MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
max_value = 1.0
|
||||
step = 0.005
|
||||
value = 0.9
|
||||
|
||||
[node name="Reload" type="Button" parent="MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
text = "Reload"
|
||||
|
||||
[node name="HSeparator" type="HSeparator" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Columns"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Columns" type="SpinBox" parent="MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
min_value = 1.0
|
||||
value = 1.0
|
||||
editable = false
|
||||
|
||||
[node name="Grid" type="CheckButton" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
button_pressed = true
|
||||
text = "Auto"
|
||||
|
||||
[node name="Label3" type="Label" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Horizontal Margin"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="MarginH" type="SpinBox" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
value = 1.0
|
||||
suffix = "px"
|
||||
|
||||
[node name="Label4" type="Label" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Vertical Margin"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="MarginV" type="SpinBox" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
max_value = 128.0
|
||||
value = 1.0
|
||||
suffix = "px"
|
||||
|
||||
[node name="Stash" type="Button" parent="MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
text = "Image Stash"
|
||||
|
||||
[node name="HSeparator2" type="HSeparator" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Button" type="Button" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Recenter View
|
||||
"
|
||||
|
||||
[node name="DisplayGrid" type="CheckBox" parent="MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
button_pressed = true
|
||||
text = "Show Grid"
|
||||
|
||||
[node name="HSeparator3" type="HSeparator" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="CustomName" type="LineEdit" parent="MarginContainer/VBoxContainer/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
placeholder_text = "Image Name"
|
||||
|
||||
[node name="SavePNG" type="Button" parent="MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
text = "Save PNG"
|
||||
|
||||
[node name="Status" type="Label" parent="."]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
text = "Drop folder or image files here to start.
|
||||
|
||||
Images should be of the same size. If their sizes don't match, the generator will try to use the dominating size.
|
||||
|
||||
The images will be automatically cropped based on the Alpha Threshold value. Greater value means more exact crop.
|
||||
|
||||
Supported formats: %s
|
||||
|
||||
If you drop a single image, the generator will instead edit it as spritesheet."
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="View" type="CanvasLayer" parent="."]
|
||||
layer = -1
|
||||
|
||||
[node name="CenterContainer" type="CenterContainer" parent="View"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Background" type="ColorRect" parent="View/CenterContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
mouse_filter = 1
|
||||
color = Color(0, 0.501961, 0.501961, 1)
|
||||
|
||||
[node name="GridContainer" type="GridContainer" parent="View/CenterContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
theme_override_constants/h_separation = 0
|
||||
theme_override_constants/v_separation = 0
|
||||
columns = 3
|
||||
|
||||
[node name="VBoxContainer" type="GridContainer" parent="View"]
|
||||
anchors_preset = 3
|
||||
anchor_left = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -40.0
|
||||
offset_top = -40.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 0
|
||||
mouse_filter = 2
|
||||
columns = 3
|
||||
|
||||
[node name="Label" type="Label" parent="View/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "LMB"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="VSeparator" type="VSeparator" parent="View/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label2" type="Label" parent="View/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "rearrange images"
|
||||
|
||||
[node name="Label3" type="Label" parent="View/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "RMB"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="VSeparator2" type="VSeparator" parent="View/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label4" type="Label" parent="View/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "delete images"
|
||||
|
||||
[node name="Label5" type="Label" parent="View/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "MMB"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="VSeparator3" type="VSeparator" parent="View/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label6" type="Label" parent="View/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "pan view"
|
||||
|
||||
[node name="CanvasLayer" type="CanvasLayer" parent="."]
|
||||
|
||||
[node name="Error" type="Label" parent="CanvasLayer"]
|
||||
unique_name_in_owner = true
|
||||
modulate = Color(1, 0, 0, 1)
|
||||
anchors_preset = 12
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_top = -14.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 0
|
||||
size_flags_vertical = 0
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Timer" type="Timer" parent="CanvasLayer"]
|
||||
unique_name_in_owner = true
|
||||
wait_time = 5.0
|
||||
one_shot = true
|
||||
|
||||
[node name="SplitDialog" type="ConfirmationDialog" parent="."]
|
||||
title = "Edit Spritesheet"
|
||||
position = Vector2i(-500, 0)
|
||||
size = Vector2i(272, 343)
|
||||
visible = true
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="SplitDialog"]
|
||||
offset_left = 8.0
|
||||
offset_top = 8.0
|
||||
offset_right = 264.0
|
||||
offset_bottom = 294.0
|
||||
|
||||
[node name="Label" type="Label" parent="SplitDialog/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Split Frames"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="SplitDialog/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
alignment = 1
|
||||
|
||||
[node name="SplitX" type="SpinBox" parent="SplitDialog/VBoxContainer/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
min_value = 1.0
|
||||
max_value = 1000.0
|
||||
value = 1.0
|
||||
select_all_on_focus = true
|
||||
|
||||
[node name="Label" type="Label" parent="SplitDialog/VBoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "x"
|
||||
|
||||
[node name="SplitY" type="SpinBox" parent="SplitDialog/VBoxContainer/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
min_value = 1.0
|
||||
max_value = 1000.0
|
||||
value = 1.0
|
||||
select_all_on_focus = true
|
||||
|
||||
[node name="CenterContainer" type="CenterContainer" parent="SplitDialog/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="PanelContainer" type="PanelContainer" parent="SplitDialog/VBoxContainer/CenterContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxTexture_kjgn5")
|
||||
|
||||
[node name="SplitPreview" type="TextureRect" parent="SplitDialog/VBoxContainer/CenterContainer/PanelContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
|
||||
[node name="StashDialog" type="AcceptDialog" parent="."]
|
||||
title = "Image Stash"
|
||||
position = Vector2i(-500, 500)
|
||||
size = Vector2i(309, 100)
|
||||
visible = true
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="StashDialog"]
|
||||
offset_left = 8.0
|
||||
offset_top = 8.0
|
||||
offset_right = 301.0
|
||||
offset_bottom = 51.0
|
||||
|
||||
[node name="Label" type="Label" parent="StashDialog/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Click frame to re-add it to spritesheet."
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="StashImages" type="HFlowContainer" parent="StashDialog/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
|
||||
[connection signal="pressed" from="MarginContainer/VBoxContainer/Reload" to="." method="load_images"]
|
||||
[connection signal="value_changed" from="MarginContainer/VBoxContainer/Columns" to="." method="columns_changed"]
|
||||
[connection signal="toggled" from="MarginContainer/VBoxContainer/Grid" to="." method="toggle_auto"]
|
||||
[connection signal="value_changed" from="MarginContainer/VBoxContainer/MarginH" to="." method="hmargin_changed"]
|
||||
[connection signal="value_changed" from="MarginContainer/VBoxContainer/MarginV" to="." method="vmargin_changed"]
|
||||
[connection signal="pressed" from="MarginContainer/VBoxContainer/Stash" to="StashDialog" method="popup_centered_ratio" binds= [0.5]]
|
||||
[connection signal="pressed" from="MarginContainer/VBoxContainer/Button" to="." method="recenter"]
|
||||
[connection signal="toggled" from="MarginContainer/VBoxContainer/DisplayGrid" to="." method="toggle_grid"]
|
||||
[connection signal="text_changed" from="MarginContainer/VBoxContainer/HBoxContainer/CustomName" to="." method="update_save_button" unbinds=1]
|
||||
[connection signal="pressed" from="MarginContainer/VBoxContainer/SavePNG" to="." method="save_png"]
|
||||
[connection signal="hidden" from="CanvasLayer/Error" to="." method="error_hidden"]
|
||||
[connection signal="timeout" from="CanvasLayer/Timer" to="CanvasLayer/Error" method="hide"]
|
||||
[connection signal="confirmed" from="SplitDialog" to="." method="split_spritesheet"]
|
||||
[connection signal="value_changed" from="SplitDialog/VBoxContainer/HBoxContainer/SplitX" to="." method="update_split_preview" unbinds=1]
|
||||
[connection signal="value_changed" from="SplitDialog/VBoxContainer/HBoxContainer/SplitY" to="." method="update_split_preview" unbinds=1]
|
||||
[connection signal="draw" from="SplitDialog/VBoxContainer/CenterContainer/PanelContainer/SplitPreview" to="." method="draw_split_preview"]
|
7
addons/SpritesheetGenerator/plugin.cfg
Normal file
|
@ -0,0 +1,7 @@
|
|||
[plugin]
|
||||
|
||||
name="Spritesheet Generator"
|
||||
description="Generates cropped spritesheets from multiple images."
|
||||
author="KoBeWi"
|
||||
version="1.2"
|
||||
script="SpriteSheetGenerator.gd"
|
2029
addons/fontawesome/All.gd
Normal file
44
addons/fontawesome/FontAwesome.gd
Normal file
|
@ -0,0 +1,44 @@
|
|||
@tool
|
||||
extends Label
|
||||
|
||||
@export_category("FontAwesome")
|
||||
@export_range(1, 16384) var icon_size: int = 16: set = set_icon_size
|
||||
@export_enum("solid", "regular", "brands") var icon_type: String = "solid": set = set_icon_type
|
||||
@export var icon_name: String = "circle-question": set = set_icon_name
|
||||
|
||||
const icon_fonts: Dictionary = {
|
||||
"solid": "res://addons/fontawesome/fonts/fa-solid-900.woff2",
|
||||
"regular": "res://addons/fontawesome/fonts/fa-regular-400.woff2",
|
||||
"brands": "res://addons/fontawesome/fonts/fa-brands-400.woff2"
|
||||
}
|
||||
|
||||
const cheatsheet: Dictionary = preload("res://addons/fontawesome/All.gd").all
|
||||
|
||||
func _init():
|
||||
horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
# disable some things, this is icon not text
|
||||
auto_translate = false
|
||||
localize_numeral_system = false
|
||||
|
||||
set_icon_type(icon_type)
|
||||
set_icon_size(icon_size)
|
||||
set_icon_name(icon_name)
|
||||
|
||||
func set_icon_size(new_size: int):
|
||||
icon_size = clamp(new_size, 1, 16384)
|
||||
add_theme_font_size_override("font_size", icon_size)
|
||||
size = Vector2(icon_size, icon_size)
|
||||
|
||||
func set_icon_type(new_type: String):
|
||||
icon_type = new_type
|
||||
match icon_type:
|
||||
"solid", "regular", "brands":
|
||||
add_theme_font_override("font", load(icon_fonts[icon_type]))
|
||||
|
||||
func set_icon_name(new_name: String):
|
||||
icon_name = new_name
|
||||
var iconcode = ""
|
||||
if icon_name in cheatsheet[icon_type]:
|
||||
iconcode = cheatsheet[icon_type][icon_name]
|
||||
set_text(iconcode)
|
|
@ -1,6 +1,6 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2022 Addons By Aura
|
||||
Copyright (c) 2023 LetterN
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
1
addons/fontawesome/flag-solid.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="flag" class="svg-inline--fa fa-flag fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="16" height="16"><path stroke="black" stroke-width="2" fill="#a5efac" d="M349.565 98.783C295.978 98.783 251.721 64 184.348 64c-24.955 0-47.309 4.384-68.045 12.013a55.947 55.947 0 0 0 3.586-23.562C118.117 24.015 94.806 1.206 66.338.048 34.345-1.254 8 24.296 8 56c0 19.026 9.497 35.825 24 45.945V488c0 13.255 10.745 24 24 24h16c13.255 0 24-10.745 24-24v-94.4c28.311-12.064 63.582-22.122 114.435-22.122 53.588 0 97.844 34.783 165.217 34.783 48.169 0 86.667-16.294 122.505-40.858C506.84 359.452 512 349.571 512 339.045v-243.1c0-23.393-24.269-38.87-45.485-29.016-34.338 15.948-76.454 31.854-116.95 31.854z"></path></svg>
|
After Width: | Height: | Size: 806 B |
37
addons/fontawesome/flag-solid.svg.import
Normal file
|
@ -0,0 +1,37 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cdk6bwkag1wre"
|
||||
path="res://.godot/imported/flag-solid.svg-f443982cac7d006eea43c772e2428bae.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/fontawesome/flag-solid.svg"
|
||||
dest_files=["res://.godot/imported/flag-solid.svg-f443982cac7d006eea43c772e2428bae.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
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
165
addons/fontawesome/fonts/LICENSE.txt
Normal file
|
@ -0,0 +1,165 @@
|
|||
Fonticons, Inc. (https://fontawesome.com)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Font Awesome Free License
|
||||
|
||||
Font Awesome Free is free, open source, and GPL friendly. You can use it for
|
||||
commercial projects, open source projects, or really almost whatever you want.
|
||||
Full Font Awesome Free license: https://fontawesome.com/license/free.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
# Icons: CC BY 4.0 License (https://creativecommons.org/licenses/by/4.0/)
|
||||
|
||||
The Font Awesome Free download is licensed under a Creative Commons
|
||||
Attribution 4.0 International License and applies to all icons packaged
|
||||
as SVG and JS file types.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
# Fonts: SIL OFL 1.1 License
|
||||
|
||||
In the Font Awesome Free download, the SIL OFL license applies to all icons
|
||||
packaged as web and desktop font files.
|
||||
|
||||
Copyright (c) 2023 Fonticons, Inc. (https://fontawesome.com)
|
||||
with Reserved Font Name: "Font Awesome".
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
SIL OPEN FONT LICENSE
|
||||
Version 1.1 - 26 February 2007
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting — in part or in whole — any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
# Code: MIT License (https://opensource.org/licenses/MIT)
|
||||
|
||||
In the Font Awesome Free download, the MIT license applies to all non-font and
|
||||
non-icon files.
|
||||
|
||||
Copyright 2023 Fonticons, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
# Attribution
|
||||
|
||||
Attribution is required by MIT, SIL OFL, and CC BY licenses. Downloaded Font
|
||||
Awesome Free files already contain embedded comments with sufficient
|
||||
attribution, so you shouldn't need to do anything additional when using these
|
||||
files normally.
|
||||
|
||||
We've kept attribution comments terse, so we ask that you do not actively work
|
||||
to remove them from files, especially code. They're a great way for folks to
|
||||
learn about Font Awesome.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
# Brand Icons
|
||||
|
||||
All brand icons are trademarks of their respective owners. The use of these
|
||||
trademarks does not indicate endorsement of the trademark holder by Font
|
||||
Awesome, nor vice versa. **Please do not use brand logos for any purpose except
|
||||
to represent the company, product, or service to which they refer.**
|
BIN
addons/fontawesome/fonts/fa-brands-400.woff2
Normal file
33
addons/fontawesome/fonts/fa-brands-400.woff2.import
Normal file
|
@ -0,0 +1,33 @@
|
|||
[remap]
|
||||
|
||||
importer="font_data_dynamic"
|
||||
type="FontFile"
|
||||
uid="uid://clt4puu367e82"
|
||||
path="res://.godot/imported/fa-brands-400.woff2-01946f939132baa0e37dbdeac9412933.fontdata"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/fontawesome/fonts/fa-brands-400.woff2"
|
||||
dest_files=["res://.godot/imported/fa-brands-400.woff2-01946f939132baa0e37dbdeac9412933.fontdata"]
|
||||
|
||||
[params]
|
||||
|
||||
Rendering=null
|
||||
antialiasing=1
|
||||
generate_mipmaps=false
|
||||
multichannel_signed_distance_field=false
|
||||
msdf_pixel_range=8
|
||||
msdf_size=48
|
||||
allow_system_fallback=true
|
||||
force_autohinter=false
|
||||
hinting=1
|
||||
subpixel_positioning=1
|
||||
oversampling=0.0
|
||||
Fallbacks=null
|
||||
fallbacks=[]
|
||||
Compress=null
|
||||
compress=true
|
||||
preload=[]
|
||||
language_support={}
|
||||
script_support={}
|
||||
opentype_features={}
|
BIN
addons/fontawesome/fonts/fa-regular-400.woff2
Normal file
33
addons/fontawesome/fonts/fa-regular-400.woff2.import
Normal file
|
@ -0,0 +1,33 @@
|
|||
[remap]
|
||||
|
||||
importer="font_data_dynamic"
|
||||
type="FontFile"
|
||||
uid="uid://ew3t30vlpjit"
|
||||
path="res://.godot/imported/fa-regular-400.woff2-bb494eebb9050a2fb4b1382e97f43781.fontdata"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/fontawesome/fonts/fa-regular-400.woff2"
|
||||
dest_files=["res://.godot/imported/fa-regular-400.woff2-bb494eebb9050a2fb4b1382e97f43781.fontdata"]
|
||||
|
||||
[params]
|
||||
|
||||
Rendering=null
|
||||
antialiasing=1
|
||||
generate_mipmaps=false
|
||||
multichannel_signed_distance_field=false
|
||||
msdf_pixel_range=8
|
||||
msdf_size=48
|
||||
allow_system_fallback=true
|
||||
force_autohinter=false
|
||||
hinting=1
|
||||
subpixel_positioning=1
|
||||
oversampling=0.0
|
||||
Fallbacks=null
|
||||
fallbacks=[]
|
||||
Compress=null
|
||||
compress=true
|
||||
preload=[]
|
||||
language_support={}
|
||||
script_support={}
|
||||
opentype_features={}
|
BIN
addons/fontawesome/fonts/fa-solid-900.woff2
Normal file
33
addons/fontawesome/fonts/fa-solid-900.woff2.import
Normal file
|
@ -0,0 +1,33 @@
|
|||
[remap]
|
||||
|
||||
importer="font_data_dynamic"
|
||||
type="FontFile"
|
||||
uid="uid://bkqnxsphaabhw"
|
||||
path="res://.godot/imported/fa-solid-900.woff2-a9219e5bf1517e35af668434330a4deb.fontdata"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/fontawesome/fonts/fa-solid-900.woff2"
|
||||
dest_files=["res://.godot/imported/fa-solid-900.woff2-a9219e5bf1517e35af668434330a4deb.fontdata"]
|
||||
|
||||
[params]
|
||||
|
||||
Rendering=null
|
||||
antialiasing=1
|
||||
generate_mipmaps=false
|
||||
multichannel_signed_distance_field=false
|
||||
msdf_pixel_range=8
|
||||
msdf_size=48
|
||||
allow_system_fallback=true
|
||||
force_autohinter=false
|
||||
hinting=1
|
||||
subpixel_positioning=1
|
||||
oversampling=0.0
|
||||
Fallbacks=null
|
||||
fallbacks=[]
|
||||
Compress=null
|
||||
compress=true
|
||||
preload=[]
|
||||
language_support={}
|
||||
script_support={}
|
||||
opentype_features={}
|
6
addons/fontawesome/plugin.cfg
Normal file
|
@ -0,0 +1,6 @@
|
|||
[plugin]
|
||||
name="FontAwesome"
|
||||
description="FontAwesome 6 Icons"
|
||||
author="LetterN"
|
||||
version="6.3.0"
|
||||
script="plugin.gd"
|
8
addons/fontawesome/plugin.gd
Normal file
|
@ -0,0 +1,8 @@
|
|||
@tool
|
||||
extends EditorPlugin
|
||||
|
||||
func _enter_tree():
|
||||
add_custom_type("FontAwesome", "Label", preload("res://addons/fontawesome/FontAwesome.gd"), preload("res://addons/fontawesome/flag-solid.svg"))
|
||||
|
||||
func _exit_tree():
|
||||
remove_custom_type("FontAwesome")
|
|
@ -1,47 +0,0 @@
|
|||
@icon("../icons/animation_state.png")
|
||||
class_name AnimationState
|
||||
extends State
|
||||
|
||||
## Plays an animation from the linked [member animation_player].
|
||||
## The name of the animation to be played comes from the name of the node.
|
||||
|
||||
## Emitted when the animation started by this state has finished playing.
|
||||
signal animation_finished
|
||||
|
||||
|
||||
@export_range(0, 20, 1, "or_greater")
|
||||
## How many times to play before emitting [signal State.choose_new_substate_requested].
|
||||
## [b]If set to zero, it will go forever.[/b]
|
||||
var loops := 0
|
||||
|
||||
|
||||
var _loops_left := 0
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
set_meta(&"description", "Plays the named animation from the linked AnimationPlayer.")
|
||||
|
||||
|
||||
func _on_animation_finished(animation_name: StringName) -> void:
|
||||
if animation_name != name: return
|
||||
if loops == 0:
|
||||
animation_player.play(name)
|
||||
elif _loops_left <= 0:
|
||||
choose_new_substate_requested.emit()
|
||||
else:
|
||||
_loops_left -= 1
|
||||
animation_player.play(name)
|
||||
|
||||
|
||||
func enter(set_target: Node, set_animation_player: AnimationPlayer, set_debug_mode := false) -> void:
|
||||
super(set_target, set_animation_player, set_debug_mode)
|
||||
assert(animation_player != null, "AnimationPlayer must be set, either directly or by an ancestor.")
|
||||
animation_player.animation_finished.connect(_on_animation_finished)
|
||||
_loops_left = loops - 1
|
||||
animation_player.play(name)
|
||||
|
||||
|
||||
func exit() -> void:
|
||||
super()
|
||||
animation_player.animation_finished.disconnect(_on_animation_finished)
|
||||
animation_player.stop()
|
|
@ -1,139 +0,0 @@
|
|||
@icon("../icons/state_machine_debugger.png")
|
||||
class_name StateMachineDebugger
|
||||
extends Tree
|
||||
|
||||
|
||||
## Displays an interactive state tree.
|
||||
# This source code is a mess, I'm trying to make it less so.
|
||||
|
||||
|
||||
@export
|
||||
## Root state machine to reference.
|
||||
var state_machine_root : State:
|
||||
set(value):
|
||||
state_machine_root = value
|
||||
_setup_tree()
|
||||
|
||||
@export
|
||||
## What color to make the item when a state is active.
|
||||
var active_color := Color.FOREST_GREEN
|
||||
|
||||
@export
|
||||
## Forcefully switch states by double-clicking them.
|
||||
## Due to its nature, it has the potential to be destructive
|
||||
## and/ or not behave completely how one might expect.
|
||||
var allow_state_switching := false:
|
||||
set(value):
|
||||
allow_state_switching = value
|
||||
if allow_state_switching:
|
||||
item_activated.connect(_on_item_activated)
|
||||
else:
|
||||
item_activated.disconnect(_on_item_activated)
|
||||
|
||||
|
||||
@export_group("Signals", "signal_")
|
||||
@export
|
||||
## Show when a state emits a relevant signal.
|
||||
var signal_show := false:
|
||||
set(value):
|
||||
signal_show = value
|
||||
|
||||
if state_machine_root == null:
|
||||
return
|
||||
|
||||
if signal_show:
|
||||
connect_signals()
|
||||
else:
|
||||
disconnect_signals()
|
||||
|
||||
@export
|
||||
## Which signals to connect to on each state, as long as they exist.
|
||||
var signal_connections : Array[StringName] = [
|
||||
&"entered",
|
||||
&"exited",
|
||||
&"choose_new_substate_requested",
|
||||
&"animation_finished",
|
||||
]
|
||||
|
||||
@export
|
||||
## Delay before hiding signal.
|
||||
var signal_hide_delay := 1.0
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
columns = 2
|
||||
|
||||
|
||||
func change_state_by_path(path: NodePath) -> void:
|
||||
if not state_machine_root.has_node(path):
|
||||
return
|
||||
var state := state_machine_root
|
||||
for i in path.get_name_count():
|
||||
var part := path.get_name(i)
|
||||
state = await state.change_state_name(part)
|
||||
|
||||
|
||||
func connect_signals(state := state_machine_root) -> void:
|
||||
if not state.has_meta(&"tree_item"):
|
||||
return
|
||||
for signal_name in signal_connections:
|
||||
if state.has_signal(signal_name) and not \
|
||||
state.is_connected(signal_name, _on_state_signal):
|
||||
state.connect(signal_name, _on_state_signal.bind(signal_name, state.get_meta(&"tree_item")))
|
||||
for child in(state.get_children() as Array[State]):
|
||||
connect_signals(child)
|
||||
|
||||
|
||||
func disconnect_signals(state := state_machine_root) -> void:
|
||||
for signal_name in signal_connections:
|
||||
if state.has_signal(signal_name) and \
|
||||
state.is_connected(signal_name, _on_state_signal):
|
||||
state.disconnect(signal_name, _on_state_signal)
|
||||
for child in (state.get_children() as Array[State]):
|
||||
disconnect_signals(child)
|
||||
|
||||
|
||||
func _setup_tree(state := state_machine_root, parent_item: TreeItem = null) -> void:
|
||||
if state == state_machine_root:
|
||||
if get_root() != null:
|
||||
disconnect_signals()
|
||||
clear()
|
||||
if state_machine_root == null:
|
||||
return
|
||||
# state.print_tree_pretty()
|
||||
|
||||
# TODO: add icons
|
||||
var item := create_item(parent_item)
|
||||
item.set_text(0, state.name)
|
||||
item.set_metadata(0, state)
|
||||
state.set_meta(&"tree_item", item)
|
||||
connect_signals(state)
|
||||
|
||||
for child in (state.get_children() as Array[State]):
|
||||
_setup_tree(child, item)
|
||||
|
||||
|
||||
func _on_item_activated() -> void:
|
||||
change_state_by_path(state_machine_root.get_path_to(
|
||||
get_selected().get_metadata(0) as State))
|
||||
|
||||
|
||||
func _on_state_signal(signal_name: StringName, state_item: TreeItem) -> void:
|
||||
match signal_name:
|
||||
&"entered":
|
||||
for i in columns:
|
||||
state_item.set_custom_color(i, active_color)
|
||||
&"exited":
|
||||
for i in columns:
|
||||
state_item.clear_custom_color(i)
|
||||
|
||||
if not signal_show:
|
||||
return
|
||||
|
||||
state_item.set_text(1, signal_name)
|
||||
var timer := state_item.get_metadata(1) as SceneTreeTimer
|
||||
if timer != null:
|
||||
timer.timeout.disconnect(state_item.set_text)
|
||||
timer = get_tree().create_timer(signal_hide_delay)
|
||||
timer.timeout.connect(state_item.set_text.bind(1, ""))
|
||||
state_item.set_metadata(1, timer)
|
|
@ -1,34 +0,0 @@
|
|||
@icon("../icons/random_state.png")
|
||||
class_name RandomState
|
||||
extends State
|
||||
|
||||
## Activates a random one of its substates.
|
||||
## Useful in conjuction with [AnimationState] for random idles.
|
||||
|
||||
|
||||
@export
|
||||
## When one of its children asks for a state change,
|
||||
## instead of picking another one itself, it defers that choice to its parent.
|
||||
## Allows for nested random states for finer control over flow and probability.
|
||||
var defer_choice := false
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
set_meta(&"description", "Pseudo-randomly picks a state to start.")
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
randomize()
|
||||
super()
|
||||
|
||||
|
||||
# You can define which state is picked automatically (like on enter).
|
||||
# If you would like to call it yourself, use the public version (choose_substate).
|
||||
func _choose_substate() -> State:
|
||||
if get_child_count() == 0:
|
||||
return null
|
||||
if defer_choice and _active_substate != null:
|
||||
choose_new_substate_requested.emit()
|
||||
return null
|
||||
return get_child(randi() % get_child_count()) as State
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
@icon("../icons/sequence_state.png")
|
||||
class_name SequenceState
|
||||
extends State
|
||||
|
||||
|
||||
## Executes its children in order, one after the other. Like an [Array] in [State] form!
|
||||
|
||||
|
||||
@export_range(0, 20, 1, "or_greater")
|
||||
## How many times the sequence should be looped through before emitting [signal State.choose_new_substate_requested].
|
||||
## [b]If set to zero, it will go forever.[/b]
|
||||
var loops := 1
|
||||
|
||||
|
||||
var _loops_left := 0
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
set_meta(&"description", "Starts its children one after the other in order, \
|
||||
waiting for each one to be done before starting the next.")
|
||||
|
||||
|
||||
# You can define which state is picked automatically (like on [method enter]).
|
||||
# If you would like to call it yourself, use the public version ([method choose_substate]).
|
||||
func _choose_substate() -> State:
|
||||
if _active_substate == null:
|
||||
return get_child(0) as State if get_child_count() > 0 else null
|
||||
|
||||
if _active_substate.get_index() == get_child_count() - 1:
|
||||
if loops == 0:
|
||||
return get_child(0) as State
|
||||
elif _loops_left == 0:
|
||||
choose_new_substate_requested.emit()
|
||||
return null
|
||||
else:
|
||||
_loops_left -= 1
|
||||
return get_child(0) as State
|
||||
return get_child(_active_substate.get_index() + 1) as State
|
||||
|
||||
|
||||
func enter(set_target: Node, set_animation_player: AnimationPlayer, set_debug := false) -> void:
|
||||
super(set_target, set_animation_player, set_debug)
|
||||
_loops_left = loops - 1
|
|
@ -1,291 +0,0 @@
|
|||
@icon("../icons/state.png")
|
||||
class_name State
|
||||
extends Node
|
||||
|
||||
## The bare, basic state. Use it if you want total control over the state-flow.
|
||||
##
|
||||
## Properties marked as [b](inherited)[/b] are passed to substates,
|
||||
## meaning you don't have to set it on each individual state, only the root.
|
||||
## You can override it of course, and that will be passed to all of [i]its[/i] children.
|
||||
|
||||
|
||||
## Emitted between [method _enter] and [method _after_enter].
|
||||
signal entered
|
||||
|
||||
## Emitted after [method _exit].
|
||||
signal exited
|
||||
|
||||
## Emitted between [method _update] and [method _after_update]
|
||||
signal updated
|
||||
|
||||
## Switched active substates.
|
||||
signal active_substate_changed(new: State, old: State)
|
||||
|
||||
## A request for the parent to pick a new substate to activate.
|
||||
## Mainly used by children of [RandomState], such as an [AnimationState].
|
||||
signal choose_new_substate_requested
|
||||
|
||||
|
||||
## Active or not.
|
||||
enum Status {
|
||||
INACTIVE, ## Inactive
|
||||
ACTIVE, ## Active
|
||||
}
|
||||
|
||||
|
||||
@export
|
||||
## The node that the states will act upon. [b](inherited)[/b]
|
||||
## Doesn't actually get used in the addon scripts, it's just
|
||||
## included for your convenience when scripting your own behaviour.
|
||||
var target: Node:
|
||||
set(value):
|
||||
target = value
|
||||
if _active_substate != null:
|
||||
_active_substate.target = target
|
||||
|
||||
@export
|
||||
## Where to play animations from. [b](inherited)[/b]
|
||||
var animation_player: AnimationPlayer
|
||||
|
||||
@export_range(0, 120, 1, "or_greater")
|
||||
## How many seconds the state should be active before emitting [signal choose_new_substate_requested].
|
||||
## [b]If set to zero, it will go forever.[/b]
|
||||
var timer := 0.0
|
||||
|
||||
@export
|
||||
## Whether to force-restart the chosen substate in the callback for [signal choose_new_substate_requested] if it was already active.
|
||||
var force := true
|
||||
|
||||
@export
|
||||
## The state will not be activated under any circumstances.
|
||||
var disabled := false:
|
||||
set(value):
|
||||
disabled = value
|
||||
var root := is_root()
|
||||
if root and not disabled:
|
||||
enter(target, animation_player, debug_mode)
|
||||
elif status == Status.ACTIVE:
|
||||
exit()
|
||||
|
||||
@export
|
||||
## Print a message avery time there is a state change. [b](inherited)[/b]
|
||||
var debug_mode := false:
|
||||
set(value):
|
||||
debug_mode = value
|
||||
if _active_substate != null:
|
||||
_active_substate.debug_mode = debug_mode
|
||||
|
||||
## The status of this state, ie. whether it's running or not.
|
||||
var status := Status.INACTIVE
|
||||
|
||||
|
||||
# The substate that is currently active, if any.
|
||||
var _active_substate: State:
|
||||
set(value):
|
||||
if _active_substate != null:
|
||||
_active_substate.choose_new_substate_requested.disconnect(_on_choose_new_substate_requested)
|
||||
active_substate_changed.emit(value, _active_substate)
|
||||
_active_substate = value
|
||||
if _active_substate != null:
|
||||
_active_substate.choose_new_substate_requested.connect(_on_choose_new_substate_requested)
|
||||
|
||||
# If a timer is set, the object will be stored here.
|
||||
var _timer_object: SceneTreeTimer
|
||||
|
||||
|
||||
#########################
|
||||
### VIRTUAL METHODS ###
|
||||
#########################
|
||||
func _init() -> void:
|
||||
set_physics_process(false)
|
||||
set_meta(&"description", "A bare, basic state - will only ever automatically start its first child.")
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
for child in get_children():
|
||||
assert(child is State, "A State should not have any children that are not other States.")
|
||||
if is_root() and not disabled:
|
||||
enter(target, animation_player, debug_mode)
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if status == Status.INACTIVE:
|
||||
set_physics_process(false)
|
||||
return
|
||||
update(delta)
|
||||
|
||||
|
||||
## [b][parents, then children][/b] Called when the state is activated.
|
||||
func _enter() -> void:
|
||||
pass
|
||||
|
||||
|
||||
## [b][children, then parents][/b] Called after the state is activated.
|
||||
func _after_enter() -> void:
|
||||
pass
|
||||
|
||||
|
||||
## [b][parents, then children][/b] Called every physics frame (only when the state is active, of course).
|
||||
func _update(delta: float) -> void:
|
||||
pass
|
||||
|
||||
|
||||
## [b][children, then parents][/b] Called at the end of every physics frame.
|
||||
func _after_update(delta: float) -> void:
|
||||
pass
|
||||
|
||||
|
||||
## [b][parents, then children][/b] Called before the state is deactivated.
|
||||
func _before_exit() -> void:
|
||||
pass
|
||||
|
||||
|
||||
## [b][children, then parents][/b] Called when the state is deactivated.
|
||||
func _exit() -> void:
|
||||
pass
|
||||
|
||||
|
||||
## You can define which state is picked automatically (like on [method enter]).
|
||||
## Return `null` to not change substate at all.
|
||||
## If you would like to call it yourself, use the public version ([method choose_substate]).
|
||||
func _choose_substate() -> State:
|
||||
return get_child(0) as State if get_child_count() > 0 else null
|
||||
|
||||
|
||||
########################
|
||||
### PUBLIC METHODS ###
|
||||
########################
|
||||
|
||||
## Switch to the specified substate by name. It is just a shortcut to [method change_state_node].
|
||||
func change_state_name(name: String, force := false) -> State:
|
||||
return await change_state_node(get_node_or_null(name) as State, force)
|
||||
|
||||
|
||||
## Switch to the specified substate by node. If it is not a direct child, nothing will happen.
|
||||
## If `force`, it will start a state again even if it's already running.
|
||||
## It waits for the next [signal updated] to make sure it's not
|
||||
## switching all over the place in one tick.
|
||||
func change_state_node(node: State, force := false) -> State:
|
||||
await updated
|
||||
if (
|
||||
node == null
|
||||
or node.disabled
|
||||
or (node.status != Status.INACTIVE and not force)
|
||||
or node.get_parent() != self
|
||||
):
|
||||
return node
|
||||
|
||||
var old := _active_substate
|
||||
_active_substate = node
|
||||
if old != null:
|
||||
old.exit()
|
||||
_active_substate.enter(target, animation_player, debug_mode)
|
||||
|
||||
if debug_mode:
|
||||
print(
|
||||
("FORCE " if force else "") +
|
||||
"STATE: " +
|
||||
str(get_root().get_parent().get_path_to(_active_substate))
|
||||
)
|
||||
return _active_substate
|
||||
|
||||
|
||||
## Return the currently active substate, if any.
|
||||
func get_active_substate() -> State:
|
||||
return _active_substate
|
||||
|
||||
|
||||
## Public [method _choose_substate].
|
||||
func choose_substate() -> State:
|
||||
return _choose_substate()
|
||||
|
||||
|
||||
## Shortcut for `change_state_node(choose_substate())`.
|
||||
func change_to_next_substate(force := false) -> void:
|
||||
await change_state_node(choose_substate(), force)
|
||||
|
||||
|
||||
## Whether this state is the root of the state tree,
|
||||
## ie. it is the common ancestor of all the others.
|
||||
func is_root() -> bool:
|
||||
# If your parent is not a state, then you are the root.
|
||||
return not get_parent() is State
|
||||
|
||||
|
||||
## Get the root state.
|
||||
func get_root() -> State:
|
||||
var node: State = self
|
||||
while not node.is_root():
|
||||
node = node.get_parent() as State
|
||||
return node
|
||||
|
||||
|
||||
## Runs [method _enter] and [method _after_enter],
|
||||
## not a good idea to call it yourself unless you really know what you're doing.
|
||||
func enter(set_target: Node, set_animation_player: AnimationPlayer, set_debug_mode: bool) -> void:
|
||||
for child in get_children():
|
||||
assert(child is State, "A State should not have any children that are not other States.")
|
||||
|
||||
_enter()
|
||||
entered.emit()
|
||||
status = Status.ACTIVE
|
||||
if timer != 0:
|
||||
_timer_object = get_tree().create_timer(timer)
|
||||
_timer_object.timeout.connect(_on_timer_timeout)
|
||||
set_physics_process(is_root())
|
||||
|
||||
# Only set them if they're not being overridden
|
||||
if target == null:
|
||||
target = set_target
|
||||
if animation_player == null:
|
||||
animation_player = set_animation_player
|
||||
if debug_mode == false:
|
||||
debug_mode = set_debug_mode
|
||||
|
||||
change_to_next_substate()
|
||||
_after_enter()
|
||||
|
||||
|
||||
## Runs [method _update] and [method _after_update],
|
||||
## not a good idea to call it yourself unless you really know what you're doing.
|
||||
func update(delta: float) -> void:
|
||||
_update(delta)
|
||||
updated.emit()
|
||||
if _active_substate != null:
|
||||
_active_substate.update(delta)
|
||||
_after_update(delta)
|
||||
|
||||
|
||||
## Runs [method _exit] and [method _before_exit],
|
||||
## not a good idea to call it yourself unless you really know what you're doing.
|
||||
func exit() -> void:
|
||||
_before_exit()
|
||||
status = Status.INACTIVE
|
||||
if _active_substate != null:
|
||||
_active_substate.exit()
|
||||
_active_substate = null
|
||||
|
||||
if is_instance_valid(_timer_object):
|
||||
_timer_object.timeout.disconnect(_on_timer_timeout)
|
||||
_timer_object = null
|
||||
|
||||
_exit()
|
||||
exited.emit()
|
||||
set_physics_process(false)
|
||||
|
||||
|
||||
#########################
|
||||
### PRIVATE METHODS ###
|
||||
#########################
|
||||
|
||||
|
||||
#################
|
||||
### CALLBACKS ###
|
||||
#################
|
||||
|
||||
func _on_choose_new_substate_requested() -> void:
|
||||
change_to_next_substate(force)
|
||||
|
||||
|
||||
func _on_timer_timeout() -> void:
|
||||
choose_new_substate_requested.emit()
|
|
@ -1,14 +0,0 @@
|
|||
extends State
|
||||
|
||||
|
||||
const NEXT_STATE_ACTION = "demo_next_state"
|
||||
|
||||
|
||||
func _enter() -> void:
|
||||
if InputMap.has_action(NEXT_STATE_ACTION):
|
||||
return
|
||||
var input_event := InputEventKey.new()
|
||||
input_event.keycode = KEY_TAB
|
||||
|
||||
InputMap.add_action(NEXT_STATE_ACTION)
|
||||
InputMap.action_add_event(NEXT_STATE_ACTION, input_event)
|
|
@ -1,218 +0,0 @@
|
|||
[gd_scene load_steps=17 format=3 uid="uid://clnliyc6fmqy6"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/simple-state/classes/debugger.gd" id="1_rqf1w"]
|
||||
[ext_resource type="Script" path="res://addons/simple-state/demo/description_box.gd" id="2_gktik"]
|
||||
[ext_resource type="Script" path="res://addons/simple-state/classes/sequence_state.gd" id="3_4afa7"]
|
||||
[ext_resource type="Script" path="res://addons/simple-state/demo/demo.gd" id="3_x0hcs"]
|
||||
[ext_resource type="Script" path="res://addons/simple-state/classes/random_state.gd" id="4_wxjoe"]
|
||||
[ext_resource type="Script" path="res://addons/simple-state/demo/emit_next.gd" id="6_kxcgl"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ysqm7"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_wxupu"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_7gdgn"]
|
||||
draw_center = false
|
||||
border_width_left = 1
|
||||
border_width_top = 1
|
||||
border_width_right = 1
|
||||
border_width_bottom = 1
|
||||
|
||||
[sub_resource type="Animation" id="Animation_5pgem"]
|
||||
resource_name = "RESET"
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("ColorRect:color")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 0,
|
||||
"values": [Color(1, 1, 1, 1)]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_mwhj1"]
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("ColorRect:color")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 0,
|
||||
"values": [Color(0, 0, 0, 1)]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_yyph0"]
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("ColorRect:color")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 0,
|
||||
"values": [Color(0, 0, 1, 1)]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_xmkhy"]
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("ColorRect:color")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 0,
|
||||
"values": [Color(0, 1, 0, 1)]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_4pwkk"]
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("ColorRect:color")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 0,
|
||||
"values": [Color(1, 0, 0, 1)]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_gt7hj"]
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("ColorRect:color")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 0,
|
||||
"values": [Color(1, 1, 0, 1)]
|
||||
}
|
||||
|
||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_01hf1"]
|
||||
_data = {
|
||||
"RESET": SubResource("Animation_5pgem"),
|
||||
"black": SubResource("Animation_mwhj1"),
|
||||
"blue": SubResource("Animation_yyph0"),
|
||||
"green": SubResource("Animation_xmkhy"),
|
||||
"red": SubResource("Animation_4pwkk"),
|
||||
"yellow": SubResource("Animation_gt7hj")
|
||||
}
|
||||
|
||||
[node name="SimpleStateDemo" type="Panel"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/margin_left = 10
|
||||
theme_override_constants/margin_top = 10
|
||||
theme_override_constants/margin_right = 10
|
||||
theme_override_constants/margin_bottom = 10
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 10
|
||||
|
||||
[node name="StateMachineDebugger" type="Tree" parent="MarginContainer/HBoxContainer" node_paths=PackedStringArray("state_machine_root")]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_constants/relationship_line_width = 2
|
||||
theme_override_constants/draw_guides = 0
|
||||
theme_override_styles/panel = SubResource("StyleBoxEmpty_ysqm7")
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_wxupu")
|
||||
theme_override_styles/selected = SubResource("StyleBoxFlat_7gdgn")
|
||||
theme_override_styles/selected_focus = SubResource("StyleBoxFlat_7gdgn")
|
||||
select_mode = 1
|
||||
script = ExtResource("1_rqf1w")
|
||||
state_machine_root = NodePath("../../Root")
|
||||
allow_state_switching = true
|
||||
signal_show = true
|
||||
|
||||
[node name="DescriptionBox" type="Label" parent="MarginContainer/HBoxContainer" node_paths=PackedStringArray("tree")]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 1
|
||||
autowrap_mode = 3
|
||||
script = ExtResource("2_gktik")
|
||||
tree = NodePath("../StateMachineDebugger")
|
||||
show_descriptions = 2
|
||||
|
||||
[node name="InputInfo" type="Label" parent="MarginContainer/HBoxContainer/DescriptionBox"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 3
|
||||
anchor_left = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -349.0
|
||||
offset_top = -78.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 0
|
||||
text = "MOUSE CLICK on state: select
|
||||
DOUBLE MOUSE CLICK on state: start
|
||||
TAB: next substate (only has effect on leaves)"
|
||||
horizontal_alignment = 2
|
||||
vertical_alignment = 2
|
||||
|
||||
[node name="ColorRect" type="ColorRect" parent="MarginContainer"]
|
||||
custom_minimum_size = Vector2(50, 50)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 0
|
||||
size_flags_vertical = 8
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="MarginContainer"]
|
||||
libraries = {
|
||||
"": SubResource("AnimationLibrary_01hf1")
|
||||
}
|
||||
|
||||
[node name="Root" type="Node" parent="MarginContainer" node_paths=PackedStringArray("target", "animation_player")]
|
||||
script = ExtResource("3_x0hcs")
|
||||
target = NodePath("")
|
||||
animation_player = NodePath("../AnimationPlayer")
|
||||
|
||||
[node name="SequenceState" type="Node" parent="MarginContainer/Root"]
|
||||
script = ExtResource("3_4afa7")
|
||||
|
||||
[node name="RandomState" type="Node" parent="MarginContainer/Root/SequenceState"]
|
||||
script = ExtResource("4_wxjoe")
|
||||
defer_choice = true
|
||||
|
||||
[node name="red" type="Node" parent="MarginContainer/Root/SequenceState/RandomState"]
|
||||
script = ExtResource("6_kxcgl")
|
||||
|
||||
[node name="yellow" type="Node" parent="MarginContainer/Root/SequenceState/RandomState"]
|
||||
script = ExtResource("6_kxcgl")
|
||||
|
||||
[node name="green" type="Node" parent="MarginContainer/Root/SequenceState"]
|
||||
script = ExtResource("6_kxcgl")
|
||||
|
||||
[node name="blue" type="Node" parent="MarginContainer/Root/SequenceState"]
|
||||
script = ExtResource("6_kxcgl")
|
||||
|
||||
[node name="black" type="Node" parent="MarginContainer/Root"]
|
||||
script = ExtResource("6_kxcgl")
|
||||
timer = 1.0
|
||||
metadata/description = "Will never start automatically, due to its parent being only a normal state."
|
|
@ -1,98 +0,0 @@
|
|||
extends Label
|
||||
|
||||
|
||||
## Mode of description box rendering.
|
||||
enum DisplayModes {
|
||||
NONE, ## Description box completely hidden.
|
||||
ACTIVE, ## Show descriptions of all active states.
|
||||
SELECTION, ## Show description of last selected state (also includes manual switches).
|
||||
}
|
||||
|
||||
|
||||
@export
|
||||
## [StateMachineDebugger] to reference.
|
||||
var tree : StateMachineDebugger:
|
||||
set(value):
|
||||
tree = value
|
||||
if show_descriptions == DisplayModes.SELECTION and \
|
||||
not tree.item_selected.is_connected(_on_tree_item_selected):
|
||||
tree.item_selected.connect(_on_tree_item_selected)
|
||||
|
||||
|
||||
@export
|
||||
## Show a description of a state.
|
||||
## Looks for a string metadata value by the name of [code]description[/code] on each state.
|
||||
var show_descriptions := DisplayModes.NONE:
|
||||
set(value):
|
||||
show_descriptions = value
|
||||
|
||||
match show_descriptions:
|
||||
DisplayModes.NONE:
|
||||
visible = false
|
||||
DisplayModes.ACTIVE:
|
||||
visible = true
|
||||
if not is_instance_valid(tree):
|
||||
return
|
||||
if tree.item_selected.is_connected(_on_tree_item_selected):
|
||||
tree.item_selected.disconnect(_on_tree_item_selected)
|
||||
DisplayModes.SELECTION:
|
||||
visible = true
|
||||
if not is_instance_valid(tree):
|
||||
return
|
||||
if not tree.item_selected.is_connected(_on_tree_item_selected):
|
||||
tree.item_selected.connect(_on_tree_item_selected)
|
||||
|
||||
|
||||
var _active_states : Array[State] = []
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
visible = show_descriptions != DisplayModes.NONE
|
||||
connect_signals()
|
||||
|
||||
|
||||
func connect_signals(state := tree.state_machine_root) -> void:
|
||||
if not state.has_meta(&"tree_item"):
|
||||
return
|
||||
for signal_name in tree.signal_connections:
|
||||
if state.has_signal(signal_name) and not \
|
||||
state.is_connected(signal_name, _on_state_signal):
|
||||
state.connect(signal_name, _on_state_signal.bind(signal_name, state))
|
||||
for child in(state.get_children() as Array[State]):
|
||||
connect_signals(child)
|
||||
|
||||
|
||||
func disconnect_signals(state := tree.state_machine_root) -> void:
|
||||
for signal_name in tree.signal_connections:
|
||||
if state.has_signal(signal_name) and \
|
||||
state.is_connected(signal_name, _on_state_signal):
|
||||
state.disconnect(signal_name, _on_state_signal)
|
||||
for child in (state.get_children() as Array[State]):
|
||||
disconnect_signals(child)
|
||||
|
||||
|
||||
func _set_description_from_active_states() -> void:
|
||||
text = ""
|
||||
for state in _active_states:
|
||||
text += ("" if state.is_root() else "\n\n") + \
|
||||
state.name as String + \
|
||||
": " + \
|
||||
state.get_meta(&"description", "") as String
|
||||
|
||||
|
||||
func _on_tree_item_selected() -> void:
|
||||
text = tree.get_selected() \
|
||||
.get_metadata(0).get_meta(&"description", "")
|
||||
|
||||
|
||||
func _on_state_signal(signal_name: StringName, state: State) -> void:
|
||||
match signal_name:
|
||||
&"entered":
|
||||
if show_descriptions == DisplayModes.ACTIVE:
|
||||
_active_states.push_back(state)
|
||||
_set_description_from_active_states()
|
||||
&"exited":
|
||||
if show_descriptions == DisplayModes.ACTIVE:
|
||||
_active_states.pop_back()
|
||||
_set_description_from_active_states()
|
|
@ -1,6 +0,0 @@
|
|||
extends AnimationState
|
||||
|
||||
|
||||
func _update(_delta: float) -> void:
|
||||
if Input.is_action_just_pressed(get_root().NEXT_STATE_ACTION):
|
||||
choose_new_substate_requested.emit()
|
Before Width: | Height: | Size: 2.8 KiB |
|
@ -1,2 +0,0 @@
|
|||
[InternetShortcut]
|
||||
URL=http://www.kenney.nl/
|
|
@ -1,2 +0,0 @@
|
|||
[InternetShortcut]
|
||||
URL=https://www.patreon.com/kenney/
|
|
@ -1,22 +0,0 @@
|
|||
|
||||
|
||||
Board Game Icons (1.0)
|
||||
|
||||
Created/distributed by Kenney (www.kenney.nl)
|
||||
Creation date: 10-01-2022
|
||||
|
||||
------------------------------
|
||||
|
||||
License: (Creative Commons Zero, CC0)
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
This content is free to use in personal, educational and commercial projects.
|
||||
Support us by crediting Kenney or www.kenney.nl (this is not mandatory)
|
||||
|
||||
------------------------------
|
||||
|
||||
Donate: http://support.kenney.nl
|
||||
Patreon: http://patreon.com/kenney/
|
||||
|
||||
Follow on Twitter for updates:
|
||||
http://twitter.com/KenneyNL
|
|
@ -1,14 +0,0 @@
|
|||
|
||||
###############################################################################
|
||||
|
||||
Game icon pack by Kenney Vleugels (www.kenney.nl)
|
||||
|
||||
------------------------------
|
||||
|
||||
License (CC0)
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
You may use these graphics in personal and commercial projects.
|
||||
Credit (Kenney or www.kenney.nl) would be nice but is not mandatory.
|
||||
|
||||
###############################################################################
|
|
@ -1,20 +0,0 @@
|
|||
Pictogrammers Free License
|
||||
--------------------------
|
||||
|
||||
This icon collection is released as free, open source, and GPL friendly by
|
||||
the [Pictogrammers](http://pictogrammers.com/). You may use it
|
||||
for commercial projects, open source projects, or anything really.
|
||||
|
||||
# Icons: Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0)
|
||||
Some of the icons are redistributed under the Apache 2.0 license. All other
|
||||
icons are either redistributed under their respective licenses or are
|
||||
distributed under the Apache 2.0 license.
|
||||
|
||||
# Fonts: Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0)
|
||||
All web and desktop fonts are distributed under the Apache 2.0 license. Web
|
||||
and desktop fonts contain some icons that are redistributed under the Apache
|
||||
2.0 license. All other icons are either redistributed under their respective
|
||||
licenses or are distributed under the Apache 2.0 license.
|
||||
|
||||
# Code: MIT (https://opensource.org/licenses/MIT)
|
||||
The MIT license applies to all non-font and non-icon files.
|
Before Width: | Height: | Size: 551 B |
Before Width: | Height: | Size: 424 B |
|
@ -1,12 +0,0 @@
|
|||
Icon Sources
|
||||
-----------
|
||||
[0] Board Game Icons: https://kenney.nl/assets/board-game-icons
|
||||
- state.png
|
||||
- random_state.png
|
||||
- sequence_state.png
|
||||
|
||||
[1] Game Icons: https://kenney.nl/assets/game-icons
|
||||
- animation_state.png
|
||||
|
||||
[2] Pictogrammers: <https://pictogrammers.com/library/mdi/>
|
||||
- state_machine_debugger.png (tinted)
|
Before Width: | Height: | Size: 572 B |
Before Width: | Height: | Size: 767 B |
Before Width: | Height: | Size: 1.1 KiB |
|
@ -1,34 +0,0 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dsglk01amsawf"
|
||||
path="res://.godot/imported/state_machine_debugger.png-4af22f2c577f0756aa0b1d50ce679700.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/simple-state/icons/state_machine_debugger.png"
|
||||
dest_files=["res://.godot/imported/state_machine_debugger.png-4af22f2c577f0756aa0b1d50ce679700.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
|
|
@ -1,7 +0,0 @@
|
|||
[plugin]
|
||||
|
||||
name="SimpleState"
|
||||
description="A super-simple state machine. Lightweight and (hopefully) reliable."
|
||||
author="AuraTheEnby"
|
||||
version="1.3.2"
|
||||
script="plugin.gd"
|
|
@ -1,25 +0,0 @@
|
|||
@tool
|
||||
extends EditorPlugin
|
||||
|
||||
|
||||
## It uses the icons provided by the scripts anyway, so
|
||||
## we don't really need to specify the real ones here.
|
||||
## Plus, it might help with enabling it before the project
|
||||
## has been reloaded for the first time.
|
||||
var placeholder_texture := PlaceholderTexture2D.new()
|
||||
|
||||
|
||||
func _enter_tree() -> void:
|
||||
add_custom_type("State", "Node", State, placeholder_texture)
|
||||
add_custom_type("RandomState", "Node", RandomState, placeholder_texture)
|
||||
add_custom_type("AnimationState", "Node", AnimationState, placeholder_texture)
|
||||
add_custom_type("SequenceState", "Node", SequenceState, placeholder_texture)
|
||||
add_custom_type("StateMachineDebugger", "Tree", StateMachineDebugger, placeholder_texture)
|
||||
|
||||
|
||||
func _exit_tree() -> void:
|
||||
remove_custom_type("State")
|
||||
remove_custom_type("RandomState")
|
||||
remove_custom_type("AnimationState")
|
||||
remove_custom_type("SequenceState")
|
||||
remove_custom_type("StateMachineDebugger")
|
|
@ -1,33 +0,0 @@
|
|||
# meta-default: true
|
||||
extends _BASE_
|
||||
|
||||
|
||||
# Called when the state is activated. (parents, then children)
|
||||
func _enter() -> void:
|
||||
pass
|
||||
|
||||
|
||||
# Called after the state is activated. (children, then parents)
|
||||
func _after_enter() -> void:
|
||||
pass
|
||||
|
||||
|
||||
# Called every physics frame (only when the state is active, of course). (parents, then children)
|
||||
func _update(delta: float) -> void:
|
||||
pass
|
||||
|
||||
|
||||
# Called at the end of every physics frame. (children, then parents)
|
||||
func _after_update(delta: float) -> void:
|
||||
pass
|
||||
|
||||
|
||||
# Called before the state is deactivated. (parents, then children)
|
||||
func _before_exit() -> void:
|
||||
pass
|
||||
|
||||
|
||||
# Called when the state is deactivated. (children, then parents)
|
||||
func _exit() -> void:
|
||||
pass
|
||||
|
201
addons/yet_another_behavior_tree/LICENSE.md
Normal file
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
7
addons/yet_another_behavior_tree/plugin.cfg
Normal file
|
@ -0,0 +1,7 @@
|
|||
[plugin]
|
||||
|
||||
name="Yet Another Behavior Tree"
|
||||
description="A Behavior Tree implementation for Godot Engine"
|
||||
author="Adrien Quillet"
|
||||
version="3.0.0"
|
||||
script="yet_another_behavior_tree.gd"
|
BIN
addons/yet_another_behavior_tree/src/Assets/Icons/Icons.pdn
Normal file
BIN
addons/yet_another_behavior_tree/src/Assets/Icons/btaction.png
Normal file
After Width: | Height: | Size: 286 B |
|
@ -2,16 +2,16 @@
|
|||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cna1s8hi8xc58"
|
||||
path="res://.godot/imported/animation_state.png-5f10255295e45d80e555d2885de83e22.ctex"
|
||||
uid="uid://b48sosvxi4n24"
|
||||
path="res://.godot/imported/btaction.png-18977c497a76704723d083978b2ea595.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/simple-state/icons/animation_state.png"
|
||||
dest_files=["res://.godot/imported/animation_state.png-5f10255295e45d80e555d2885de83e22.ctex"]
|
||||
source_file="res://addons/yet_another_behavior_tree/src/Assets/Icons/btaction.png"
|
||||
dest_files=["res://.godot/imported/btaction.png-18977c497a76704723d083978b2ea595.ctex"]
|
||||
|
||||
[params]
|
||||
|
After Width: | Height: | Size: 271 B |
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cbnehk2kgxha0"
|
||||
path="res://.godot/imported/btactionblackboarddelete.png-e03a9a160a95593083f9e35e81bdc103.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/yet_another_behavior_tree/src/Assets/Icons/btactionblackboarddelete.png"
|
||||
dest_files=["res://.godot/imported/btactionblackboarddelete.png-e03a9a160a95593083f9e35e81bdc103.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
|
After Width: | Height: | Size: 299 B |
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://boyttypw3logy"
|
||||
path="res://.godot/imported/btactionblackboardset.png-1278deabaaedde513ea46a9a4bb621bb.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/yet_another_behavior_tree/src/Assets/Icons/btactionblackboardset.png"
|
||||
dest_files=["res://.godot/imported/btactionblackboardset.png-1278deabaaedde513ea46a9a4bb621bb.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
|
After Width: | Height: | Size: 317 B |
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://2oj3rjstv2l6"
|
||||
path="res://.godot/imported/btactioncallable.png-8ff3e8c57248454d9afe7b8c14b8034f.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/yet_another_behavior_tree/src/Assets/Icons/btactioncallable.png"
|
||||
dest_files=["res://.godot/imported/btactioncallable.png-8ff3e8c57248454d9afe7b8c14b8034f.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
|
After Width: | Height: | Size: 358 B |
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://ct3k7bwcr4n23"
|
||||
path="res://.godot/imported/btactionwait.png-35eefe67990a95ed2449e53d56e2cf8f.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/yet_another_behavior_tree/src/Assets/Icons/btactionwait.png"
|
||||
dest_files=["res://.godot/imported/btactionwait.png-35eefe67990a95ed2449e53d56e2cf8f.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
|
After Width: | Height: | Size: 197 B |
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bc3t7dlq5ojd7"
|
||||
path="res://.godot/imported/btblackboard.png-7f733cee4dbff616004368a725149731.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/yet_another_behavior_tree/src/Assets/Icons/btblackboard.png"
|
||||
dest_files=["res://.godot/imported/btblackboard.png-7f733cee4dbff616004368a725149731.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
|
After Width: | Height: | Size: 145 B |
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://61mky8di67wd"
|
||||
path="res://.godot/imported/btcomposite.png-e026d4d004e93322dbcd1e6f926f41a2.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/yet_another_behavior_tree/src/Assets/Icons/btcomposite.png"
|
||||
dest_files=["res://.godot/imported/btcomposite.png-e026d4d004e93322dbcd1e6f926f41a2.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
|
After Width: | Height: | Size: 258 B |
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://d30ihyblas1o0"
|
||||
path="res://.godot/imported/btcondition.png-afc407604bdfe2e82f2cbf0d2c34ed27.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/yet_another_behavior_tree/src/Assets/Icons/btcondition.png"
|
||||
dest_files=["res://.godot/imported/btcondition.png-afc407604bdfe2e82f2cbf0d2c34ed27.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
|
After Width: | Height: | Size: 299 B |
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://b4q7fnl5uons7"
|
||||
path="res://.godot/imported/btconditionblackboardkeyexists.png-6b1c537ccdd672a561e7966389cda13e.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/yet_another_behavior_tree/src/Assets/Icons/btconditionblackboardkeyexists.png"
|
||||
dest_files=["res://.godot/imported/btconditionblackboardkeyexists.png-6b1c537ccdd672a561e7966389cda13e.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
|
After Width: | Height: | Size: 317 B |
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://fcjo6te2i4fh"
|
||||
path="res://.godot/imported/btconditionblackboardvaluescomparison.png-eecd4feaf86eb841c950cbbeb86bd20e.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/yet_another_behavior_tree/src/Assets/Icons/btconditionblackboardvaluescomparison.png"
|
||||
dest_files=["res://.godot/imported/btconditionblackboardvaluescomparison.png-eecd4feaf86eb841c950cbbeb86bd20e.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
|
After Width: | Height: | Size: 317 B |
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://y6usgtpm8654"
|
||||
path="res://.godot/imported/btconditioncallable.png-536cf1db6a6b7ab4d372e700c9ec5b2a.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/yet_another_behavior_tree/src/Assets/Icons/btconditioncallable.png"
|
||||
dest_files=["res://.godot/imported/btconditioncallable.png-536cf1db6a6b7ab4d372e700c9ec5b2a.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
|
After Width: | Height: | Size: 145 B |
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cmwqhdcyhptro"
|
||||
path="res://.godot/imported/btdecorator.png-8fdc93bf956127379273d9a2949c9c1c.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/yet_another_behavior_tree/src/Assets/Icons/btdecorator.png"
|
||||
dest_files=["res://.godot/imported/btdecorator.png-8fdc93bf956127379273d9a2949c9c1c.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
addons/yet_another_behavior_tree/src/Assets/Icons/btfailure.png
Normal file
After Width: | Height: | Size: 246 B |
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://c73l5rvxyrnda"
|
||||
path="res://.godot/imported/btfailure.png-43c62fa29ae4a153c528e033a8bbecc9.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/yet_another_behavior_tree/src/Assets/Icons/btfailure.png"
|
||||
dest_files=["res://.godot/imported/btfailure.png-43c62fa29ae4a153c528e033a8bbecc9.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
addons/yet_another_behavior_tree/src/Assets/Icons/btinverter.png
Normal file
After Width: | Height: | Size: 501 B |
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://gutmaw46jlyh"
|
||||
path="res://.godot/imported/btinverter.png-2f7d6a7358d40fcfcaf67b8a6acea047.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/yet_another_behavior_tree/src/Assets/Icons/btinverter.png"
|
||||
dest_files=["res://.godot/imported/btinverter.png-2f7d6a7358d40fcfcaf67b8a6acea047.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
addons/yet_another_behavior_tree/src/Assets/Icons/btleaf.png
Normal file
After Width: | Height: | Size: 235 B |
|
@ -2,16 +2,16 @@
|
|||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cgoc214akn2d6"
|
||||
path="res://.godot/imported/random_state.png-0878745fbdc123f3f0d51012c73a7024.ctex"
|
||||
uid="uid://gxdluh7wjomk"
|
||||
path="res://.godot/imported/btleaf.png-c2431b3a96122c6dc535e0b78c164efc.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/simple-state/icons/random_state.png"
|
||||
dest_files=["res://.godot/imported/random_state.png-0878745fbdc123f3f0d51012c73a7024.ctex"]
|
||||
source_file="res://addons/yet_another_behavior_tree/src/Assets/Icons/btleaf.png"
|
||||
dest_files=["res://.godot/imported/btleaf.png-c2431b3a96122c6dc535e0b78c164efc.ctex"]
|
||||
|
||||
[params]
|
||||
|
BIN
addons/yet_another_behavior_tree/src/Assets/Icons/btlimiter.png
Normal file
After Width: | Height: | Size: 159 B |
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://byk2pkxf1m2xm"
|
||||
path="res://.godot/imported/btlimiter.png-4154342ba1ecd7c753485e0c1895d99d.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/yet_another_behavior_tree/src/Assets/Icons/btlimiter.png"
|
||||
dest_files=["res://.godot/imported/btlimiter.png-4154342ba1ecd7c753485e0c1895d99d.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
addons/yet_another_behavior_tree/src/Assets/Icons/btnode.png
Normal file
After Width: | Height: | Size: 145 B |
|
@ -2,16 +2,16 @@
|
|||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bcviu3dccvvm2"
|
||||
path="res://.godot/imported/sequence_state.png-4718f2c926301319d99a0ccd15ff62fb.ctex"
|
||||
uid="uid://sccepp5a5goa"
|
||||
path="res://.godot/imported/btnode.png-3ebad094cfaf4e989cef065b27b78174.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/simple-state/icons/sequence_state.png"
|
||||
dest_files=["res://.godot/imported/sequence_state.png-4718f2c926301319d99a0ccd15ff62fb.ctex"]
|
||||
source_file="res://addons/yet_another_behavior_tree/src/Assets/Icons/btnode.png"
|
||||
dest_files=["res://.godot/imported/btnode.png-3ebad094cfaf4e989cef065b27b78174.ctex"]
|
||||
|
||||
[params]
|
||||
|
BIN
addons/yet_another_behavior_tree/src/Assets/Icons/btparallel.png
Normal file
After Width: | Height: | Size: 205 B |
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://i8yclvjdd2po"
|
||||
path="res://.godot/imported/btparallel.png-72c2892f41b80e22bfa4396abf59a1a3.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/yet_another_behavior_tree/src/Assets/Icons/btparallel.png"
|
||||
dest_files=["res://.godot/imported/btparallel.png-72c2892f41b80e22bfa4396abf59a1a3.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
addons/yet_another_behavior_tree/src/Assets/Icons/btrandom.png
Normal file
After Width: | Height: | Size: 218 B |
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cj1bxkdykjv23"
|
||||
path="res://.godot/imported/btrandom.png-0f3e4c1202cc1fd7fd32f36ce482ef97.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/yet_another_behavior_tree/src/Assets/Icons/btrandom.png"
|
||||
dest_files=["res://.godot/imported/btrandom.png-0f3e4c1202cc1fd7fd32f36ce482ef97.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
|
After Width: | Height: | Size: 190 B |
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://b3s6eyhvmsmca"
|
||||
path="res://.godot/imported/btrandomselector.png-5bbaa6b1d149c5357046de0f8d6b7707.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/yet_another_behavior_tree/src/Assets/Icons/btrandomselector.png"
|
||||
dest_files=["res://.godot/imported/btrandomselector.png-5bbaa6b1d149c5357046de0f8d6b7707.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
|
After Width: | Height: | Size: 367 B |
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dtc18hhykvswh"
|
||||
path="res://.godot/imported/btrepeatuntil.png-b92f22528a4b73d0ca2d27142e092367.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/yet_another_behavior_tree/src/Assets/Icons/btrepeatuntil.png"
|
||||
dest_files=["res://.godot/imported/btrepeatuntil.png-b92f22528a4b73d0ca2d27142e092367.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
addons/yet_another_behavior_tree/src/Assets/Icons/btroot.png
Normal file
After Width: | Height: | Size: 213 B |
|
@ -2,16 +2,16 @@
|
|||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://b32u1sa3robj0"
|
||||
path="res://.godot/imported/state_fullsize.png-41a4827bc36d7745ba55c17c0bc213e9.ctex"
|
||||
uid="uid://bs628dnvnsxwl"
|
||||
path="res://.godot/imported/btroot.png-5ce207fd487015fa6d9a79efff94f0e4.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/simple-state/icons/state_fullsize.png"
|
||||
dest_files=["res://.godot/imported/state_fullsize.png-41a4827bc36d7745ba55c17c0bc213e9.ctex"]
|
||||
source_file="res://addons/yet_another_behavior_tree/src/Assets/Icons/btroot.png"
|
||||
dest_files=["res://.godot/imported/btroot.png-5ce207fd487015fa6d9a79efff94f0e4.ctex"]
|
||||
|
||||
[params]
|
||||
|
BIN
addons/yet_another_behavior_tree/src/Assets/Icons/btselector.png
Normal file
After Width: | Height: | Size: 181 B |
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://ctyhhfi6jks5a"
|
||||
path="res://.godot/imported/btselector.png-68934baa4bd97bc50fd24775d28386ac.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/yet_another_behavior_tree/src/Assets/Icons/btselector.png"
|
||||
dest_files=["res://.godot/imported/btselector.png-68934baa4bd97bc50fd24775d28386ac.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
addons/yet_another_behavior_tree/src/Assets/Icons/btsequence.png
Normal file
After Width: | Height: | Size: 248 B |
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://chnob03fb7a5"
|
||||
path="res://.godot/imported/btsequence.png-c2e63f47520b7d091ffbf0c6bc2a76a0.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/yet_another_behavior_tree/src/Assets/Icons/btsequence.png"
|
||||
dest_files=["res://.godot/imported/btsequence.png-c2e63f47520b7d091ffbf0c6bc2a76a0.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
addons/yet_another_behavior_tree/src/Assets/Icons/btsuccess.png
Normal file
After Width: | Height: | Size: 314 B |
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://v47uxlomir5w"
|
||||
path="res://.godot/imported/btsuccess.png-7ab9f0bea97f3881521c44275dcb2c13.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/yet_another_behavior_tree/src/Assets/Icons/btsuccess.png"
|
||||
dest_files=["res://.godot/imported/btsuccess.png-7ab9f0bea97f3881521c44275dcb2c13.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
|
|
@ -0,0 +1,89 @@
|
|||
@icon("res://addons/yet_another_behavior_tree/src/Assets/Icons/btblackboard.png")
|
||||
class_name BTBlackboard
|
||||
extends Node
|
||||
|
||||
|
||||
## Blackboard allows to share data across nodes and behavior trees. You can create/retrieve/erase
|
||||
## pairs of key-value. Keys and values are variants and can be anything.
|
||||
## [br][br]
|
||||
## Data in blackboard can be isolated in so-called [i]namespaces[/i]. A data key can exists only once in
|
||||
## a namespace, but can exists multiple times across namespaces, allowing the user to isolate data when,
|
||||
## for example, a blackboard is shared between multiple behavior trees. By default, if no namespace is
|
||||
## specified when inserting a data into a blackboard, the [i]default namespace[/i] is used.
|
||||
|
||||
|
||||
const DEFAULT_NAMESPACE:String = "_default_namespace"
|
||||
|
||||
#------------------------------------------
|
||||
# Signaux
|
||||
#------------------------------------------
|
||||
|
||||
#------------------------------------------
|
||||
# Exports
|
||||
#------------------------------------------
|
||||
|
||||
#------------------------------------------
|
||||
# Variables publiques
|
||||
#------------------------------------------
|
||||
|
||||
## A dictionnary allowing to specifies default entries before tree first execution.
|
||||
## [br][br]
|
||||
## Those entries are added in the default namespace of the blackboard. If you want to add default entries
|
||||
## in another namespace, you must do it in a script.
|
||||
@export var data:Dictionary = {}
|
||||
|
||||
#------------------------------------------
|
||||
# Variables privées
|
||||
#------------------------------------------
|
||||
|
||||
# {
|
||||
# "namespace" : {
|
||||
# DATAS
|
||||
# }
|
||||
# }
|
||||
var _execution_data:Dictionary = {}
|
||||
|
||||
#------------------------------------------
|
||||
# Fonctions Godot redéfinies
|
||||
#------------------------------------------
|
||||
|
||||
func _ready() -> void:
|
||||
# On copie le dico défini par l'utilisateur dans le dico privé
|
||||
_get_namespace_board(DEFAULT_NAMESPACE).merge(data)
|
||||
|
||||
#------------------------------------------
|
||||
# Fonctions publiques
|
||||
#------------------------------------------
|
||||
|
||||
func get_delta() -> float:
|
||||
# Delta is not in any namespace, since its a volatile data, that is valid just inside one tree tick
|
||||
return get_data("delta")
|
||||
|
||||
func has_data(key:Variant, board_namespace:String = DEFAULT_NAMESPACE) -> bool:
|
||||
var namespace_dico:Dictionary = _get_namespace_board(board_namespace)
|
||||
return namespace_dico.has(key)
|
||||
|
||||
func get_data(key:Variant, default_value:Variant = null, board_namespace:String = DEFAULT_NAMESPACE) -> Variant:
|
||||
var result:Variant = _get_namespace_board(board_namespace).get(key, default_value)
|
||||
return result.get_ref() if result is WeakRef else result
|
||||
|
||||
func set_data(key:Variant, value:Variant, board_namespace:String = DEFAULT_NAMESPACE) -> Variant:
|
||||
var namespace_dico:Dictionary = _get_namespace_board(board_namespace)
|
||||
var old_value:Variant = namespace_dico[key] if namespace_dico.has(key) else null
|
||||
namespace_dico[key] = weakref(value) if value is Node else value
|
||||
return old_value.get_ref() if old_value is WeakRef else old_value
|
||||
|
||||
func delete_data(key:Variant, board_namespace:String = DEFAULT_NAMESPACE) -> Variant:
|
||||
var namespace_dico:Dictionary = _get_namespace_board(board_namespace)
|
||||
var old_value = namespace_dico[key] if namespace_dico.has(key) else null
|
||||
namespace_dico.erase(key)
|
||||
return old_value.get_ref() if old_value is WeakRef else old_value
|
||||
|
||||
#------------------------------------------
|
||||
# Fonctions privées
|
||||
#------------------------------------------
|
||||
|
||||
func _get_namespace_board(board_namespace:String) -> Dictionary:
|
||||
if not _execution_data.has(board_namespace):
|
||||
_execution_data[board_namespace] = {}
|
||||
return _execution_data[board_namespace]
|