AIMBOT 2.0
Uue mängu 2 1. osas, umbes 9:40, on Nene kirjutatud koodilõik:
Siin on see tekstivormis koos tõlgitud kommentaaridega:
// 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(); } } }
Pärast võtet ütles Umiko for silmusele osutades, et kood kukkus kokku seetõttu, et seal on lõpmatu silmus.
Ma ei tea tegelikult C ++ -d, nii et ma pole kindel, kas see, mida ta räägib, vastab tõele.
Nagu ma näen, kordub for loop lihtsalt debüütide kaudu, mis näitlejal praegu on. Kui näitlejal pole lõpmatult palju debufe, ei usu ma, et sellest võib saada lõpmatu silmus.
Kuid ma pole kindel, sest ainus põhjus, miks kood on üles võetud, on see, et nad tahtsid siia panna lihavõttemuna, eks? Me oleksime lihtsalt saanud sülearvuti tagumisest küljest pildi ja kuulnud, kuidas Umiko ütleb: "Oh, sul on seal lõpmatu silmus". Asjaolu, et nad tegelikult mingit koodi näitasid, paneb mind mõtlema, et kuidagi on see kood mingi lihavõttemuna.
Kas kood loob tegelikult lõpmatu tsükli?
8- Ilmselt kasulik: täiendav ekraanipilt, kus Umiko ütleb: "See oli helistades samale toimingule ikka ja jälle ", mida koodis ei pruugita näidata.
- Oh! Ma ei teadnud seda! @AkiTanaka alam, mida vaatasin, ütleb "lõpmatu silmus"
- @LoganM Ma pole tegelikult nõus. Asi pole mitte ainult selles, et OP-l on küsimus mõne lähtekoodi kohta, mis juhtus pärinema animest; OP küsimus puudutab konkreetset avaldust umbes lähtekoodi anime tähemärgi järgi ja seal on animega seotud vastus, nimelt "Crunchyroll tehtud rida ja valesti tõlgitud rida".
- @senshin Ma arvan, et loete pigem seda, mida soovite, et küsimus puudutaks, mitte seda, mida tegelikult küsitakse. Küsimus annab mõne lähtekoodi ja küsib, kas see genereerib lõpmatu tsükli reaalse C ++ koodina. Uus mäng! on väljamõeldud teos; pole vaja, et selles esitatud kood vastaks tegelikele standarditele. See, mida Umiko koodi kohta ütleb, on autoriteetsem kui mis tahes C ++ standardid või kompilaatorid. Üles (aktsepteeritud) vastuses ei mainita universumisisest teavet. Ma arvan, et selle kohta võiks hea vastusega esitada teemakohase küsimuse, kuid see pole nii, nagu see on sõnastatud.
Kood ei ole lõpmatu silmus, kuid see on viga.
Seal on kaks (võib-olla kolm) küsimust:
- Kui ühtegi debuf-i pole, ei teki mingit kahju
- Kui debuf on rohkem kui 1, rakendatakse liiga suurt kahju
- Kui DestroyMe () kustutab objekti kohe ja töödeldavaid m_debufe on veel, käivitab silmus kustutatud objekti ja kustutab mälu. Enamikul mängumootoritel on selle ja muu lahendamiseks hävitamise järjekord, mis ei pruugi olla probleem.
Kahjustuste rakendamine peaks toimuma väljaspool silmust.
Siin on parandatud funktsioon:
// 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 Kas oleme koodide ülevaatamisel? : D
- 4 ujukit on tervisele suurepärane, kui te ei lähe üle 16777216 HP. Võite isegi seada tervise lõpmatuks, et luua vaenlane, keda saate lüüa, kuid mida te ei saa surra, ja teha ühe tapmise rünnak lõpmatu kahju abil, mis ikkagi ei tapa lõpmatu HP märki (INF-INFi tulemus on NaN), kuid tapab kõik muu. Nii et see on väga kasulik.
- 1 @cat Kokkuleppeliselt paljudes kodeerimisstandardites
m_
eesliide tähendab, et see on liikme muutuja. Sel juhul on muutuja väärtusDestructibleActor
. - 2 @HotelCalifornia Olen nõus, et on väike võimalus
ApplyToDamage
ei tööta ootuspäraselt, kuid ütleksin teie toodud näite puhulApplyToDamage
ka tuleb ümber töötada, et nõuda selle originaali edastamistsourceDamage
samuti selleks, et ta saaks sellistel juhtudel debufi korralikult arvutada. Et olla absoluutne pedant: siinkohal peaks dmg-teave olema struktuur, mis sisaldab algset dmg-d, praegust dmg-i ja kahju (de) olemust, samuti kui debufidel on selliseid asju nagu "haavatavus tulele". Kogemuste põhjal pole kaua aega möödas, kui mõni debuffidega mängude disain neid nõuab. - 1 @StephaneHockenhull hästi öeldud!
Tundub, et kood ei loo lõpmatut silmust.
Ainus viis, kuidas silmus oleks lõpmatu, oleks, kui
debuf.ApplyToDamage(resolvedDamage);
või
DestroyMe();
pidid lisama m_debufs
konteiner.
See tundub ebatõenäoline. Ja kui see nii oleks, võib programm konteineri muutmise tõttu itereerimisel kokku kukkuda.
Tõenäoliselt kukub programm kokku kõne tõttu DestroyMe();
mis arvatavasti hävitab praeguse objekti, mis töötab praegu tsüklit.
Me võime mõelda sellest kui koomiksist, kus „paha poiss“ saeb oksat, et „hea poiss“ sellega kukuks, kuid mõistab liiga hilja, et on lõigu valel küljel. Või Midgaardi madu sööb seda ise.
Samuti peaksin lisama, et lõpmatu ahela kõige tavalisem sümptom on see, et see külmutab programmi või muudab selle reageerimatuks. See jookseb programmi kokku, kui ta eraldab mälu korduvalt või teeb midagi, mis jaguneb lõpuks nulliga või meeldib.
Aki Tanaka kommentaari põhjal
Ilmselt kasulik: täiendav ekraanipilt Umikost, mis ütleb, et "See kutsus sama operatsiooni ikka ja jälle", mida koodis ei pruugita näidata.
"See kutsus sama operatsiooni uuesti ja uuesti" See on tõenäolisem.
Eeldades et DestroyMe();
ei ole mõeldud helistamiseks mitu korda, põhjustab see tõenäoliselt krahhi.
Selle probleemi lahendamiseks oleks vaja muuta if
midagi sellist:
if (m_currentHealth <= 0.f) { m_currentHealth = 0.f; DestroyMe(); break; }
See väljuks kontuurist, kui DestructibleActor hävitatakse, veendudes, et 1) DestroyMe
meetodit nimetatakse ainult üks kord ja 2) ärge kasutage puhvreid asjatult, kui objekti loetakse juba surnuks.
- 1 For for silmusest välja murda, kui tervis on <= 0, on kindlasti parem lahendus, kui oodata pärast silmust tervise kontrollimiseks.
- Ma arvan, et ilmselt oleksin
break
silmusest välja ja siis helistamaDestroyMe()
, lihtsalt selleks, et olla ohutu
Koodiga on mitu probleemi:
- Kui debufisid pole, ei tekitata kahju.
DestroyMe()
funktsiooni nimi kõlab ohtlikult. Sõltuvalt selle rakendamisest võib see olla probleem või mitte. Kui see on lihtsalt kõne funktsiooni sisse mähitud praeguse objekti hävitajale, siis on probleem, kuna objekt hävitatakse selle keskel koodi käivitades. Kui see on kutse funktsioonile, mis seab järjekorda praeguse objekti kustutussündmuse, siis pole probleemi, kuna objekt hävitatakse pärast selle täitmise lõpetamist ja sündmuse silmus algab.- Tegelik probleem, mida näib animes mainitud, "See kutsus sama operatsiooni ikka ja jälle" - see kutsub
DestroyMe()
nii kaua kuim_currentHealth <= 0.f
ja kordamiseks on jäänud veel debuffe, mis võivad põhjustadaDestroyMe()
mitu korda, ikka ja jälle. Silmus peaks pärast esimest lõppemaDestroyMe()
kõne, sest objekti mitu korda kustutamine toob kaasa mälu rikkumise, mis toob tõenäoliselt pikas perspektiivis kokku krahhi.
Ma pole päris kindel, miks võtab iga debuf tervise ära, selle asemel, et tervist ainult üks kord ära võtta, kusjuures kõigi debuffide mõju avaldub esialgsele kahjudele, kuid eeldan, et see on õige mänguloogika.
Õige kood oleks
// 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 - Pean juhtima tähelepanu sellele, et kuna mul on varem kirjutatud mälujagureid, ei pea sama mälu kustutamine olema probleem. See võib olla ka üleliigne. Kõik sõltub eraldaja käitumisest. Minu oma käitus lihtsalt nagu madala lingiga loend, nii et kustutatud andmete "sõlm" saab mitu korda vabaks või mitu korda uuesti tehtud (mis vastaks lihtsalt üleliigsetele kursori ümbersuunamistele). Hea saak siiski.
- Topeltvaba on viga ning viib üldiselt määratlemata käitumiseni ja krahhideni. Isegi kui teil on kohandatud eraldaja, mis keelab kuidagi sama mäluaadressi taaskasutuse, on topeltvaba haisev kood, kuna sellel pole mõtet ja staatiliste koodide analüsaatorid saavad teid karjuda.
- Muidugi! Ma ei kujundanud seda selleks otstarbeks. Mõnes keeles on funktsioonide puudumise tõttu vaja lihtsalt eraldajat. Ei ei ei. Ma lihtsalt väitsin, et krahh pole garanteeritud. Teatud disainiklassifikatsioonid ei kuku alati kokku.