You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Web-Dev-For-Beginners/translations/el/6-space-game/4-collision-detection/README.md

18 KiB

Δημιουργία ενός Διαστημικού Παιχνιδιού Μέρος 4: Προσθήκη Λέιζερ και Ανίχνευση Συγκρούσεων

Κουίζ πριν το μάθημα

Κουίζ πριν το μάθημα

Σε αυτό το μάθημα θα μάθετε πώς να πυροβολείτε λέιζερ με JavaScript! Θα προσθέσουμε δύο πράγματα στο παιχνίδι μας:

  • Ένα λέιζερ: αυτό το λέιζερ εκτοξεύεται από το διαστημόπλοιο του ήρωά σας και κινείται κάθετα προς τα πάνω.
  • Ανίχνευση συγκρούσεων, ως μέρος της υλοποίησης της δυνατότητας να πυροβολείτε, θα προσθέσουμε και κάποιους ωραίους κανόνες παιχνιδιού:
    • Το λέιζερ χτυπά εχθρό: Ο εχθρός πεθαίνει αν χτυπηθεί από λέιζερ.
    • Το λέιζερ χτυπά την κορυφή της οθόνης: Το λέιζερ καταστρέφεται αν φτάσει στο πάνω μέρος της οθόνης.
    • Σύγκρουση εχθρού και ήρωα: Ένας εχθρός και ο ήρωας καταστρέφονται αν συγκρουστούν.
    • Ο εχθρός φτάνει στο κάτω μέρος της οθόνης: Ένας εχθρός και ο ήρωας καταστρέφονται αν ο εχθρός φτάσει στο κάτω μέρος της οθόνης.

Με λίγα λόγια, εσείς -- ο ήρωας -- πρέπει να χτυπήσετε όλους τους εχθρούς με λέιζερ πριν καταφέρουν να φτάσουν στο κάτω μέρος της οθόνης.

Κάντε μια μικρή έρευνα για το πρώτο παιχνίδι υπολογιστή που γράφτηκε ποτέ. Ποια ήταν η λειτουργικότητά του;

Ας γίνουμε ήρωες μαζί!

Ανίχνευση συγκρούσεων

Πώς κάνουμε ανίχνευση συγκρούσεων; Πρέπει να σκεφτούμε τα αντικείμενα του παιχνιδιού μας ως ορθογώνια που κινούνται. Γιατί αυτό, μπορεί να ρωτήσετε; Λοιπόν, η εικόνα που χρησιμοποιείται για να σχεδιάσει ένα αντικείμενο παιχνιδιού είναι ένα ορθογώνιο: έχει x, y, πλάτος και ύψος.

Αν δύο ορθογώνια, δηλαδή ένας ήρωας και ένας εχθρός, τέμνονται, έχουμε μια σύγκρουση. Τι πρέπει να συμβεί τότε εξαρτάται από τους κανόνες του παιχνιδιού. Για να υλοποιήσετε την ανίχνευση συγκρούσεων χρειάζεστε τα εξής:

  1. Έναν τρόπο να αποκτήσετε μια ορθογώνια αναπαράσταση ενός αντικειμένου παιχνιδιού, κάτι σαν αυτό:

    rectFromGameObject() {
      return {
        top: this.y,
        left: this.x,
        bottom: this.y + this.height,
        right: this.x + this.width
      }
    }
    
  2. Μια συνάρτηση σύγκρισης, η οποία μπορεί να μοιάζει κάπως έτσι:

    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);

Πώς πυροβολούμε ένα λέιζερ

Το να πυροβολήσετε ένα λέιζερ μεταφράζεται σε απόκριση σε ένα γεγονός πλήκτρου και δημιουργία ενός αντικειμένου που κινείται προς μια συγκεκριμένη κατεύθυνση. Πρέπει λοιπόν να εκτελέσουμε τα εξής βήματα:

  1. Δημιουργία ενός αντικειμένου λέιζερ: από την κορυφή του διαστημοπλοίου του ήρωά μας, το οποίο μόλις δημιουργηθεί αρχίζει να κινείται προς τα πάνω προς την κορυφή της οθόνης.
  2. Σύνδεση κώδικα σε ένα γεγονός πλήκτρου: πρέπει να επιλέξουμε ένα πλήκτρο στο πληκτρολόγιο που να αντιπροσωπεύει τον παίκτη που πυροβολεί το λέιζερ.
  3. Δημιουργία ενός αντικειμένου παιχνιδιού που μοιάζει με λέιζερ όταν πατηθεί το πλήκτρο.

Χρονική καθυστέρηση στο λέιζερ

Το λέιζερ πρέπει να πυροβολεί κάθε φορά που πατάτε ένα πλήκτρο, όπως το 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 της σειράς διαστημικών παιχνιδιών για να θυμηθείτε τις χρονικές καθυστερήσεις.

Τι να δημιουργήσετε

Θα πάρετε τον υπάρχοντα κώδικα (τον οποίο θα έπρεπε να έχετε καθαρίσει και αναδιαρθρώσει) από το προηγούμενο μάθημα και θα τον επεκτείνετε. Ξεκινήστε είτε με τον κώδικα από το μέρος ΙΙ είτε χρησιμοποιήστε τον κώδικα στο Μέρος ΙΙΙ - αρχικό.

