Replace Color Game with pod number reaction game on the API WebSocket.
Players match a displayed digit to the correct pod via tap, with round timing and adjustable LED brightness. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
4f3435ba37
commit
440b49c889
@ -11,7 +11,7 @@ grow_horizontal = 2
|
|||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
script = ExtResource("1_color")
|
script = ExtResource("1_color")
|
||||||
|
|
||||||
[node name="ColorRect" type="ColorRect" parent="."]
|
[node name="Background" type="ColorRect" parent="."]
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
anchors_preset = 15
|
anchors_preset = 15
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
@ -19,55 +19,108 @@ anchor_bottom = 1.0
|
|||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
mouse_filter = 2
|
mouse_filter = 2
|
||||||
color = Color(0.5, 0.3, 0.7, 1)
|
color = Color(0.08, 0.09, 0.14, 1)
|
||||||
|
|
||||||
[node name="UiLayer" type="CanvasLayer" parent="."]
|
[node name="UiLayer" type="CanvasLayer" parent="."]
|
||||||
|
|
||||||
[node name="BackButton" type="Button" parent="UiLayer"]
|
[node name="TopBar" type="HBoxContainer" parent="UiLayer"]
|
||||||
|
anchors_preset = 10
|
||||||
|
anchor_right = 1.0
|
||||||
offset_left = 16.0
|
offset_left = 16.0
|
||||||
offset_top = 12.0
|
offset_top = 12.0
|
||||||
offset_right = 120.0
|
offset_right = -16.0
|
||||||
offset_bottom = 44.0
|
offset_bottom = 52.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
theme_override_constants/separation = 16
|
||||||
|
|
||||||
|
[node name="BackButton" type="Button" parent="UiLayer/TopBar"]
|
||||||
|
custom_minimum_size = Vector2(100, 0)
|
||||||
|
layout_mode = 2
|
||||||
text = "Menü"
|
text = "Menü"
|
||||||
|
|
||||||
[node name="Title" type="Label" parent="UiLayer"]
|
[node name="Title" type="Label" parent="UiLayer/TopBar"]
|
||||||
anchors_preset = 5
|
layout_mode = 2
|
||||||
anchor_left = 0.5
|
theme_override_colors/font_color = Color(0.9, 0.92, 0.98, 1)
|
||||||
anchor_right = 0.5
|
theme_override_font_sizes/font_size = 22
|
||||||
offset_left = -200.0
|
text = "Zahlen-Spiel"
|
||||||
|
|
||||||
|
[node name="StatusLabel" type="Label" parent="UiLayer/TopBar"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
theme_override_colors/font_color = Color(0.55, 0.6, 0.7, 1)
|
||||||
|
theme_override_font_sizes/font_size = 13
|
||||||
|
horizontal_alignment = 2
|
||||||
|
text = "Verbinde…"
|
||||||
|
|
||||||
|
[node name="SettingsPanel" type="HBoxContainer" parent="UiLayer"]
|
||||||
|
anchors_preset = 1
|
||||||
|
anchor_left = 1.0
|
||||||
|
anchor_right = 1.0
|
||||||
|
offset_left = -320.0
|
||||||
offset_top = 60.0
|
offset_top = 60.0
|
||||||
|
offset_right = -16.0
|
||||||
|
offset_bottom = 96.0
|
||||||
|
grow_horizontal = 0
|
||||||
|
theme_override_constants/separation = 10
|
||||||
|
|
||||||
|
[node name="IntensityCaption" type="Label" parent="UiLayer/SettingsPanel"]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_colors/font_color = Color(0.75, 0.8, 0.9, 1)
|
||||||
|
theme_override_font_sizes/font_size = 13
|
||||||
|
text = "Helligkeit:"
|
||||||
|
|
||||||
|
[node name="IntensitySlider" type="HSlider" parent="UiLayer/SettingsPanel"]
|
||||||
|
custom_minimum_size = Vector2(180, 0)
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
min_value = 0.0
|
||||||
|
max_value = 255.0
|
||||||
|
step = 1.0
|
||||||
|
value = 180.0
|
||||||
|
tick_count = 0
|
||||||
|
|
||||||
|
[node name="IntensityValueLabel" type="Label" parent="UiLayer/SettingsPanel"]
|
||||||
|
custom_minimum_size = Vector2(36, 0)
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_colors/font_color = Color(0.9, 0.92, 0.98, 1)
|
||||||
|
theme_override_font_sizes/font_size = 13
|
||||||
|
horizontal_alignment = 2
|
||||||
|
text = "180"
|
||||||
|
|
||||||
|
[node name="Center" type="VBoxContainer" parent="UiLayer"]
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -200.0
|
||||||
|
offset_top = -160.0
|
||||||
offset_right = 200.0
|
offset_right = 200.0
|
||||||
offset_bottom = 100.0
|
offset_bottom = 120.0
|
||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
grow_vertical = 2
|
||||||
theme_override_font_sizes/font_size = 28
|
theme_override_constants/separation = 16
|
||||||
horizontal_alignment = 1
|
|
||||||
text = "Color Game"
|
|
||||||
|
|
||||||
[node name="TargetRect" type="ColorRect" parent="UiLayer"]
|
[node name="SubtitleLabel" type="Label" parent="UiLayer/Center"]
|
||||||
anchors_preset = 5
|
layout_mode = 2
|
||||||
anchor_left = 0.5
|
theme_override_colors/font_color = Color(0.75, 0.8, 0.9, 1)
|
||||||
anchor_right = 0.5
|
theme_override_font_sizes/font_size = 18
|
||||||
offset_left = -60.0
|
|
||||||
offset_top = 120.0
|
|
||||||
offset_right = 60.0
|
|
||||||
offset_bottom = 240.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
color = Color(0.85, 0.2, 0.3, 1)
|
|
||||||
|
|
||||||
[node name="TargetLabel" type="Label" parent="UiLayer"]
|
|
||||||
anchors_preset = 5
|
|
||||||
anchor_left = 0.5
|
|
||||||
anchor_right = 0.5
|
|
||||||
offset_left = -100.0
|
|
||||||
offset_top = 250.0
|
|
||||||
offset_right = 100.0
|
|
||||||
offset_bottom = 280.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
theme_override_colors/font_color = Color(1, 1, 1, 0.9)
|
|
||||||
theme_override_font_sizes/font_size = 14
|
|
||||||
horizontal_alignment = 1
|
horizontal_alignment = 1
|
||||||
text = "Zielfarbe"
|
text = "Warte auf Pods…"
|
||||||
|
|
||||||
|
[node name="TargetLabel" type="Label" parent="UiLayer/Center"]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_colors/font_color = Color(0.35, 0.92, 1, 1)
|
||||||
|
theme_override_font_sizes/font_size = 140
|
||||||
|
horizontal_alignment = 1
|
||||||
|
text = "—"
|
||||||
|
|
||||||
|
[node name="TimerLabel" type="Label" parent="UiLayer/Center"]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_colors/font_color = Color(1, 0.88, 0.4, 1)
|
||||||
|
theme_override_font_sizes/font_size = 36
|
||||||
|
horizontal_alignment = 1
|
||||||
|
text = ""
|
||||||
|
|
||||||
[node name="HintLabel" type="Label" parent="UiLayer"]
|
[node name="HintLabel" type="Label" parent="UiLayer"]
|
||||||
anchors_preset = 7
|
anchors_preset = 7
|
||||||
@ -75,14 +128,13 @@ anchor_left = 0.5
|
|||||||
anchor_top = 1.0
|
anchor_top = 1.0
|
||||||
anchor_right = 0.5
|
anchor_right = 0.5
|
||||||
anchor_bottom = 1.0
|
anchor_bottom = 1.0
|
||||||
offset_left = -320.0
|
offset_left = -360.0
|
||||||
offset_top = -80.0
|
offset_top = -72.0
|
||||||
offset_right = 320.0
|
offset_right = 360.0
|
||||||
offset_bottom = -40.0
|
offset_bottom = -24.0
|
||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
grow_vertical = 0
|
grow_vertical = 0
|
||||||
theme_override_colors/font_color = Color(1, 1, 1, 0.85)
|
theme_override_colors/font_color = Color(1, 0.55, 0.5, 1)
|
||||||
theme_override_font_sizes/font_size = 14
|
theme_override_font_sizes/font_size = 16
|
||||||
horizontal_alignment = 1
|
horizontal_alignment = 1
|
||||||
autowrap_mode = 3
|
autowrap_mode = 3
|
||||||
text = "Neige das Gerät, um die Farbe anzupassen"
|
|
||||||
|
|||||||
@ -1,66 +1,275 @@
|
|||||||
extends Control
|
extends Control
|
||||||
|
|
||||||
const WS_URL := "ws://localhost:9090/ws"
|
const WS_URL := "ws://localhost:8081/ws"
|
||||||
const MENU_SCENE := "res://scenes/menu.tscn"
|
const MENU_SCENE := "res://scenes/menu.tscn"
|
||||||
|
const STREAM_INTERVAL_MS := 16
|
||||||
|
const NEXT_ROUND_DELAY_SEC := 2.5
|
||||||
|
const DEFAULT_DIGIT_INTENSITY := 180
|
||||||
|
|
||||||
@onready var color_rect: ColorRect = $ColorRect
|
enum Phase { IDLE, WAITING, PLAYING, WON }
|
||||||
@onready var target_rect: ColorRect = $UiLayer/TargetRect
|
|
||||||
|
@onready var status_label: Label = $UiLayer/TopBar/StatusLabel
|
||||||
|
@onready var target_label: Label = $UiLayer/Center/TargetLabel
|
||||||
|
@onready var subtitle_label: Label = $UiLayer/Center/SubtitleLabel
|
||||||
|
@onready var timer_label: Label = $UiLayer/Center/TimerLabel
|
||||||
@onready var hint_label: Label = $UiLayer/HintLabel
|
@onready var hint_label: Label = $UiLayer/HintLabel
|
||||||
@onready var back_button: Button = $UiLayer/BackButton
|
@onready var back_button: Button = $UiLayer/TopBar/BackButton
|
||||||
|
@onready var intensity_slider: HSlider = $UiLayer/SettingsPanel/IntensitySlider
|
||||||
|
@onready var intensity_value_label: Label = $UiLayer/SettingsPanel/IntensityValueLabel
|
||||||
|
|
||||||
var _socket := WebSocketPeer.new()
|
var _socket := WebSocketPeer.new()
|
||||||
var _accel := Vector3i.ZERO
|
var _connected := false
|
||||||
var _target_hue := 0.0
|
var _phase := Phase.IDLE
|
||||||
|
var _pod_ids: PackedInt32Array = PackedInt32Array()
|
||||||
|
var _pod_digits: Dictionary = {}
|
||||||
|
var _target_digit := -1
|
||||||
|
var _target_cid := -1
|
||||||
|
var _round_start_ms := 0
|
||||||
|
var _round_token := 0
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
back_button.pressed.connect(_return_to_menu)
|
back_button.pressed.connect(_return_to_menu)
|
||||||
_new_target_color()
|
intensity_slider.value = DEFAULT_DIGIT_INTENSITY
|
||||||
var err := _socket.connect_to_url(WS_URL)
|
intensity_slider.value_changed.connect(_on_intensity_changed)
|
||||||
if err != OK:
|
_on_intensity_changed(intensity_slider.value)
|
||||||
hint_label.text = "WebSocket connect failed: %s" % error_string(err)
|
_set_phase(Phase.IDLE, "Verbinde…")
|
||||||
else:
|
_connect_ws()
|
||||||
hint_label.text = "Neige das Gerät, um die Farbe anzupassen"
|
|
||||||
|
|
||||||
|
func _exit_tree() -> void:
|
||||||
|
_cleanup_streams()
|
||||||
|
|
||||||
|
|
||||||
func _return_to_menu() -> void:
|
func _return_to_menu() -> void:
|
||||||
|
_cleanup_streams()
|
||||||
get_tree().change_scene_to_file(MENU_SCENE)
|
get_tree().change_scene_to_file(MENU_SCENE)
|
||||||
|
|
||||||
|
|
||||||
func _new_target_color() -> void:
|
func _connect_ws() -> void:
|
||||||
_target_hue = randf()
|
_connected = false
|
||||||
target_rect.color = Color.from_hsv(_target_hue, 0.75, 0.85)
|
var err := _socket.connect_to_url(WS_URL)
|
||||||
|
if err != OK:
|
||||||
|
_set_phase(Phase.IDLE, "Verbindung fehlgeschlagen: %s" % error_string(err))
|
||||||
|
|
||||||
|
|
||||||
|
func _send(payload: Dictionary) -> void:
|
||||||
|
if _socket.get_ready_state() != WebSocketPeer.STATE_OPEN:
|
||||||
|
return
|
||||||
|
_socket.send_text(JSON.stringify(payload))
|
||||||
|
|
||||||
|
|
||||||
|
func _cleanup_streams() -> void:
|
||||||
|
if _socket.get_ready_state() != WebSocketPeer.STATE_OPEN:
|
||||||
|
return
|
||||||
|
_send({"type": "set_tap_stream", "enable": false, "interval_ms": STREAM_INTERVAL_MS})
|
||||||
|
for cid in _pod_ids:
|
||||||
|
_send({
|
||||||
|
"type": "set_tap_notify",
|
||||||
|
"client_id": cid,
|
||||||
|
"single": false,
|
||||||
|
"double_tap": false,
|
||||||
|
"triple": false,
|
||||||
|
})
|
||||||
|
_send_led_clear(cid)
|
||||||
|
|
||||||
|
|
||||||
func _physics_process(_delta: float) -> void:
|
func _physics_process(_delta: float) -> void:
|
||||||
_socket.poll()
|
_socket.poll()
|
||||||
|
var state := _socket.get_ready_state()
|
||||||
|
|
||||||
if _socket.get_ready_state() == WebSocketPeer.STATE_OPEN:
|
if state == WebSocketPeer.STATE_OPEN:
|
||||||
while _socket.get_available_packet_count() > 0:
|
while _socket.get_available_packet_count() > 0:
|
||||||
var packet := _socket.get_packet().get_string_from_utf8()
|
_handle_message(_socket.get_packet().get_string_from_utf8())
|
||||||
_handle_accel_message(packet)
|
if _connected:
|
||||||
elif _socket.get_ready_state() == WebSocketPeer.STATE_CLOSED:
|
status_label.text = "Verbunden · %s" % WS_URL
|
||||||
_socket.connect_to_url(WS_URL)
|
if _phase == Phase.PLAYING:
|
||||||
|
_update_live_timer()
|
||||||
var hue := fmod(float(_accel.x) / 20000.0 + 1.0, 1.0)
|
elif state == WebSocketPeer.STATE_CONNECTING:
|
||||||
color_rect.color = Color.from_hsv(hue, 0.75, 0.85)
|
status_label.text = "Verbinde…"
|
||||||
|
elif state == WebSocketPeer.STATE_CLOSING or state == WebSocketPeer.STATE_CLOSED:
|
||||||
var diff := absf(hue - _target_hue)
|
_connected = false
|
||||||
diff = minf(diff, 1.0 - diff)
|
_pod_ids = PackedInt32Array()
|
||||||
if diff < 0.04:
|
_set_phase(Phase.IDLE, "Getrennt – erneuter Verbindungsversuch…")
|
||||||
hint_label.text = "Treffer! Neues Ziel…"
|
if state == WebSocketPeer.STATE_CLOSED:
|
||||||
_new_target_color()
|
_connect_ws()
|
||||||
else:
|
|
||||||
hint_label.text = "Passe deine Farbe der Zielfarbe an (Neigung steuert den Farbton)"
|
|
||||||
|
|
||||||
|
|
||||||
func _handle_accel_message(text: String) -> void:
|
func _handle_message(text: String) -> void:
|
||||||
var data = JSON.parse_string(text)
|
var data = JSON.parse_string(text)
|
||||||
if typeof(data) != TYPE_DICTIONARY:
|
if typeof(data) != TYPE_DICTIONARY:
|
||||||
return
|
return
|
||||||
if data.get("type") != "accel" or not data.get("success", false):
|
|
||||||
return
|
match data.get("type", ""):
|
||||||
if not data.has("x") or not data.has("y") or not data.has("z"):
|
"hello":
|
||||||
|
_connected = true
|
||||||
|
_send({"type": "list_clients"})
|
||||||
|
"client_list":
|
||||||
|
_on_client_list(data)
|
||||||
|
"tap":
|
||||||
|
_on_tap(data)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_client_list(data: Dictionary) -> void:
|
||||||
|
if not data.get("success", false):
|
||||||
|
_set_phase(Phase.IDLE, "Client-Liste fehlgeschlagen: %s" % data.get("error", "?"))
|
||||||
return
|
return
|
||||||
|
|
||||||
_accel = Vector3i(int(data["x"]), int(data["y"]), int(data["z"]))
|
_pod_ids = PackedInt32Array()
|
||||||
|
for entry in data.get("clients", []):
|
||||||
|
if typeof(entry) != TYPE_DICTIONARY:
|
||||||
|
continue
|
||||||
|
if not entry.get("available", false):
|
||||||
|
continue
|
||||||
|
var cid := int(entry.get("id", 0))
|
||||||
|
if cid > 0:
|
||||||
|
_pod_ids.append(cid)
|
||||||
|
|
||||||
|
_pod_ids.sort()
|
||||||
|
|
||||||
|
if _pod_ids.size() < 2:
|
||||||
|
_set_phase(Phase.WAITING, "Mindestens 2 online Pods nötig (aktuell: %d)" % _pod_ids.size())
|
||||||
|
target_label.text = "—"
|
||||||
|
timer_label.text = ""
|
||||||
|
return
|
||||||
|
|
||||||
|
_start_round()
|
||||||
|
|
||||||
|
|
||||||
|
func _start_round() -> void:
|
||||||
|
_round_token += 1
|
||||||
|
_pod_digits.clear()
|
||||||
|
|
||||||
|
var pool: Array = []
|
||||||
|
for d in range(10):
|
||||||
|
pool.append(d)
|
||||||
|
pool.shuffle()
|
||||||
|
|
||||||
|
for i in _pod_ids.size():
|
||||||
|
_pod_digits[_pod_ids[i]] = int(pool[i])
|
||||||
|
|
||||||
|
var pick_idx := randi() % _pod_ids.size()
|
||||||
|
_target_cid = _pod_ids[pick_idx]
|
||||||
|
_target_digit = int(_pod_digits[_target_cid])
|
||||||
|
|
||||||
|
for cid in _pod_ids:
|
||||||
|
_send_led_digit(cid, int(_pod_digits[cid]))
|
||||||
|
|
||||||
|
_enable_tap_stream()
|
||||||
|
_round_start_ms = Time.get_ticks_msec()
|
||||||
|
_set_phase(Phase.PLAYING, "%d Pods bereit" % _pod_ids.size())
|
||||||
|
target_label.text = str(_target_digit)
|
||||||
|
subtitle_label.text = "Drücke den Pod mit dieser Zahl"
|
||||||
|
timer_label.text = "0,00 s"
|
||||||
|
hint_label.text = ""
|
||||||
|
|
||||||
|
|
||||||
|
func _enable_tap_stream() -> void:
|
||||||
|
for cid in _pod_ids:
|
||||||
|
_send({
|
||||||
|
"type": "set_tap_notify",
|
||||||
|
"client_id": cid,
|
||||||
|
"single": true,
|
||||||
|
"double_tap": false,
|
||||||
|
"triple": false,
|
||||||
|
})
|
||||||
|
_send({"type": "set_tap_stream", "enable": true, "interval_ms": STREAM_INTERVAL_MS})
|
||||||
|
|
||||||
|
|
||||||
|
func _on_tap(data: Dictionary) -> void:
|
||||||
|
if _phase != Phase.PLAYING or not data.get("success", false):
|
||||||
|
return
|
||||||
|
|
||||||
|
for event in data.get("events", []):
|
||||||
|
if typeof(event) != TYPE_DICTIONARY:
|
||||||
|
continue
|
||||||
|
var cid := int(event.get("client_id", 0))
|
||||||
|
if not _pod_digits.has(cid):
|
||||||
|
continue
|
||||||
|
if cid == _target_cid:
|
||||||
|
_on_correct_tap()
|
||||||
|
else:
|
||||||
|
hint_label.text = "Falsch! Pod #%d hat %d — versuch es nochmal." % [cid, int(_pod_digits[cid])]
|
||||||
|
_send_led_blink(cid, Color(1.0, 0.2, 0.2))
|
||||||
|
var wrong_digit := int(_pod_digits[cid])
|
||||||
|
get_tree().create_timer(0.5).timeout.connect(
|
||||||
|
func() -> void:
|
||||||
|
if _phase == Phase.PLAYING and _pod_digits.has(cid):
|
||||||
|
_send_led_digit(cid, wrong_digit),
|
||||||
|
CONNECT_ONE_SHOT
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_correct_tap() -> void:
|
||||||
|
var elapsed_sec := (Time.get_ticks_msec() - _round_start_ms) / 1000.0
|
||||||
|
_set_phase(Phase.WON, "%d Pods" % _pod_ids.size())
|
||||||
|
timer_label.text = "%.2f s" % elapsed_sec
|
||||||
|
subtitle_label.text = "Richtig!"
|
||||||
|
hint_label.text = "Nächste Runde in %.0f s…" % NEXT_ROUND_DELAY_SEC
|
||||||
|
_send_led_blink(_target_cid, Color(0.2, 1.0, 0.35))
|
||||||
|
|
||||||
|
var token := _round_token
|
||||||
|
get_tree().create_timer(NEXT_ROUND_DELAY_SEC).timeout.connect(
|
||||||
|
func() -> void:
|
||||||
|
if _round_token != token or not is_inside_tree():
|
||||||
|
return
|
||||||
|
if _pod_ids.size() >= 2:
|
||||||
|
_start_round(),
|
||||||
|
CONNECT_ONE_SHOT
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func _update_live_timer() -> void:
|
||||||
|
var elapsed_sec := (Time.get_ticks_msec() - _round_start_ms) / 1000.0
|
||||||
|
timer_label.text = "%.2f s" % elapsed_sec
|
||||||
|
|
||||||
|
|
||||||
|
func _set_phase(phase: Phase, status: String) -> void:
|
||||||
|
_phase = phase
|
||||||
|
status_label.text = status
|
||||||
|
if phase == Phase.WAITING or phase == Phase.IDLE:
|
||||||
|
subtitle_label.text = "Warte auf Pods…"
|
||||||
|
hint_label.text = ""
|
||||||
|
|
||||||
|
|
||||||
|
func _digit_intensity() -> int:
|
||||||
|
return int(intensity_slider.value)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_intensity_changed(_value: float) -> void:
|
||||||
|
intensity_value_label.text = str(_digit_intensity())
|
||||||
|
if _pod_digits.is_empty():
|
||||||
|
return
|
||||||
|
for cid in _pod_digits:
|
||||||
|
_send_led_digit(cid, int(_pod_digits[cid]))
|
||||||
|
|
||||||
|
|
||||||
|
func _send_led_digit(cid: int, digit: int) -> void:
|
||||||
|
_send({
|
||||||
|
"type": "set_led_ring",
|
||||||
|
"client_id": cid,
|
||||||
|
"mode": "digit",
|
||||||
|
"digit": digit,
|
||||||
|
"r": 40,
|
||||||
|
"g": 220,
|
||||||
|
"b": 255,
|
||||||
|
"intensity": _digit_intensity(),
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
func _send_led_clear(cid: int) -> void:
|
||||||
|
_send({"type": "set_led_ring", "client_id": cid, "mode": "clear"})
|
||||||
|
|
||||||
|
|
||||||
|
func _send_led_blink(cid: int, color: Color) -> void:
|
||||||
|
_send({
|
||||||
|
"type": "set_led_ring",
|
||||||
|
"client_id": cid,
|
||||||
|
"mode": "blink",
|
||||||
|
"blink_ms": 200,
|
||||||
|
"blink_count": 2,
|
||||||
|
"r": int(color.r * 255),
|
||||||
|
"g": int(color.g * 255),
|
||||||
|
"b": int(color.b * 255),
|
||||||
|
"intensity": _digit_intensity(),
|
||||||
|
})
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user