Kepiye cara nambah mekanika petungan balistik kanggo penembak seluler kanthi algoritma kompensasi latensi jaringan

Kepiye cara nambah mekanika petungan balistik kanggo penembak seluler kanthi algoritma kompensasi latensi jaringan

Hai, aku Nikita Brizhak, pangembang server saka Pixonic. Dina iki aku arep ngomong babagan ngimbangi lag ing multiplier seluler.

Akeh artikel sing wis ditulis babagan kompensasi server lag, kalebu ing basa Rusia. Iki ora nggumunake, amarga teknologi iki wis aktif digunakake ing nggawe FPS bebarengan wiwit 90s pungkasan. Contone, sampeyan bisa ngelingi mod QuakeWorld, sing minangka salah sawijining sing pertama nggunakake.

Kita uga digunakake ing penembake multiplier seluler Dino Squad.

Ing artikel iki, tujuanku ora mbaleni apa sing wis ditulis kaping sewu, nanging kanggo nyritakake kepiye carane ngetrapake kompensasi lag ing game kita, kanthi nganggep tumpukan teknologi lan fitur gameplay inti.

Sawetara tembung babagan korteks lan teknologi kita.

Dino Squad minangka penembak PvP seluler jaringan. Pemain ngontrol dinosaurus sing dilengkapi macem-macem gaman lan gelut ing tim 6v6.

Klien lan server adhedhasar Unity. Arsitèktur cukup klasik kanggo penembak: server otoriter, lan prediksi klien bisa digunakake ing klien. Simulasi game ditulis nggunakake ECS ing omah lan digunakake ing server lan klien.

Yen iki pisanan sampeyan krungu babagan ganti rugi lag, iki minangka kunjungan singkat menyang masalah kasebut.

Ing game FPS bebarengan, pertandhingan kasebut biasane disimulasikan ing server remot. Pemain ngirim input sing (informasi bab tombol dipencet) kanggo server, lan nanggepi server ngirim negara game dianyari njupuk menyang akun data ditampa. Kanthi skema interaksi iki, wektu tundha antarane menet tombol maju lan wayahe karakter pemain ing layar bakal luwih gedhe tinimbang ping.

Nalika ing jaringan lokal, wektu tundha iki (sing umum disebut input lag) bisa uga ora katon, nalika muter liwat Internet nggawe perasaan "nggeser ing es" nalika ngontrol karakter. Masalah iki kaping pindho cocog kanggo jaringan seluler, ing ngendi kasus nalika ping pamuter 200 ms isih dianggep minangka sambungan sing apik banget. Asring ping bisa 350, 500, utawa 1000 ms. Banjur dadi meh mokal kanggo muter penembake cepet karo lag input.

Solusi kanggo masalah iki yaiku prediksi simulasi sisih klien. Kene klien dhewe aplikasi input kanggo karakter pamuter, tanpa nunggu respon saka server. Lan nalika jawaban ditampa, mung mbandhingake asil lan nganyari posisi mungsuh. Wektu tundha antarane mencet tombol lan nampilake asil ing layar ing kasus iki minimal.

Penting kanggo mangerteni nuansa ing kene: klien tansah nggambar dhewe miturut input pungkasan, lan mungsuh - kanthi wektu tundha jaringan, miturut negara sadurunge saka data saka server. Yaiku, nalika njupuk mungsuh, pemain ndeleng dheweke ing jaman kepungkur relatif marang awake dhewe. Liyane babagan prediksi klien kita nulis sadurungΓ©.

Mangkono, prediksi klien solves siji masalah, nanging nggawe liyane: yen pemain shoots ing titik ngendi mungsuh ana ing sasi, ing server nalika njupuk ing titik sing padha, mungsuh bisa maneh ing panggonan sing. Kompensasi server lag nyoba kanggo ngatasi masalah iki. Nalika gegaman wis murub, server mulihake negara game sing pemain weruh lokal ing wektu dijupuk, lan mriksa apa pancene bisa wis kenek mungsuh. Yen jawabane "ya," hit diitung, sanajan mungsuh ora ana maneh ing server nalika iku.

