Anonim

AIMBOT 2.0

Jaunās spēles 1. epizodē, ap pulksten 9:40, ir šāviens koda, ko Nene ir uzrakstījis:

Šeit ir teksta forma ar tulkotiem komentāriem:

// 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ēc šāviena Umiko, norādot uz for loop, teica, ka koda avārijas iemesls ir tas, ka pastāv bezgalīga cilpa.

Es īsti nezinu C ++, tāpēc neesmu pārliecināts, vai tas, ko viņa saka, ir taisnība.

No tā, ko es redzu, for cikls ir tikai atkārtots, izmantojot debifus, kas pašlaik ir aktierim. Ja vien Aktieram nav bezgalīgi daudz debufu, es nedomāju, ka tas, iespējams, var kļūt par bezgalīgu cilpu.

Bet es neesmu pārliecināts, jo vienīgais iemesls, kāpēc ir kods, ir tas, ka viņi gribēja šeit ievietot Lieldienu olu, vai ne? Mēs tikko būtu saņēmuši klēpjdatora aizmugures kadru un dzirdējuši, kā Umiko saka: "Ak, tur tev ir bezgalīga cilpa". Fakts, ka viņi patiešām parādīja kādu kodu, man liek domāt, ka kaut kā kods ir kaut kāda Lieldienu ola.

Vai kods tiešām izveidos bezgalīgu cilpu?

8
  • Iespējams, noderīgi: papildu ekrānuzņēmums, kurā Umiko saka: "Tas bija izsaucot to pašu darbību atkal un atkal ", kas, iespējams, netiek parādīts kodā.
  • Ak! Es to nezināju! @AkiTanaka apakšnodaļā, kuru es skatījos, teikts "bezgalīga cilpa"
  • @LoganM Īsti nepiekrītu. OP nav tikai jautājums par kādu avota kodu, kas nejauši radies no anime; OP jautājums ir par konkrētu izteikumu par pirmkods, kuru raksturo anime rakstzīme, un ir ar anime saistīta atbilde, proti, "Crunchyroll izdarīts dumjš un nepareizi tulkots rindā".
  • @senshin Es domāju, ka jūs lasāt nevis to, kas patiesībā tiek uzdots, bet gan to, par ko vēlaties. Jautājumā ir norādīts kāds avota kods un jautāts, vai tas ģenerē bezgalīgu loku kā reālā C ++ kodu. Jauna spēle! ir izdomāts darbs; nav nepieciešams, lai tajā uzrādītais kods atbilstu reālās dzīves standartiem. Umiko teiktais par kodu ir autoritatīvāks nekā jebkurš C ++ standarts vai kompilators. Augšējā (pieņemtajā) atbildē nav pieminēta nekāda informācija Visumā. Es domāju, ka par to varētu uzdot jautājumu par tēmu ar labu atbildi, taču, kā formulēts, tas tā nav.

Kods nav bezgalīga cilpa, bet tā ir kļūda.

Ir divi (iespējams, trīs) jautājumi:

  • Ja nav debufu, bojājumi vispār netiks nodarīti
  • Pārmērīgs kaitējums tiks piemērots, ja ir vairāk nekā 1 debuf
  • Ja DestroyMe () nekavējoties izdzēš objektu un joprojām ir apstrādājami m_debufs, cilpa tiks izpildīta, izmantojot izdzēstu objektu un pārvietojot atmiņu. Lielākajai daļai spēļu dzinēju ir iznīcināšanas rinda, lai apietu šo un vēl vairāk, tāpēc tas var nebūt jautājums.

Bojājumu piemērošanai jābūt ārpus cilpas.

Labotā funkcija ir šāda:

// 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 Vai mēs esam Code Review? : D
  • 4 pludiņi ir lieliski piemēroti veselībai, ja nepārsniedzat 16777216 ZS. Jūs pat varat iestatīt veselību līdz bezgalībai, lai izveidotu ienaidnieku, kuru varat nosist, bet nemirstat, un veikt vienas nogalināšanas uzbrukumu, izmantojot bezgalīgus bojājumus, kas joprojām nenogalinās bezgalīgu HP rakstzīmi (INF-INF rezultāts ir NaN), bet nogalinās visu pārējo. Tāpēc tas ir ļoti noderīgi.
  • 1 @cat Pēc vienošanās daudzos kodēšanas standartos m_ prefikss nozīmē, ka tas ir dalībnieka mainīgais. Šajā gadījumā locekļa mainīgais ir DestructibleActor.
  • 2 @HotelCalifornia Piekrītu, ka ir maza iespēja ApplyToDamage nedarbojas, kā paredzēts, bet es teiktu jūsu sniegtajā piemērā ApplyToDamage arī ir jāpārstrādā, lai prasītu nodot oriģinālu sourceDamage kā arī lai tajos gadījumos varētu pareizi aprēķināt debuf. Lai būtu absolūts pedants: šajā brīdī dmg informācijai jābūt struktūrai, kas ietver sākotnējo dmg, pašreizējo dmg un kaitējuma (-u) veidu, kā arī, ja debufs ir tādas lietas kā "ugunsneaizsargātība". Pēc pieredzes nav ilgi jāgaida, kad kāds spēles dizains ar debufs to pieprasa.
  • 1 @StephaneHockenhull labi pateikts!

Šķiet, ka kods nerada bezgalīgu cilpu.

