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/he/6-space-game/4-collision-detection/README.md

13 KiB

בניית משחק חלל חלק 4: הוספת לייזר וזיהוי התנגשויות

שאלון לפני השיעור

שאלון לפני השיעור

בשיעור הזה תלמדו איך לירות לייזרים באמצעות JavaScript! נוסיף שני דברים למשחק שלנו:

  • לייזר: הלייזר נורה מהחללית של הגיבור שלכם כלפי מעלה.
  • זיהוי התנגשויות: כחלק מיישום היכולת לירות, נוסיף גם כמה כללי משחק נחמדים:
    • לייזר פוגע באויב: אויב מת אם לייזר פוגע בו.
    • לייזר פוגע בחלק העליון של המסך: לייזר נהרס אם הוא פוגע בחלק העליון של המסך.
    • התנגשות בין אויב לגיבור: אויב וגיבור נהרסים אם הם מתנגשים זה בזה.
    • אויב פוגע בתחתית המסך: אויב וגיבור נהרסים אם האויב מגיע לתחתית המסך.

בקיצור, אתם -- הגיבור -- צריכים לפגוע בכל האויבים עם לייזר לפני שהם מצליחים להגיע לתחתית המסך.

בצעו מחקר קטן על משחק המחשב הראשון שנכתב אי פעם. מה הייתה הפונקציונליות שלו?

בואו נהיה גיבורים יחד!

זיהוי התנגשויות

איך מבצעים זיהוי התנגשויות? אנחנו צריכים לחשוב על אובייקטי המשחק שלנו כמלבנים שנעים. למה, אתם שואלים? ובכן, התמונה שמשמשת לציור אובייקט משחק היא מלבן: יש לה x, y, width ו-height.

אם שני מלבנים, כלומר גיבור ואויב, מצטלבים, יש לכם התנגשות. מה שצריך לקרות אז תלוי בכללי המשחק. כדי ליישם זיהוי התנגשויות, תצטרכו את הדברים הבאים:

  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. יצירת אובייקט משחק שנראה כמו לייזר כאשר המקש נלחץ.

זמן המתנה ללייזר

הלייזר צריך להיירות בכל פעם שאתם לוחצים על מקש, למשל רווח. כדי למנוע מהמשחק לייצר יותר מדי לייזרים בזמן קצר, נצטרך לתקן זאת. התיקון הוא באמצעות יישום מה שנקרא זמן המתנה, טיימר, שמבטיח שלייזר יוכל להיירות רק בתדירות מסוימת. ניתן ליישם זאת כך:

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.
    }
  }
}

חזרו לשיעור הראשון בסדרת משחק החלל כדי להזכיר לעצמכם את נושא זמן ההמתנה.

מה לבנות

תיקחו את הקוד הקיים (שכבר ניקיתם ושיפרתם) מהשיעור הקודם, ותאריכו אותו. תוכלו להתחיל עם הקוד מחלק II או להשתמש בקוד ב-חלק III - התחלה.

טיפ: הלייזר שתעבדו איתו כבר נמצא בתיקיית הנכסים שלכם ומוזכר בקוד שלכם.

  • הוסיפו זיהוי התנגשויות, כאשר לייזר מתנגש במשהו, הכללים הבאים צריכים לחול:
    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 בכתובת 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. הוסיפו הודעת אירוע מקש. מקש רווח צריך ליצור לייזר ממש מעל החללית של הגיבור. הוסיפו שלוש קבועות לאובייקט Messages:

       KEY_EVENT_SPACE: "KEY_EVENT_SPACE",
       COLLISION_ENEMY_LASER: "COLLISION_ENEMY_LASER",
       COLLISION_ENEMY_HERO: "COLLISION_ENEMY_HERO",
      
    2. טפלו במקש רווח. ערכו את פונקציית window.addEventListener keyup כדי לטפל במקש רווח:

        } else if(evt.keyCode === 32) {
          eventEmitter.emit(Messages.KEY_EVENT_SPACE);
        }
      
    3. הוסיפו מאזינים. ערכו את פונקציית initGame() כדי לוודא שהגיבור יכול לירות כאשר מקש הרווח נלחץ:

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

בשלב הזה, למשחק שלכם יש קצת פונקציונליות! אתם יכולים לנווט עם מקשי החצים, לירות לייזר עם מקש הרווח, ואויבים נעלמים כשאתם פוגעים בהם. כל הכבוד!


🚀 אתגר

הוסיפו פיצוץ! הסתכלו על נכסי המשחק ב-מאגר האמנות של החלל ונסו להוסיף פיצוץ כאשר לייזר פוגע בחייזר.

שאלון אחרי השיעור

שאלון אחרי השיעור

סקירה ולימוד עצמי

נסו לשחק עם המרווחים במשחק שלכם עד כה. מה קורה כשאתם משנים אותם? קראו עוד על אירועי תזמון ב-JavaScript.

משימה

חקירת התנגשויות


כתב ויתור:
מסמך זה תורגם באמצעות שירות תרגום מבוסס בינה מלאכותית Co-op Translator. למרות שאנו שואפים לדיוק, יש לקחת בחשבון שתרגומים אוטומטיים עשויים להכיל שגיאות או אי-דיוקים. המסמך המקורי בשפתו המקורית נחשב למקור הסמכותי. למידע קריטי, מומלץ להשתמש בתרגום מקצועי על ידי בני אדם. איננו נושאים באחריות לכל אי-הבנה או פרשנות שגויה הנובעת משימוש בתרגום זה.