portaldacalheta.pt
  • Основен
  • Пъргав
  • Иновация
  • Тенденции
  • Back-End
Back-End

Единство с MVC: Как да изравните развитието на игрите си



Програмистите за първи път обикновено започват да учат занаята с класическата Hello World програма. Оттам нататък непременно ще последват все по-големи и по-големи задачи. Всяко ново предизвикателство носи у дома важен урок:

Колкото по-голям е проектът, толкова по-големи са спагетите.



Скоро е лесно да се види, че в големи или малки екипи човек не може безразсъдно да прави каквото си иска. Кодът трябва да се поддържа и може да продължи дълго време. Компаниите, в които сте работили, не могат просто да търсят данните ви за контакт и да ви питат всеки път, когато искат да поправят или подобрят кодовата база (а вие не искате и те).



Това е причината модели на софтуерно проектиране съществуват; те налагат прости правила, които да диктуват цялостната структура на софтуерен проект. Те помагат на един или повече програмисти да отделят основни части от голям проект и да ги организират по стандартизиран начин, като елиминират объркването, когато се срещне някаква непозната част от кодовата база.



Тези правила, когато се спазват от всички, позволяват по-добре да се поддържа и навигира наследения код и да се добавя по-бързо нов код. По-малко време се отделя за планиране на методологията на разработване. Тъй като проблемите не идват в един вкус, няма модел на сребърен куршум. Човек трябва внимателно да обмисли силните и слабите страни на всеки модел и да намери най-подходящото за предизвикателството.

В този урок ще свържа моя опит с популярното Unity платформа за разработка на игри и моделът на модел-изглед-контролер (MVC) за разработване на игри. През седемте си години на разработка, след като се борих с моя справедлив дял от спагети за разработчици на игри, постигнах страхотна структура на кода и скорост на разработка, използвайки този модел на проектиране.



Ще започна, като обясня малко от основната архитектура на Unity, модела на Entity-Component. След това ще продължа, за да обясня как MVC се вписва отгоре му, и ще използвам малък фалшив проект като пример.

python масив от екземпляри на клас

Мотивация

В литературата за софтуера ще открием голям брой дизайнерски модели. Въпреки че имат набор от правила, разработчиците обикновено правят малко огъване на правила, за да адаптират по-добре модела към специфичния си проблем.



Тази „свобода на програмиране“ е доказателство, че все още не сме намерили нито един окончателен метод за проектиране на софтуер. По този начин тази статия не е предназначена да бъде най-доброто решение на проблема ви, а по-скоро да покаже предимствата и възможностите на два добре познати модела: Entity-Component и Model-View-Controller.

Модел на компонент на обект

Entity-Component (EC) е модел на проектиране, при който първо дефинираме йерархията на елементите, съставляващи приложението (Entities), а по-късно дефинираме характеристиките и данните, които всеки ще съдържа (Components). По-точно „програмист“, Обект може да бъде обект с масив от 0 или повече Компоненти. Нека изобразим Обект като този:



some-entity [component0, component1, ...]

Ето един прост пример за EC дърво.

- app [Application] - game [Game] - player [KeyboardInput, Renderer] - enemies - spider [SpiderAI, Renderer] - ogre [OgreAI, Renderer] - ui [UI] - hud [HUD, MouseInput, Renderer] - pause-menu [PauseMenu, MouseInput, Renderer] - victory-modal [VictoryModal, MouseInput, Renderer] - defeat-modal [DefeatModal, MouseInput, Renderer]

EC е добър модел за облекчаване на проблемите на множественото наследяване, където сложна структура на класа може да доведе до проблеми като диамантен проблем където клас D, наследяващ два класа, B и C, с един и същ основен клас A, може да въведе конфликти, защото как B и C модифицират характеристиките на A по различен начин.



ИЗОБРАЖЕНИЕ: ДИАМАНТЕН ПРОБЛЕМ

Този тип проблеми могат да бъдат често срещани при разработването на игри, където наследяването често се използва широко.



