תכנות לילדים באמצעות Game Maker/a first person shooter/צעד 5: יריות

מתוך ויקיספר, אוסף הספרים והמדריכים החופשי

בגלל שהגדרנו את המשחק בתור משחק יריות מגוף ראשון, כדאי שנוסיף את האפשרות לירות. אבל כדי לבחון את היריות אנחנו צריכים משהו שאפשר לירות בו. לכן נתחיל בהוספת חביות שיכולות להתפוצץ.

הוספת חביות[עריכה]

עכשיו תורכם:

הוסיפו אובייקט barrel עם האנימציה של החבית מהאתר הזה (זה אתר של ספרייטים מהמשחק דום שהוא משחק יריות מגוף ראשון פופולרי) ע"י שימוש בשיטה ליצירת אנימציה שלמדנו בצעד הקודם (מומלץ להקטין את מהירות האנימציה למשהו כמו 0.1). כשהחבית נהרסת נוצר במקומה אובייקט חבית מתפוצצת (כדאי להשתמש באנימציה מהדף השני של אותו אתר שנפתח כשלוחצים על רובה הציד שבראש הדף אבל להקטין קצת את המהירות), שנעלם כשהאנימציה שלו נפסקת. כדאי לשים אירוע לחיצה על מקש שבו החביות יהרסו כדי לבדוק את הפיצוץ, אבל אל תשכחו להוריד את האירוע אחרי זה.

תוספת נחמדה לאובייקט הפיצוץ תהיה להוסיף לאירוע הציור שלו את השורה הבאה:

draw_set_alpha(1-0.05*image_index);

לפני הפקודה של ציור הקיר - ככה הפיצוץ ילך ויעשה שקוף יותר (זה נראה כאילו הוא דועך) ככל שמתקדמים באנימציה. אבל אל תשכחו לכתוב אחרי הפקודה של ציור הקיר draw_set_alpha(1) אחרי ציור הקיר כדי שאובייקטים שמצוירים אחר כך לא יראו שקופים גם הם. תשנו גם את ה-depth למספר נמוך כדי שהשקיפות תעבוד כמו שהסברנו בפרק הקודם.



נסו את המשחק ותראו אם צריך לדעתכם לשנות את מהירויות האנימציה או מהירות הדעיכה של הפיצוץ.




הרובה[עריכה]

במשחקי יריות מגוף ראשון השחקן נושא את הנשק שלו לכל מקום ותמיד רואים אותו מלפניו. אבל אנחנו לא באמת צריכים לתכנת שהרובה יעקוב אחרי השחקן. כמעט בכל משחקי היריות מגוף ראשון הרובה הוא בעצם ציור דו מימדי שמצויר מעל הציור התלת מימדי של המסך. אז ננסה לקחת את הספרייט של רובה הציד מראש העמוד הזה (כדאי להגדיל אותו בערך פי 2 בעריכת הספרייטים), ואז ליצור אובייקט רובה (כרגע תעשו את מהירות האנימציה 0 כדי שיראו רק את הרובה ולא את אנימציית הירייה והטעינה) שמצייר את התת תמונה הנוכחית של הספרייט בעזרת הפעולה לציור ספרייט. המיקום הכי טוב לדעתי עבור הרובה הוא x=0 כי הספרייט שלו ארוך וב-x של 0 הוא נראה באמצע המסך, ו y=224 כי כשמוסיפים את גובה הספרייט הוא יוצא ממש בתחתית של המסך.


מה רואים?



הרובה לא נמצא מעל העולם התלת מימדי אלא נראה כאילו הוא במקום מסוים בתוכו. הסיבה היא שבמצב תלת מימדי הגיים מייקר מנסה להחיל הקרנה פרספקטיבית (דברים רחוקים יותר נראים קטנים יותר) והסרת משטחים נסתרים (דברים קרובים מסתירים דברים רחוקים) גם על פעולות הציור הדו מימדיות. זה יכול להיות שימושי לפעמים אבל במקרה שלנו אנחנו רוצים לבטל את האפשרויות האלו זמנית. למזלנו יש פונקציות שמיועדות בדיוק בשביל זה. כדי לבטל את הסרת המשטחים הנסתרים צריך רק לכתוב d3d_set_hidden(false) (מי שזוכר זאת אותה פונקציה שהשתמשנו בה בצעד 2 כדי להתחיל את הסרת המשטחים הנסתרים אבל אז כתבנו true), וכדי שהסרת המשטחים תעבוד עבור האובייקטים האחרים צריך להדליק אותה חזרה אחרי פעולת הציור. במקרה של ההקרנה הפרספקטיבית זה קצת יותר מסובך, אבל גם יש פונקציה שמתאימה בדיוק למה שאנחנו רוצים, שהיא הפונקציה d3d_set_projection_ortho, שמאפשרת לצייר בהקרנה אורתוגראפית (ההפך מפרספקטיבית) באיזור מסוים בחדר שנקבע ע"י הפרמטרים. במקרה שלנו אנחנו צריכים לכתוב d3d_set_projection_ortho(0,0,640,480,0) לפני פעולת הציור כדי שנוכל לצייר על איזור שהמיקום שלו הוא (0,0) (זה מה שהפרמטר הראשון והשני קובעים - את ה-x וה-y), הגודל שלו זהה לזה של המסך (הפרמטר השלישי והרביעי), ובלי זווית סיבוב (הפרמטר האחרון). חוץ ממה שעשינו אנחנו צריכים גם לוודא שהרובה מצויר אחרון, גם אחרי האובייקטים החצי שקופים, כדי שהגיים מייקר לא ינסה לצייר דברים מעליו. כדי לעשות את זה אנחנו צריכים לתת לו עומק נמוך במיוחד ולוודא שהוא יותר נמוך מהעומקים של כל האובייקטים האחרים.


