Input Touch, Sensori e Performance in Godot 4 per Android

Guide Godot 4 per Android – Capitolo 2: Input, sensori e ottimizzazione

Nel primo capitolo della serie “Guide Godot 4 per Android” abbiamo visto come installare Godot 4, configurare Android Studio, JDK, le variabili d’ambiente e come generare il primo APK di test. In questo secondo capitolo ci concentriamo su ciò che rende un’app davvero “mobile”: input touch, sensori, ottimizzazione delle performance e gestione del ciclo di vita dell’app Android.

Alla fine della guida avrai un progetto Godot pronto a gestire correttamente il touch, leggere accelerometro e giroscopio, comportarsi bene quando l’utente mette in pausa l’app e consumare meno risorse sui dispositivi Android.

1. Introduzione: da APK di test ad app pronta per il mobile

Se hai seguito il primo capitolo, ora sei in grado di:

  • Installare e avviare Godot 4.
  • Configurare Android Studio, SDK e JDK.
  • Impostare le variabili d’ambiente per la build Android.
  • Esportare un semplice APK di test sul tuo dispositivo.

In questo capitolo partiamo da questa base per trasformare il tuo progetto in una vera app mobile, affrontando gli aspetti tipici della piattaforma Android:

  • Gestione avanzata dell’input touch e delle gesture.
  • Lettura dei sensori hardware principali (accelerometro, giroscopio, magnetometro).
  • Ottimizzazione del rendering e della memoria per dispositivi anche poco performanti.
  • Corretta gestione del ciclo di vita dell’app (pausa, ripresa, tasto indietro).
  • Risoluzione dei problemi più comuni su Android.

2. Gestire l’input touch in Godot 4

Su Android (e in generale su mobile) il mouse è praticamente inesistente: tutto ruota attorno al touch e alle gesture. Godot 4 espone il touch attraverso alcuni tipi di evento specifici, che ricevi in _input(event) o _unhandled_input(event).

2.1 Differenza tra input mouse e input touch

In Godot, il mouse usa eventi come InputEventMouseButton e InputEventMouseMotion. Su Android, quando l’utente tocca lo schermo, riceverai invece:

  • InputEventScreenTouch: quando un dito tocca o rilascia lo schermo.
  • InputEventScreenDrag: quando un dito si muove mentre è a contatto con lo schermo.

Questo significa che, per supportare correttamente il mobile, è consigliabile gestire esplicitamente questi due tipi di evento nel tuo script.

2.2 InputEventScreenTouch e InputEventScreenDrag

Ecco un esempio base di gestione del touch in un Node2D o Control:

extends Node2D

func _input(event: InputEvent) -> void:
    if event is InputEventScreenTouch:
        if event.pressed:
            print("Touch iniziato su posizione:", event.position, " indice:", event.index)
        else:
            print("Touch rilasciato su posizione:", event.position, " indice:", event.index)

    elif event is InputEventScreenDrag:
        print("Trascinamento su posizione:", event.position, " delta:", event.relative, " indice:", event.index)

Campi importanti:

  • position: la posizione sullo schermo in pixel.
  • index: l’indice del dito (0, 1, 2…) utile per il multitouch.
  • pressed (solo screen touch): true quando il dito tocca, false quando lascia.
  • relative (solo screen drag): il delta di movimento rispetto al frame precedente.

2.3 Multitouch: gestire più dita contemporaneamente

Su Android è normale che l’utente usi due o più dita (ad esempio per lo zoom). Godot assegna ad ogni dito un index. Puoi salvare le posizioni delle dita in un dizionario:

extends Node2D

var touches := {} # index -> position

func _input(event: InputEvent) -> void:
    if event is InputEventScreenTouch:
        if event.pressed:
            touches[event.index] = event.position
        else:
            touches.erase(event.index)

    elif event is InputEventScreenDrag:
        touches[event.index] = event.position

    # Esempio: stampa il numero di dita sullo schermo
    if touches.size() > 0:
        print("Dita attive:", touches.size())

2.4 Riconoscere tap, swipe e pinch-to-zoom

Godot non fornisce (al momento) un sistema di gesture complete pronto all’uso per il touch, ma puoi implementare le più comuni con poco codice.

Tap singolo

Per un tap puoi controllare la durata del tocco e la distanza percorsa:

extends Node2D

const MAX_TAP_TIME := 0.2
const MAX_TAP_DISTANCE := 20.0

var touch_start_time := {}
var touch_start_pos := {}