Bersenjata karo kawruh iki, kita wiwit ngleksanakake ganti rugi server lag ing Dino Squad. Kaping pisanan, kita kudu ngerti carane mulihake ing server apa sing dideleng klien? Lan apa persis sing kudu dipulihake? Ing game kita, hit saka gaman lan kabisan diwilang liwat raycasts lan overlays - yaiku, liwat interaksi karo tabrakan fisik mungsuh. Patut, kita kudu ngasilake posisi colliders iki, sing pemain "sawang" lokal, ing server. Nalika iku kita nggunakake Unity versi 2018.x. API fisika ana statis, donya fisik ana ing salinan siji. Ora ana cara kanggo nyimpen negara lan banjur mulihake saka kothak. Dadi apa sing kudu ditindakake?

Solusi kasebut ana ing permukaan; kabeh unsur kasebut wis digunakake kanggo ngatasi masalah liyane:

  1. Kanggo saben klien, kita kudu ngerti ing wektu apa dheweke weruh mungsuh nalika mencet tombol. Kita wis nulis informasi iki menyang paket input lan digunakake kanggo nyetel prediksi klien.
  2. Kita kudu bisa nyimpen sajarah negara game. Ing kono kita bakal nyekel posisi mungsuh kita (lan mulane tabrakan). Kita wis duwe sajarah negara ing server, kita digunakake kanggo mbangun delta. Ngerti wektu sing tepat, kita bisa kanthi gampang nemokake negara sing bener ing sejarah.
  3. Saiki kita duwe negara game saka sajarah ing tangan, kita kudu bisa nyinkronake data pamuter karo negara ing donya fisik. Tabrakan sing ana - obah, sing ilang - nggawe, sing ora perlu - numpes. Logika iki uga wis ditulis lan kasusun saka sawetara sistem ECS. Kita digunakake kanggo terus sawetara kamar game ing siji proses Unity. Lan amarga jagad fisik minangka siji saben proses, mula kudu digunakake maneh ing antarane kamar. Sadurunge saben obah saka simulasi, kita "ngreset" kahanan ing donya fisik lan reinitialized karo data kanggo kamar saiki, nyoba kanggo nggunakake maneh obyek game Unity sabisa liwat sistem pooling pinter. Kabeh sing isih ana yaiku njaluk logika sing padha kanggo negara game saka jaman biyen.

Kanthi nggabungake kabeh unsur kasebut, kita entuk "mesin wektu" sing bisa muter maneh kahanan fisik ing wayahe. Kode kasebut dadi prasaja:

public class TimeMachine : ITimeMachine
{
     //Π˜ΡΡ‚ΠΎΡ€ΠΈΡ ΠΈΠ³Ρ€ΠΎΠ²Ρ‹Ρ… состояний
     private readonly IGameStateHistory _history;

     //Π’Π΅ΠΊΡƒΡ‰Π΅Π΅ ΠΈΠ³Ρ€ΠΎΠ²ΠΎΠ΅ состояниС Π½Π° сСрвСрС
     private readonly ExecutableSystem[] _systems;

     //Набор систСм, Ρ€Π°ΡΡΡ‚Π°Π²Π»ΡΡŽΡ‰ΠΈΡ… ΠΊΠΎΠ»Π»Π°ΠΉΠ΄Π΅Ρ€Ρ‹ Π² физичСском ΠΌΠΈΡ€Π΅ 
     //ΠΏΠΎ Π΄Π°Π½Π½Ρ‹ΠΌ ΠΈΠ· ΠΈΠ³Ρ€ΠΎΠ²ΠΎΠ³ΠΎ состояния
     private readonly GameState _presentState;

     public TimeMachine(IGameStateHistory history, GameState presentState, ExecutableSystem[] timeInitSystems)
     {
         _history = history; 
         _presentState = presentState;
         _systems = timeInitSystems;  
     }

     public GameState TravelToTime(int tick)
     {
         var pastState = tick == _presentState.Time ? _presentState : _history.Get(tick);
         foreach (var system in _systems)
         {
             system.Execute(pastState);
         }
         return pastState;
     }
}

Kabeh sing isih ana kanggo mangerteni carane nggunakake mesin iki kanggo gampang ijol kanggo nembak lan kabisan.

Ing kasus sing paling gampang, nalika mekanika adhedhasar siji hitscan, kabeh katon jelas: sadurunge pamuter njupuk, dheweke kudu mbalekake jagad fisik menyang negara sing dikarepake, nindakake sinar, ngetung hit utawa kantun, lan bali donya menyang negara wiwitan.

