Skriptaus (jatkuu)

Prosessointi

Useat toiminnot Godotissa suoritetaan takaisinkutsuina (callback) tai virtuaalifunktioina, joten jatkuvasti suoritettavaa koodia ei ole tarvetta kirjoittaa.

On silti tavallista, että skripti täytyy prosessoida jokaisella ruudunpäivityksellä. Prosessointia on kahdentyyppistä: joutoprosessointia ja fysiikkaprosessointia.

Joutoprosessointi aktivoituu, kun skriptistä löytyy Node._process() metodi. Se voidaan kytkeä päälle ja pois Node.set_process() funktiolla.

Tätä metodia kutsutaan jokaisella ruudun piirtokerralla:

func _process(delta):
    # Do something...
    pass
public override void _Process(float delta)
{
    // Do something...
}

On hyvä pitää mielessä, että taajuus jolla _process() metodia kutsutaan riippuu siitä kuinka monta ruutua per sekunti (FPS) sovelluksesi kykenee käsittelemään. Tämä nopeus voi vaihdella eri hetkillä ja laitteilla.

To help manage this variability, the delta parameter contains the time elapsed in seconds as a floating-point number since the previous call to _process().

Parametria käyttämällä voidaan pitää huoli siitä, että asiat vievät aina saman verran aikaa, riippumatta pelin FPS-nopeudesta.

For example, movement is often multiplied with a time delta to make movement speed both constant and independent of the frame rate.

Fysiikkaprosessointi _physics_process() funktiolla on samanlaista, mutta sitä tulisi käyttää sellaiseen käsittelyyn, jonka täytyy tapahtua jokaisen fysiikkapäivityksen yhteydessä, kuten hahmon ohjaaminen. Se suoritetaan aina ennen fysiikkavaihetta ja sitä kutsutaan tasaisin väliajoin: oletusarvoisesti 60 kertaa sekunnissa. Voit muuttaa aikaväliä projektin asetuksista, kohdasta Physics -> Common -> Physics Fps.

_process() funktio ei kuitenkaan ole synkronoitu fysiikan kanssa. Sen päivitysnopeus ei ole vakio ja riippuu laitteistosta ja pelin optimoinneista. Yksisäikeisissä peleissä sen suoritus tehdään fysiikkavaiheen jälkeen.

Yksinkertainen tapa nähdä _process() funktio toiminnassa, on luoda skene, jossa on yksittäinen Label solmu seuraavalla skriptillä varustettuna:

extends Label

var accum = 0

func _process(delta):
    accum += delta
    text = str(accum) # 'text' is a built-in label property.
public class CustomLabel : Label
{
    private float _accum;

    public override void _Process(float delta)
    {
        _accum += delta;
        Text = _accum.ToString(); // 'Text' is a built-in label property.
    }
}

Se näyttää kunkin ruudunpäivityksen yhteydessä kasvavan laskurin.

Ryhmät

Ryhmät Godotissa toimivat kuin tägit joihin olet voinut törmätä muissa ohjelmistoissa. Solmu voidaan lisätä niin moneen ryhmään kuin halutaan. Tämä on hyödyllinen ominaisuus laajojen skenejen järjestelemiseksi. On kaksi tapaa lisätä solmu ryhmään. Ensimmäinen on käyttöliittymästä, Ryhmät-painikkeesta Solmu-paneelilla:

../../_images/groups_in_nodes.png

Toinen tapa on koodista käsin. Seuraava skripti lisää nykyisen solmun enemies ryhmään heti kun se ilmestyy skenepuuhun.

func _ready():
    add_to_group("enemies")
public override void _Ready()
{
    base._Ready();

    AddToGroup("enemies");
}

Tällä tapaa, jos pelaaja jää kiinni hiipiessään salaiseen tukikohtaan, kaikille vihollisille voidaan antaa tieto hälytyksen soimisesta käyttämällä SceneTree.call_group() funktiota:

func _on_discovered(): # This is a purely illustrative function.
    get_tree().call_group("enemies", "player_was_discovered")
