|
3 weeks ago | |
---|---|---|
.. | ||
solution | 4 weeks ago | |
your-work | 4 weeks ago | |
README.md | 3 weeks ago | |
assignment.md | 4 weeks ago |
README.md
Δημιουργία Παιχνιδιού Διαστήματος Μέρος 4: Προσθήκη Λέιζερ και Ανίχνευση Συγκρούσεων
Κουίζ Πριν το Μάθημα
Σε αυτό το μάθημα θα μάθετε πώς να πυροβολείτε λέιζερ με JavaScript! Θα προσθέσουμε δύο πράγματα στο παιχνίδι μας:
- Ένα λέιζερ: αυτό το λέιζερ εκτοξεύεται από το διαστημόπλοιο του ήρωά σας και κινείται κάθετα προς τα πάνω.
- Ανίχνευση συγκρούσεων, ως μέρος της υλοποίησης της δυνατότητας να πυροβολείτε, θα προσθέσουμε και κάποιους ωραίους κανόνες παιχνιδιού:
- Το λέιζερ χτυπάει εχθρό: Ο εχθρός πεθαίνει αν χτυπηθεί από λέιζερ.
- Το λέιζερ χτυπάει την κορυφή της οθόνης: Το λέιζερ καταστρέφεται αν φτάσει στην κορυφή της οθόνης.
- Σύγκρουση εχθρού και ήρωα: Εχθρός και ήρωας καταστρέφονται αν συγκρουστούν.
- Ο εχθρός φτάνει στο κάτω μέρος της οθόνης: Εχθρός και ήρωας καταστρέφονται αν ο εχθρός φτάσει στο κάτω μέρος της οθόνης.
Με λίγα λόγια, εσείς -- ο ήρωας -- πρέπει να χτυπήσετε όλους τους εχθρούς με λέιζερ πριν καταφέρουν να φτάσουν στο κάτω μέρος της οθόνης.
✅ Κάντε μια μικρή έρευνα για το πρώτο παιχνίδι υπολογιστή που δημιουργήθηκε ποτέ. Ποια ήταν η λειτουργικότητά του;
Ας γίνουμε ηρωικοί μαζί!
Ανίχνευση Συγκρούσεων
Πώς κάνουμε ανίχνευση συγκρούσεων; Πρέπει να σκεφτούμε τα αντικείμενα του παιχνιδιού μας ως ορθογώνια που κινούνται. Γιατί αυτό, μπορεί να ρωτήσετε; Λοιπόν, η εικόνα που χρησιμοποιείται για να σχεδιάσει ένα αντικείμενο παιχνιδιού είναι ένα ορθογώνιο: έχει x
, y
, πλάτος
και ύψος
.
Αν δύο ορθογώνια, δηλαδή ένας ήρωας και ένας εχθρός, τέμνονται, έχουμε σύγκρουση. Τι πρέπει να συμβεί τότε εξαρτάται από τους κανόνες του παιχνιδιού. Για να υλοποιήσετε την ανίχνευση συγκρούσεων, χρειάζεστε τα εξής:
-
Έναν τρόπο να αποκτήσετε μια ορθογώνια αναπαράσταση ενός αντικειμένου παιχνιδιού, κάτι σαν αυτό:
rectFromGameObject() { return { top: this.y, left: this.x, bottom: this.y + this.height, right: this.x + this.width } }
-
Μια συνάρτηση σύγκρισης, η οποία μπορεί να μοιάζει κάπως έτσι:
function intersectRect(r1, r2) { return !(r2.left > r1.right || r2.right < r1.left || r2.top > r1.bottom || r2.bottom < r1.top); }
Πώς καταστρέφουμε αντικείμενα
Για να καταστρέψετε αντικείμενα σε ένα παιχνίδι, πρέπει να ενημερώσετε το παιχνίδι ότι δεν πρέπει πλέον να σχεδιάζει αυτό το αντικείμενο στον βρόχο του παιχνιδιού που ενεργοποιείται σε ένα συγκεκριμένο διάστημα. Ένας τρόπος να το κάνετε αυτό είναι να χαρακτηρίσετε ένα αντικείμενο παιχνιδιού ως νεκρό όταν συμβεί κάτι, όπως αυτό:
// collision happened
enemy.dead = true
Στη συνέχεια, μπορείτε να φιλτράρετε τα νεκρά αντικείμενα πριν ξανασχεδιάσετε την οθόνη, όπως αυτό:
gameObjects = gameObject.filter(go => !go.dead);
Πώς πυροβολούμε ένα λέιζερ
Το να πυροβολήσετε ένα λέιζερ σημαίνει να ανταποκριθείτε σε ένα γεγονός πλήκτρου και να δημιουργήσετε ένα αντικείμενο που κινείται προς μια συγκεκριμένη κατεύθυνση. Πρέπει λοιπόν να εκτελέσουμε τα εξής βήματα:
- Δημιουργία ενός αντικειμένου λέιζερ: από την κορυφή του διαστημοπλοίου του ήρωά μας, το οποίο μόλις δημιουργηθεί αρχίζει να κινείται προς τα πάνω.
- Σύνδεση κώδικα σε ένα γεγονός πλήκτρου: πρέπει να επιλέξουμε ένα πλήκτρο στο πληκτρολόγιο που θα αντιπροσωπεύει την ενέργεια του παίκτη να πυροβολήσει το λέιζερ.
- Δημιουργία ενός αντικειμένου παιχνιδιού που μοιάζει με λέιζερ όταν πατηθεί το πλήκτρο.
Χρονικό διάστημα για το λέιζερ
Το λέιζερ πρέπει να πυροβολείται κάθε φορά που πατάτε ένα πλήκτρο, όπως το space για παράδειγμα. Για να αποτρέψουμε το παιχνίδι από το να δημιουργεί πάρα πολλά λέιζερ σε σύντομο χρονικό διάστημα, πρέπει να διορθώσουμε αυτό το πρόβλημα. Η λύση είναι να υλοποιήσουμε ένα λεγόμενο χρονικό διάστημα, έναν χρονοδιακόπτη, που διασφαλίζει ότι ένα λέιζερ μπορεί να πυροβοληθεί μόνο κάθε τόσο. Μπορείτε να το υλοποιήσετε με τον εξής τρόπο:
class Cooldown {
constructor(time) {
this.cool = false;
setTimeout(() => {
this.cool = true;
}, time)
}
}
class Weapon {
constructor {
}
fire() {
if (!this.cooldown || this.cooldown.cool) {
// produce a laser
this.cooldown = new Cooldown(500);
} else {
// do nothing - it hasn't cooled down yet.
}
}
}
✅ Ανατρέξτε στο μάθημα 1 της σειράς παιχνιδιών διαστήματος για να θυμηθείτε τα χρονικά διαστήματα.
Τι να δημιουργήσετε
Θα πάρετε τον υπάρχοντα κώδικα (τον οποίο θα πρέπει να έχετε καθαρίσει και αναδιαρθρώσει) από το προηγούμενο μάθημα και θα τον επεκτείνετε. Ξεκινήστε είτε με τον κώδικα από το μέρος II είτε χρησιμοποιήστε τον κώδικα από το Μέρος III - αρχικό.
συμβουλή: το λέιζερ με το οποίο θα δουλέψετε βρίσκεται ήδη στον φάκελο των πόρων σας και αναφέρεται στον κώδικά σας.
- Προσθέστε ανίχνευση συγκρούσεων, όταν ένα λέιζερ συγκρούεται με κάτι, οι παρακάτω κανόνες πρέπει να ισχύουν:
- Το λέιζερ χτυπάει εχθρό: ο εχθρός πεθαίνει αν χτυπηθεί από λέιζερ.
- Το λέιζερ χτυπάει την κορυφή της οθόνης: Το λέιζερ καταστρέφεται αν φτάσει στην κορυφή της οθόνης.
- Σύγκρουση εχθρού και ήρωα: ένας εχθρός και ο ήρωας καταστρέφονται αν συγκρουστούν.
- Ο εχθρός φτάνει στο κάτω μέρος της οθόνης: ένας εχθρός και ο ήρωας καταστρέφονται αν ο εχθρός φτάσει στο κάτω μέρος της οθόνης.
Προτεινόμενα βήματα
Βρείτε τα αρχεία που έχουν δημιουργηθεί για εσάς στον υποφάκελο your-work
. Θα πρέπει να περιέχει τα εξής:
-| assets
-| enemyShip.png
-| player.png
-| laserRed.png
-| index.html
-| app.js
-| package.json
Ξεκινήστε το πρότζεκτ σας στον φάκελο your_work
πληκτρολογώντας:
cd your-work
npm start
Το παραπάνω θα ξεκινήσει έναν HTTP Server στη διεύθυνση http://localhost:5000
. Ανοίξτε έναν περιηγητή και εισάγετε αυτή τη διεύθυνση. Προς το παρόν, θα πρέπει να εμφανίζεται ο ήρωας και όλοι οι εχθροί, αλλά τίποτα δεν κινείται - ακόμα :).
Προσθέστε κώδικα
-
Ρυθμίστε μια ορθογώνια αναπαράσταση του αντικειμένου παιχνιδιού σας για να χειριστείτε συγκρούσεις. Ο παρακάτω κώδικας σας επιτρέπει να αποκτήσετε μια ορθογώνια αναπαράσταση ενός
GameObject
. Επεξεργαστείτε την κλάση GameObject για να την επεκτείνετε:rectFromGameObject() { return { top: this.y, left: this.x, bottom: this.y + this.height, right: this.x + this.width, }; }
-
Προσθέστε κώδικα που ελέγχει συγκρούσεις. Αυτή θα είναι μια νέα συνάρτηση που ελέγχει αν δύο ορθογώνια τέμνονται:
function intersectRect(r1, r2) { return !( r2.left > r1.right || r2.right < r1.left || r2.top > r1.bottom || r2.bottom < r1.top ); }
-
Προσθέστε δυνατότητα πυροβολισμού λέιζερ
-
Προσθέστε μήνυμα γεγονότος πλήκτρου. Το πλήκτρο space θα πρέπει να δημιουργεί ένα λέιζερ ακριβώς πάνω από το διαστημόπλοιο του ήρωα. Προσθέστε τρεις σταθερές στο αντικείμενο Messages:
KEY_EVENT_SPACE: "KEY_EVENT_SPACE", COLLISION_ENEMY_LASER: "COLLISION_ENEMY_LASER", COLLISION_ENEMY_HERO: "COLLISION_ENEMY_HERO",
-
Χειριστείτε το πλήκτρο space. Επεξεργαστείτε τη συνάρτηση
window.addEventListener
keyup για να χειριστείτε το πλήκτρο space:} else if(evt.keyCode === 32) { eventEmitter.emit(Messages.KEY_EVENT_SPACE); }
-
Προσθέστε listeners. Επεξεργαστείτε τη συνάρτηση
initGame()
για να διασφαλίσετε ότι ο ήρωας μπορεί να πυροβολήσει όταν πατηθεί το πλήκτρο space:eventEmitter.on(Messages.KEY_EVENT_SPACE, () => { if (hero.canFire()) { hero.fire(); }
και προσθέστε μια νέα συνάρτηση
eventEmitter.on()
για να διασφαλίσετε τη συμπεριφορά όταν ένας εχθρός συγκρούεται με ένα λέιζερ:eventEmitter.on(Messages.COLLISION_ENEMY_LASER, (_, { first, second }) => { first.dead = true; second.dead = true; })
-
Κινήστε το αντικείμενο, Διασφαλίστε ότι το λέιζερ κινείται σταδιακά προς την κορυφή της οθόνης. Θα δημιουργήσετε μια νέα κλάση Laser που επεκτείνει το
GameObject
, όπως κάνατε πριν:class Laser extends GameObject { constructor(x, y) { super(x,y); (this.width = 9), (this.height = 33); this.type = 'Laser'; this.img = laserImg; let id = setInterval(() => { if (this.y > 0) { this.y -= 15; } else { this.dead = true; clearInterval(id); } }, 100) } }
-
Χειριστείτε συγκρούσεις, Υλοποιήστε κανόνες συγκρούσεων για το λέιζερ. Προσθέστε μια συνάρτηση
updateGameObjects()
που ελέγχει τα αντικείμενα για συγκρούσεις:function updateGameObjects() { const enemies = gameObjects.filter(go => go.type === 'Enemy'); const lasers = gameObjects.filter((go) => go.type === "Laser"); // laser hit something lasers.forEach((l) => { enemies.forEach((m) => { if (intersectRect(l.rectFromGameObject(), m.rectFromGameObject())) { eventEmitter.emit(Messages.COLLISION_ENEMY_LASER, { first: l, second: m, }); } }); }); gameObjects = gameObjects.filter(go => !go.dead); }
Βεβαιωθείτε ότι προσθέσατε τη
updateGameObjects()
στον βρόχο του παιχνιδιού στοwindow.onload
. -
Υλοποιήστε χρονικό διάστημα για το λέιζερ, ώστε να μπορεί να πυροβολείται μόνο κάθε τόσο.
Τέλος, επεξεργαστείτε την κλάση Hero ώστε να μπορεί να έχει χρονικό διάστημα:
class Hero extends GameObject { constructor(x, y) { super(x, y); (this.width = 99), (this.height = 75); this.type = "Hero"; this.speed = { x: 0, y: 0 }; this.cooldown = 0; } fire() { gameObjects.push(new Laser(this.x + 45, this.y - 10)); this.cooldown = 500; let id = setInterval(() => { if (this.cooldown > 0) { this.cooldown -= 100; } else { clearInterval(id); } }, 200); } canFire() { return this.cooldown === 0; } }
-
Σε αυτό το σημείο, το παιχνίδι σας έχει κάποια λειτουργικότητα! Μπορείτε να πλοηγηθείτε με τα πλήκτρα βελών, να πυροβολήσετε λέιζερ με το πλήκτρο space και οι εχθροί εξαφανίζονται όταν τους χτυπάτε. Μπράβο!
🚀 Πρόκληση
Προσθέστε μια έκρηξη! Ρίξτε μια ματιά στα γραφικά του παιχνιδιού στον φάκελο Space Art και προσπαθήστε να προσθέσετε μια έκρηξη όταν το λέιζερ χτυπάει έναν εξωγήινο.
Κουίζ Μετά το Μάθημα
Ανασκόπηση & Αυτομελέτη
Πειραματιστείτε με τα διαστήματα στο παιχνίδι σας μέχρι τώρα. Τι συμβαίνει όταν τα αλλάζετε; Διαβάστε περισσότερα για τα χρονικά γεγονότα της JavaScript.
Εργασία
Αποποίηση Ευθύνης:
Αυτό το έγγραφο έχει μεταφραστεί χρησιμοποιώντας την υπηρεσία αυτόματης μετάφρασης AI Co-op Translator. Παρόλο που καταβάλλουμε προσπάθειες για ακρίβεια, παρακαλούμε να έχετε υπόψη ότι οι αυτόματες μεταφράσεις ενδέχεται να περιέχουν σφάλματα ή ανακρίβειες. Το πρωτότυπο έγγραφο στη μητρική του γλώσσα θα πρέπει να θεωρείται η αυθεντική πηγή. Για κρίσιμες πληροφορίες, συνιστάται επαγγελματική ανθρώπινη μετάφραση. Δεν φέρουμε ευθύνη για τυχόν παρεξηγήσεις ή εσφαλμένες ερμηνείες που προκύπτουν από τη χρήση αυτής της μετάφρασης.