Skip to content

Commit

Permalink
Add tile properties window, allowing you to change each tile's probab…
Browse files Browse the repository at this point in the history
…ility

More options can be added there in the future. Perhaps we could even add Godot tileset data, once we add Godot tileset exporting.
  • Loading branch information
OverloadedOrama committed Feb 9, 2025
1 parent f2f465a commit 34ef0d4
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 12 deletions.
8 changes: 8 additions & 0 deletions Translations/Translations.pot
Original file line number Diff line number Diff line change
Expand Up @@ -3551,3 +3551,11 @@ msgstr ""
#: src/UI/TilesPanel.tscn
msgid "Show empty tile:"
msgstr ""

#: src/UI/TilesPanel.tscn
msgid "Tile properties"
msgstr ""

#: src/UI/TilesPanel.tscn
msgid "Probability:"
msgstr ""
5 changes: 4 additions & 1 deletion src/Autoload/OpenSave.gd
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,10 @@ func open_pxo_file(path: String, is_backup := false, replace_empty := true) -> v
var image := Image.create_from_data(
tile_size.x, tile_size.y, false, new_project.get_image_format(), image_data
)
tileset.add_tile(image, null, 0)
if j > tileset.tiles.size() - 1:
tileset.add_tile(image, null, 0)
else:
tileset.tiles[j].image = image
for cel in new_project.get_all_pixel_cels():
if cel is CelTileMap:
cel.find_times_used_of_tiles()
Expand Down
48 changes: 45 additions & 3 deletions src/Classes/TileSetCustom.gd
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ class Tile:
var image: Image
## The amount of tiles this tile is being used in tilemaps.
var times_used := 1
## The relative probability of this tile appearing when drawing random tiles.
var probability := 1.0

func _init(_image: Image) -> void:
image = _image
Expand All @@ -38,6 +40,14 @@ class Tile:
func can_be_removed() -> bool:
return times_used <= 0

func serialize() -> Dictionary:
return {"times_used": times_used, "probability": probability}

func deserialize(dict: Dictionary, skip_times_used := false) -> void:
if not skip_times_used:
times_used = dict.get("times_used", times_used)
probability = dict.get("probability", probability)


func _init(_tile_size: Vector2i, _name := "", add_empty_tile := true) -> void:
tile_size = _tile_size
Expand Down Expand Up @@ -150,17 +160,48 @@ func find_using_layers(project: Project) -> Array[LayerTileMap]:
return tilemaps


func pick_random_tile(selected_tile_indices: Array[int]) -> int:
if selected_tile_indices.is_empty():
for i in tiles.size():
selected_tile_indices.append(i)
var sum := 0.0
for i in selected_tile_indices:
sum += tiles[i].probability
var rand := randf_range(0.0, sum)
var current := 0.0
for i in selected_tile_indices:
current += tiles[i].probability
if current >= rand:
return i
return selected_tile_indices[0]


## Serializes the data of this class into the form of a [Dictionary],
## which is used so the data can be stored in pxo files.
func serialize() -> Dictionary:
return {"name": name, "tile_size": tile_size, "tile_amount": tiles.size()}
var dict := {"name": name, "tile_size": tile_size, "tile_amount": tiles.size()}
var tile_data := {}
for i in tiles.size():
tile_data[i] = tiles[i].serialize()
dict["tile_data"] = tile_data
return dict


## Deserializes the data of a given [member dict] [Dictionary] into class data,
## which is used so data can be loaded from pxo files.
func deserialize(dict: Dictionary) -> void:
name = dict.get("name", name)
tile_size = str_to_var("Vector2i" + dict.get("tile_size"))
var tile_data := dict.get("tile_data", {}) as Dictionary
for i_str in tile_data:
var i := int(i_str)
var tile: Tile
if i > tiles.size() - 1:
tile = Tile.new(null)
tiles.append(tile)
else:
tile = tiles[i]
tile.deserialize(tile_data[i_str], true)


## Serializes the data of each tile in [member tiles] into the form of a [Dictionary],
Expand All @@ -169,7 +210,7 @@ func serialize_undo_data() -> Dictionary:
var dict := {}
for tile in tiles:
var image_data := tile.image.get_data()
dict[tile.image] = [image_data.compress(), image_data.size(), tile.times_used]
dict[tile.image] = [image_data.compress(), image_data.size(), tile.serialize()]
return dict


