diff --git a/behaviours/illuminable/boolean_illuminable.gd b/behaviours/illuminable/boolean_illuminable.gd
new file mode 100644
index 0000000..2969483
--- /dev/null
+++ b/behaviours/illuminable/boolean_illuminable.gd
@@ -0,0 +1,14 @@
+extends Illuminable
+class_name BooleanIlluminable
+
+
+## Whether the parent object has been hit by an [Illuminator].
+var is_lit := false
+
+
+func light(illuminator: Illuminator) -> void:
+ if not is_lit:
+ is_lit = true
+ super.light(illuminator)
+ else:
+ Log.trace(self, "Refusing to light up, already lit")
diff --git a/behaviours/illuminable/boolean_illuminable.tscn b/behaviours/illuminable/boolean_illuminable.tscn
new file mode 100644
index 0000000..9e9af27
--- /dev/null
+++ b/behaviours/illuminable/boolean_illuminable.tscn
@@ -0,0 +1,6 @@
+[gd_scene load_steps=2 format=3 uid="uid://w26hyy8v5u3i"]
+
+[ext_resource type="Script" path="res://behaviours/illuminable/boolean_illuminable.gd" id="1_tow2r"]
+
+[node name="BooleanIlluminable" type="Node"]
+script = ExtResource("1_tow2r")
diff --git a/behaviours/illuminable/illuminable.gd b/behaviours/illuminable/illuminable.gd
new file mode 100644
index 0000000..4b53008
--- /dev/null
+++ b/behaviours/illuminable/illuminable.gd
@@ -0,0 +1,12 @@
+@icon("./illuminable.svg")
+extends Node
+class_name Illuminable
+
+
+## Emitted when the illuminable gets lit.
+signal lit
+
+
+func light(illuminator: Illuminator) -> void:
+ Log.trace(self, "Lit up by: %s" % illuminator)
+ lit.emit()
diff --git a/behaviours/illuminable/illuminable.svg b/behaviours/illuminable/illuminable.svg
new file mode 100644
index 0000000..3d12ce9
--- /dev/null
+++ b/behaviours/illuminable/illuminable.svg
@@ -0,0 +1,39 @@
+
+
diff --git a/behaviours/illuminable/illuminable.svg.import b/behaviours/illuminable/illuminable.svg.import
new file mode 100644
index 0000000..656a601
--- /dev/null
+++ b/behaviours/illuminable/illuminable.svg.import
@@ -0,0 +1,37 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dvkvtq0u3c2mt"
+path="res://.godot/imported/illuminable.svg-cf5c5af44471ca08e093ec52ae78a1d1.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://behaviours/illuminable/illuminable.svg"
+dest_files=["res://.godot/imported/illuminable.svg-cf5c5af44471ca08e093ec52ae78a1d1.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
diff --git a/behaviours/illuminator/illuminator.gd b/behaviours/illuminator/illuminator.gd
new file mode 100644
index 0000000..0fe4457
--- /dev/null
+++ b/behaviours/illuminator/illuminator.gd
@@ -0,0 +1,25 @@
+@icon("./illuminator.svg")
+extends Node
+class_name Illuminator
+
+
+## Tags an object as able to trigger [Illuminable] entities.
+
+func _ready() -> void:
+ var parent: Node = get_parent()
+ if not parent is RigidBody2D:
+ Log.warning(self, "Not a parent of a RigidBody2D, can't connect.")
+ return
+
+ var rigidbody: RigidBody2D = parent
+ rigidbody.body_entered.connect(_parent_body_entered)
+ Log.trace(self, "Connected _parent_body_entered to: %s" % parent)
+
+func _parent_body_entered(body: Node) -> void:
+ if body:
+ var illuminables: Array[Node] = body.find_children("*", "Illuminable")
+ if len(illuminables) == 0:
+ Log.trace(self, "No illuminables found on: %s" % body)
+ for illuminable in illuminables:
+ assert(illuminable is Illuminable, "Illuminable is not an illuminable.")
+ illuminable.light(self)
diff --git a/behaviours/illuminator/illuminator.svg b/behaviours/illuminator/illuminator.svg
new file mode 100644
index 0000000..79c77cc
--- /dev/null
+++ b/behaviours/illuminator/illuminator.svg
@@ -0,0 +1,39 @@
+
+
diff --git a/behaviours/illuminator/illuminator.svg.import b/behaviours/illuminator/illuminator.svg.import
new file mode 100644
index 0000000..c6d69f1
--- /dev/null
+++ b/behaviours/illuminator/illuminator.svg.import
@@ -0,0 +1,37 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cq815vk3hba0t"
+path="res://.godot/imported/illuminator.svg-bf1c9f706bf7f8e28cfbc53ed5bdba6c.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://behaviours/illuminator/illuminator.svg"
+dest_files=["res://.godot/imported/illuminator.svg-bf1c9f706bf7f8e28cfbc53ed5bdba6c.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
diff --git a/behaviours/illuminator/illuminator.tscn b/behaviours/illuminator/illuminator.tscn
new file mode 100644
index 0000000..d30a918
--- /dev/null
+++ b/behaviours/illuminator/illuminator.tscn
@@ -0,0 +1,6 @@
+[gd_scene load_steps=2 format=3 uid="uid://dsdi475dymkh7"]
+
+[ext_resource type="Script" path="res://behaviours/illuminator/illuminator.gd" id="1_inei7"]
+
+[node name="Illuminator" type="Node"]
+script = ExtResource("1_inei7")
diff --git a/prefabs/ball.tscn b/prefabs/ball.tscn
index e2f48d8..ec9ab02 100644
--- a/prefabs/ball.tscn
+++ b/prefabs/ball.tscn
@@ -1,4 +1,6 @@
-[gd_scene load_steps=3 format=3 uid="uid://ylvptuj0xnm8"]
+[gd_scene load_steps=4 format=3 uid="uid://ylvptuj0xnm8"]
+
+[ext_resource type="PackedScene" uid="uid://dsdi475dymkh7" path="res://behaviours/illuminator/illuminator.tscn" id="1_c8jcw"]
[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_1mhds"]
bounce = 0.92
@@ -8,7 +10,12 @@ radius = 24.0
[node name="Ball" type="RigidBody2D"]
physics_material_override = SubResource("PhysicsMaterial_1mhds")
+continuous_cd = 2
+contact_monitor = true
+max_contacts_reported = 4
[node name="Shape" type="CollisionShape2D" parent="."]
shape = SubResource("CircleShape2D_xd6lq")
debug_color = Color(0.7, 0, 0, 0.419608)
+
+[node name="Illuminator" parent="." instance=ExtResource("1_c8jcw")]
diff --git a/prefabs/peg.gd b/prefabs/peg.gd
new file mode 100644
index 0000000..8c6c8d8
--- /dev/null
+++ b/prefabs/peg.gd
@@ -0,0 +1,6 @@
+extends StaticBody2D
+class_name Peg
+
+
+func _on_lit() -> void:
+ $"Shape".debug_color = Color(0, 0.69, 0, 0.41)
diff --git a/prefabs/peg.tscn b/prefabs/peg.tscn
index eff5d27..43243e1 100644
--- a/prefabs/peg.tscn
+++ b/prefabs/peg.tscn
@@ -1,10 +1,18 @@
-[gd_scene load_steps=2 format=3 uid="uid://bbtm3534mdeat"]
+[gd_scene load_steps=4 format=3 uid="uid://bbtm3534mdeat"]
+
+[ext_resource type="PackedScene" uid="uid://w26hyy8v5u3i" path="res://behaviours/illuminable/boolean_illuminable.tscn" id="1_lpcqw"]
+[ext_resource type="Script" path="res://prefabs/peg.gd" id="1_xl7sk"]
[sub_resource type="CircleShape2D" id="CircleShape2D_cj4kg"]
radius = 24.0
[node name="Peg" type="StaticBody2D"]
+script = ExtResource("1_xl7sk")
-[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+[node name="Shape" type="CollisionShape2D" parent="."]
shape = SubResource("CircleShape2D_cj4kg")
debug_color = Color(0.7, 0.7, 0.7, 0.419608)
+
+[node name="BooleanIlluminable" parent="." instance=ExtResource("1_lpcqw")]
+
+[connection signal="lit" from="BooleanIlluminable" to="." method="_on_lit"]
diff --git a/root.tscn b/root.tscn
index 7d43704..d6e2e60 100644
--- a/root.tscn
+++ b/root.tscn
@@ -6,7 +6,7 @@
[node name="Root" type="Node2D"]
[node name="Ball" parent="." instance=ExtResource("1_d2cjj")]
-position = Vector2(42, -281)
+position = Vector2(-44, -269)
[node name="Peg" parent="." instance=ExtResource("2_i427g")]
position = Vector2(77, -102)
diff --git a/utils/log/log.gd b/utils/log/log.gd
index 9704b13..88631df 100644
--- a/utils/log/log.gd
+++ b/utils/log/log.gd
@@ -33,7 +33,11 @@ func error(obj: Node, message: String) -> void:
func _log(level: int, obj: Node, message: String) -> void:
var color = _get_color(level)
- var max_level = _get_max_level(obj)
+ var max_level = _get_max_level(obj)
+ if level <= 10:
+ push_error("<%s> %s" % [obj, message])
+ elif level <= 20:
+ push_warning("<%s> %s" % [obj, message])
if level <= max_level:
print_rich("[color=%s]<%s> %s[/color]" % [color, obj, message])