Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

Personaggio cinematico (2D)

Introduzione

Sì, il nome suona strano. "Personaggio cinematico". Che cos'è? Il motivo del nome è che, quando sono stati introdotti i motori di fisica, venivano chiamati motori di "dinamiche" (perché si occupavano principalmente delle risposte alle collisioni). Sono stati fatti molti tentativi per creare un controller per personaggi attraverso i motori di dinamiche, ma non era così semplice come sembrava. Godot ha una delle migliori implementazioni di controller dinamico per personaggi che si possano trovare (come si può vedere nella demo 2D/piattaforme), ma il suo utilizzo richiede un livello considerevole di abilità e comprensione dei motori di fisica (oppure molta pazienza con tentativi ed errori).

Alcuni motori di fisica, come Havok, sembrano considerare i controller dinamici per personaggi come l'opzione migliore, mentre altri (PhysX) preferiscono promuovere quelli cinematici.

Allora, qual è la differenza?:

  • Un controller dinamico per personaggi utilizza un corpo rigido con un tensore di inerzia infinito. È un corpo rigido che non può ruotare. I motori di fisica permetto sempre agli oggetti di muoversi e collidere, per poi risolvere le collisioni tutte insieme. Questo permette ai controller dinamici per personaggi di interagire con altri oggetti fisici senza problemi, come si vede nella demo piattaforme. Tuttavia, queste interazioni non sono sempre prevedibili. Le collisioni possono richiedere più di un frame per essere risolte, quindi alcune collisioni possono sembrare causare un piccolo spostamento. Questi problemi si possono risolvere, ma richiedono una certa abilità.

  • Un controller cinematico per personaggi suppone che inizi sempre in uno stato non in collisione, e si muova sempre verso uno stato non in collisione. Se inizia in uno stato in collisione, cercherà di liberarsi come fanno i corpi rigidi, ma questa è l'eccezione, non la regola. Ciò rende il loro controllo e movimento molto più prevedibili e più facili da programmare. Tuttavia, come svantaggio, non possono interagire direttamente con altri oggetti fisici, a meno che non sia fatto manualmente tramite codice.

Questo breve tutorial si concentra sul controller cinematico per personaggi. Utilizza il metodo tradizionale per gestire le collisioni, che non è necessariamente più semplice internamente, ma è ben nascosto e presentato come un'API.

Processo di fisica

To manage the logic of a kinematic body or character, it is always advised to use physics process, because it's called before physics step and its execution is in sync with physics server, also it is called the same amount of times per second, always. This makes physics and motion calculation work in a more predictable way than using regular process, which might have spikes or lose precision if the frame rate is too high or too low.

extends CharacterBody2D

func _physics_process(delta):
    pass

Impostazione della scena

Per avere qualcosa da testare, ecco la scena (dal tutorial sulle tilemap): kinematic_character_2d_starter.zip. Creeremo una nuova scena per il personaggio. Usa lo sprite del robot e crea una scena come questa:

../../_images/kbscene.webp

Noterai che accanto al nodo CollisionShape2D è presente un'icona di avviso; questo perché non abbiamo ancora definito una forma. Crea un nuovo CircleShape2D nella proprietà shape di CollisionShape2D. Clicca su <CircleShape2D> per accedere alle opzioni e imposta il raggio (radius) a 30:

../../_images/kbradius.webp

Nota: come accennato in precedenza nel tutorial sulla fisica, il motore di fisica non è in grado di gestire la scala per la maggior parte delle forme (funzionano solo poligoni, piani e segmenti di collisione), quindi modifica sempre i parametri (come il raggio) della forma invece di ridimensionarla. Lo stesso vale anche per i corpi cinematici/rigidi/statici stessi, poiché la loro scala influenza la scala della forma.

Ora, crea uno script per il personaggio; quello usato come esempio sopra dovrebbe funzionare come base.

Infine, crea un'istanza della scena del personaggio nella tilemap e imposta la scena della mappa come principale, in modo che venga eseguita quando premi play.

../../_images/kbinstance.webp

Spostare il personaggio cinematico

Torna alla scena del personaggio e apri lo script: ora comincia la magia! Il corpo cinematico di suo non farà nulla, ma ha una funzione utile chiamata CharacterBody2D.move_and_collide(). Questa funzione accetta un Vector2 come argomento e tenta di applicare quel movimento al corpo cinematico. Se si verifica una collisione, si ferma esattamente nel momento della collisione.

Quindi, muoviamo il nostro sprite verso il basso finché non tocca il pavimento:

extends CharacterBody2D

func _physics_process(delta):
    move_and_collide(Vector2(0, 1)) # Move down 1 pixel per physics frame

Il risultato è che il personaggio si muoverà, ma si fermerà proprio quando tocca il terreno. Piuttosto geniale, no?

Il prossimo passo sarà aggiungere la gravità al misto, in modo che si comporti un po' più come un tipico personaggio di un videogioco:

extends CharacterBody2D

const GRAVITY = 200.0

func _physics_process(delta):
    velocity.y += delta * GRAVITY

    var motion = velocity * delta
    move_and_collide(motion)

Ora il personaggio cade dolcemente. Facciamolo camminare lateralmente, a sinistra e a destra quando si premono i tasti direzionali. Ricorda che i valori utilizzati (almeno per la velocità) sono in pixel/secondo.

Questo aggiunge un supporto basilare per camminare quando si preme a sinistra e a destra:

extends CharacterBody2D

const GRAVITY = 200.0
const WALK_SPEED = 200

func _physics_process(delta):
    velocity.y += delta * GRAVITY

    if Input.is_action_pressed("ui_left"):
        velocity.x = -WALK_SPEED
    elif Input.is_action_pressed("ui_right"):
        velocity.x =  WALK_SPEED
    else:
        velocity.x = 0

    # "move_and_slide" already takes delta time into account.
    move_and_slide()

E fagli una prova.

Questo è un buon punto di partenza per un gioco piattaforme. Una demo più completa è disponibile nel file zip della demo distribuito con il motore, oppure all'indirizzo https://github.com/godotengine/godot-demo-projects/tree/master/2d/kinematic_character.