συμβουλή: το λέιζερ με το οποίο θα δουλέψετε βρίσκεται ήδη στον φάκελο των πόρων σας και αναφέρεται στον κώδικά σας

  • Προσθέστε ανίχνευση συγκρούσεων, όταν ένα λέιζερ συγκρούεται με κάτι, οι παρακάτω κανόνες πρέπει να ισχύουν:
    1. Το λέιζερ χτυπά εχθρό: ο εχθρός πεθαίνει αν χτυπηθεί από λέιζερ.
    2. Το λέιζερ χτυπά την κορυφή της οθόνης: Το λέιζερ καταστρέφεται αν φτάσει στο πάνω μέρος της οθόνης.
    3. Σύγκρουση εχθρού και ήρωα: ένας εχθρός και ο ήρωας καταστρέφονται αν συγκρουστούν.
    4. Ο εχθρός φτάνει στο κάτω μέρος της οθόνης: Ένας εχθρός και ο ήρωας καταστρέφονται αν ο εχθρός φτάσει στο κάτω μέρος της οθόνης.

Προτεινόμενα βήματα

Βρείτε τα αρχεία που έχουν δημιουργηθεί για εσάς στον υποφάκελο 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. Ανοίξτε έναν περιηγητή και εισάγετε αυτή τη διεύθυνση, αυτή τη στιγμή θα πρέπει να εμφανίζει τον ήρωα και όλους τους εχθρούς, τίποτα δεν κινείται - ακόμα :).

Προσθήκη κώδικα

  1. Ρυθμίστε μια ορθογώνια αναπαράσταση του αντικειμένου παιχνιδιού σας για να χειριστείτε συγκρούσεις Ο παρακάτω κώδικας σας επιτρέπει να αποκτήσετε μια ορθογώνια αναπαράσταση ενός GameObject. Επεξεργαστείτε την κλάση GameObject για να την επεκτείνετε:

    rectFromGameObject() {
        return {
          top: this.y,
          left: this.x,
          bottom: this.y + this.height,
          right: this.x + this.width,
        };
      }
    
  2. Προσθέστε κώδικα που ελέγχει συγκρούσεις Αυτή θα είναι μια νέα συνάρτηση που ελέγχει αν δύο ορθογώνια τέμνονται:

    function intersectRect(r1, r2) {
      return !(
        r2.left > r1.right ||
        r2.right < r1.left ||
        r2.top > r1.bottom ||
        r2.bottom < r1.top
      );
    }
    
  3. Προσθέστε δυνατότητα πυροβολισμού λέιζερ

    1. Προσθέστε μήνυμα γεγονότος πλήκτρου. Το πλήκτρο space πρέπει να δημιουργεί ένα λέιζερ ακριβώς πάνω από το διαστημόπλοιο του ήρωα. Προσθέστε τρεις σταθερές στο αντικείμενο Messages:

       KEY_EVENT_SPACE: "KEY_EVENT_SPACE",
       COLLISION_ENEMY_LASER: "COLLISION_ENEMY_LASER",
       COLLISION_ENEMY_HERO: "COLLISION_ENEMY_HERO",
      
    2. Χειριστείτε το πλήκτρο space. Επεξεργαστείτε τη συνάρτηση window.addEventListener keyup για να χειριστείτε το πλήκτρο space:

        } else if(evt.keyCode === 32) {
          eventEmitter.emit(Messages.KEY_EVENT_SPACE);
        }
      
    3. Προσθέστε 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;
      })
      
    4. Μετακινήστε το αντικείμενο, Διασφαλίστε ότι το λέιζερ κινείται σταδιακά προς την κορυφή της οθόνης. Θα δημιουργήσετε μια νέα κλάση 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)
        }
      }
      
    5. Χειριστείτε συγκρούσεις, Υλοποιήστε τους κανόνες συγκρούσεων για το λέιζερ. Προσθέστε μια συνάρτηση 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.

    6. Υλοποιήστε χρονική καθυστέρηση στο λέιζερ, ώστε να μπορεί να πυροβολείται μόνο σε συγκεκριμένα διαστήματα.

      Τέλος, επεξεργαστείτε την κλάση 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 repo και προσπαθήστε να προσθέσετε μια έκρηξη όταν το λέιζερ χτυπά έναν εξωγήινο.

Κουίζ μετά το μάθημα

Κουίζ μετά το μάθημα

Ανασκόπηση & Αυτομελέτη

Πειραματιστείτε με τα διαστήματα στο παιχνίδι σας μέχρι τώρα. Τι συμβαίνει όταν τα αλλάζετε; Διαβάστε περισσότερα για τα γεγονότα χρονισμού της JavaScript.

Εργασία

Εξερευνήστε τις συγκρούσεις


Αποποίηση ευθύνης:
Αυτό το έγγραφο έχει μεταφραστεί χρησιμοποιώντας την υπηρεσία αυτόματης μετάφρασης AI Co-op Translator. Παρόλο που καταβάλλουμε προσπάθειες για ακρίβεια, παρακαλούμε να έχετε υπόψη ότι οι αυτόματες μεταφράσεις ενδέχεται να περιέχουν σφάλματα ή ανακρίβειες. Το πρωτότυπο έγγραφο στη μητρική του γλώσσα θα πρέπει να θεωρείται η αυθεντική πηγή. Για κρίσιμες πληροφορίες, συνιστάται επαγγελματική ανθρώπινη μετάφραση. Δεν φέρουμε ευθύνη για τυχόν παρεξηγήσεις ή εσφαλμένες ερμηνείες που προκύπτουν από τη χρήση αυτής της μετάφρασης.