Ο κώδικας που ελέγχει ένα τρέχον παιχνίδι πρέπει να μπορεί να φτάσει σε κάθε αντικείμενο και στοιχείο για να μετακινηθεί, να κλιμακώσει, να κινήσει, να διαγράψει και να χειριστεί αυτό που βλέπει και ακούει ο παίκτης. Ο μηχανισμός διεύθυνση του Defold το καθιστά δυνατό.
Το Defold χρησιμοποιεί διευθύνσεις (ή διευθύνσεις URL, αλλά ας το αγνοήσουμε προς το παρόν) για να αναφέρεται σε αντικείμενα και στοιχεία παιχνιδιού. Αυτές οι διευθύνσεις αποτελούνται από αναγνωριστικά. Τα παρακάτω είναι όλα τα παραδείγματα του τρόπου με τον οποίο το Defold χρησιμοποιεί διευθύνσεις. Μέσω αυτού του εγχειριδίου θα εξετάσουμε λεπτομερώς πώς λειτουργούν:
local id = factory.create("#enemy_factory")
label.set_text("my_gameobject#my_label", "Hello World!")
local pos = go.get_position("my_gameobject")
go.set_position(pos, "/level/stuff/other_gameobject")
msg.post("#", "hello_there")
local id = go.get_id(".")
Ας ξεκινήσουμε με ένα πολύ απλό παράδειγμα. Ας υποθέσουμε ότι έχετε ένα αντικείμενο παιχνιδιού με ένα μόνο στοιχείο sprite. Έχετε επίσης ένα στοιχείο δέσμης ενεργειών για τον έλεγχο του αντικειμένου του παιχνιδιού. Η εγκατάσταση στο πρόγραμμα επεξεργασίας θα μοιάζει με αυτό:
Τώρα θέλετε να απενεργοποιήσετε το sprite όταν ξεκινά το παιχνίδι, ώστε να μπορείτε να το εμφανίσετε αργότερα. Αυτό γίνεται εύκολα τοποθετώντας τον ακόλουθο κώδικα στο “controller.script”:
function init(self)
msg.post("#body", "disable") -- <1>
end
Αυτό θα λειτουργήσει όπως αναμενόταν. Όταν ξεκινά το παιχνίδι, το στοιχείο script * διευθύνει * το sprite στοιχείο από το αναγνωριστικό του “body” και χρησιμοποιεί αυτή τη διεύθυνση για να του στείλει ένα * μήνυμα * με το “disable”. Το αποτέλεσμα αυτού του ειδικού μηνύματος της μηχανής είναι ότι το στοιχείο sprite κρύβει τα γραφικά sprite. Σχηματικά, η εγκατάσταση μοιάζει με αυτήν:
Τα αναγνωριστικά στη ρύθμιση είναι αυθαίρετα. Εδώ επιλέξαμε να δώσουμε στο αντικείμενο του παιχνιδιού το αναγνωριστικό “bean”, το sprite συστατικό του έχει ονομαστεί “body” και το στοιχείο script που ελέγχει τον χαρακτήρα ονομάστηκε “controller”.
Εάν δεν επιλέξετε όνομα, ο κειμενογράφος θα το κάνει. Κάθε φορά που δημιουργείτε ένα νέο αντικείμενο παιχνιδιού ή στοιχείο στο πρόγραμμα επεξεργασίας, ορίζεται αυτόματα μια μοναδική ιδιότητα * Id *.
Μπορείτε να διατηρήσετε αυτά τα αυτόματα εκχωρημένα ονόματα εάν θέλετε, αλλά σας προτείνουμε να αλλάξετε τα αναγνωριστικά σε καλά, περιγραφικά ονόματα.
Τώρα, ας προσθέσουμε ένα άλλο συστατικό sprite και δώστε στο φασόλι μια ασπίδα:
Το νέο στοιχείο πρέπει να αναγνωριστεί με μοναδικό τρόπο στο αντικείμενο του παιχνιδιού. Εάν του δώσατε το όνομα “body”, ο κωδικός script θα ήταν ασαφής ως προς το sprite που θα έπρεπε να στείλει το μήνυμα “disable”. Επομένως επιλέγουμε το μοναδικό (και περιγραφικό) αναγνωριστικό “ασπίδα”. Τώρα μπορούμε να ενεργοποιήσουμε και να απενεργοποιήσουμε τα sprites “body” και “shield” κατά βούληση.
Εάν προσπαθήσετε να χρησιμοποιήσετε ένα αναγνωριστικό περισσότερες από μία φορές, ο επεξεργαστής θα επισημάνει ένα σφάλμα, οπότε αυτό δεν είναι ποτέ πρόβλημα στην πράξη:
Τώρα, ας δούμε τι θα συμβεί αν προσθέσετε περισσότερα αντικείμενα παιχνιδιού. Ας υποθέσουμε ότι θέλετε να συνδυάσετε δύο “φασόλια” σε μια μικρή ομάδα. Αποφασίζετε να καλέσετε ένα από τα αντικείμενα του παιχνιδιού φασολιών “bean” και το άλλο “buddy”. Επιπλέον, όταν το “bean” είναι αδρανές για λίγο, θα πρέπει να πει στον “φίλο” να αρχίσει να χορεύει. Αυτό γίνεται αποστέλλοντας ένα προσαρμοσμένο μήνυμα που ονομάζεται “dance” από το στοιχείο script “controller”(ελεγκτής) στο “bean” στο script “controller”(ελεγκτής) στο “buddy”:
Υπάρχουν δύο ξεχωριστά συστατικά που ονομάζονται “controller”(ελεγκτής), ένα σε κάθε αντικείμενο παιχνιδιού, αλλά αυτό είναι απολύτως νόμιμο, καθώς κάθε αντικείμενο παιχνιδιού δημιουργεί ένα νέο πλαίσιο ονομασίας.
Εφόσον ο παραλήπτης του μηνύματος βρίσκεται εκτός του αντικειμένου παιχνιδιού που στέλνει το μήνυμα (“bean”), ο κωδικός πρέπει να καθορίσει ποιος “controller”(ελεγκτής) πρέπει να λάβει το μήνυμα. Πρέπει να καθορίσει τόσο το αναγνωριστικό αντικειμένου παιχνιδιού στόχου όσο και το αναγνωριστικό id. Η πλήρης διεύθυνση στο στοιχείο γίνεται "buddy#controller"
και αυτή η διεύθυνση αποτελείται από δύο ξεχωριστά μέρη.
Επιστρέφοντας στο προηγούμενο παράδειγμα με ένα αντικείμενο παιχνιδιού, βλέπουμε ότι αφήνοντας το αναγνωριστικό αντικειμένου παιχνιδιού μέρος της διεύθυνση προορισμού, ο κώδικας μπορεί να απευθύνεται σε στοιχεία στο * τρέχον αντικείμενο παιχνιδιού *.
Για παράδειγμα, το “#body” “δηλώνει τη διεύθυνση στο στοιχείο “body” στο τρέχον αντικείμενο παιχνιδιού. Αυτό είναι πολύ χρήσιμο επειδή αυτός ο κώδικας θα λειτουργήσει σε * οποιοδήποτε * αντικείμενο παιχνιδιού, αρκεί να υπάρχει ένα στοιχείο “body”.
Οι συλλογές καθιστούν δυνατή τη δημιουργία ομάδων ή ιεραρχιών αντικειμένων παιχνιδιού και την επαναχρησιμοποίησή τους με ελεγχόμενο τρόπο. Χρησιμοποιείτε αρχεία συλλογής ως templates (ή “πρωτότυπα” ή “προκατασκευασμένα”) στο πρόγραμμα επεξεργασίας όταν συμπληρώνετε το παιχνίδι σας με περιεχόμενο.
Ας υποθέσουμε ότι θέλετε να δημιουργήσετε έναν μεγάλο αριθμό ομάδων φασολιών / φίλων. Ένας καλός τρόπος για να το κάνετε αυτό είναι να δημιουργήσετε ένα πρότυπο template σε ένα νέο * αρχείο συλλογής * (ονομάστε το “team.collection”). Δημιουργήστε τα ομαδικά αντικείμενα παιχνιδιού στο αρχείο συλλογής και αποθηκεύστε το. Στη συνέχεια, τοποθετήστε μια οντότητα instance του περιεχομένου αυτού του αρχείου συλλογής στην κύρια συλλογή bootstrap και δώστε στην οντότητα instance ένα αναγνωριστικό (ονομάστε το “team_1”):
Με αυτήν τη δομή, το αντικείμενο παιχνιδιού “bean” μπορεί ακόμα να αναφέρεται στο στοιχείο “ελεγκτή” στο “buddy” με τη διεύθυνση "buddy#controller"
.
Και αν προσθέσετε μια δεύτερη οντότητα instance του “team.collection” (ονομάστε το “team_2”), ο κώδικας που εκτελείται μέσα στα στοιχεία του σεναρίου “team_2” θα λειτουργήσει εξίσου καλά. Η οντότητα instance αντικειμένου παιχνιδιού “bean” από τη συλλογή “team_2” μπορεί ακόμα να αντιμετωπίσει το στοιχείο “ελεγκτή” στο “buddy” με τη διεύθυνση "buddy#controller"
.
Η διεύθυνση "buddy#controller"
“λειτουργεί για τα αντικείμενα του παιχνιδιού και στις δύο συλλογές, επειδή είναι * σχετική * διεύθυνση. Κάθε μία από τις συλλογές “team_1” και “team_2” δημιουργεί ένα νέο πλαίσιο ονομάτων ή “namespace” εάν θέλετε. Το Defold αποφεύγει την ονομασία συγκρούσεων λαμβάνοντας υπόψη το πλαίσιο ονομάτων που δημιουργεί μια συλλογή για να αντιμετωπίσει:
Η σχετική διευθυνσιοδότηση λειτουργεί προπαρασκευάζοντας αυτόματα το τρέχον πλαίσιο ονομάτων κατά την επίλυση μιας διεύθυνσης προορισμού. Αυτό είναι πάλι εξαιρετικά χρήσιμο και ισχυρό, επειδή μπορείτε να δημιουργήσετε ομάδες αντικειμένων παιχνιδιού με κώδικα και να τα επαναχρησιμοποιήσετε αποτελεσματικά σε όλο το παιχνίδι.
Το Defold παρέχει δύο εύχρηστες στενογραφίες που μπορείτε να χρησιμοποιήσετε για να στείλετε μήνυμα χωρίς να καθορίσετε μια πλήρη διεύθυνση URL:
.
#
For example:
-- Let this game object acquire input focus
msg.post(".", "acquire_input_focus")
-- Post "reset" to the current script
msg.post("#", "reset")
Για να κατανοήσουμε σωστά το μηχανισμό ονομασίας, ας δούμε τι συμβαίνει όταν δημιουργείτε και εκτελείτε το project:
Οι ταυτότητες αποθηκεύονται ως hashed (κατακερματισμένες) τιμές. Ο χρόνος εκτέλεσης αποθηκεύει επίσης την κατάσταση hash (κατακερματισμού) για κάθε ταυτότητα συλλογής που χρησιμοποιείται, για τη συνέχιση hashing (κατακερματισμού) σχετικής συμβολοσειράς σε απόλυτο αναγνωριστικό.
Στο χρόνο εκτέλεσης, η ομαδοποίηση συλλογών δεν υπάρχει. Δεν υπάρχει τρόπος να μάθετε σε ποια συλλογή ανήκε ένα συγκεκριμένο αντικείμενο παιχνιδιού πριν από την εκτέλση . Ούτε είναι δυνατό να χειριστείτε όλα τα αντικείμενα σε μια συλλογή ταυτόχρονα. Εάν πρέπει να κάνετε τέτοιες λειτουργίες, μπορείτε εύκολα να κάνετε την παρακολούθηση μόνοι σας σε κώδικα. Το αναγνωριστικό κάθε αντικειμένου είναι στατικό, είναι εγγυημένο ότι θα παραμείνει σταθερό καθ ‘όλη τη διάρκεια ζωής του αντικειμένου. Αυτό σημαίνει ότι μπορείτε να αποθηκεύσετε με ασφάλεια την ταυτότητα ενός αντικειμένου και να το χρησιμοποιήσετε αργότερα.
Είναι δυνατό να χρησιμοποιήσετε τα πλήρη αναγνωριστικά που περιγράφονται παραπάνω κατά τη διεύθυνση. Στις περισσότερες περιπτώσεις προτιμάται η σχετική διευθυνσιοδότηση, δεδομένου ότι επιτρέπει την επαναχρησιμοποίηση περιεχομένου, αλλά υπάρχουν περιπτώσεις όπου η απόλυτη διευθέτηση καθίσταται απαραίτητη.
Για παράδειγμα, ας υποθέσουμε ότι θέλετε έναν διαχειριστή AI που παρακολουθεί την κατάσταση κάθε αντικειμένου φασολιών. Θέλετε τα φασόλια να αναφέρουν την ενεργή κατάστασή τους στον διαχειριστή και ο διαχειριστής λαμβάνει τακτικές αποφάσεις και δίνει εντολές στα φασόλια με βάση την κατάστασή τους. Θα ήταν απολύτως λογικό σε αυτήν την περίπτωση να δημιουργηθεί ένα αντικείμενο παιχνιδιού με έναν διαχειριστή και να το τοποθετήσετε μαζί με τις συλλογές της ομάδας στη συλλογή bootstrap.
Στη συνέχεια, κάθε φασόλι είναι υπεύθυνο για την αποστολή μηνυμάτων κατάστασης στον διαχειριστή: “επικοινωνήστε” εάν εντοπίσετε έναν εχθρό ή “ωχ!” εάν χτυπηθεί και πάθει ζημιά. Για να λειτουργήσει αυτό, τα scrips του φασολιού χρησιμοποιούν απόλυτη διεύθυνση για να στέλνουν μηνύματα στο στοιχείο “ελεγκτής” στο “manager”.
Κάθε διεύθυνση που ξεκινά με ‘/’ θα επιλυθεί από τη ρίζα του κόσμου του παιχνιδιού. Αυτό αντιστοιχεί στη ρίζα της συλλογής bootstrap collection που φορτώνεται κατά την έναρξη του παιχνιδιού.
Η απόλυτη διεύθυνση του σεναρίου διαχειριστή είναι "/manager#controller"
και αυτή η απόλυτη διεύθυνση θα επιλυθεί στο σωστό στοιχείο ανεξάρτητα από το πού χρησιμοποιείται.
Η μηχανή αποθηκεύει όλα τα αναγνωριστικά ως hashed (κατακερματισμένες) τιμές. Όλες οι functions (συναρτήσεις) που λαμβάνουν ως όρισμα ένα στοιχείο ή ένα αντικείμενο παιχνιδιού δέχονται μια συμβολοσειρά, κατακερματισμό hash ή αντικείμενο URL. Έχουμε δει πώς να χρησιμοποιούμε συμβολοσειρές για την διεύνθυνση παραπάνω.
Όταν λάβετε το αναγνωριστικό ενός αντικειμένου παιχνιδιού, η μνχανή θα επιστρέφει πάντα ένα απόλυτο αναγνωριστικό διαδρομής που έχει hashed (κατακερματιστεί):
local my_id = go.get_id()
print(my_id) --> hash: [/path/to/the/object]
local spawned_id = factory.create("#some_factory")
print(spawned_id) --> hash: [/instance42]
Μπορείτε να χρησιμοποιήσετε ένα τέτοιο αναγνωριστικό στη θέση ενός αναγνωριστικού συμβολοσειράς ή να δημιουργήσετε ένα μόνοι σας. Λάβετε υπόψη ότι ένα κατακερματισμένο αναγνωριστικό αντιστοιχεί στη διαδρομή προς το αντικείμενο, δηλαδή σε απόλυτη διεύθυνση:
Ο λόγος για τον οποίο οι σχετικές διευθύνσεις πρέπει να δοθούν ως strings (συμβολοσειρές) είναι επειδή η μηχανή θα υπολογίσει ένα νέο αναγνωριστικό κατακερματισμού βάσει της κατάστασης κατακερματισμού του τρέχοντος περιβάλλοντος ονομασίας (συλλογή) με τη δεδομένη συμβολοσειρά να προστεθεί στο hash.
local spawned_id = factory.create("#some_factory")
local pos = vmath.vector3(100, 100, 0)
go.set_position(pos, spawned_id)
local other_id = hash("/path/to/the/object")
go.set_position(pos, other_id)
-- This will not work! Relative addresses must be given as strings.
local relative_id = hash("my_object")
go.set_position(pos, relative_id)
Για να ολοκληρώσετε την εικόνα, ας δούμε την πλήρη μορφή των διευθύνσεων του Defold: τη διεύθυνση URL.
Η διεύθυνση URL είναι ένα αντικείμενο, συνήθως γραμμένο με ειδικά διαμορφωμένων συμβολοσειρών. Ένα γενικό URL αποτελείται από τρία μέρη:
[socket:][path][#fragment]
Όπως έχουμε δει παραπάνω, μπορείτε να αφήσετε μερικές ή περισσότερες από αυτές τις πληροφορίες στις περισσότερες περιπτώσεις. Σχεδόν ποτέ δεν χρειάζεται να καθορίσετε την υποδοχή, και συχνά, αλλά όχι πάντα, πρέπει να καθορίσετε τη διαδρομή. Σε αυτές τις περιπτώσεις όταν πρέπει να αντιμετωπίσετε πράγματα σε έναν άλλο κόσμο παιχνιδιού, τότε πρέπει να καθορίσετε το τμήμα υποδοχής του URL. Για παράδειγμα, η πλήρης συμβολοσειρά URL για το σενάριο “ελεγκτής” στο αντικείμενο παιχνιδιού “διαχειριστής” παραπάνω είναι:
"main:/manager#controller"
και ο ελεγκτής φίλων στην ομάδα_2 είναι:
"main:/team_2/buddy#controller"
Μπορούμε να τους στείλουμε μηνύματα:
-- Send "hello" to the manager script and team buddy bean
msg.post("main:/manager#controller", "hello_manager")
msg.post("main:/team_2/buddy#controller", "hello_buddy")
Τα αντικείμενα URL μπορούν επίσης να κατασκευαστούν μέσω προγραμματισμού σε κώδικα Lua:
-- Construct URL object from a string:
local my_url = msg.url("main:/manager#controller")
print(my_url) --> url: [main:/manager#controller]
print(my_url.socket) --> 786443 (internal numeric value)
print(my_url.path) --> hash: [/manager]
print(my_url.fragment) --> hash: [controller]
-- Construct URL from parameters:
local my_url = msg.url("main", "/manager", "controller")
print(my_url) --> url: [main:/manager#controller]
-- Build from empty URL object:
local my_url = msg.url()
my_url.socket = "main" -- specify by valid name
my_url.path = hash("/manager") -- specify as string or hash
my_url.fragment = "controller" -- specify as string or hash
-- Post to target specified by URL
msg.post(my_url, "hello_manager!")
Did you spot an error or do you have a suggestion? Please let us know on GitHub!
GITHUB