Чрез разбиване на функциите и обработващите данни на по-малки Компоненти, те могат да бъдат прикачени и използвани повторно в различни Обекти, без да се разчита на множество наследства (което между другото дори не е функция на C # или Javascript, основните езици, използвани от Unity ).

Където компонентът на компонент пада кратко

Като едно ниво над OOP, EC помага за дефрагментиране и по-добра организация на вашата архитектура на кода. В големите проекти обаче ние все още сме „твърде свободни“ и можем да се озовем в „океан на характеристиките“, трудно да намерим правилните обекти и компоненти или да разберем как трябва да си взаимодействат. Има безкрайни начини за сглобяване на обекти и компоненти за дадена задача.

ИЗОБРАЖЕНИЕ: ЕО ФУНКЦИЯ ОКЕАН

Един от начините да се избегне бъркотията е да се наложат някои допълнителни насоки върху Entity-Component. Например един начин, по който обичам да мисля за софтуера, е да го разделя на три различни категории:

  • Някои обработват необработените данни, позволявайки им да бъдат създадени, прочетени, актуализирани, изтрити или търсени (т.е. ЖЕСТКО концепция).
  • Други реализират интерфейса за взаимодействие с други елементи, като откриват събития, свързани с техния обхват, и задействат известия, когато се появят.
  • И накрая, някои елементи са отговорни за получаването на тези известия, вземането на решения за бизнес логика и решаването на начина, по който данните трябва да бъдат манипулирани.

За щастие вече имаме модел, който се държи точно по този начин.

Моделът на модел-изглед-контролер (MVC)

The Модел модел на изглед-контролер (MVC) разделя софтуера на три основни компонента: модели (Data CRUD), изгледи (интерфейс / откриване) и контролери (решение / действие). MVC е достатъчно гъвкав, за да бъде приложен дори върху ECS или OOP.

Разработването на игри и потребителски интерфейс има обичайния работен процес на изчакване за въвеждане от потребителя или друго задействащо условие, изпращане на известие за тези събития някъде подходящо, вземане на решение какво да се направи в отговор и актуализиране на данните съответно. Тези действия ясно показват съвместимостта на тези приложения с MVC.

Тази методология въвежда още един абстракционен слой, който ще помогне при софтуерното планиране, а също така ще позволи на новите програмисти да се ориентират дори в по-голяма кодова база. Чрез разделяне на процеса на мислене на данни, интерфейс и решения, разработчиците могат да намалят броя на изходните файлове, които трябва да бъдат търсени, за да добавят или поправят функционалност.

Единство и ЕО

Нека първо разгледаме отблизо какво ни дава Unity отпред.

Unity е базирана на ЕО платформа за развитие, където всички субекти са екземпляри на GameObject и функциите, които ги правят „видими“, „подвижни“, „взаимодействащи“ и т.н., се предоставят от класове, разширяващи се Component

Редакторът на Unity Йерархичен панел и Инспекторски панел предоставят мощен начин за сглобяване на вашето приложение, прикачване на компоненти, конфигуриране на първоначалното им състояние и стартиране на играта ви с много по-малко изходен код, отколкото обикновено.

СКРИНШОТ: ИЕРАРХИЧЕН ПАНЕЛ Йерархичен панел с четири GameObjects вдясно

СКРИНШОТ: ИНСПЕКТОРЕН ПАНЕЛ Инспекторски панел с компоненти на GameObject

И все пак, както вече обсъждахме, можем да ударим проблема „твърде много функции“ и да се озовем в гигантска йерархия, с функции, разпръснати навсякъде, което прави живота на разработчика много по-труден.

Мислейки по MVC начин, вместо това можем да започнем с разделяне на нещата според тяхната функция, като структурираме нашето приложение като примера по-долу:

SCREENSHOT: UNITY MVC ПРИМЕРНА СТРУКТУРА

Адаптиране на MVC към среда за разработка на игри

Сега бих искал да представя две малки модификации на общия модел на MVC, които помагат да се адаптира към уникалните ситуации, които съм срещал при изграждането на проекти на Unity с MVC:

  1. Препратките към класа MVC лесно се разпръскват из целия код. - В рамките на Unity разработчиците обикновено трябва да плъзгат и пускат екземпляри наоколо, за да ги направят достъпни, или в противен случай да ги достигнат чрез тромави инструкции за търсене като GetComponent( ... ) - Адът на загубените препратки ще настъпи, ако Unity се срине или някоя грешка накара всички изтеглени препратки да изчезнат. - Това налага наличието на единичен коренен обект, чрез който всички екземпляри в Приложение може да бъде достигнато и възстановено.
  2. Някои елементи капсулират обща функционалност, която трябва да бъде многократно използвана и която естествено не попада в една от трите основни категории Модел, Изглед или Контролер. Тези, които обичам да наричам просто Компоненти . Те също са „Компоненти“ в смисъла на Същност-Компонент, но просто действат като помощници в рамката на MVC. - Например a Rotator Компонент, който само върти нещата с дадена ъглова скорост и не уведомява, съхранява или решава нищо.

За да помогна за облекчаване на тези два проблема, измислих модифициран модел, който наричам AMVCC , или Application-Model-View-Controller-Component.

ИЗОБРАЖЕНИЕ: СХЕМА НА AMVCC

  • Приложение - Единична входна точка към вашето приложение и контейнер на всички критични екземпляри и данни, свързани с приложението.
  • MVC - Трябва да знаете това досега. :)
  • Съставна част - Малък, добре съдържащ се скрипт, който може да се използва повторно.

