Skip to content

Commit e2e3a57

Browse files
committed
Merge branch 'main' of github.com:db0/godot-card-game-framework into main
2 parents f714d84 + d38b7fb commit e2e3a57

19 files changed

+292
-151
lines changed

CHANGELOG.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
# Changelog
22

3-
## 1.15 (Ongoing)
3+
## 1.15
4+
5+
### Important for Upgrades
6+
7+
* New property `CFConst.FONT_SIZE_CACHE` has to exist. Best practice is to set it to "user://CGFFontCache.json"
48

59
### New Features
610

11+
* Now each card type has exported variables for the canonical card size as well as the various scaling. **This finally allows the game to utilize different card sizes at the same time**. CardContainers and BoardGrid for different card sizes now also need to have a defined card_size of the card they're going to host.
712
* Added exported vars for controlling card tween duration (@stevosaurus)
813
* Mouse will not teleport to a card's top-right when dragging starts. (@stevosaurus)
14+
* Adjustments to prevent Rich Text Labels from sizing at 4 font size
15+
* Recursive rescaling will also now take into account MarginContainer margins
16+
* Added font_size_caching which should now reduce time lost while calculating font sizes.
917

1018
#### ScriptingEngine
1119

src/core/BoardPlacementGrid.gd

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#
77
# Adjust its highlight colour and the amount of columns it should have as well
88
#
9-
# The BoardPlacementSlots will adjust to CFConst.CARD_SIZE on runtime, but
9+
# The BoardPlacementSlots will adjust to card_size on runtime, but
1010
# If you want to visually see on the editor your result
1111
class_name BoardPlacementGrid
1212
extends Control
@@ -22,11 +22,16 @@ export(Color) var highlight = CFConst.TARGET_HOVER_COLOUR
2222
# when find_available_slot() is used and there's no more available slots
2323
# (only useful when using the ScriptingEngine)
2424
export var auto_extend := false
25+
# Used to adjust the grid according to the card size that will be put into it.
26+
# This size should match the
27+
export var card_size := CFConst.CARD_SIZE
28+
export var card_play_scale := CFConst.PLAY_AREA_SCALE
2529

2630
# Sets a custom label for this grid
2731
onready var name_label = $Control/Label
2832

2933
func _ready() -> void:
34+
rect_size = (card_size * card_play_scale) + Vector2(4,4)
3035
# We ensure the separation of the grid slots is always 1 pixel larger
3136
# Than the radius of the mouse pointer collision area.
3237
# This ensures that we don't highlight 2 slots at the same time.

src/core/BoardPlacementSlot.gd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ onready var owner_grid = get_parent().get_parent()
1414
func _ready() -> void:
1515
# We set the initial size of our highlight and area, to
1616
# fit the size of the cards on the board.
17-
rect_min_size = CFConst.CARD_SIZE * CFConst.PLAY_AREA_SCALE
17+
rect_min_size = owner_grid.card_size * owner_grid.card_play_scale
1818
$Highlight.rect_min_size = rect_min_size
1919
$Area2D/CollisionShape2D.shape.extents = rect_min_size / 2
2020
$Area2D/CollisionShape2D.position = rect_min_size / 2

src/core/CFControl.gd

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ var _ut_show_token_buttons := CFConst.SHOW_TOKEN_BUTTONS
2424
# It is initiated by looking for [CFConst#SETTINGS_FILENAME], but if it
2525
# doesn't exist, defaults to the values specified in CFConst, if applicable.
2626
var game_settings := {}
27+
# This variable stores the font and icon size for each string of text.
28+
# based on the current card size. This allows us to avoid calculating fonts
29+
# on the fly all the time and adding delay to card instancing.
30+
var font_size_cache := {}
31+
var cache_commit_timer: SceneTreeTimer
2732
# If set to true, the player will be prevented from interacting with the game
2833
var game_paused := false setget set_game_paused
2934
# If this is false, all CardContainers will pause in their ready() scene
@@ -85,6 +90,7 @@ var ov_utils = load(CFConst.PATH_OVERRIDABLE_UTILS).new()
8590

