Anonim

AIMBOT 2.0

Naujojo 2 žaidimo 1 epizode apie 9:40 yra Nene parašyto kodo kadras:

Štai teksto forma su išverstais komentarais:

// 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(); } } } 

Po šūvio Umiko, rodydamas „for loop“, pasakė, kad kodas sugedo dėl to, kad yra begalinė kilpa.

Aš tikrai nežinau C ++, todėl nesu tikras, ar tai, ką ji sako, yra tiesa.

Iš to, ką matau, „for loop“ tik kartoja debiutus, kuriuos šiuo metu turi aktorius. Nemanau, kad aktorius gali tapti begaline kilpa, nebent aktorius turi begalinį kiekį debufų.

Bet aš nesu tikras, nes vienintelė priežastis, kodėl yra šūvis kodo, yra ta, kad jie norėjo čia įdėti velykinį kiaušinį, tiesa? Mes būtume ką tik nufotografavę nešiojamojo kompiuterio užpakalinę dalį ir išgirdę Umiko sakant „O jūs turite begalinę kilpą“. Tai, kad jie iš tikrųjų parodė tam tikrą kodą, verčia mane galvoti, kad kažkaip kodas yra kažkoks velykinis kiaušinis.

Ar kodas iš tikrųjų sukurs begalinę kilpą?

8
  • Tikriausiai naudinga: papildoma ekrano nuotrauka, kurioje Umiko sako: „Taip buvo skambindamas ta pačia operacija dar ir dar kartą “, kuris gali būti nerodomas kode.
  • Oi! Aš to nežinojau! @AkiTanaka sub, kurį žiūrėjau, sako „begalinė kilpa“
  • @LoganM Aš tikrai nesutinku. Tai ne tik tai, kad OP kyla klausimas dėl tam tikro šaltinio kodo, kuris atsitiko iš anime; OP klausimas yra apie konkretų pareiškimą apie šaltinio kodą, kurį parašė anime veikėjas, ir yra su anime susijęs atsakymas, būtent „Crunchyroll padaryta ir klaidingai išversta eilutė“.
  • @senshin, manau, jūs skaitote tai, apie ką norite atsakyti, o ne iš tikrųjų. Klausime pateikiamas šaltinio kodas ir klausiama, ar jis sukuria begalinę kilpą kaip realųjį C ++ kodą. Naujas žaidimas! yra išgalvotas kūrinys; nereikia, kad jame pateiktas kodas atitiktų realaus gyvenimo standartus. Tai, ką Umiko sako apie kodą, yra labiau autoritetinga nei bet kokie C ++ standartai ar kompiliatoriai. Viršutiniame (priimtame) atsakyme neminima jokia visatos informacija. Manau, kad apie tai būtų galima užduoti klausimą su geru atsakymu, tačiau, kaip suformuluota, tai ne taip.

Kodas nėra begalinė kilpa, bet tai yra klaida.

Yra du (galbūt trys) klausimai:

  • Jei nėra jokių debufų, jokia žala nebus padaryta
  • Per didelė žala bus padaryta, jei yra daugiau nei 1 debuf
  • Jei „DestroyMe“) nedelsdamas ištrina objektą ir vis dar yra apdorojamų m_debufs, kilpa bus vykdoma per ištrintą objektą ir šiukšliadėžę. Daugeliui žaidimų variklių yra eilė, kad būtų galima išspręsti šią problemą ir dar daugiau, todėl tai gali būti ne problema.

Žalos taikymas turėtų būti už kilpos ribų.

Štai pataisyta funkcija:

// 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 Ar mes atliekame kodo peržiūrą? : D
  • 4 plūdės puikiai tinka sveikatai, jei neviršysite 16777216 AG. Jūs netgi galite nustatyti sveikatą iki begalybės, kad sukurtumėte priešą, kurį galite užpulti, bet nenumirsite, ir užpulti vieną žmogų, naudojant begalinę žalą, kuri vis tiek nežudys begalinio HP simbolio (INF-INF rezultatas yra NaN), bet nužudys visa kita. Taigi tai labai naudinga.
  • 1 @cat Pagal daugelį kodavimo standartų įprasta m_ priešdėlis reiškia, kad tai kintamasis narys. Šiuo atveju narys kintamasis DestructibleActor.
  • 2 @HotelCalifornia Sutinku, kad yra maža tikimybė ApplyToDamage neveikia taip, kaip tikėtasi, bet sakyčiau jūsų pateiktu pavyzdžiu ApplyToDamage taip pat reikia perdaryti, kad būtų reikalaujama perduoti originalą sourceDamage taip pat, kad tais atvejais galėtų tinkamai apskaičiuoti debuf. Norėdami būti absoliučiu pedantu: šiuo metu informacija apie dmg turėtų būti struktūra, apimanti pradinį dmg, dabartinį dmg ir žalos pobūdį, taip pat jei debufai turi tokius dalykus kaip „pažeidžiamumas gaisrui“. Remiantis patirtimi, neilgai trukus jų reikalauja bet koks žaidimų dizainas su „debufs“.
  • 1 @StephaneHockenhull gerai pasakyta!

Panašu, kad kodas nesukuria begalinės kilpos.