func _input(event: InputEvent) -> void:
    if event is InputEventScreenTouch:
        if event.pressed:
            touch_start_time[event.index] = Time.get_ticks_msec() / 1000.0
            touch_start_pos[event.index] = event.position
        else:
            var start_time := touch_start_time.get(event.index, 0.0)
            var start_pos := touch_start_pos.get(event.index, event.position)
            var duration := Time.get_ticks_msec() / 1000.0 - start_time
            var distance := start_pos.distance_to(event.position)

            if duration <= MAX_TAP_TIME and distance <= MAX_TAP_DISTANCE:
                _on_tap(event.position)

            touch_start_time.erase(event.index)
            touch_start_pos.erase(event.index)

func _on_tap(pos: Vector2) -> void:
    print("Tap rilevato a:", pos)

Swipe

Per uno swipe ti interessa soprattutto la direzione e la distanza:

const MIN_SWIPE_DISTANCE := 80.0

func _on_swipe(start_pos: Vector2, end_pos: Vector2) -> void:
    var delta := end_pos - start_pos
    if delta.length() < MIN_SWIPE_DISTANCE:
        return

    if abs(delta.x) > abs(delta.y):
        if delta.x > 0:
            print("Swipe verso destra")
        else:
            print("Swipe verso sinistra")
    else:
        if delta.y > 0:
            print("Swipe verso il basso")
        else:
            print("Swipe verso l'alto")

Pinch-to-zoom

Per il pinch-to-zoom servono almeno due dita: confronti la distanza tra le due dita nel frame corrente con quella del frame precedente.

var pinch_prev_distance := 0.0

func _process(delta: float) -> void:
    if touches.size() == 2:
        var keys := touches.keys()
        var p1 := touches[keys[0]]
        var p2 := touches[keys[1]]
        var current_distance := p1.distance_to(p2)

        if pinch_prev_distance > 0.0:
            var diff := current_distance - pinch_prev_distance
            if abs(diff) > 1.0:
                if diff > 0:
                    _on_zoom(1) # zoom in
                else:
                    _on_zoom(-1) # zoom out

        pinch_prev_distance = current_distance
    else:
        pinch_prev_distance = 0.0

func _on_zoom(direction: int) -> void:
    print("Zoom direction:", direction)

Nota importante

Se stai portando un gioco pensato per il mouse su Android, evita di mappare alla lettera il click su tap. Per una buona esperienza utente, ripensa l’interazione (ad esempio con aree touch più grandi, pulsanti ben distanziati e gesture intuitive).

3. Usare i sensori Android in Godot

Molti giochi mobile sfruttano i sensori del dispositivo per creare controlli alternativi o effetti realistici. In Godot 4, i principali sensori Android sono accessibili tramite la classe Input.

3.1 Abilitare i sensori nel progetto

Prima di leggere i valori dei sensori, assicurati che siano abilitati nelle impostazioni di progetto:

  • Apri Project > Project Settings.
  • Vai alla sezione Input Devices > Sensors.
  • Abilita i sensori che ti servono, ad esempio:
    • use_accelerometer
    • use_gyroscope
    • use_magnetometer
  • Salva le impostazioni e riavvia il progetto sul dispositivo Android (i sensori non funzionano in genere nell’editor su PC).

3.2 Accelerometro: Input.get_accelerometer()

L’accelerometro misura l’accelerazione (inclusa la gravità) lungo gli assi X, Y, Z del dispositivo. In Godot lo leggi così:

func _physics_process(delta: float) -> void:
    var accel: Vector3 = Input.get_accelerometer()
    # Esempio: controlla un personaggio inclinando il dispositivo
    var tilt_x := accel.x

    if tilt_x > 0.1:
        _move_right()
    elif tilt_x < -0.1:
        _move_left()

Attenzione: l’orientamento degli assi dipende dall’orientamento dello schermo (portrait/landscape). È buona pratica testare il comportamento direttamente sul dispositivo.

3.3 Giroscopio: Input.get_gyroscope()

Il giroscopio misura la velocità di rotazione del dispositivo. È utile per effetti più precisi rispetto all’accelerometro o per la realtà aumentata.

func _physics_process(delta: float) -> void:
    var gyro: Vector3 = Input.get_gyroscope()
    # gyro.x, gyro.y, gyro.z sono le velocità di rotazione per asse
    rotation += gyro.y * delta

Come per l’accelerometro, sperimenta per trovare i fattori di scala giusti e non rendere il controllo troppo sensibile.