8691
func _ready() -> void:
8792
init_settings_from_file()
93+
init_font_cache()
8894
if not game_settings.has('fancy_movement'):
8995
game_settings['fancy_movement'] = CFConst.FANCY_MOVEMENT
9096
if not game_settings.has('focus_style'):
@@ -108,7 +114,6 @@ func _ready() -> void:
108114
set_seed(game_rng_seed)
109115
card_definitions = load_card_definitions()
110116

111-
112117
# Run when all necessary nodes (Board, CardContainers etc) for the game
113118
# have been initialized. Allows them to proceed with their ready() functions.
114119
func _on_all_nodes_mapped() -> void:
@@ -239,6 +244,38 @@ func init_settings_from_file() -> void:
239244
game_settings = data.duplicate()
240245

241246

247+
func set_font_cache() -> void:
248+
# var timer = Timer.new()
249+
# timer.connect("timeout", self, "_commit_font_cache", [timer])
250+
# timer.wait_time = 1
251+
# timer.start()
252+
if not cache_commit_timer:
253+
cache_commit_timer = get_tree().create_timer(1.0)
254+
cache_commit_timer.connect("timeout", self, "_commit_font_cache")
255+
256+
257+
# Whenever a setting is changed via this function, it also stores it
258+
# permanently on-disk.
259+
func _commit_font_cache() -> void:
260+
# timer.disconnect("timeout", self, "_commit_font_cache")
261+
# timer.queue_free()
262+
var file = File.new()
263+
file.open(CFConst.FONT_SIZE_CACHE, File.WRITE)
264+
file.store_string(JSON.print(font_size_cache, '\t'))
265+
file.close()
266+
cache_commit_timer = null
267+
268+
269+
# Initiates game_settings from the contents of CFConst.SETTINGS_FILENAME
270+
func init_font_cache() -> void:
271+
var file = File.new()
272+
if file.file_exists(CFConst.FONT_SIZE_CACHE):
273+
file.open(CFConst.FONT_SIZE_CACHE, File.READ)
274+
var data = parse_json(file.get_as_text())
275+
file.close()
276+
if typeof(data) == TYPE_DICTIONARY:
277+
font_size_cache = data.duplicate()
278+
242279
# This function resets the game to the same state as when
243280
# the board loads for the first time. Only works when you're running
244281
# off of the Main scene.

src/core/Card/CardFront.gd

Lines changed: 122 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ onready var card_owner = get_parent().get_parent().get_parent()
4747

4848
# Set a label node's text.
4949
# As the string becomes longer, the font size becomes smaller
50-
func set_label_text(node: Label, value):
50+
func set_label_text(node: Label, value, scale: float = 1):
5151
# while font_thread and font_thread.is_active():
5252
# yield(get_tree(), "idle_frame")
5353
# font_thread = Thread.new()
@@ -57,29 +57,36 @@ func set_label_text(node: Label, value):
5757
return
5858
resizing_labels.append(node)
5959
value = _check_for_replacements(node, value)
60-
# We add a yield here to allow the calling function to continue
61-
# and thus avoid the game waiting for the label to resize
62-
yield(get_tree(), "idle_frame")
63-
var working_value: String
64-
# If the label node has been set to uppercase the text
65-
# Then we need to work off-of uppercased text value
66-
# otherwise our calculation will be off and we'll
67-
# end up extending the rect_size.y anyway
68-
if node.uppercase:
69-
working_value = value.to_upper()
70-
else:
71-
working_value = value
72-
_capture_original_font_size(node)
73-
var line_spacing = node.get("custom_constants/line_spacing")
74-
if not line_spacing:
75-
line_spacing = 3
76-
var starting_font_size: int = font_sizes[node.name]
7760
var label_font :Font = get_card_label_font(node)
78-
label_font.size = starting_font_size
79-
var font_adjustment := _adjust_font_size(label_font, working_value, node.rect_min_size, line_spacing)
80-
# if node.name == "Abilities": font_adjustment = -17
81-
# We always start shrinking the size, starting from the original size.
82-
label_font.size = starting_font_size + font_adjustment
61+
# print_debug(scaled_fonts.get(node.name, 1))
62+
var cached_font_size = get_cached_font_size(node,value,scale)
63+
if cached_font_size:
64+
label_font.size = cached_font_size
65+
else:
66+
# We add a yield here to allow the calling function to continue
67+
# and thus avoid the game waiting for the label to resize
68+
yield(get_tree(), "idle_frame")
69+
var working_value: String
70+
# If the label node has been set to uppercase the text
71+
# Then we need to work off-of uppercased text value
72+
# otherwise our calculation will be off and we'll
73+
# end up extending the rect_size.y anyway
74+
if node.uppercase:
75+
working_value = value.to_upper()
76+
else:
77+
working_value = value
78+
_capture_original_font_size(node)
79+
var line_spacing = node.get("custom_constants/line_spacing")
80+
if not line_spacing:
81+
line_spacing = 3
82+
var starting_font_size: int = font_sizes[node.name]
83+
label_font.size = starting_font_size
84+
var font_adjustment := _adjust_font_size(label_font, working_value, node.rect_min_size, line_spacing)
85+
# if node.name == "Abilities": font_adjustment = -17
86+
# We always start shrinking the size, starting from the original size.
87+
# print_debug(scaled_fonts.get(node.name, 1))
88+
_cache_font_size(node,value,starting_font_size + font_adjustment,scale)
89+
label_font.size = starting_font_size + font_adjustment
8390
set_card_label_font(node, label_font)
8491
node.text = value
8592
resizing_labels.erase(node)
@@ -127,16 +134,16 @@ func scale_to(scale_multiplier: float) -> void:
127134
yield(get_tree(), "idle_frame")
128135
if card_labels[l] as RichTextLabel:
129136
var label : RichTextLabel = card_labels[l]
130-
call_deferred("set_rich_label_text",label, label.bbcode_text, true)
137+
call_deferred("set_rich_label_text",label, label.bbcode_text, true, scale_multiplier)
131138
else:
132139
var label : Label = card_labels[l]
133-
call_deferred("set_label_text",label, label.text)
140+
call_deferred("set_label_text",label, label.text, scale_multiplier)
134141

