Ինչպես մենք բարելավեցինք բալիստիկ հաշվարկների մեխանիզմը շարժական հրաձիգի համար ցանցի հետաձգման փոխհատուցման ալգորիթմով

Ինչպես մենք բարելավեցինք բալիստիկ հաշվարկների մեխանիզմը շարժական հրաձիգի համար ցանցի հետաձգման փոխհատուցման ալգորիթմով

Ողջույն, ես Նիկիտա Բրիժակն եմ՝ Pixonic-ից սերվերի մշակող: Այսօր ես կցանկանայի խոսել բջջային մուլտիպլեյերի հետաձգման փոխհատուցման մասին:

Սերվերի հետաձգման փոխհատուցման մասին բազմաթիվ հոդվածներ են գրվել, այդ թվում՝ ռուսերեն։ Սա զարմանալի չէ, քանի որ 90-ականների վերջից այս տեխնոլոգիան ակտիվորեն օգտագործվում է բազմախաղաց FPS-ի ստեղծման գործում: Օրինակ, կարող եք հիշել QuakeWorld ռեժիմը, որն առաջիններից էր, որ օգտագործեց այն:

Մենք նաև օգտագործում ենք այն մեր շարժական մուլտիպլեյեր հրաձիգ Dino Squad-ում:

Այս հոդվածում իմ նպատակն է ոչ թե կրկնել այն, ինչ արդեն գրվել է հազար անգամ, այլ պատմել, թե ինչպես ենք մենք իրականացրել հետաձգման փոխհատուցում մեր խաղում՝ հաշվի առնելով մեր տեխնոլոգիական փաթեթը և հիմնական խաղային առանձնահատկությունները:

Մի քանի խոսք մեր կեղևի և տեխնոլոգիայի մասին։

Dino Squad-ը ցանցային շարժական PvP հրաձիգ է: Խաղացողները կառավարում են տարբեր զենքերով հագեցած դինոզավրեր և կռվում միմյանց հետ 6v6 թիմերում:

Ե՛վ հաճախորդը, և՛ սերվերը հիմնված են Unity-ի վրա: Ճարտարապետությունը բավականին դասական է հրաձիգների համար. սերվերը ավտորիտար է, և հաճախորդի կանխատեսումն աշխատում է հաճախորդների վրա: Խաղի սիմուլյացիան գրված է ներքին ECS-ի միջոցով և օգտագործվում է ինչպես սերվերի, այնպես էլ հաճախորդի վրա:

Եթե ​​դուք առաջին անգամ եք լսում հետաձգման փոխհատուցման մասին, ահա թեմայի վերաբերյալ համառոտ էքսկուրսիա:

Multiplayer FPS խաղերում խաղը սովորաբար մոդելավորվում է հեռավոր սերվերի վրա: Խաղացողներն ուղարկում են իրենց մուտքը (սեղմված ստեղների մասին տեղեկությունները) սերվերին, և ի պատասխան սերվերը նրանց ուղարկում է խաղի թարմացված վիճակ՝ հաշվի առնելով ստացված տվյալները: Այս փոխազդեցության սխեմայով առաջ ստեղնը սեղմելու և խաղացողի կերպարի էկրանի վրա շարժվելու պահի միջև ուշացումը միշտ ավելի մեծ կլինի, քան պինգը:

Մինչ լոկալ ցանցերում այս ուշացումը (սովորաբար կոչվում է մուտքային ուշացում) կարող է աննկատ լինել, ինտերնետի միջոցով խաղալիս այն ստեղծում է «սառույցի վրա սահելու» զգացում կերպարը կառավարելիս: Այս խնդիրը կրկնակի արդիական է բջջային ցանցերի համար, որտեղ այն դեպքը, երբ խաղացողի ping-ը 200 ms է, դեռ համարվում է գերազանց կապ։ Հաճախ պինգը կարող է լինել 350, 500 կամ 1000 ms: Այնուհետև գրեթե անհնար է դառնում արագ հրաձիգ խաղալ մուտքային ուշացումով:

Այս խնդրի լուծումը հաճախորդի կողմից սիմուլյացիայի կանխատեսումն է: Այստեղ հաճախորդն ինքն է կիրառում մուտքագրումը խաղացողի կերպարի վրա՝ չսպասելով սերվերի պատասխանին: Եվ երբ պատասխանը ստացվում է, այն պարզապես համեմատում է արդյունքները և թարմացնում հակառակորդների դիրքերը։ Բանալին սեղմելու և արդյունքը էկրանին ցուցադրելու միջև ուշացումն այս դեպքում նվազագույն է:

Այստեղ կարևոր է հասկանալ նրբերանգը. հաճախորդը միշտ նկարում է իրեն ըստ իր վերջին մուտքի, իսկ թշնամիները՝ ցանցի ուշացումով, սերվերի տվյալներից նախկին վիճակի համաձայն: Այսինքն՝ թշնամու վրա կրակելիս խաղացողը նրան տեսնում է անցյալում իր նկատմամբ։ Ավելին հաճախորդի կանխատեսման մասին մենք գրել էինք ավելի վաղ.

Այսպիսով, հաճախորդի կանխատեսումը լուծում է մի խնդիր, բայց ստեղծում է մեկ այլ խնդիր. եթե խաղացողը կրակում է այն կետում, որտեղ նախկինում եղել է թշնամին, սերվերի վրա, երբ կրակում է նույն կետում, հակառակորդը կարող է այլևս այդ տեղում չլինել: Սերվերի հետաձգման փոխհատուցումը փորձում է լուծել այս խնդիրը: Երբ զենք է կրակում, սերվերը վերականգնում է խաղի վիճակը, որը խաղացողը տեսել է կրակոցի պահին, և ստուգում է, թե արդյոք նա իսկապես կարող էր հարվածել թշնամուն: Եթե ​​պատասխանը «այո» է, հարվածը հաշվվում է, նույնիսկ եթե այդ պահին թշնամին այլևս սերվերում չէ:

Այս գիտելիքներով զինված՝ մենք սկսեցինք իրականացնել սերվերի հետաձգման փոխհատուցում Dino Squad-ում: Առաջին հերթին մենք պետք է հասկանայինք, թե ինչպես վերականգնել սերվերի վրա այն, ինչ տեսել է հաճախորդը: Իսկ կոնկրետ ի՞նչն է պետք վերականգնել։ Մեր խաղում զենքերից և հնարավորություններից հարվածները հաշվարկվում են ճառագայթների և ծածկույթների միջոցով, այսինքն՝ հակառակորդի ֆիզիկական բախիչների հետ փոխազդեցության միջոցով: Համապատասխանաբար, մենք պետք է վերարտադրեինք այս բախիչների դիրքը, որը խաղացողը «տեսավ» տեղում, սերվերի վրա: Այդ ժամանակ մենք օգտագործում էինք Unity տարբերակը 2018.x: Այնտեղ ֆիզիկայի API-ն ստատիկ է, ֆիզիկական աշխարհը գոյություն ունի մեկ օրինակով: Ոչ մի կերպ հնարավոր չէ փրկել նրա վիճակը, իսկ հետո վերականգնել այն տուփից։ Այսպիսով, ինչ անել:

Լուծումը երևում էր, դրա բոլոր տարրերն արդեն օգտագործվել էին մեր կողմից այլ խնդիրներ լուծելու համար.

  1. Յուրաքանչյուր հաճախորդի համար մենք պետք է իմանանք, թե երբ է նա տեսել հակառակորդներին, երբ սեղմել է ստեղները: Մենք արդեն գրել ենք այս տեղեկատվությունը մուտքային փաթեթում և օգտագործել այն հաճախորդի կանխատեսումը հարմարեցնելու համար:
  2. Մենք պետք է կարողանանք պահել խաղային վիճակների պատմությունը: Դրա մեջ է, որ մենք կպահենք մեր հակառակորդների (հետևաբար նրանց բախողների) դիրքերը։ Մենք արդեն ունեինք պետական ​​պատմություն սերվերի վրա, այն օգտագործեցինք կառուցելու համար դելտաներ. Իմանալով ճիշտ ժամանակը, մենք հեշտությամբ կարողացանք պատմության մեջ գտնել ճիշտ վիճակը:
  3. Այժմ, երբ մենք ունենք խաղի վիճակը պատմությունից, մենք պետք է կարողանանք համաժամեցնել խաղացողի տվյալները ֆիզիկական աշխարհի վիճակի հետ: Գոյություն ունեցող բախիչներ՝ շարժվել, բացակայողներ՝ ստեղծել, ավելորդներ՝ ոչնչացնել։ Այս տրամաբանությունը նույնպես արդեն գրված էր և բաղկացած էր մի քանի ECS համակարգերից։ Մենք այն օգտագործել ենք մի քանի խաղասենյակներ անցկացնելու համար մեկ Unity գործընթացում: Եվ քանի որ ֆիզիկական աշխարհը մեկ գործընթաց է, այն պետք է նորից օգտագործվեր սենյակների միջև: Սիմուլյացիայի յուրաքանչյուր նշանից առաջ մենք «վերակայում էինք» ֆիզիկական աշխարհի վիճակը և այն վերսկսում էինք ընթացիկ սենյակի տվյալների հետ՝ փորձելով հնարավորինս վերօգտագործել Unity խաղի օբյեկտները խելացի միավորման համակարգի միջոցով: Մնում էր միայն անցյալի խաղի վիճակի նույն տրամաբանությունը վկայակոչել։