public void _OnDiscovered() // This is a purely illustrative function.
{
    GetTree().CallGroup("enemies", "player_was_discovered");
}

Yllä oleva koodi kutsuu player_was_discovered funktiota enemies ryhmän jokaiselle jäsenelle.

On myös mahdollista saada kokonainen lista enemies solmuista kutsumalla SceneTree.get_nodes_in_group() funktiota:

var enemies = get_tree().get_nodes_in_group("enemies")
var enemies = GetTree().GetNodesInGroup("enemies");

SceneTree luokka tarjoaa monia hyödyllisiä metodeja, kuten skenejen, niiden solmuhierarkian ja solmuryhmien käsittelyä. Se sallii sinun vaihtaa tai uudelleenladata skenejä helposti, ja lopettaa, keskeyttää tai palauttaa pelin ajamisen. Sen mukana tulee myös mielenkiintoisia signaaleja. Joten vilkaise sitä, jos sinulla on aikaa!

Ilmoitukset (notifications)

Godotissa on järjestelmä ilmoituksille. Niitä ei yleensä tarvita skriptauksessa, koska ne ovat liian alhaisen tason koodia ja useimmille on tarjolla vastaava virtuaalifunktio. On silti hyvä olla tietoinen niiden olemassaolosta. Voit esimerkiksi lisätä Object._notification() funktion skriptiisi:

func _notification(what):
    match what:
        NOTIFICATION_READY:
            print("This is the same as overriding _ready()...")
        NOTIFICATION_PROCESS:
            print("This is the same as overriding _process()...")
public override void _Notification(int what)
{
    base._Notification(what);

    switch (what)
    {
        case NotificationReady:
            GD.Print("This is the same as overriding _Ready()...");
            break;
        case NotificationProcess:
            var delta = GetProcessDeltaTime();
            GD.Print("This is the same as overriding _Process()...");
            break;
    }
}

The documentation of each class in the Class Reference shows the notifications it can receive. However, in most cases GDScript provides simpler overridable functions.

Overridable functions

Such overridable functions, which are described as follows, can be applied to nodes:

func _enter_tree():
    # When the node enters the Scene Tree, it becomes active
    # and  this function is called. Children nodes have not entered
    # the active scene yet. In general, it's better to use _ready()
    # for most cases.
    pass

func _ready():
    # This function is called after _enter_tree, but it ensures
    # that all children nodes have also entered the Scene Tree,
    # and became active.
    pass

func _exit_tree():
    # When the node exits the Scene Tree, this function is called.
    # Children nodes have all exited the Scene Tree at this point
    # and all became inactive.
    pass

func _process(delta):
    # This function is called every frame.
    pass

func _physics_process(delta):
    # This is called every physics frame.
    pass
public override void _EnterTree()
{
    // When the node enters the Scene Tree, it becomes active
    // and  this function is called. Children nodes have not entered
    // the active scene yet. In general, it's better to use _ready()
    // for most cases.
    base._EnterTree();
}

public override void _Ready()
{
    // This function is called after _enter_tree, but it ensures
    // that all children nodes have also entered the Scene Tree,
    // and became active.
    base._Ready();
}

public override void _ExitTree()
{
    // When the node exits the Scene Tree, this function is called.
    // Children nodes have all exited the Scene Tree at this point
    // and all became inactive.
    base._ExitTree();
}

public override void _Process(float delta)
{
    // This function is called every frame.
    base._Process(delta);
}

public override void _PhysicsProcess(float delta)
{
    // This is called every physics frame.
    base._PhysicsProcess(delta);
}

Kuten mainittu aikaisemmin, on parempi käyttää näitä funktioita ilmoitusjärjestelmän sijaan.

Solmujen luonti

Luodaksesi uuden solmun koodissa, kutsu .new() metodia, kuten minkä tahansa luokkapohjaisen tietotyypin tapauksessa. Esimerkiksi:

var s
func _ready():
    s = Sprite.new() # Create a new sprite!
    add_child(s) # Add it as a child of this node.
private Sprite _sprite;