Nanging ana sawetara mekanika kaya ing Dino Squad! Umume gaman ing game nggawe proyektil - peluru umur dawa sing mabur kanggo sawetara ticks simulasi (ing sawetara kasus, puluhan kutu). Apa sing kudu dilakoni karo dheweke, jam pira dheweke kudu mabur?

Π’ artikel kuna babagan tumpukan jaringan Half-Life, wong lanang saka Valve takon pitakonan sing padha, lan jawabane yaiku: kompensasi lag projectile ana masalah, lan luwih becik nyingkiri.

Kita ora duwe pilihan iki: senjata adhedhasar projectile minangka fitur utama desain game. Dadi kita kudu teka munggah karo soko. Sawise brainstorming sethitik, kita ngrumusake rong opsi sing katon bisa:

1. We dasi projectile kanggo wektu pamuter sing digawe. Saben obah saka simulasi server, kanggo saben peluru saben pemain, kita muter bali donya fisik menyang negara klien lan nindakake petungan perlu. Pendekatan iki ndadekake bisa duwe beban sing disebarake ing server lan wektu proyektil sing bisa diprediksi. Predictability utamanΓ© penting kanggo kita, amarga kita duwe kabeh projectiles, kalebu projectiles mungsuh, mbadek ing klien.

Kepiye cara nambah mekanika petungan balistik kanggo penembak seluler kanthi algoritma kompensasi latensi jaringan
Ing gambar, pemain ing obah 30 murub rudal ing antisipasi: dheweke weruh arah mungsuh mlaku lan ngerti kacepetan kira-kira rudal. Sacara lokal, dheweke ndeleng target kasebut ing obah kaping 33. Thanks kanggo ganti rugi lag, uga bakal katon ing server

2. Kita nindakake kabeh padha kaya ing pilihan pisanan, nanging, wis dietung siji obah saka simulasi peluru, kita ora mandheg, nanging terus kanggo simulasi pesawat ing obah server padha, saben wektu nggawa wektu nyedhaki server. siji-siji obah lan nganyari posisi collider. Kita nindakake iki nganti salah siji saka rong perkara:

  • Peluru wis kadaluwarsa. Iki tegese petungan wis rampung, kita bisa count a miss utawa hit. Lan iki ana ing obah sing padha ditembak! Kanggo kita iki loro plus lan minus. A plus - amarga kanggo pemain shooting iki Ngartekno suda wektu tundha antarane hit lan nyuda ing kesehatan mungsuh. Kakurangan iku efek sing padha diamati nalika mungsuh murub ing pamuter: mungsuh, iku bakal katon, mung murub roket alon, lan karusakan wis dietung.
  • Peluru wis tekan wektu server. Ing kasus iki, simulasi bakal terus ing obah server sabanjurΓ© tanpa rugi lag. Kanggo projectiles alon, iki bisa miturut teori bisa nyuda jumlah rollbacks fisika dibandhingake opsi pisanan. Ing wektu sing padha, beban sing ora rata ing simulasi saya tambah: server ora aktif, utawa ing siji centang server ngitung puluhan ticks simulasi kanggo sawetara peluru.

Kepiye cara nambah mekanika petungan balistik kanggo penembak seluler kanthi algoritma kompensasi latensi jaringan
Skenario sing padha kaya ing gambar sadurunge, nanging diwilang miturut skema kapindho. Rudal "kejiret" karo wektu server ing obah padha sing dijupuk, lan hit bisa diitung minangka awal minangka obah sabanjurΓ©. Ing centhang kaping 31, ing kasus iki, ganti rugi lag ora ditrapake maneh

Ing implementasine, loro pendekatan iki beda-beda mung ing sawetara baris kode, supaya kita digawe loro, lan kanggo dangu padha ana ing podo karo. Gumantung ing mekanika gegaman lan kacepetan peluru, kita milih siji utawa opsi liyane kanggo saben dinosaurus. Titik balik ing kene yaiku tampilan ing game mekanika kaya "yen sampeyan nabrak mungsuh kaping pirang-pirang ing wektu kasebut, entuk bonus kasebut." Sembarang mekanik ing ngendi wektu ing ngendi pemain kenek mungsuh main peran penting ora gelem bisa karo pendekatan kapindho. Supaya kita rampung munggah karo pilihan pisanan, lan saiki ditrapake kanggo kabeh gaman lan kabeh kabisan aktif ing game.