135142

136143

137144
# Set a label node's bbcode text.
138145
# As the string becomes longer, the font size becomes smaller
139-
func set_rich_label_text(node: RichTextLabel, value: String, is_resize := false):
146+
func set_rich_label_text(node: RichTextLabel, value: String, is_resize := false, scale : float = 1):
140147
# We need to avoid other functions to trying to resize this label
141148
# while it's already resizing, as due to all the yields
142149
# it causes a mess
@@ -163,59 +170,102 @@ func set_rich_label_text(node: RichTextLabel, value: String, is_resize := false)
163170
# We always start shrinking the size, starting from the original size.
164171
_capture_original_font_size(node)
165172
_capture_rt_font_size_variations(node)
166-
var starting_font_size: int = font_sizes[node.name]
167-
var font_adjustment:= 0
168-
# label_font.size = font_sizes[node.name]
169-
var label_size = node.rect_min_size
170-
_set_card_rtl_fonts(node, label_fonts, starting_font_size + font_adjustment)
171-
_assign_bbcode_text(node, value, starting_font_size + font_adjustment)
172-
# Rich Text has no way to grab its total size without setting the bbcode first
173-
# After we set the bbcode, we need to wait for the next frame for the label to adjust
174-
# and then we can grab its height
175-
yield(get_tree(), "idle_frame")
176-
var bbcode_height = node.get_content_height()
177-
# To save some time, we use the same trick we do in normal labels
178-
# where we reduce the font size to fits its rect
179-
# However unlike normal labels, we might have icons and different font sizes
180-
# which will not be taken into account.
181-
# Therefore this gives us the starting point, but further reduction might be
182-
# needed.
183-
if bbcode_height > label_size.y:
184-
font_adjustment = _adjust_font_size(label_fonts["normal_font"], node.text, label_size)
185-
_set_card_rtl_fonts(node, label_fonts, starting_font_size + font_adjustment)
186-
yield(get_tree(), "idle_frame")
187-
bbcode_height = node.get_content_height()
188-
# print_debug(bbcode_height, ':', font_adjustment, ':', label_size.y)
189-
# If the reduction of font sizes when checking against the normal font
190-
# was not enough to bring the total rich label height into the rect.y we want
191-
# we use a while loop where we do the following in order
192-
# * reduce all rich-text font sizes by 1
193-
# * reset the bbcode text
194-
# * Wait for the next frame
195-
# * grab the new rich text height
196-
# Unitl the rich text height is smaller than the labels' rect size.
197-
while bbcode_height > label_size.y:
198-
font_adjustment -= 1
173+
var cached_font_size = get_cached_font_size(node,value,scale)
174+
if cached_font_size:
175+
_set_card_rtl_fonts(node, label_fonts, cached_font_size)
176+
_assign_bbcode_text(node, value, cached_font_size)
177+
else:
178+
var starting_font_size: int = font_sizes[node.name]
179+
var font_adjustment:= 0
180+
# label_font.size = font_sizes[node.name]
181+
var label_size = node.rect_min_size
199182
_set_card_rtl_fonts(node, label_fonts, starting_font_size + font_adjustment)
200183
_assign_bbcode_text(node, value, starting_font_size + font_adjustment)
184+
# Rich Text has no way to grab its total size without setting the bbcode first
185+
# After we set the bbcode, we need to wait for the next frame for the label to adjust
186+
# and then we can grab its height
201187
yield(get_tree(), "idle_frame")
202-
bbcode_height = node.get_content_height()
203-
# If we don't keep the card front face-up while setting the RTL,
204-
# The bbcode_height will be returned as either 0 or 1000 after setting the
205-
# bbcode_text. Regardless of how long we wait.
206-
# The below snipper was debugging code to keep the code waiting to resize
207-
# until the card was turned face-up
208-
# while bbcode_height == 0 or bbcode_height > 1000:
209-
# _set_card_rtl_fonts(node, label_fonts, starting_font_size + font_adjustment)
210-
# _assign_bbcode_text(node, value, starting_font_size + font_adjustment)
211-
# yield(get_tree(), "idle_frame")
212-
# bbcode_height = node.get_content_height()
213-
if starting_font_size + font_adjustment == 4:
214-
break
188+
var _retries := 0
189+
var bbcode_height = node.get_content_height()
190+
while bbcode_height == 0 or bbcode_height > 1000:
191+
_retries += 1
192+
print_debug("BBcode height:" + bbcode_height + " retrying: " + _retries)
193+
yield(get_tree(), "idle_frame")
194+
bbcode_height = node.get_content_height()
195+
if _retries >= 10:
196+
break
197+
# To save some time, we use the same trick we do in normal labels
198+
# where we reduce the font size to fits its rect
199+
# However unlike normal labels, we might have icons and different font sizes
200+
# which will not be taken into account.
201+
# Therefore this gives us the starting point, but further reduction might be
202+
# needed.
203+
if bbcode_height > label_size.y:
204+
font_adjustment = _adjust_font_size(label_fonts["normal_font"], node.text, label_size)
205+
_set_card_rtl_fonts(node, label_fonts, starting_font_size + font_adjustment)
206+
yield(get_tree(), "idle_frame")
207+
bbcode_height = node.get_content_height()
208+
# print_debug(bbcode_height, ':', font_adjustment, ':', label_size.y)
209+
# If the reduction of font sizes when checking against the normal font
210+
# was not enough to bring the total rich label height into the rect.y we want
211+
# we use a while loop where we do the following in order
212+
# * reduce all rich-text font sizes by 1
213+
# * reset the bbcode text
214+
# * Wait for the next frame
215+
# * grab the new rich text height
216+
# Unitl the rich text height is smaller than the labels' rect size.
217+
while bbcode_height > label_size.y:
218+
font_adjustment -= 1
219+
_set_card_rtl_fonts(node, label_fonts, starting_font_size + font_adjustment)
220+
_assign_bbcode_text(node, value, starting_font_size + font_adjustment)
221+
yield(get_tree(), "idle_frame")
222+
bbcode_height = node.get_content_height()
223+
_retries = 0
224+
while bbcode_height == 0 or bbcode_height > 1000:
225+
_retries += 1
226+
print_debug("BBcode height:" + bbcode_height + " retrying: " + _retries)
227+
yield(get_tree(), "idle_frame")
228+
bbcode_height = node.get_content_height()
229+
if _retries >= 10:
230+
break
231+
# If we don't keep the card front face-up while setting the RTL,
232+
# The bbcode_height will be returned as either 0 or 1000 after setting the
233+
# bbcode_text. Regardless of how long we wait.
234+
# The below snipper was debugging code to keep the code waiting to resize
235+
# until the card was turned face-up
236+
# while bbcode_height == 0 or bbcode_height > 1000:
237+
# _set_card_rtl_fonts(node, label_fonts, starting_font_size + font_adjustment)
238+
# _assign_bbcode_text(node, value, starting_font_size + font_adjustment)
239+
# yield(get_tree(), "idle_frame")
240+
# bbcode_height = node.get_content_height()
241+
if starting_font_size + font_adjustment == 4:
242+
break
243+
_cache_font_size(node,value,starting_font_size + font_adjustment, scale)
215244
modulate.a = 1
216245
resizing_labels.erase(node)
217246