3.4 Magnetometro: Input.get_magnetometer()

Il magnetometro misura il campo magnetico terrestre ed è spesso usato per implementare una bussola. In Godot:

func _physics_process(delta: float) -> void:
    var mag: Vector3 = Input.get_magnetometer()
    # Esempio molto semplificato di "bussola" 2D
    var angle := atan2(mag.x, mag.y)
    $CompassNeedle.rotation = angle

Non tutti i dispositivi Android hanno un magnetometro; in quel caso il vettore restituito può essere vicino a Vector3.ZERO o non aggiornarsi.

4. Ottimizzazione delle performance per mobile

I dispositivi Android variano moltissimo per potenza, memoria e GPU. Per evitare lag e crash, è essenziale ottimizzare il progetto pensando ai dispositivi di fascia bassa.

4.1 Usare il profiler di Godot

Godot include un profiler integrato che ti aiuta a capire dove stai spendendo più tempo per frame.

  • Collega il tuo dispositivo Android tramite Debug > Deploy with Remote Debug.
  • Una volta in esecuzione, apri Debugger > Profiler.
  • Osserva:
    • Frame Time: quanto dura un frame (target < 16 ms per 60 FPS).
    • Draw Calls: numero di oggetti disegnati.
    • Tempo speso in physics, script, render.

4.2 Ridurre le draw call e usare texture atlases

Ogni oggetto disegnato dalla GPU è una draw call. Su mobile, troppe draw call causano rapidamente cali di frame rate. Alcuni suggerimenti:

  • Unisci le sprite in un unico texture atlas (spritesheet) invece di usare tanti file PNG separati.
  • Quando possibile, usa TileMap invece di tante Sprite2D singole.
  • Evita materiali unici per ogni oggetto; riusa materiali condivisi.
  • Riduci il numero di nodi attivi in scena (specie luci e nodi 3D).

4.3 Ottimizzare la viewport e le impostazioni di qualità

Nel menu Project > Project Settings > Display puoi controllare la risoluzione e il comportamento della viewport:

  • Imposta una base resolution ragionevole (ad es. 1280×720 per 2D) e lascia che Android la scali.
  • Evita risoluzioni troppo alte inutili su schermi piccoli.
  • Per progetti 3D valuta l’uso di render scale < 1.0 per ridurre il carico sulla GPU.

Nelle impostazioni di esportazione Android, nella sezione Rendering puoi scegliere il renderer:

  • Mobile: pensato per la maggior parte dei dispositivi moderni; buone performance.
  • Compatibility: per dispositivi più vecchi o con problemi driver; meno feature, ma maggiore compatibilità.

4.4 Gestione della memoria e batching

La memoria è spesso il limite principale su Android. Alcune buone pratiche:

  • Riduci la dimensione delle texture (es. 1024×1024 invece di 4096×4096, quando possibile).
  • Usa formati compressi (ETC2/ASTC) dove supportati.
  • Evita di caricare tutto in memoria: usa ResourceLoader.load() o preload() solo per ciò che ti serve davvero.
  • Libera risorse quando non ti servono più (es. cambi scena e distruggi nodi inutili).
  • Sfrutta il batching automatico del renderer mantenendo materiali e texture condivisi.

5. Gestione del ciclo di vita dell’app Android

Su Android l’utente può uscire dall’app in molti modi: tasto indietro, tasto Home, cambio app, blocco schermo. Godot invia notifiche che puoi intercettare per salvare stato, mettere in pausa il gioco, rilasciare risorse, ecc.

5.1 ApplicationNotification e NOTIFICATION_WM_GO_BACK_REQUEST

In qualsiasi Node puoi sovrascrivere il metodo _notification(what) per reagire ad eventi di sistema. Per il tasto indietro su Android, Godot 4 usa NOTIFICATION_WM_GO_BACK_REQUEST:

extends Node

func _notification(what: int) -> void:
    match what:
        NOTIFICATION_WM_GO_BACK_REQUEST:
            # Ad esempio: mostra una finestra di conferma uscita
            _on_back_pressed()

func _on_back_pressed() -> void:
    print("Tasto indietro premuto")
    # Puoi decidere di chiudere l'app o tornare a un menu
    get_tree().quit()

5.2 Pause, resume e salvataggio dello stato

Quando l’utente mette l’app in background (es. Home o multitasking), Godot invia notifiche di pausa e ripresa. Su Android è importante salvare lo stato velocemente, perché il sistema può decidere di chiudere il processo in background.

extends Node