Այս բոլոր տարրերը միասին հավաքելով՝ մենք ստացանք «ժամանակի մեքենա», որը կարող էր հետ մղել ֆիզիկական աշխարհի վիճակը ճիշտ պահին: Կոդը պարզվեց.

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;
     }
}

Մնում էր միայն պարզել, թե ինչպես օգտագործել այս մեքենան՝ կրակոցներն ու կարողությունները հեշտությամբ փոխհատուցելու համար:

Ամենապարզ դեպքում, երբ մեխանիզմը հիմնված է մեկ հիթսկանի վրա, թվում է, թե ամեն ինչ պարզ է. նախքան խաղացողը կրակելը, նա պետք է հետ գլորի ֆիզիկական աշխարհը ցանկալի վիճակին, կատարի ռեյքաստ, հաշվի հարվածը կամ բաց թողնումը և վերադարձնել աշխարհը սկզբնական վիճակին.

Բայց Dino Squad-ում նման մեխանիկներ շատ քիչ կան: Խաղի զենքերի մեծ մասը ստեղծում է արկեր՝ երկարակյաց փամփուշտներ, որոնք թռչում են մի քանի սիմուլյացիոն տիզերի համար (որոշ դեպքերում՝ տասնյակ տիզ): Ի՞նչ անել նրանց հետ, քանի՞ ժամին պետք է թռչեն:

В հնագույն հոդված Half-Life ցանցի ստեկի մասին, Valve-ի տղաները տվեցին նույն հարցը, և նրանց պատասխանը հետևյալն էր. արկերի հետաձգման փոխհատուցումը խնդրահարույց է, և ավելի լավ է խուսափել դրանից:

Մենք չունեինք այս տարբերակը. հրթիռների վրա հիմնված զենքերը խաղի ձևավորման հիմնական առանձնահատկությունն էին: Այսպիսով, մենք պետք է ինչ-որ բան մտածեինք: Որոշ ուղեղային փոթորկից հետո մենք ձևակերպեցինք երկու տարբերակ, որոնք կարծես թե աշխատում էին.

1. Արկը կապում ենք այն ստեղծած խաղացողի ժամանակին։ Սերվերի սիմուլյացիայի յուրաքանչյուր նշան, յուրաքանչյուր խաղացողի յուրաքանչյուր կետի համար մենք ֆիզիկական աշխարհը վերադարձնում ենք հաճախորդի վիճակ և կատարում ենք անհրաժեշտ հաշվարկները: Այս մոտեցումը հնարավորություն տվեց ունենալ բաշխված բեռ սերվերի վրա և արկերի թռիչքի կանխատեսելի ժամանակ։ Մեզ համար հատկապես կարևոր էր կանխատեսելիությունը, քանի որ մենք ունենք բոլոր արկերը, ներառյալ թշնամու արկերը, կանխատեսված պատվիրատուի վրա:

Ինչպես մենք բարելավեցինք բալիստիկ հաշվարկների մեխանիզմը շարժական հրաձիգի համար ցանցի հետաձգման փոխհատուցման ալգորիթմով
Նկարում տիզ 30-ի խաղացողը ակնկալիքով հրթիռ է արձակում. նա տեսնում է, թե որ ուղղությամբ է վազում թշնամին և գիտի հրթիռի մոտավոր արագությունը: Տեղում տեսնում է, որ 33-րդ տիզին հարվածել է թիրախին։ Հետաձգման փոխհատուցման շնորհիվ այն կհայտնվի նաև սերվերում