הרובה שלנו לא יכול לירות אבל עכשיו הוא לפחות נראה כאילו הוא נישא ע"י הדמות.




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

יריות[עריכה]

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

בשביל לעשות את זה נשתמש במשתנה מצב דומה לזה שהשתמשנו בחייזרים - can_shoot, ונאתחל אותו לאחד באירוע היצירה של הרובה. עכשיו נוסיף אירוע לחיצה על רווח באובייקט הרובה, ובו נשים בדיקה אם can_shoot שווה לאחד ואם כן נהפוך את image_speed למספר שהוא לא אפס (תשחקו עם זה קצת כדי לראות מה נראה לכם) כדי להתחיל את אנימציית הירייה, וכדאי גם להשמיע צליל של ירייה (אל תשכחו לקבץ את שתי הפעולות בבלוק). כדי לתת לשחקן לירות שוב כשהאנימציה נגמרת נשתמש באירוע Animation end (סוף האנימציה) שגם עליו למדנו בחייזרים ובו נפסיק את האנימציה (נהפוך את image_speed וגם את image_index לאפס) ונחזיר את can_shoot לאחד שוב.



עכשיו הרובה נראה כאילו הוא יורה אבל לא הורס כלום.




עכשיו צריך לתכנת גם את החישוב של הירייה עצמו, ובשביל זה נשתמש בקוד הבא שנשים באירוע הלחיצה על רווח של הרובה (לא לשכוח לשים את פעולת הקוד בתוך הבדיקה אם אפשר לירות!):

var xx, yy, dx, dy, ii;
xx = obj_player.x;
yy = obj_player.y;
dx = 4*cos(obj_player.direction*pi/180);
dy = -4*sin(obj_player.direction*pi/180);
repeat (100)
{
xx += dx;
yy += dy;
ii = instance_position(xx,yy,obj_wall_basic);
if (ii == noone) continue;
if (ii.object_index == obj_barrel)
with (ii) instance_destroy();
break;
}

הקוד הזה עובד בעזרת "התקדמות" בצעדים קטנים ובדיקה כל פעם אם הכדור פוגע במשהו. נעבור עליו שורה שורה: קודם כל אתחול המשתנים. המשתנים xx ו-yy מייצגים את המיקום הנוכחי שאנחנו בודקים בו, והם מאותחלים למיקום השחקן. dx ו-dy מייצגים כמה צריך להוסיף ל-x וכמה ל-y בכל צעד כדי להתקדם צעד אחד בכיוון שהשחקן מסתכל אליו והם מחושבים ע"י טריגונומטריה. אחרי זה אנחנו מגיעים ללולאה. בכל סיבוב של הלולאה אנחנו קודם כל מעלים את xx ו-yy בערכים המתאימים כדי להתקדם צעד. אחר כך אנחנו משתמשים בפונקציה instance_position שבודקת אם יש אובייקט שיורש מהקיר הבסיסי במיקום הנוכחי שלנו, אם כן היא מחזירה את המספר המזהה שלו ואם לא היא מחזירה noone. את מה שהיא מחזירה אנחנו מציבים במשתנה ii. בשורה אחר כך אנחנו בודקים אם לא היה קיר (והפונקציה החזירה noone) ואם כן אנחנו משתמשים במילה continue כדי לדלג על שאר הפקודות ולעבור לסיבוב הבא. אחר כך אנחנו בודקים אם סוג האובייקט (object_index) של המופע שמצאנו הוא חבית. אם כן אנחנו הורסים אותו (לולאת ה-with מאפשרת לנו להשתמש בפקודה ביחס אליו כמו שלמדנו בטטריס) ובסוף אנחנו שמנו את הפקודה ליציאה מהלולאה כי אם הגענו לשם סימן שכבר התנגשנו במשהו ואין טעם להמשיך עם הלולאה.

תכנתנו משהו מסובך ולכן חשוב לבדוק אותו.



אם הכל עובד כמו שצריך אתה אמור להיות מסוגל לפוצץ את החביות.