218247

248+
func _cache_font_size(label: Control, text: String, font_size: int, scale : float) -> void:
249+
var text_md5 = text.md5_text()
250+
# We will store each label's font size in a key based on the card scale
251+
# The default scale being 1
252+
# It has to be a string because the Godot Json print converts ints to
253+
# Strings when saving to file
254+
var card_size = str(scale)
255+
if not cfc.font_size_cache.has(card_size):
256+
cfc.font_size_cache[card_size] = {}
257+
if not cfc.font_size_cache[card_size].has(label.name):
258+
cfc.font_size_cache[card_size][label.name] = {}
259+
cfc.font_size_cache[card_size][label.name][text_md5] = font_size
260+
cfc.set_font_cache()
261+
262+
263+
func get_cached_font_size(label: Control, text: String, scale : float):
264+
var text_md5 = text.md5_text()
265+
var card_size = str(scale)
266+
var cached_font_size = cfc.font_size_cache.get(card_size, {}).get(label.name, {}).get(text_md5)
267+
return(cached_font_size)
268+
219269
# Stores the original font size this label had.
220270
# We use this to start shrinking the label from this size, which allows us to
221271
# also increase it's size when its text changes to be smaller.

src/core/CardContainer.gd

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export(CFInt.OverlapShiftDirection) var overlap_shift_direction
3535
# In case of multiple CardContainers using the same anchor placement
3636
# specifies which container should be displaced more.
3737
export(CFInt.IndexShiftPriority) var index_shift_priority
38+
export var card_size := CFConst.CARD_SIZE
3839

