Anonim

AIMBOT 2.0

בפרק 1 של המשחק 2 החדש, בסביבות השעה 9:40, יש זריקה של הקוד שכתב ננה:

הנה זה בטקסט עם התגובות המתורגמות:

// the calculation of damage when attacked void DestructibleActor::ReceiveDamage(float sourceDamage) { // apply debuffs auto resolvedDamage = sourceDamage; for (const auto& debuf:m_debufs) { resolvedDamage = debuf.ApplyToDamage(resolvedDamage); m_currentHealth -= resolvedDamage if (m_currentHealth <= 0.f) { m_currentHealth = 0.f; DestroyMe(); } } } 

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

אני לא ממש מכיר את C ++ אז אני לא בטוח אם מה שהיא אומרת נכון.

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

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

האם למעשה הקוד ייצור לולאה אינסופית?

8
  • כנראה מועיל: צילום מסך נוסף של אומיקו האומר ש"זה היה קורא לאותה פעולה שוב ושוב ", שאולי לא יוצג בקוד.
  • הו! לא ידעתי את זה! @ AkiTanaka המשנה שצפיתי בה אומרת "לולאה אינסופית"
  • @LoganM אני לא ממש מסכים. לא סתם ל- OP יש שאלה לגבי קוד מקור כלשהו שבמקרה הגיע מאנימה; שאלת OP נוגעת להצהרה מסוימת על אודות את קוד המקור לפי דמות באנימה, ויש תשובה הקשורה לאנימה, כלומר "Crunchyroll נעשה מטופש ותורגם באופן שגוי את הקו".
  • @senshin אני חושב שאתה קורא על מה אתה רוצה שהשאלה תהיה, ולא על מה שנשאל בפועל. השאלה מספקת קוד מקור כלשהו ושואלת האם הוא מייצר לולאה אינסופית כקוד C + + אמיתי. משחק חדש! היא יצירה בדיונית; אין צורך בקוד המוצג בו כדי להתאים לסטנדרטים האמיתיים. מה שאומיקו אומר על הקוד הוא סמכותי יותר מכל תקני C ++ או מהדרים. בתשובה העליונה (המקובלת) אין שום אזכור למידע ביקום. אני חושב שאפשר לשאול שאלה בנושא בנושא עם תשובה טובה, אבל כפי שמנסח זאת זה לא זה.

הקוד אינו לולאה אינסופית אך הוא באג.

יש שתי (אולי שלוש) סוגיות:

  • אם לא קיימים debufs לא ייגרם נזק כלל
  • נזק מוגזם יופעל אם יש יותר מ- debuf אחד
  • אם DestroyMe () מוחק את האובייקט באופן מיידי ועדיין יש לעבד m_debufs הלולאה תבוצע על אובייקט שנמחק וזיכרון אשפה. לרוב מנועי המשחק יש תור להרוס כדי לעקוף את זה ועוד, כך שאולי לא תהיה בעיה.

יישום הנזק צריך להיות מחוץ לולאה.

הנה הפונקציה המתוקנת:

// the calculation of damage when attacked void DestructibleActor::ReceiveDamage(float sourceDamage) { // apply debuffs auto resolvedDamage = sourceDamage; for (const auto& debuf:m_debufs) { resolvedDamage = debuf.ApplyToDamage(resolvedDamage); } m_currentHealth -= resolvedDamage if (m_currentHealth <= 0.f) { m_currentHealth = 0.f; DestroyMe(); } } 
12
  • 15 האם אנחנו בבדיקת קוד? : ד
  • 4 מצופים נהדרים לבריאות אם אינך עולה על 16777216 HP. אתה יכול אפילו להגדיר את הבריאות לאינסוף כדי ליצור אויב שאתה יכול לפגוע בו אבל לא ימות, ולקיים התקפה של הרג אחד תוך שימוש בנזק אינסופי שעדיין לא יהרוג אופי HP אינסופי (תוצאה של INF-INF היא NaN) אבל יהרוג את כל השאר. אז זה מאוד שימושי.
  • 1 @cat על פי מוסכמה בסטנדרטים רבים של קידוד m_ קידומת פירושה שזה משתנה חבר. במקרה זה משתנה חבר של DestructibleActor.
  • 2 @HotelCalifornia אני מסכים שיש סיכוי קטן ApplyToDamage לא עובד כמצופה אבל במקרה הדוגמה שאתה נותן הייתי אומר ApplyToDamage גַם צריך לעבד מחדש כדי לדרוש להעביר את המקור sourceDamage כמו כן כדי שיוכל לחשב את debuf כראוי במקרים אלה. כדי להיות פדנט מוחלט: בשלב זה המידע על dmg צריך להיות מבנה שכולל את ה- dmg המקורי, ה- dmg הנוכחי ואופי הנזק / ים גם אם ל debufs יש דברים כמו "פגיעות לאש". מניסיון לא עבר זמן רב עד שעיצוב משחק עם debufs דורש זאת.
  • 1 @StephaneHockenhull אמר טוב!