Vienintelis būdas, kaip kilpa būtų begalinė, būtų, jei

debuf.ApplyToDamage(resolvedDamage); 

arba

DestroyMe(); 

turėjo pridėti naujų elementų prie m_debufs konteinerį.

Tai atrodo mažai tikėtina. Jei taip būtų, programa gali sugesti dėl to, kad pakeisdami sudėtinį rodinį kartoję.

Programa greičiausiai užstrigs dėl skambučio DestroyMe(); kuris, tikėtina, sunaikina dabartinį objektą, kuris šiuo metu vykdo kilpą.

Galime galvoti apie tai kaip animacinį filmą, kuriame „blogas vaikinas“ pamato šaką, kad „geras vaikinas“ nukristų su juo, tačiau per vėlai supranta, kad jis atsidūrė ne toje pjūvio pusėje. Arba Midgaardo gyvatė valgo savo uodegą.


Taip pat turėčiau pridurti, kad labiausiai paplitęs begalinės kilpos simptomas yra tai, kad ji užšaldo programą arba nereaguoja. Tai sugadins programą, jei ji pakartotinai paskirstys atmintį, ar padarys ką nors, kas galų gale padalijama iš nulio, ar panašių.


Remiantis Aki Tanaka komentaru,

Tikriausiai naudinga: papildoma „Umiko“ ekrano kopija, kurioje sakoma, kad „Tai vėl ir vėl skambino tai pačiai operacijai“, kuri gali būti nerodoma kode.

"Tai skambino tą pačią operaciją vėl ir vėl" Tai labiau tikėtina.

Tariant, kad DestroyMe(); nėra sukurtas skambinti daugiau nei vieną kartą, jis greičiausiai sukels avariją.

Būdas išspręsti šią problemą būtų pakeisti if tokiam dalykui:

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

Tai išeitų iš kilpos, kai sunaikinamas „DestructibleActor“, užtikrinant, kad 1 DestroyMe metodas vadinamas tik vieną kartą ir 2) nenaudokite bufų nenaudingai, kai objektas jau laikomas negyvu.

2
  • 1 Išsiskyrimas iš ciklo, kai sveikata <= 0 yra tikrai geresnis sprendimas, nei laukimas, kol bus patikrinta sveikata.
  • Manau, kad tikriausiai break iš ciklo ir tada skambutis DestroyMe(), kad tik būtų saugu

Yra keletas su kodu susijusių problemų:

  1. Jei nėra debufų, žala nebus padaryta.
  2. DestroyMe() funkcijos pavadinimas skamba pavojingai. Priklausomai nuo to, kaip jis įgyvendinamas, tai gali būti problema. Jei tai tik skambutis dabartinio objekto, įvynioto į funkciją, sunaikintojui, kyla problema, nes objektas būtų sunaikintas jo viduryje vykdant kodą. Jei tai yra iškvietimas į funkciją, kuri įtraukia eilę į dabartinio objekto ištrynimo įvykį, problemos nėra, nes objektas būtų sunaikintas baigus jį vykdyti ir įvykio kilpą įjungus.
  3. Faktinis klausimas, kuris, atrodo, minimas anime, „Tai skambino tą pačią operaciją vėl ir vėl“ - tai paskambins DestroyMe() tol, kol m_currentHealth <= 0.f ir liko daugiau pakartotinių debuffų, kurie gali sukelti DestroyMe() skambinama kelis kartus, vėl ir vėl. Po pirmojo kilpa turėtų sustoti DestroyMe() skambutį, nes ištrynus objektą daugiau nei vieną kartą, gali sugesti atmintis, o tai ilgainiui greičiausiai sukels avariją.

Nesu tikras, kodėl kiekvienas debufas atima sveikatą, užuot sveikatą atėmęs tik vieną kartą, o visų debuffų poveikis daro pradinę žalą, tačiau manysiu, kad tai teisinga žaidimo logika.

Teisingas kodas būtų

// 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
  • Turėčiau pabrėžti, kad, kadangi anksčiau rašiau atminties skirstytuvus, tos pačios atminties ištrynimas neturi būti problema. Tai taip pat gali būti nereikalinga. Viskas priklauso nuo paskirstytojo elgesio. Mano tiesiog veikė kaip žemo lygio susietų sąrašų, todėl ištrintų duomenų „mazgas“ kelis kartus nustatomas kaip laisvas arba kelis kartus iš naujo ištrinamas (o tai tik atitiktų nereikalingus rodyklių peradresavimus). Geras laimikis.
  • „Double-free“ yra klaida ir paprastai sukelia neapibrėžtą elgesį ir avarijas. Net jei turite pasirinktinį skirstytuvą, kuris kažkaip neleidžia pakartotinai naudoti tą patį atminties adresą, dvigubai nemokamai yra dvokiantis kodas, nes jis neturi prasmės, o statinių kodų analizatoriai jums sušuks.
  • Žinoma! Aš to nesukūriau tam tikslui. Kai kurioms kalboms dėl funkcijų trūkumo tiesiog reikalingas paskirstytojas. Ne ne ne. Aš tik pareiškiau, kad avarija nėra garantuota. Tam tikros dizaino klasifikacijos ne visada sugenda.