Тези две модификации задоволиха нуждите ми за всички проекти, в които съм ги използвал.

Пример: 10 отскока

Като прост пример, нека разгледаме малка игра, наречена 10 отскока , където ще използвам основните елементи на модела AMVCC.

Настройката на играта е проста: A Ball с SphereCollider и a Rigidbody (което ще започне да пада след „Игра“), a Cube като основа и 5 скрипта за съставяне на AMVCC.

Йерархия

Преди да създавам скриптове, обикновено започвам от йерархията и създавам контур на моя клас и активи. Винаги следвайки този нов AMVCC стил.

СКРИНШОТ: СГРАДА НА ИЕРАРХИЯТА

Както виждаме, view GameObject съдържа всички визуални елементи, както и такива с други View скриптове. model и controller GameObjects, за малки проекти, обикновено съдържат само съответните им скриптове. За по-големи проекти те ще съдържат GameObjects с по-специфични скриптове.

Когато някой, който навигира във вашия проект, иска достъп:

  • Данни: Отидете на application > model > ...
  • Логика / работен поток: Отидете на application > controller > ...
  • Оказване / интерфейс / откриване: Отидете на application > view > ...

Ако всички екипи спазват тези прости правила, наследствените проекти не трябва да се превръщат в проблем.

Имайте предвид, че няма Component контейнер, защото, както вече обсъждахме, те са по-гъвкави и могат да бъдат прикрепени към различни елементи в свободното време на разработчика.

Сценарии

Забележка: Скриптовете, показани по-долу, са абстрактни версии на реални реализации. Подробно изпълнение няма да е от полза за читателя много. Ако обаче искате да проучите повече, ето връзката към моята лична MVC рамка за Unity, Unity MVC. Ще намерите основни класове, които прилагат AMVCC структурна рамка, необходима за повечето приложения.

компилиране на C++ код

Нека да разгледаме структурата на скриптовете за 10 отскока .

Преди да започнем, за тези, които не са запознати с работния процес на Unity, нека изясним накратко как скриптовете и GameObjects работят заедно. В Unity „Компонентите“, в смисъла Entity-Component, са представени от MonoBehaviour клас. За да съществува такъв по време на изпълнение, разработчикът трябва или да плъзне и пусне своя изходен файл в GameObject (който е „Entity“ на модела Entity-Component) или да използва командата AddComponent() След това скриптът ще бъде създаден и готов за използване по време на изпълнение.

За начало дефинираме клас Application („A“ в AMVCC), който ще бъде основният клас, съдържащ препратки към всички екземпляри на игровите елементи. Също така ще създадем помощен основен клас, наречен Element, който ни дава достъп до екземпляра на Приложението и екземплярите на MVC на децата му.

Имайки това предвид, нека дефинираме Application клас („A“ в AMVCC), който ще има уникален екземпляр. В него три променливи, model, view и controller, ще ни дадат точки за достъп за всички екземпляри на MVC по време на изпълнение. Тези променливи трябва да бъдат MonoBehaviour s с public препратки към желаните скриптове.

След това ще създадем и помощен основен клас, наречен Element, който ни дава достъп до екземпляра на Приложението. Този достъп ще позволи на всеки MVC клас да достигне всеки друг.

Имайте предвид, че и двата класа се разширяват MonoBehaviour. Те са „Компоненти“, които ще бъдат прикачени към GameObject „Entities“.

// BounceApplication.cs // Base class for all elements in this application. public class BounceElement : MonoBehaviour { // Gives access to the application and all instances. public BounceApplication app { get { return GameObject.FindObjectOfType(); }} } // 10 Bounces Entry Point. public class BounceApplication : MonoBehaviour { // Reference to the root instances of the MVC. public BounceModel model; public BounceView view; public BounceController controller; // Init things here void Start() { } }