Expand All @@ -180,9 +221,10 @@ func deserialize_undo_data(dict: Dictionary, cel: CelTileMap) -> void:
for image: Image in dict:
var tile_data = dict[image]
var buffer_size := tile_data[1] as int
var tile_dictionary := tile_data[2] as Dictionary
var image_data := (tile_data[0] as PackedByteArray).decompress(buffer_size)
image.set_data(tile_size.x, tile_size.y, false, image.get_format(), image_data)
tiles[i] = Tile.new(image)
tiles[i].times_used = tile_data[2]
tiles[i].deserialize(tile_dictionary)
i += 1
updated.emit(cel, -1)
23 changes: 17 additions & 6 deletions src/UI/TilesPanel.gd
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ static var selected_tile_index := 0:
selected_tiles = [value]
_call_update_brushes()
get:
return selected_tiles.pick_random()
if is_instance_valid(current_tileset):
return current_tileset.pick_random_tile(selected_tiles)
return selected_tiles[0]
static var selected_tiles: Array[int] = [0]
static var is_flipped_h := false:
set(value):
Expand All @@ -38,7 +40,7 @@ static var is_transposed := false:
set(value):
is_transposed = value
_call_update_brushes()
var current_tileset: TileSetCustom
static var current_tileset: TileSetCustom
var button_size := 36:
set(value):
if button_size == value:
Expand All @@ -61,6 +63,8 @@ var tile_index_menu_popped := 0
@onready var options: Popup = $Options
@onready var tile_size_slider: ValueSlider = %TileSizeSlider
@onready var tile_button_popup_menu: PopupMenu = $TileButtonPopupMenu
@onready var tile_properties: AcceptDialog = $TileProperties
@onready var tile_probability_slider: ValueSlider = %TileProbabilitySlider


func _ready() -> void:
Expand Down Expand Up @@ -197,7 +201,7 @@ func _on_tile_button_gui_input(event: InputEvent, index: int) -> void:
tile_button_popup_menu.popup_on_parent(Rect2(get_global_mouse_position(), Vector2.ONE))
tile_index_menu_popped = index
tile_button_popup_menu.set_item_disabled(
0, not current_tileset.tiles[index].can_be_removed()
1, not current_tileset.tiles[index].can_be_removed()
)


Expand Down Expand Up @@ -277,9 +281,12 @@ func _on_show_empty_tile_toggled(toggled_on: bool) -> void:


func _on_tile_button_popup_menu_index_pressed(index: int) -> void:
if tile_index_menu_popped == 0:
return
if index == 0: # Delete
if index == 0: # Properties
tile_probability_slider.value = current_tileset.tiles[tile_index_menu_popped].probability
tile_properties.popup_centered()
elif index == 1: # Delete
if tile_index_menu_popped == 0:
return
if current_tileset.tiles[tile_index_menu_popped].can_be_removed():
var undo_data := current_tileset.serialize_undo_data()
current_tileset.tiles.remove_at(tile_index_menu_popped)
Expand All @@ -295,3 +302,7 @@ func _on_tile_button_popup_menu_index_pressed(index: int) -> void:
project.undo_redo.add_undo_method(Global.undo_or_redo.bind(true))
project.undo_redo.add_do_method(Global.undo_or_redo.bind(false))
project.undo_redo.commit_action()


func _on_tile_probability_slider_value_changed(value: float) -> void:
current_tileset.tiles[tile_index_menu_popped].probability = value
46 changes: 44 additions & 2 deletions src/UI/TilesPanel.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -343,8 +343,49 @@ button_pressed = true
text = "On"

[node name="TileButtonPopupMenu" type="PopupMenu" parent="."]
item_count = 1
item_0/text = "Delete"
item_count = 2
item_0/text = "Properties"
item_1/text = "Delete"
item_1/id = 1

[node name="TileProperties" type="AcceptDialog" parent="."]
title = "Tile properties"
size = Vector2i(300, 200)

[node name="GridContainer" type="GridContainer" parent="TileProperties"]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = 8.0
offset_top = 8.0
offset_right = -8.0
offset_bottom = -49.0
grow_horizontal = 2
grow_vertical = 2
columns = 2

[node name="TileProbabilityLabel" type="Label" parent="TileProperties/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Probability:"

[node name="TileProbabilitySlider" type="TextureProgressBar" parent="TileProperties/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
focus_mode = 2
mouse_default_cursor_shape = 2
theme_type_variation = &"ValueSlider"
max_value = 10.0
step = 0.001
value = 1.0
allow_greater = true
nine_patch_stretch = true
stretch_margin_left = 3
stretch_margin_top = 3
stretch_margin_right = 3
stretch_margin_bottom = 3
script = ExtResource("10_wfr6s")

[connection signal="toggled" from="VBoxContainer/MarginContainer/VBoxContainer/Buttons/PlaceTiles" to="." method="_on_place_tiles_toggled"]
[connection signal="pressed" from="VBoxContainer/MarginContainer/VBoxContainer/Buttons/TransformButtonsContainer/RotateLeftButton" to="." method="_on_rotate_pressed" binds= [false]]
Expand All @@ -358,3 +399,4 @@ item_0/text = "Delete"
[connection signal="value_changed" from="Options/MarginContainer/ScrollContainer/GridContainer/TileSizeSlider" to="." method="_on_tile_size_slider_value_changed"]
[connection signal="toggled" from="Options/MarginContainer/ScrollContainer/GridContainer/ShowEmptyTile" to="." method="_on_show_empty_tile_toggled"]
[connection signal="index_pressed" from="TileButtonPopupMenu" to="." method="_on_tile_button_popup_menu_index_pressed"]
[connection signal="value_changed" from="TileProperties/GridContainer/TileProbabilitySlider" to="." method="_on_tile_probability_slider_value_changed"]

0 comments on commit 34ef0d4

Please sign in to comment.