Callables and lambdas
Six operations kept in an array as Callables, five lambdas and one method with bind, each one handed to Array.map over the same numbers.
The editor above is running this project. Change a line and it reloads.
Godot classes used
CallableCallable.bindArray.map
The code
scripts/main.gd
extends Node
const SOURCE: Array = [3, 8, 1, 6, 9, 4, 7, 2]
const TICK: float = 0.45
var operations: Array = []
var rows: Array = []
var buttons: Array = []
var status: Label
var elapsed: float = 0.0
var active: int = 0
func _ready() -> void:
operations = [
{name = 'double', fn = func(value: int) -> int: return value * 2},
{name = 'square', fn = func(value: int) -> int: return value * value},
{name = 'halve', fn = func(value: int) -> int: return roundi(value * 0.5)},
{name = 'mirror', fn = func(value: int) -> int: return 10 - value},
{name = 'cap at five', fn = func(value: int) -> int: return mini(value, 5)},
{name = 'add bonus, bound', fn = _add_bonus.bind(12)},
]
var row: HBoxContainer = _root()
_menu(row)
_table(row)
_apply(0)
print('every entry in the list is a Callable, five lambdas and one method with bind')
func _process(delta: float) -> void:
elapsed += delta
if elapsed < TICK:
return
elapsed = 0.0
_apply((active + 1) % operations.size())
func _add_bonus(value: int, bonus: int) -> int:
return value + bonus
func _apply(index: int) -> void:
active = index
var operation: Dictionary = operations[index]
var result: Array = SOURCE.map(operation.fn)
var ceiling: int = maxi(int(result.max()), 1)
for i in SOURCE.size():
var line: Dictionary = rows[i]
line.result.text = str(result[i])
line.bar.max_value = ceiling
line.bar.value = result[i]
for i in buttons.size():
buttons[i].add_theme_color_override('font_color', Color('#8eef97') if i == index else Color('#8a90a0'))
status.text = 'SOURCE.map(operations[%d].fn) gave %s' % [index, str(result)]
func _menu(row: HBoxContainer) -> void:
var column: VBoxContainer = VBoxContainer.new()
column.custom_minimum_size = Vector2(300, 0)
column.add_theme_constant_override('separation', 8)
row.add_child(column)
var title: Label = Label.new()
title.text = 'the list of Callables'
title.add_theme_font_size_override('font_size', 22)
title.add_theme_color_override('font_color', Color('#8da5f3'))
column.add_child(title)
for i in operations.size():
var button: Button = Button.new()
button.text = operations[i].name
button.pressed.connect(_apply.bind(i))
column.add_child(button)
buttons.append(button)
func _table(row: HBoxContainer) -> void:
var column: VBoxContainer = VBoxContainer.new()
column.custom_minimum_size = Vector2(660, 0)
column.add_theme_constant_override('separation', 8)
row.add_child(column)
var title: Label = Label.new()
title.text = 'the same eight numbers, mapped'
title.add_theme_font_size_override('font_size', 22)
title.add_theme_color_override('font_color', Color('#8eef97'))
column.add_child(title)
for value in SOURCE:
var line: HBoxContainer = HBoxContainer.new()
line.add_theme_constant_override('separation', 14)
column.add_child(line)
var source: Label = Label.new()
source.text = str(value)
source.custom_minimum_size = Vector2(34, 0)
source.add_theme_color_override('font_color', Color('#8a90a0'))
line.add_child(source)
var arrow: Label = Label.new()
arrow.text = '->'
arrow.add_theme_color_override('font_color', Color('#8a90a0'))
line.add_child(arrow)
var result: Label = Label.new()
result.custom_minimum_size = Vector2(48, 0)
result.add_theme_font_size_override('font_size', 20)
line.add_child(result)
var bar: ProgressBar = ProgressBar.new()
bar.show_percentage = false
bar.custom_minimum_size = Vector2(440, 18)
bar.add_theme_stylebox_override('background', _bar_style(Color('#2a2f3d')))
bar.add_theme_stylebox_override('fill', _bar_style(Color('#8da5f3')))
line.add_child(bar)
rows.append({result = result, bar = bar})
func _bar_style(color: Color) -> StyleBoxFlat:
var style: StyleBoxFlat = StyleBoxFlat.new()
style.bg_color = color
style.set_corner_radius_all(5)
return style
func _root() -> HBoxContainer:
var background: ColorRect = ColorRect.new()
background.color = Color('#12141a')
add_child(background)
background.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
var margin: MarginContainer = MarginContainer.new()
for side in ['margin_left', 'margin_right', 'margin_top', 'margin_bottom']:
margin.add_theme_constant_override(side, 48)
add_child(margin)
margin.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
var column: VBoxContainer = VBoxContainer.new()
column.add_theme_constant_override('separation', 16)
margin.add_child(column)
var title: Label = Label.new()
title.text = 'A function kept in a variable'
title.add_theme_font_size_override('font_size', 28)
column.add_child(title)
var hint: Label = Label.new()
hint.text = 'Nothing below knows what the operation is. It receives a Callable and hands it to Array.map.'
hint.add_theme_color_override('font_color', Color('#8a90a0'))
column.add_child(hint)
var row: HBoxContainer = HBoxContainer.new()
row.add_theme_constant_override('separation', 36)
column.add_child(row)
status = Label.new()
status.add_theme_font_size_override('font_size', 18)
status.add_theme_color_override('font_color', Color('#8eef97'))
column.add_child(status)
return row