Vienīgais veids, kā cilpa būtu bezgalīga, būtu, ja

debuf.ApplyToDamage(resolvedDamage); 

vai

DestroyMe(); 

bija pievienot jaunus vienumus m_debufs konteiners.

Tas šķiet maz ticams. Un, ja tas tā būtu, programma varētu avarēt, jo konteinera maiņas laikā tiek atkārtota.

Programma, visticamāk, avarētu zvana dēļ DestroyMe(); kas, domājams, iznīcina pašreizējo objektu, kurā pašlaik darbojas cilpa.

Mēs varam domāt par karikatūru, kurā 'sliktais puisis' zāģē zaru, lai 'labais puisis' ar to nokristu, bet pārāk vēlu saprot, ka atrodas nepareizajā griezuma pusē. Vai arī Midgaard Snake, kas ēd savu asti.


Man arī jāpiebilst, ka visbiežākais bezgalīgās cilpas simptoms ir tas, ka tas iesaldē programmu vai padara to nereaģējošu. Tas avarēs programmu, ja tā atkārtoti piešķirs atmiņu vai izdarīs kaut ko, kas galu galā dalās ar nulli, vai tamlīdzīgu.


Pamatojoties uz Aki Tanaka komentāru,

Iespējams, noderīgs: papildu ekrānuzņēmums ar Umiko, kurā teikts, ka "Tas atkal un atkal izsauca to pašu darbību", kas, iespējams, netiks parādīts kodā.

"Tā sauca to pašu operāciju atkal un atkal" Tas ir ticamāk.

Pieņemot, ka DestroyMe(); nav paredzēts izsaukšanai vairāk nekā vienu reizi, tas, visticamāk, izraisīs avāriju.

Veids, kā novērst šo problēmu, būtu mainīt if kaut kam līdzīgam:

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

Tas izietu no cilpas, kad iznīcināms DestructibleActor, pārliecinoties, ka DestroyMe metodi sauc tikai vienu reizi, un 2) nelietojiet bufetes bezjēdzīgi, tiklīdz objekts jau tiek uzskatīts par mirušu.

2
  • 1 Iziešana no for for loop, kad veselība <= 0 noteikti ir labāks risinājums nekā gaidīšana līdz beigām, lai pārbaudītu veselību.
  • Es domāju, ka droši vien gribētu break ārpus cilpas un pēc tam zvanu DestroyMe(), tikai lai būtu drošībā

Ar kodu ir vairākas problēmas:

  1. Ja nav debufu, zaudējumi netiks nodarīti.
  2. DestroyMe() funkcijas nosaukums izklausās bīstami. Atkarībā no tā ieviešanas tas var būt vai var nebūt problēma. Ja tas ir tikai zvans pašreizējā objekta iznīcinātājam, kas iesaiņots funkcijā, rodas problēma, jo objekts tiktu iznīcināts tā vidū, izpildot kodu. Ja tas ir izsaukums uz funkciju, kas ievieto pašreizējā objekta dzēšanas notikumu rindā, tad problēma nav, jo objekts tiktu iznīcināts pēc tā izpildes pabeigšanas un notikuma cilpas sākuma.
  3. Faktiskais jautājums, kas, šķiet, ir minēts anime, "Tas atkal un atkal izsauca to pašu darbību" - tas izsauks DestroyMe() kamēr vien m_currentHealth <= 0.f un atkārtošanai ir atlicis vairāk debuffu, kas varētu izraisīt DestroyMe() tiek saukts vairākas reizes, atkal un atkal. Cilpai vajadzētu apstāties pēc pirmās DestroyMe() zvanu, jo, izdzēšot objektu vairāk nekā vienu reizi, tiek bojāta atmiņa, kas ilgtermiņā, iespējams, izraisīs avāriju.

Es neesmu īsti pārliecināts, kāpēc katrs debufs atņem veselību, tā vietā, lai veselība tiktu atņemta tikai vienu reizi, un visu debuffu ietekme uz sākotnēji nodarītajiem zaudējumiem, taču es pieņemu, ka tā ir pareiza spēles loģika.

Pareizais kods būtu

// 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
  • Man jānorāda, ka, tā kā man iepriekš ir bijuši rakstīti atmiņas sadalītāji, tās pašas atmiņas dzēšanai nav jābūt problēmai. Tas varētu būt arī lieks. Viss ir atkarīgs no sadalītāja uzvedības. Manējais vienkārši rīkojās kā zema līmeņa saistīts saraksts, tāpēc izdzēsto datu "mezgls" vairākas reizes tiek iestatīts kā brīvs vai vairākas reizes izdzēsts (kas vienkārši atbilstu lieko rādītāju novirzīšanai). Labs loms tomēr.
  • Double-free ir kļūda, un tas parasti izraisa nedefinētu uzvedību un avārijas. Pat ja jums ir pielāgots sadalītājs, kas kaut kādā veidā aizliedz tās pašas atmiņas adreses atkārtotu izmantošanu, dubultā bezmaksas lietošana ir smirdošs kods, jo tam nav jēgas, un statisko kodu analizatori jūs uz jums kliegs.
  • Protams! Es to neveidoju šim nolūkam. Dažām valodām funkciju trūkuma dēļ ir nepieciešams tikai sadalītājs. Nē nē nē. Es tikai apgalvoju, ka avārija nav garantēta. Noteiktas dizaina klasifikācijas ne vienmēr avarē.