func _notification(what: int) -> void:
    match what:
        NOTIFICATION_APPLICATION_PAUSED:
            _on_app_paused()
        NOTIFICATION_APPLICATION_RESUMED:
            _on_app_resumed()

func _on_app_paused() -> void:
    print("App in pausa, salvo lo stato...")
    _save_game_state()

func _on_app_resumed() -> void:
    print("App ripresa, ripristino lo stato...")
    _load_game_state()

func _save_game_state() -> void:
    var save_data := {
        "score": 100,
        "level": 3,
    }
    var file := FileAccess.open("user://savegame.json", FileAccess.WRITE)
    file.store_string(JSON.stringify(save_data))
    file.close()

func _load_game_state() -> void:
    if not FileAccess.file_exists("user://savegame.json"):
        return
    var file := FileAccess.open("user://savegame.json", FileAccess.READ)
    var text := file.get_as_text()
    file.close()
    var result := JSON.parse_string(text)
    if typeof(result) == TYPE_DICTIONARY:
        print("Stato caricato:", result)

5.3 Gestire l’orientamento dello schermo

Per decidere se la tua app funziona in portrait, landscape o entrambi, usa le impostazioni di visualizzazione:

  • Vai in Project > Project Settings > Display > Window.
  • Modifica Orientation scegliendo tra Landscape, Portrait, Sensor Landscape, ecc.
  • Su Android, assicurati che nelle impostazioni di esportazione il campo Screen Orientation sia coerente con quanto scelto nel progetto.

Se cambi orientamento dinamicamente, considera che il layout UI (Control) può dover essere aggiornato o ridisegnato per evitare elementi tagliati.

6. Problemi comuni su Android e soluzioni

Durante i test su dispositivi reali è normale incontrare problemi. Vediamo i più frequenti e alcune strategie per risolverli.

6.1 Lag su dispositivi low-end

Sintomi: FPS bassi, input che risponde in ritardo, animazioni scattose.

  • Riduci la risoluzione o usa un render scale più basso.
  • Riduci il numero di oggetti in scena e semplifica la logica di gioco.
  • Disabilita effetti pesanti (ombre dinamiche, luci in eccesso, post-processing).
  • Assicurati di usare il renderer Mobile o Compatibility in base al dispositivo.

6.2 Crash legati alla memoria

Sintomi: l’app si chiude improvvisamente, spesso quando carichi una nuova scena o molte texture.

  • Riduci la dimensione e il numero delle texture.
  • Evita di mantenere in memoria scene non utilizzate (usa queue_free() sui nodi vecchi).
  • Usa streaming audio per musiche lunghe invece di caricarle completamente in RAM.
  • Testa su dispositivi con poca RAM (2 GB o meno) per individuare i colli di bottiglia.

6.3 Touch non registrato o impreciso

Sintomi: l’utente tocca un pulsante ma non succede nulla, oppure i tocchi vengono rilevati in posizioni sbagliate.

  • Verifica che i nodi Control abbiano Mouse > Filter impostato correttamente (ad es. Stop per catturare l’input).
  • Assicurati che non ci siano nodi UI trasparenti sopra il pulsante che intercettano il tocco.
  • Stampa in debug event.position per capire dove Godot “vede” il tocco.
  • Evita pulsanti troppo piccoli: su mobile è consigliabile una dimensione minima di circa 40–48dp.

6.4 Sensori non disponibili o che non rispondono

Sintomi: valori sempre a zero, nessun cambiamento anche muovendo il dispositivo.

  • Controlla che i sensori siano abilitati in Project Settings > Input Devices > Sensors.
  • Verifica su un secondo dispositivo: alcuni smartphone non hanno tutti i sensori.
  • Gestisci il caso “sensore non disponibile” mostrando un controllo alternativo (es. pulsanti al posto del tilt).
  • Ricorda che nell’editor su PC i sensori non funzionano: testa sempre su dispositivo reale.

7. Conclusione e prossimi passi

In questo secondo capitolo hai visto come trasformare il tuo progetto Godot 4 in un’app più adatta al mondo mobile: hai imparato a gestire l’input touch, leggere i sensori Android, migliorare le performance e reagire correttamente agli eventi del ciclo di vita dell’app.

Nel prossimo capitolo della serie su apptutorial.link vedremo come passare da progetto di sviluppo ad app pubblicata, affrontando firma dell’APK/AAB, preparazione della scheda store, test di pubblicazione e invio sul Google Play Store.

Commenti

Lascia un commento