Kapisah, iku worth mundhakaken Jeksa Agung bisa ngetokake saka kinerja. Yen sampeyan mikir yen kabeh iki bakal alon-alon, aku mangsuli: iku. Unity cukup alon ing obah colliders lan nguripake lan mateni. Ing Dino Squad, ing kasus "paling awon", bisa uga ana sawetara atus proyektil sing ana ing pertempuran bebarengan. Obah colliders kanggo count saben projectile individu iku kemewahan unaffordable. Mulane, pancen perlu kanggo nyilikake jumlah "mundur" fisika. Kanggo nindakake iki, kita nggawe komponen kapisah ing ECS ​​kang kita ngrekam wektu pamuter. We ditambahake kanggo kabeh entitas sing mbutuhake ganti rugi lag (projectiles, kabisan, etc.). Sadurunge miwiti ngolah entitas kasebut, kita nglumpukake wektu iki lan ngolah bebarengan, muter maneh jagad fisik sapisan kanggo saben klompok.

Ing tataran iki kita duwe sistem umume digunakake. Kode ing wangun sing rada disederhanakake:

public sealed class LagCompensationSystemGroup : ExecutableSystem
{
     //Машина Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ
     private readonly ITimeMachine _timeMachine;

     //Набор систСм лагкомпСнсации
     private readonly LagCompensationSystem[] _systems;
     
     //Наша рСализация кластСризатора
     private readonly TimeTravelMap _travelMap = new TimeTravelMap();

    public LagCompensationSystemGroup(ITimeMachine timeMachine, 
        LagCompensationSystem[] lagCompensationSystems)
     {
         _timeMachine = timeMachine;
         _systems = lagCompensationSystems;
     }

     public override void Execute(GameState gs)
     {
         //На Π²Ρ…ΠΎΠ΄ кластСризатор ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π΅ ΠΈΠ³Ρ€ΠΎΠ²ΠΎΠ΅ состояниС,
         //Π° Π½Π° Π²Ρ‹Ρ…ΠΎΠ΄ Π²Ρ‹Π΄Π°Π΅Ρ‚ Π½Π°Π±ΠΎΡ€ Β«ΠΊΠΎΡ€Π·ΠΈΠ½Β». Π’ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΠΊΠΎΡ€Π·ΠΈΠ½Π΅ Π»Π΅ΠΆΠ°Ρ‚ энтити,
         //ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌ для лагкомпСнсации Π½ΡƒΠΆΠ½ΠΎ ΠΎΠ΄Π½ΠΎ ΠΈ Ρ‚ΠΎ ΠΆΠ΅ врСмя ΠΈΠ· истории.
         var buckets = _travelMap.RefillBuckets(gs);

         for (int bucketIndex = 0; bucketIndex < buckets.Count; bucketIndex++)
         {
             ProcessBucket(gs, buckets[bucketIndex]);
         }

         //Π’ ΠΊΠΎΠ½Ρ†Π΅ лагкомпСнсации ΠΌΡ‹ восстанавливаСм физичСский ΠΌΠΈΡ€ 
         //Π² исходноС состояниС
         _timeMachine.TravelToTime(gs.Time);
     }

     private void ProcessBucket(GameState presentState, TimeTravelMap.Bucket bucket)
     {
         //ΠžΡ‚ΠΊΠ°Ρ‚Ρ‹Π²Π°Π΅ΠΌ врСмя ΠΎΠ΄ΠΈΠ½ Ρ€Π°Π· для ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΠΊΠΎΡ€Π·ΠΈΠ½Ρ‹
         var pastState = _timeMachine.TravelToTime(bucket.Time);

         foreach (var system in _systems)
         {
               system.PastState = pastState;
               system.PresentState = presentState;

               foreach (var entity in bucket)
               {
                   system.Execute(entity);
               }
          }
     }
}

Kabeh sing isih ana yaiku ngatur rincian:

1. Ngerti carane mbatesi jarak maksimum gerakan ing wektu.

Penting kanggo nggawe game kasebut bisa diakses sabisa-bisa ing kahanan jaringan seluler sing ora apik, mula kita mbatesi crita kanthi wates 30 ticks (kanthi tingkat obah 20 Hz). Iki ngidini pemain kanggo mencet mungsuh malah ing ping dhuwur banget.

2. Nemtokake obyek sing bisa dipindhah ing wektu lan ora bisa.