public override void _Ready()
{
    base._Ready();

    _sprite = new Sprite(); // Create a new sprite!
    AddChild(_sprite); // Add it as a child of this node.
}

Solmun tuhoamiseksi, oli se sitten skenen sisällä tai ulkopuolella, on käytettävä free() metodia:

func _someaction():
    s.free() # Immediately removes the node from the scene and frees it.
public void _SomeAction()
{
    _sprite.Free(); // Immediately removes the node from the scene and frees it.
}

Kun solmu vapautetaan, myös kaikki sen alisolmut vapautetaan. Tästä johtuen solmujen manuaalinen tuhoaminen on paljon helpompaa kuin miltä se vaikuttaa. Vapauta pohjasolmu ja kaikki muu alipuussa menee sen mukana.

Sellainen tilanne voi sattua, että haluamme poistaa solmun, joka on parhaillaan "estetty", koska se on lähettämässä signaalia tai kutsumassa funktiota. Tämä kaataa pelin. Godotin ajaminen debuggerissa pyydystää usein tämäntyyppisen tapauksen ja varoittaa sinua siitä.

Turvallisin tapa solmun tuhoamiseksi on käyttää Node.queue_free() metodia. Tämä poistaa solmun turvallisesti toimettomalla hetkellä.

func _someaction():
    s.queue_free() # Removes the node from the scene and frees it when it becomes safe to do so.
public void _SomeAction()
{
    _sprite.QueueFree(); // Removes the node from the scene and frees it when it becomes safe to do so.
}

Skenejen instantiointi

Skenejen instantiointi koodissa tehdään kahdessa vaiheessa. Ensiksi skene ladataan kiintolevyltä:

var scene = load("res://myscene.tscn") # Will load when the script is instanced.
var scene = GD.Load<PackedScene>("res://myscene.tscn"); // Will load when the script is instanced.

Sen esilataaminen saattaa olla sopivampaa, koska se tapahtuu skriptin jäsennysaikana (vain GDScript):

var scene = preload("res://myscene.tscn") # Will load when parsing the script.

Mutta scene ei ole vielä solmu. Se on pakattu erityiseen PackedScene nimiseen resurssiin. Varsinaisen solmun luomiseksi täytyy kutsua PackedScene.instance() funktiota. Tämä palauttaa solmupuun, joka voidaan lisätä aktiiviseen skeneen:

var node = scene.instance()
add_child(node)
var node = scene.Instance();
AddChild(node);

Tämän kaksivaiheisen prosessin etu on, että pakattu skene voidaan pitää ladattuna ja käyttövalmiina, niin että siitä voidaan luoda niin monta ilmentymää kuin on tarpeen. Se on käytännöllistä varsinkin useiden vihollisten, ammusten ja muiden yksiköiden luomisessa aktiiviseen skeneen.

Skriptien rekisteröinti luokiksi

Godotissa on "skriptiluokka"-ominaisuus yksittäisten skriptien rekisteröintiin editorissa. Lähtökohtaisesti pääset käsiksi nimeämättömiin skripteihin vain lataamalla tiedoston suoraan.

Voit nimetä skriptin ja rekisteröidä sen tyypiksi editorissa class_name avainsanalla, jota seuraa luokan nimi. Voit lisätä pilkun ja valinnaisen polun ikonina käytettävään kuvaan. Löydät tämän jälkeen uuden tyyppisi Solmu- tai Resurssinluontidialogista.

extends Node

# Declare the class name here
class_name ScriptName, "res://path/to/optional/icon.svg"

func _ready():
    var this = ScriptName           # reference to the script
    var cppNode = MyCppNode.new()   # new instance of a class named MyCppNode

    cppNode.queue_free()
../../_images/script_class_nativescript_example.png

Varoitus

Godot 3.1 versiossa:

  • Vain GDScript ja NativeScript, eli C++ ja muut GDNative-käyttöiset kielet, voivat rekisteröidä skriptejä.
  • Vain GDScript luo globaaleja muuttujia kullekin nimetylle skriptille.