Files
tyler parker bb1d70c620 Godot + Arduino series: companion project code
Self-contained project code for the "Godot Isn't Just for Games" series:
Arduino sketches, the Python serial<->UDP bridge, and the Godot 4 projects,
one folder per article.
2026-08-09 21:14:55 +00:00

64 lines
2.3 KiB
GDScript

extends Control
const TELEMETRY_PORT := 4242
const COMMAND_ADDR := "127.0.0.1"
const COMMAND_PORT := 4243
const ADC_MAX := 1023.0
const SMOOTH_SPEED := 12.0 # higher = snappier, lower = floatier
@onready var led_button: Button = $Panel/LedButton
@onready var pad: Panel = $Panel/Pad
@onready var dot: ColorRect = $Panel/Pad/Dot
var _udp_in := PacketPeerUDP.new()
var _udp_out := PacketPeerUDP.new()
var _target_x := 512.0 # rest near center so the dot starts in the middle
var _target_y := 512.0
var _smoothed_x := 512.0
var _smoothed_y := 512.0
var _btn_pressed := false
var _led_on := false
const COLOR_DOT_IDLE := Color(0.3, 0.7, 1.0) # cyan
const COLOR_DOT_PRESSED := Color(0.2, 1.0, 0.4) # green
func _ready() -> void:
_udp_in.bind(TELEMETRY_PORT, "127.0.0.1")
# set_dest_address is the reliable way to *send* with PacketPeerUDP in Godot 4;
# connect_to_host is aimed at receiving and can silently drop outbound packets.
_udp_out.set_dest_address(COMMAND_ADDR, COMMAND_PORT)
led_button.pressed.connect(_on_led_pressed)
func _process(delta: float) -> void:
# Drain the queue; the newest packet wins. Format: "x,y,btn" e.g. "512,498,0"
while _udp_in.get_available_packet_count() > 0:
var parts := _udp_in.get_packet().get_string_from_utf8().split(",")
if parts.size() >= 3 and parts[0].is_valid_int() and parts[1].is_valid_int():
_target_x = float(parts[0])
_target_y = float(parts[1])
_btn_pressed = parts[2].strip_edges() == "1"
# Frame-rate-independent smoothing so the dot glides instead of twitching.
var t := 1.0 - exp(-SMOOTH_SPEED * delta)
_smoothed_x = lerpf(_smoothed_x, _target_x, t)
_smoothed_y = lerpf(_smoothed_y, _target_y, t)
# Normalize raw ADC (0..1023) to 0..1.
var nx := clampf(_smoothed_x / ADC_MAX, 0.0, 1.0)
var ny := clampf(_smoothed_y / ADC_MAX, 0.0, 1.0)
# Move the dot within the pad. Invert Y so pushing the stick UP moves the dot UP.
# (If it feels backwards, change "1.0 - ny" to "ny", or swap for X below.)
var travel := pad.size - dot.size
dot.position = Vector2(nx * travel.x, (1.0 - ny) * travel.y)
# Reflect the stick's push-button by recoloring the dot.
dot.color = COLOR_DOT_PRESSED if _btn_pressed else COLOR_DOT_IDLE
func _on_led_pressed() -> void:
_led_on = not _led_on
_udp_out.put_packet(("L1" if _led_on else "L0").to_utf8_buffer())
led_button.text = "LED: ON" if _led_on else "LED: OFF"