Kita, mesthi, ngobahake mungsuh. Nanging tameng energi sing bisa diinstal, umpamane, ora. Kita mutusake manawa luwih becik menehi prioritas kanggo kemampuan pertahanan, kaya sing asring ditindakake ing penembake online. Yen pemain wis sijine tameng ing saiki, peluru lag-kompensasi saka sasi ngirim ora fly liwat.

3. Temtokake apa perlu kanggo ngimbangi kemampuan dinosaurus: cokotan, serangan buntut, lan liya-liyane. Kita mutusake apa sing dibutuhake lan diproses miturut aturan sing padha karo peluru.

4. Nemtokake apa sing kudu dilakoni karo tabrakan pemain sing kompensasi lag ditindakake. Kanthi cara sing apik, posisi kasebut ora kudu pindhah menyang jaman kepungkur: pamuter kudu ndeleng awake dhewe ing wektu sing padha saiki ana ing server. Nanging, kita uga muter maneh tabrakan saka pamuter shooting, lan ana sawetara alasan kanggo iki.

First, iku mbenakake clustering: kita bisa nggunakake negara fisik padha kanggo kabeh pemain karo ping cedhak.

Kapindho, ing kabeh sinar lan tumpang tindih kita mesthi ngilangi tabrakan pemain sing duwe kabisan utawa proyektil. Ing Dino Squad, pemain ngontrol dinosaurus, sing duwe geometri non-standar miturut standar penembake. Malah yen pamuter shoots ing amba mboten umum lan lintasan peluru liwat tabrakan dinosaurus pamuter, peluru bakal nglirwakake.

Katelu, kita ngetung posisi senjata dinosaurus utawa titik aplikasi saka kemampuan nggunakake data saka ECS malah sadurunge wiwitan ganti rugi lag.

AkibatΓ©, posisi nyata saka tabrakan pemain lag-kompensasi ora penting kanggo kita, mula kita njupuk dalan sing luwih produktif lan ing wektu sing padha luwih gampang.

Latensi jaringan ora bisa dicopot, mung bisa ditutupi. Kaya metode penyamaran liyane, kompensasi server lag duwe bathi. Iku mbenakake pengalaman game saka pamuter sing njupuk ing beyo saka pamuter kang dijupuk ing. Nanging kanggo Dino Squad, pilihan ing kene jelas.

Mesthine, kabeh iki uga kudu dibayar kanthi nambah kerumitan kode server kanthi sakabehe - kanggo programer lan desainer game. Yen sadurungé simulasi minangka telpon urutan prasaja saka sistem, banjur karo kompensasi lag, puteran nested lan cabang katon ing. Kita uga ngginakaken akèh gaweyan kanggo nggawe trep kanggo bisa karo.

Ing versi 2019 (lan bisa uga luwih dhisik), Unity nambahake dhukungan lengkap kanggo adegan fisik mandiri. We dipun ginakaken ing server meh sanalika sawise nganyari, amarga kita wanted kanggo cepet njaluk nyisihaken saka donya fisik umum kanggo kabeh kamar.

We menehi saben kamar game pemandangan fisik dhewe lan kanthi mangkono ngilangi perlu kanggo "mbusak" pemandangan saka data saka kamar tetanggan sadurunge ngetung simulasi. Kaping pisanan, nambah produktivitas sing signifikan. Sareh, iku bisa kanggo njaluk nyisihaken saka kabèh kelas kewan omo sing muncul yen programmer nggawe kesalahan ing kode ngresiki pemandangan nalika nambah unsur game anyar. Kesalahan kasebut angel didebug, lan asring nyebabake kahanan obyek fisik ing adegan siji kamar "mili" menyang kamar liyane.

Kajaba iku, kita nindakake riset babagan apa adegan fisik bisa digunakake kanggo nyimpen sejarah jagad fisik. Sing, kondisional, nyedhiakke ora siji pemandangan kanggo saben kamar, nanging 30 pemandangan, lan nggawe buffer siklik metu saka wong-wong mau, kang kanggo nyimpen crita. UmumΓ©, pilihan kasebut bisa digunakake, nanging ora ditindakake: ora nuduhake peningkatan produktivitas, nanging mbutuhake owah-owahan sing rada beboyo. Iku angel kanggo prΓ©dhiksi carane server bakal nindakake nalika digunakake kanggo dangu karo akeh pemandangan. Mulane, kita tindakake aturan: "Yen ora rusak, aja ndandani".

Source: www.habr.com

Add a comment