נראה שהקוד לא יוצר לולאה אינסופית.

הדרך היחידה שהלולאה תהיה אינסופית תהיה אם

debuf.ApplyToDamage(resolvedDamage); 

אוֹ

DestroyMe(); 

היו להוסיף פריטים חדשים ל m_debufs מְכוֹלָה.

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

התוכנית ככל הנראה תקרוס בגלל הקריאה ל- DestroyMe(); ככל הנראה הורס את האובייקט הנוכחי שמפעיל כרגע את הלולאה.

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


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


בהתבסס על ההערה של אקי טנאקה,

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

"זה קרא לאותה פעולה שוב ושוב" זה סביר יותר.

בהנחה ש DestroyMe(); לא נועד להיקרא יותר מפעם אחת, סביר יותר שהוא יגרום להתרסקות.

דרך לפתור בעיה זו תהיה לשנות את if למשהו כזה:

 if (m_currentHealth <= 0.f) { m_currentHealth = 0.f; DestroyMe(); break; } 

פעולה זו תצא מהלולאה כאשר DestructibleActor נהרס, וודא כי 1) DestroyMe השיטה נקראת רק פעם אחת ו- 2) אל תמרחו חובבים ללא תועלת ברגע שהאובייקט כבר נחשב למת.

2
  • 1 פריצה מהלולאה עבור כאשר בריאות <= 0 היא בהחלט תיקון טוב יותר מאשר לחכות עד לאחר הלולאה כדי לבדוק את הבריאות.
  • אני חושב שכנראה break מחוץ לולאה, ו לאחר מכן שִׂיחָה DestroyMe(), רק כדי להיות בטוח

ישנן מספר בעיות בקוד:

  1. אם אין debufs, לא ייגרם נזק.
  2. DestroyMe() שם הפונקציה נשמע מסוכן. תלוי איך הוא מיושם, זה עשוי להיות בעיה או לא. אם זו רק קריאה להרס האובייקט הנוכחי עטוף בפונקציה, אז יש בעיה, שכן האובייקט ייהרס באמצע ביצוע קוד. אם זו קריאה לפונקציה שתור לתור את אירוע המחיקה של האובייקט הנוכחי, אז אין שום בעיה, מכיוון שהאובייקט ייהרס לאחר שיסיים את ביצועו ולולאת האירוע תיכנס.
  3. הסוגיה האמיתית שנראית מוזכרת באנימה, "זה היה קורא לאותה פעולה שוב ושוב" - היא תקרא DestroyMe() כל עוד m_currentHealth <= 0.f ונותרו עוד דיבובים לאירוף, מה שעלול לגרום ל DestroyMe() נקרא מספר פעמים, שוב ושוב. הלולאה צריכה להיפסק אחרי הראשונה DestroyMe() להתקשר, מכיוון שמחיקת אובייקט לא אחת גורמת לשחיתות בזיכרון, מה שעלול לגרום לקרוס בטווח הארוך.

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

הקוד הנכון יהיה

// the calculation of damage when attacked void DestructibleActor::ReceiveDamage(float sourceDamage) { // apply debuffs auto resolvedDamage = sourceDamage; for (const auto& debuf:m_debufs) { resolvedDamage = debuf.ApplyToDamage(resolvedDamage); m_currentHealth -= resolvedDamage if (m_currentHealth <= 0.f) { m_currentHealth = 0.f; DestroyMe(); break; } } } 
3
  • עלי לציין שכפי שכתבתי בעבר הקצאות זיכרון, מחיקת אותו זיכרון אינה חייבת להיות בעיה. זה יכול להיות מיותר. הכל תלוי בהתנהגות המקצה. שלי פשוט התנהג כמו רשימה מקושרת ברמה נמוכה, כך שה"צומת "עבור הנתונים שנמחקו או נקבע כחופשי מספר פעמים או שנמחק שוב מספר פעמים (מה שפשוט יתאים להפניות מחדש של מצביע מיותר). לתפוס טוב בכל זאת.
  • ללא כפול הוא באג, ובדרך כלל מוביל להתנהגות לא מוגדרת ולהתרסקויות. גם אם יש לך מקצה מותאם אישית שאיכשהו אינו מאפשר שימוש חוזר באותה כתובת זיכרון, ללא כפול זה קוד מסריח מכיוון שזה לא הגיוני ותזעק אותך על ידי מנתחי קוד סטטי.
  • כמובן! לא תכננתי אותו למטרה זו. בחלק מהשפות יש צורך בהקצאה בגלל היעדר תכונות. לא לא לא. רק אמרתי שקריסה אינה מובטחת. סיווגי עיצוב מסוימים לא תמיד קורסים.