От BounceElement можем да създадем основните класове на MVC. BounceModel, BounceView И BounceController скриптовете обикновено действат като контейнери за по-специализирани екземпляри, но тъй като това е прост пример, само View ще има вложена структура. Моделът и контролерът могат да бъдат направени в един скрипт за всеки:

// BounceModel.cs // Contains all data related to the app. public class BounceModel : BounceElement { // Data public int bounces; public int winCondition; } // BounceView .cs // Contains all views related to the app. public class BounceView : BounceElement { // Reference to the ball public BallView ball; } // BallView.cs // Describes the Ball view and its features. public class BallView : BounceElement { // Only this is necessary. Physics is doing the rest of work. // Callback called upon collision. void OnCollisionEnter() { app.controller.OnBallGroundHit(); } } // BounceController.cs // Controls the app workflow. public class BounceController : BounceElement { // Handles the ball hit event public void OnBallGroundHit() { app.model.bounces++; Debug.Log(“Bounce ”+app.model.bounce); if(app.model.bounces >= app.model.winCondition) { app.view.ball.enabled = false; app.view.ball.GetComponent().isKinematic=true; // stops the ball OnGameComplete(); } } // Handles the win condition public void OnGameComplete() { Debug.Log(“Victory!!”); } }

С всички създадени скриптове можем да продължим с прикачването и конфигурирането им.

Йерархичното оформление трябва да бъде такова:

- application [BounceApplication] - model [BounceModel] - controller [BounceController] - view [BounceView] - ... - ball [BallView] - ...

Използване на BounceModel като пример можем да видим как изглежда в редактора на Unity:

СКРИНШОТ: BounceModel IN INSPECTOR BounceModel с bounces и winCondition полета.

След като всички скриптове са настроени и играта работи, трябва да получим този изход в Конзолен панел .

SCREENSHOT: КОНСОЛИРАН ИЗХОД

Известия

Както е показано в горния пример, когато топката се удари в земята, нейният изглед изпълнява app.controller.OnBallGroundHit() което е метод. По никакъв начин не е „погрешно“ да се прави това за всички известия в приложението. Според моя опит обаче постигнах по-добри резултати, използвайки проста система за уведомяване, внедрена в класа на приложението AMVCC.

За да приложим това, нека актуализираме оформлението на BounceApplication да бъде:

// BounceApplication.cs class BounceApplication { // Iterates all Controllers and delegates the notification data // This method can easily be found because every class is “BounceElement” and has an “app” // instance. public void Notify(string p_event_path, Object p_target, params object[] p_data) { BounceController[] controller_list = GetAllControllers(); foreach(BounceController c in controller_list) { c.OnNotification(p_event_path,p_target,p_data); } } // Fetches all scene Controllers. public BounceController[] GetAllControllers() { /* ... */ } }

След това се нуждаем от нов скрипт, където всички разработчици ще добавят имената на събитието за уведомяване, които могат да бъдат изпратени по време на изпълнението.

// BounceNotifications.cs // This class will give static access to the events strings. class BounceNotification { static public string BallHitGround = “ball.hit.ground”; static public string GameComplete = “game.complete”; /* ... */ static public string GameStart = “game.start”; static public string SceneLoad = “scene.load”; /* ... */ }

Лесно е да се види, че по този начин четливостта на кода се подобрява, тъй като разработчиците не трябва да търсят в целия изходен код за controller.OnSomethingComplexName методи, за да се разбере какъв вид действия могат да се случат по време на изпълнение. Чрез проверка само на един файл е възможно да се разбере цялостното поведение на приложението.

Сега трябва само да адаптираме BallView и BounceController да се справят с тази нова система.

// BallView.cs // Describes the Ball view and its features. public class BallView : BounceElement { // Only this is necessary. Physics is doing the rest of work. // Callback called upon collision. void OnCollisionEnter() { app.Notify(BounceNotification.BallHitGround,this); } } // BounceController.cs // Controls the app workflow. public class BounceController : BounceElement { // Handles the ball hit event public void OnNotification(string p_event_path,Object p_target,params object[] p_data) { switch(p_event_path) { case BounceNotification.BallHitGround: app.model.bounces++; Debug.Log(“Bounce ”+app.model.bounce); if(app.model.bounces >= app.model.winCondition) { app.view.ball.enabled = false; app.view.ball.GetComponent().isKinematic=true; // stops the ball // Notify itself and other controllers possibly interested in the event app.Notify(BounceNotification.GameComplete,this); } break; case BounceNotification.GameComplete: Debug.Log(“Victory!!”); break; } } }