3940
# Used for debugging
4041
var _debugger_hook := false
@@ -301,12 +302,12 @@ func re_place():
301302
# Right position always start from the right-side of the viewport
302303
# minus the width of the container
303304
Anchors.TOP_RIGHT, Anchors.RIGHT_MIDDLE, Anchors.BOTTOM_RIGHT:
304-
place.x = get_viewport().size.x - (CFConst.CARD_SIZE.x * scale.x)
305+
place.x = get_viewport().size.x - (card_size.x * scale.x)
305306
add_to_group("right")
306307
# Middle placement is the middle of the viewport width,
307308
# minues half the height of the container
308309
Anchors.TOP_MIDDLE, Anchors.BOTTOM_MIDDLE:
309-
place.x = get_viewport().size.x / 2 - (CFConst.CARD_SIZE.x / 2 * scale.x)
310+
place.x = get_viewport().size.x / 2 - (card_size.x / 2 * scale.x)
310311
# Now we adjust the y position. Same logic for
311312
match placement:
312313
# Top position always start from y == 0,
@@ -317,12 +318,12 @@ func re_place():
317318
# Bottom position always start from the bottom of the viewport
318319
# minus the height of the container
319320
Anchors.BOTTOM_LEFT, Anchors.BOTTOM_MIDDLE, Anchors.BOTTOM_RIGHT:
320-
place.y = get_viewport().size.y - (CFConst.CARD_SIZE.y * scale.y)
321+
place.y = get_viewport().size.y - (card_size.y * scale.y)
321322
add_to_group("bottom")
322323
# Middle placement is the middle of the viewport height
323324
# minus half the height of the container
324325
Anchors.RIGHT_MIDDLE, Anchors.LEFT_MIDDLE:
325-
place.y = get_viewport().size.y / 2 - (CFConst.CARD_SIZE.y / 2 * scale.y)
326+
place.y = get_viewport().size.y / 2 - (card_size.y / 2 * scale.y)
326327
# Now we try to discover if more than one CardContainer share
327328
# the same anchor and the figure out which to displace.
328329
var duplicate_anchors := {}

0 commit comments

Comments
 (0)