2. Մենք ամեն ինչ անում ենք այնպես, ինչպես առաջին տարբերակում, բայց, հաշվելով գնդակի սիմուլյացիայի մեկ նշանը, մենք չենք դադարում, այլ շարունակում ենք մոդելավորել դրա թռիչքը նույն սերվերի տիզում, ամեն անգամ իր ժամանակը մոտեցնելով սերվերին: մեկ առ մեկ նշում և թարմացնում է կոլայդերների դիրքերը: Մենք դա անում ենք այնքան ժամանակ, մինչև տեղի ունենա երկու բաներից մեկը.

  • Փամփուշտի ժամկետը լրացել է։ Սա նշանակում է, որ հաշվարկներն ավարտվել են, մենք կարող ենք հաշվել բաց թողնելը կամ հարվածը։ Եվ սա այն նույն տիզն է, որում արձակվել է կրակոցը։ Մեզ համար սա և՛ պլյուս էր, և՛ մինուս։ Գումար - քանի որ կրակող խաղացողի համար դա զգալիորեն նվազեցրեց հարվածի և հակառակորդի առողջության նվազման միջև ընկած ժամանակահատվածը: Բացասական կողմն այն է, որ նույն էֆեկտը նկատվում էր, երբ հակառակորդները կրակում էին խաղացողի վրա. թշնամին, թվում էր, միայն դանդաղ հրթիռ է արձակել, և վնասն արդեն հաշվվել է:
  • Գնդակը հասել է սերվերի ժամանակին: Այս դեպքում դրա սիմուլյացիան կշարունակվի սերվերի հաջորդ տիզում՝ առանց որևէ ուշացման փոխհատուցման: Դանդաղ արկերի դեպքում դա տեսականորեն կարող է նվազեցնել ֆիզիկայի հետադարձումների քանակը՝ համեմատած առաջին տարբերակի հետ: Միևնույն ժամանակ, սիմուլյացիայի անհավասար ծանրաբեռնվածությունը մեծացավ. սերվերը կա՛մ անգործության էր մատնված, կա՛մ սերվերի մեկ տիզում այն ​​հաշվարկում էր մի քանի փամփուշտների համար մեկ տասնյակ սիմուլյացիոն տիզ:

Ինչպես մենք բարելավեցինք բալիստիկ հաշվարկների մեխանիզմը շարժական հրաձիգի համար ցանցի հետաձգման փոխհատուցման ալգորիթմով
Նույն սցենարը, ինչպես նախորդ նկարում, բայց հաշվարկված է երկրորդ սխեմայով: Հրթիռը «բռնեց» սերվերի ժամանակին այն նույն տիզում, որով տեղի է ունեցել կրակոցը, և հարվածը կարելի է հաշվել հենց հաջորդ տիզը: 31-րդ կետում այս դեպքում հետաձգման փոխհատուցում այլևս չի կիրառվում

Մեր իրականացման ընթացքում այս երկու մոտեցումները տարբերվում էին ընդամենը մի քանի տող կոդով, այնպես որ մենք ստեղծեցինք երկուսն էլ, և երկար ժամանակ դրանք գոյություն ունեին զուգահեռ: Կախված զենքի մեխանիզմից և փամփուշտի արագությունից՝ յուրաքանչյուր դինոզավրի համար ընտրեցինք այս կամ այն ​​տարբերակը։ Այստեղ բեկումնային պահը մեխանիկայի խաղի մեջ հայտնվելն էր, օրինակ՝ «եթե այսքան ժամանակ թշնամուն այդքան հարված հասցնես, ստացիր այսինչ բոնուսը»: Ցանկացած մեխանիկ, որտեղ խաղացողը հարվածել է թշնամուն, կարևոր դեր է խաղացել, հրաժարվում է աշխատել երկրորդ մոտեցմամբ: Այսպիսով, մենք ավարտեցինք առաջին տարբերակը, և այն այժմ վերաբերում է բոլոր զենքերին և խաղի բոլոր ակտիվ ունակություններին:

Առանձին-առանձին արժե բարձրացնել կատարման հարցը։ Եթե ​​կարծում էիք, որ այս ամենը կդանդաղեցնի իրադարձությունները, ես պատասխանում եմ՝ այդպես է։ Unity-ը բավականին դանդաղ է բախվող սարքերի շարժման և դրանք միացնելու և անջատելու մեջ: Dino Squad-ում, «ամենավատ» դեպքում, մարտում կարող են լինել միաժամանակ մի քանի հարյուր արկեր: Յուրաքանչյուր արկ առանձին-առանձին հաշվելու համար բախվող սարքերը անհասանելի շքեղություն է: Հետևաբար, մեզ համար բացարձակապես անհրաժեշտ էր նվազագույնի հասցնել ֆիզիկայի «վերադարձների» քանակը։ Դա անելու համար ECS-ում ստեղծեցինք առանձին բաղադրիչ, որում գրանցում ենք խաղացողի ժամանակը: Մենք այն ավելացրել ենք բոլոր այն կազմակերպություններին, որոնք պահանջում են հետաձգման փոխհատուցում (արկեր, կարողություններ և այլն): Նախքան մենք կսկսենք մշակել այդպիսի սուբյեկտները, մենք մինչև այս պահը հավաքում ենք դրանք և մշակում դրանք միասին՝ յուրաքանչյուր կլաստերի համար մեկ անգամ հետ գլորելով ֆիզիկական աշխարհը:

Այս փուլում մենք ընդհանուր առմամբ գործող համակարգ ունենք։ Դրա ծածկագիրը փոքր-ինչ պարզեցված ձևով.

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

Մնում էր միայն կարգավորել մանրամասները.

1. Հասկացեք, թե որքանով է պետք ժամանակի ընթացքում սահմանափակել շարժման առավելագույն հեռավորությունը:

Մեզ համար կարևոր էր խաղը հնարավորինս հասանելի դարձնել բջջային ցանցերի վատ պայմաններում, ուստի մենք սահմանափակեցինք պատմությունը 30 տիկ մարժանով (20 Հց հաճախականությամբ): Սա թույլ է տալիս խաղացողներին հարվածել հակառակորդներին նույնիսկ շատ բարձր պինգերում:

2. Որոշեք, թե որ առարկաները կարելի է տեղափոխել ժամանակի ընթացքում, որոնք՝ ոչ:

Մենք, իհարկե, շարժում ենք մեր հակառակորդներին։ Սակայն տեղադրվող էներգետիկ վահանները, օրինակ, չեն: Մենք որոշեցինք, որ ավելի լավ է առաջնահերթությունը տալ պաշտպանողական ունակություններին, ինչպես դա հաճախ արվում է առցանց հրաձիգներում։ Եթե ​​խաղացողն արդեն վահան է տեղադրել ներկայում, ապա անցյալից փոխհատուցվող փամփուշտները չպետք է թռչեն դրա միջով:

3. Որոշեք, թե արդյոք անհրաժեշտ է փոխհատուցել դինոզավրերի կարողությունները՝ կծում, պոչով հարված և այլն: Մենք որոշեցինք, թե ինչ է անհրաժեշտ և մշակել դրանք նույն կանոններով, ինչ փամփուշտները:

4. Որոշեք, թե ինչ անել այն խաղացողի բախիչների հետ, որոնց համար կատարվում է հետաձգման փոխհատուցում: Լավ իմաստով, նրանց դիրքը չպետք է անցնի անցյալ. խաղացողը պետք է իրեն տեսնի այն նույն ժամանակահատվածում, երբ այժմ գտնվում է սերվերում: Այնուամենայնիվ, մենք նաև հետ ենք գլորում հրաձիգ խաղացողի բախողները, և դրա համար կան մի քանի պատճառներ։

Նախ, այն բարելավում է կլաստերավորումը. մենք կարող ենք օգտագործել նույն ֆիզիկական վիճակը բոլոր խաղացողների համար, ովքեր ունեն փակ պինգ:

Երկրորդ, բոլոր ճառագայթների և համընկնումների ժամանակ մենք միշտ բացառում ենք այն խաղացողի բախողները, ովքեր տիրապետում են կարողություններին կամ արկերին: Dino Squad-ում խաղացողները կառավարում են դինոզավրերին, որոնք հրաձիգների չափանիշներով ունեն բավականին ոչ ստանդարտ երկրաչափություն: Նույնիսկ եթե խաղացողը կրակում է անսովոր անկյան տակ, և գնդակի հետագիծն անցնում է խաղացողի դինոզավրերի բախիչով, փամփուշտը անտեսում է այն:

Երրորդ, մենք հաշվարկում ենք դինոզավրի զենքի դիրքերը կամ ունակության կիրառման կետը, օգտագործելով ECS-ի տվյալները նույնիսկ ուշացման փոխհատուցման մեկնարկից առաջ:

Արդյունքում մեզ համար կարևոր չէ ուշացումով փոխհատուցվող խաղացողի բախողների իրական դիրքը, ուստի մենք գնացինք ավելի արդյունավետ և միևնույն ժամանակ ավելի պարզ ճանապարհով։

Ցանցի հետաձգումը պարզապես հնարավոր չէ հեռացնել, այն կարելի է միայն դիմակավորել: Ինչպես քողարկման ցանկացած այլ եղանակ, սերվերի հետաձգման փոխհատուցումն ունի իր փոխզիջումները: Այն բարելավում է այն խաղացողի խաղային փորձը, ով կրակում է այն խաղացողի հաշվին, ում վրա կրակում են: Dino Squad-ի համար, սակայն, այստեղ ընտրությունն ակնհայտ էր.

Իհարկե, այս ամենի համար պետք էր վճարել նաև սերվերի կոդի բարդության մեծացումը՝ և՛ ծրագրավորողների, և՛ խաղերի դիզայներների համար: Եթե ​​նախկինում սիմուլյացիան համակարգերի պարզ հաջորդական կանչ էր, ապա ուշացման փոխհատուցմամբ դրանում հայտնվեցին բույնի օղակներ և ճյուղեր։ Մենք նույնպես մեծ ջանքեր ենք ծախսել, որպեսզի հարմար լինի դրա հետ աշխատելը։

2019-ի տարբերակում (և միգուցե մի փոքր ավելի վաղ) Unity-ն ավելացրեց լիարժեք աջակցություն անկախ ֆիզիկական տեսարանների համար: Մենք դրանք ներդրեցինք սերվերի վրա թարմացումից գրեթե անմիջապես հետո, քանի որ ցանկանում էինք արագ ազատվել բոլոր սենյակների համար ընդհանուր ֆիզիկական աշխարհից:

Մենք յուրաքանչյուր խաղասենյակի տվեցինք իր ֆիզիկական տեսարանը և այդպիսով վերացրեցինք տեսարանը հարևան սենյակի տվյալներից «մաքրելու» անհրաժեշտությունը նախքան սիմուլյացիան հաշվարկելը: Նախ, դա բերեց արտադրողականության զգալի աճ։ Երկրորդ, դա հնարավոր եղավ ազատվել սխալների մի ամբողջ դասից, որոնք առաջանում էին, եթե ծրագրավորողը սխալ է թույլ տվել տեսարանի մաքրման կոդի մեջ՝ խաղի նոր տարրեր ավելացնելիս: Նման սխալները դժվար էր կարգաբերել, և դրանք հաճախ հանգեցնում էին նրան, որ մի սենյակի տեսարանի ֆիզիկական առարկաները «հոսում» են մյուս սենյակ:

Բացի այդ, մենք որոշ հետազոտություններ կատարեցինք, թե արդյոք ֆիզիկական տեսարանները կարող են օգտագործվել ֆիզիկական աշխարհի պատմությունը պահելու համար: Այսինքն՝ պայմանականորեն յուրաքանչյուր սենյակին հատկացնել ոչ թե մեկ տեսարան, այլ 30 տեսարան և դրանցից ցիկլային բուֆեր պատրաստել, որում պահել պատմությունը։ Ընդհանուր առմամբ, տարբերակն աշխատում էր, բայց մենք այն չկիրառեցինք. արտադրողականության խելահեղ աճ չցուցաբերեց, բայց բավականին ռիսկային փոփոխություններ էր պահանջում։ Դժվար էր կանխատեսել, թե ինչպես կվարվեր սերվերը, երբ երկար աշխատի այդքան տեսարաններով։ Հետևաբար, մենք հետևեցինք կանոնին.Եթե ​​այն կոտրված չէ, մի շտկեք այն.

Source: www.habr.com

Добавить комментарий