По-големите проекти ще имат много известия. Така че, за да се избегне получаване на голяма структура на случай на превключване, препоръчително е да създадете различни контролери и да ги накарате да обработват различни обхвати за уведомяване.

AMVCC в реалния свят

Този пример показа прост случай на използване на модела AMVCC. Коригирането на начина ви на мислене по отношение на трите елемента на MVC и научаването да визуализирате обектите като подредена йерархия са уменията, които трябва да бъдат усъвършенствани.

При по-големи проекти разработчиците ще се сблъскат с по-сложни сценарии и съмнения дали нещо трябва да бъде View или Controller, или дали даден клас трябва да бъде по-щателно разделен в по-малки.

Правила на палеца (от Едуардо)

Никъде няма „Универсално ръководство за MVC сортиране“. Но има някои прости правила, които обикновено спазвам, за да ми помогнат да определя дали да определя нещо като Модел, Изглед или Контролер, както и кога да разделя даден клас на по-малки парчета.

Обикновено това се случва органично, докато мисля за софтуерната архитектура или по време на скриптове.

Сортиране в клас

Модели

  • Съхранявайте основните данни и състояние на приложението, като плейър health или пистолет ammo.
  • Сериализирайте, десериализирайте и / или конвертирайте между типовете.
  • Заредете / запазете данни (локално или в мрежата).
  • Уведомявайте контролерите за хода на операциите.
  • Съхранявайте Състоянието на играта за Играта Крайна държавна машина .
  • Никога няма достъп до Views.

Изгледи

  • Може да получава данни от Модели, за да представи на потребителя актуално състояние на играта. Например метод View player.Run() може да използва вътрешно model.speed за да прояви способностите на играча.
  • Никога не трябва да мутира модели.
  • Стриктно прилага функционалностите на своя клас. Например:
    • A PlayerView не трябва да прилагат откриване на вход или да променят състоянието на играта.
    • Изгледът трябва да действа като черна кутия, която има интерфейс и известява за важни събития.
    • Не съхранява основните данни (като скорост, здраве, живот, ...).

Контролери

  • Не съхранявайте основните данни.
  • Понякога може да филтрира известия от нежелани изгледи.
  • Актуализирайте и използвайте данните на модела.
  • Управлява работния процес на сцената на Unity.

Класова йерархия

В този случай няма много стъпки, които следвам. Обикновено възприемам, че някой клас трябва да бъде разделен, когато променливите започват да показват твърде много „префикси“ или започват да се появяват твърде много варианти на един и същ елемент (като Player класове в MMO или Gun типове в FPS).

Например единичен Model съдържащи данните на Player ще имат много playerDataA, playerDataB,... или a Controller обработка на известия на Player ще има OnPlayerDidA,OnPlayerDidB,.... Искаме да намалим размера на скрипта и да се отървем от player и OnPlayer представки.

Позволете ми да демонстрирам с помощта на Model клас, защото е по-лесно да се разбере само с данни.

По време на програмирането обикновено започвам с един Model клас, съдържащ всички данни за играта.

// Model.cs class Model { public float playerHealth; public int playerLives; public GameObject playerGunPrefabA; public int playerGunAmmoA; public GameObject playerGunPrefabB; public int playerGunAmmoB; // Ops Gun[C D E ...] will appear... /* ... */ public float gameSpeed; public int gameLevel; }

Лесно е да се види, че колкото по-сложна е играта, толкова по-многобройни ще бъдат променливите. С достатъчно сложност бихме могли да получим гигантски клас, съдържащ model.playerABCDFoo променливи. Влагащите елементи ще опростят завършването на кода и също така ще дадат възможност за превключване между варианти на данни.

плюсове и минуси на корпорациите
// Model.cs class Model { public PlayerModel player; // Container of the Player data. public GameModel game; // Container of the Game data. } // GameModel.cs class GameModel { public float speed; // Game running speed (influencing the difficulty) public int level; // Current game level/stage loaded } // PlayerModel.cs class PlayerModel { public float health; // Player health from 0.0 to 1.0. public int lives; // Player “retry” count after he dies. public GunModel[] guns; // Now a Player can have an array of guns to switch ingame. } // GunModel.cs class GunModel { public GunType type; // Enumeration of Gun types. public GameObject prefab; // Template of the 3D Asset of the weapon. public int ammo; // Current number of bullets public int clips; // Number of reloads possible }

С тази конфигурация на класове разработчиците могат да се ориентират интуитивно в изходния код една по една концепция. Нека приемем игра за стрелба от първо лице, където оръжията и техните конфигурации могат да станат наистина многобройни. Фактът, че GunModel се съдържа в клас позволява създаването на списък от Prefabs (предварително конфигурирани GameObjects за бързо дублиране и повторно използване в играта) за всяка категория и съхранявани за по-късна употреба.

За разлика от това, ако информацията за пистолета е била съхранявана заедно в единичната GunModel клас, в променливи като gun0Ammo, gun1Ammo, gun0Clips и т.н., след това потребителят, когато е изправен пред необходимостта от съхраняване Gun данни, ще трябва да съхранява цялата Model включително нежеланото Player данни. В този случай би било очевидно, че нов GunModel клас би било по-добре.

ИЗОБРАЖЕНИЕ: КЛАСНА ИЕРАРХИЯ Подобряване на йерархията на класовете.

Както при всичко, има две страни на медала. Понякога човек може ненужно да прекалява и да увеличи сложността на кода. Само опитът може да усъвършенства уменията ви достатъчно, за да намерите най-доброто MVC сортиране за вашия проект.

Отключена е нова способност за разработчици на специални възможности: Unity игри с MVC модел. Tweet

Заключение

Има много софтуерни модели там. В този пост се опитах да покажа този, който ми помогна най-много в минали проекти. Разработчици винаги трябва да поглъща нови знания, но винаги също ги поставя под съмнение. Надявам се, че този урок ще ви помогне да научите нещо ново и в същото време ще ви послужи като стъпка, докато развивате свой собствен стил.

Също така наистина ви насърчавам да изследвате други модели и да намерите този, който ви подхожда най-добре. Една добра отправна точка е тази статия в Уикипедия , с отличния си списък с модели и техните характеристики.

Ако харесвате модела AMVCC и искате да го тествате, не забравяйте да изпробвате библиотеката ми, Единство MVC , който съдържа всички основни класове, необходими за стартиране на AMVCC приложение.

Създаване на умопомрачителни илюстрации със скица и лупер за нула време

Инструменти И Уроци

Създаване на умопомрачителни илюстрации със скица и лупер за нула време
Стартиране на финансиране за основатели: Вашият контролен списък

Стартиране на финансиране за основатели: Вашият контролен списък

Финансови Процеси

Популярни Публикации
ApeeScape разраства връзката си с Amazon Web Services, за да продължи да стимулира икономиката на талантите
ApeeScape разраства връзката си с Amazon Web Services, за да продължи да стимулира икономиката на талантите
Въведение в теорията и сложността на изчислимостта
Въведение в теорията и сложността на изчислимостта
Ръководство стъпка по стъпка за проектиране на персонализирани илюстрации без предишен опит
Ръководство стъпка по стъпка за проектиране на персонализирани илюстрации без предишен опит
Обяснено оптимизиране на ефективността на Magento
Обяснено оптимизиране на ефективността на Magento
Изчерпателно ръководство за дизайн на известия
Изчерпателно ръководство за дизайн на известия
 
Малки данни, големи възможности
Малки данни, големи възможности
Достъпност в мрежата: Защо стандартите W3C често се игнорират
Достъпност в мрежата: Защо стандартите W3C често се игнорират
Бъдещето на UX е нашето човечество
Бъдещето на UX е нашето човечество
Предвиждащ дизайн: Как да създадем магически потребителски опит
Предвиждащ дизайн: Как да създадем магически потребителски опит
Въведение в Python Microservices с Nameko
Въведение в Python Microservices с Nameko
Популярни Публикации
  • използвайки raspberry pi като сървър
  • гръцка финансова криза за манекени
  • какво представляват xml данни в word
  • php запис в лог файл
  • discord бот, който отговаря на съобщения
  • цена на еластичността на търсенето
Категории
  • Пъргав
  • Иновация
  • Тенденции
  • Back-End
  • © 2022 | Всички Права Запазени

    portaldacalheta.pt