JS战斗

程序员游戏

ВыможетепомнитьАлександраКоротаевапобраузернойверсии«ГероевМечаиМагии»:расшифровкаегодокладаонейсобраланаХабрегромадноеколичествопросмотров。 Атеперьонсделалигру,ориентированнуюнапрограммистов:игратьвнеёнадоJS-кодом。

Вэтотразнаразработкуушлинегоды,анедели,нобезинтересныхчелленджейвсёравнонеобошл。 Каксделать,чтобыиграбылаудобнадажеразработчикам,ранеенетрогавшимJavaScript? Какзащититьсяотпростыхспособовперехитритьигру?

ВитогеАлександрсновасделалдокладнаHolyJS,организаторыконференцииподготовилидлятекстовуюверси。

Унасвкомпаниибылпроведенбольшойтурнир,вкоторомучаствовалифактическилюбыепрограммстсты。

JS —移相器。ИзтехнологийяиспользовалсамыйпопулярныйигровойдвижокизмираJS。 Ace编辑器。Самыйбольшойипопулярныйчастоиспользуемый。 lim,ооо,Sublime VS VSCodeооооооооооооо。。。。 ЕщеяиспользовалRxJS,чтобыработатьсасинхроннымивзаимодействиямиотразныхпользтателейи精确。 工人和Websocket在一起。Изнативныхтехнологийособенночастоработалс

Игрыдляпрограммистов

Чтовообщетакоеигрыдляпрограммистов? Намойвзгляд, «电梯英雄传奇»—випешескриптыдлялифтовпоопределеннымпарамет。 «爬行»—пробиологию,молекулы,пишетескриптыдляних。

Естьещеигрушки,которыеиногдабываютнаконференциях。 Самаяпопулярнаяизних«黑暗中的密码»,您可以在самаяпыпалапредставлена上找到。 Кстати,《黑暗中的代码》,ччм-товдохновиламенянаэтовсё。

Зачемэтобылосделано? Мнепоступилазадача,чтонужнопридуматьчто-топрикольноесостендомнаконференцию,что-тонеоб。 Нетак,чтобыстоялиэйчарысопросниками。 Понятно,чтовоехочетсяпривлечьксебевниманиеисобратьконтакты。 Мырешилипойтидальшеипридумаличто-токлассноеифановоедляпрограммистов。 Японял,чтопрограммистыхотятсражаться,посостязаться,инадодатьимтакуювозможность。 Нужносоздатьстенд,накоторыйонипридутибудуткодить。

Геймификация。 Мыпроводилиэтонетолькосредипрактикующихпрограммистов,ноисредиучащихся。 Мыпроводилитакиематчивинститутахв«Денькарьеры»。 Намнужнобылокак-топосмотреть,какиетамребята,годятсянамилинет。 Мыиспользовалигеймификацию,чтобызавлечьлюдейвпроцесс,посмотреть,каконидействуют,чтоо。 Ониигралиибылиотвлечены,ноэтодавалонаминформацию。 Некоторыепушиликод,дажениразунезапустивего,ибылосразувидно,чтовразработкуимпок。

Какэтовыгляделовпервойверсии。 Этобылглавныйэкранидваноутбукадляигроков。 Всеэтосвязывалосьссервером,州серверхранил国家ишарилегомеждувсемиподключеннымиклиентами。 Каждыйэкранбылподключеннымклиентом。 Ноутбукиигроковбылиинтерактивнымиэкранами,скоторыхможнобылоэтот州изменять。 Экраныжесткопривязаныкодномусерверу。

Историяонехваткевремени

Перваяистория,скоторойястолкнулсявэтойразработке,этоисторияотом,чтоуменябылоочень。 Буквальнозапятьминутбылапридумалаидея,запятьсекундбылопридуманоназваниесоеноо ,могпотратитьнаэтовсёвсеголишьчетыречасавечером,отнимаяихдажеужены。 Витогеменяоставалосьвсиготринеделидоконференции,чтобыреализоватьэтохотькак-то。 Аначиналосьвсетак,чтопростонужнобыловыдуматьидеюврамкахбрейншторма,запятьминутродиласьидея:«Давайтеписатькакой-нибудьискусственныйинтеллектдляRPGнаJS»。 Этокруто,весело,ясмогуэтореализовать。

Впервойреализациинаэкранебылредакторкодаиэкранбитвы,以及которомбыласамабитва。 БылииспользованыPhaser,Ace编辑器和Node.jsкаксервербезвсякихфреймворков。 Очемяпотомпожалел,правда,нотогдаотсервераничегоособогонетребовалось。

渲染器,которыйрисовалсамубитву。 Самойсложнойчастьюоказалась沙盒дляJSкода,тоестьпесочница, Такжебыл状态共享,由которыйприходилсссервера。 Игрокикак-томеняли州,закидывалинасервер,серверрассылалостальнымповеб-сокетам。 Сервербылисточникомистины,ивссподключенныеклиентыдоверялитому,чтоприходилоотсервера。

Песочница

Чтожетакогосложноговреализациипесочницы? Деловтом,чтопесочница—этоцелыймирдлякода,在которомкоддолженсуществовать。 Тоестьвысоздаетеемупримернотакойжемер, JS的Какэтореализоватьна? Кажется,чтоJSкэтомунеспособен,оннастолькодырявисвободен,чтопростонеполучитсясделатьтак,чтобыполностьюзаключитькодпользователявкакую-токоробочку,неиспользуяотдельнуювиртуалкусотдельнойОС。

Чтодолжнаделатьпесочница?

Во-первых,какужесказал,изолироватькод。 ,тодолженбытьмир,изкоторогонельзяпрорватьсянаружу。

ТакжетудадолженбытьпрокинутAPIдляуправленияюнитами。 Игрокидолжнывзаимодействоватьсполембоя,двигаяюнитов,направляяих,задаваяимвекторатаки。
Илюбыедействияюнитовасинхронныы,тоестьэтокак-тодолжноработатьсасинхроннымкодом。

Чтояхотелсказатьпроасинхронность? Деловтом,чтоJSонабазовореализованаспомощью许诺。 Тутдлявсехпонятно,承诺отличнаяштука,отличноработают,почтивсегдабылиунас。 Ужемноголетвсезнают,какснимиработать,ноэтаигрушкабыланетолькодляджаваскриптеров。 Представляете,еслияначалобъяснятьджавистам,какписатькодбитвыспомощью承诺吗? 然后先Какделать,然后почемуиногданенадо…Чтоделатьсусловиямиилициклами?

Можно,конечно,пойтилучшимпутемивзятьсинтаксис异步/等待。 [Слайд8:57]Нопредставляететоже,какпрограммистамнеизмираджаваскриптаобъяснитьчтопочтит Витогелучшийпутьработысасинхронностью—图库视频影像。

ДелатьмаксимальносинхронныйкодимаксимальнопростойAPI,похожийнапрактическилюбойязыкпрогр。 Мыделаемигрушкунетолькодлялюдей,пишущихнаJS,мыхотимсделатьеедоступнойдлявсех,кто。

Намэтовсенадокак-тозапустить。 Пользовательпишеткод,инамнужноеговыполнить,подвигатьюнитовнакарте。 Первымделомприходитвголову,чтонамнуженeval()плюснерекомендуемыйоператор与которыннерек。 тобудетработать,нотутестьсвоипроблемы。

Например,您喜欢код,которыйполностьюрушитвсюнашуидею,您喜欢которыйвообщенедаетнеенетдальшен。 Этокод,которыйблокируетвыполнение。 Нужнокак-тосделатьтак,чтобыпользовательнесмогзаблокироватьприложение。 Например,бесконечныйциклможетвсесломать。 Еслиalert()或提示符()到можнопереопределить,тобесконечныйциклмынеможемпереопределитьвообще。

eval()是邪恶的

Такмыдоходимдотого,чтоeval()—этозло。 Незряегоназываютзлом,потомучтоэтоковарнаяфункция,котораяфактическивбираетвсебявсесамоесвободноеиоткрытое,чтоестьвJS,иоставляетнасполностьюбеззащитными。 Однойпростойфункциеймыделаемогромнуюдырувсвоемприложении。

Ночто,еслияскажувам, [голосомСтиваДжобса] чтомыпереизобрелиeval()?

Мысделалиeval()之前的日期,онработаетпочтитакже,кактотжеeval(),которыйунасуж。 使用pr代理在工人,使用иProxy的манявкодеевьфункцияeval()中。

Почему工人? Деловтом,чтоонисоздаютотдельныйпотоеоононер .тодаетнаммногопреимуществ。 Например,врамкахтехжебесконечныхцикловмыможемоборватьпоток,созданныйчерез工人,изглавногопотока,пожалуй,этоглавное,почемуяиспользовал工人。 Еслиworkerуспелотработатьбыстрее,чемзаоднусекунду,мысчитаемегоуспешным,получаемегорезу。 Еслинет,томыегопростообрываем。 Фактическипользовательскийкодпокакой-топричиненесработал,произошликакие-тонопонятные Многиесегодняпыталисьписатьwhile(true),япредупреждал,чтоэтонебудетработать。

workerтобынаписатьнаш工人,конструктоскормитьскрипт工人,которыйбудетзугезагружен。 Внутрискриптамыдолжнысделатьобработчиксообщенияизглавногопотока。 注释postMessage()工作者мыможемнаправлятьсообщениявглавныйпоток。 Такимобразоммыделаемобщениемеждудвумяпотоками。 ДовольноудобныйпростойAPI,новнемчего-тонехватает,以及именнопользовательскогокодокодокоы Небудемжемыкаждыйразгенерироватькакой-тофайлскриптанасервереискармливатьеговоркеру。

URL URL.createObjectURL()。 srcworker’аМыделаемнекийблокискармливаемего。 Такимобразом,онвыгружаетнашкодпрямоизстроки。 Кстати,этотпутьработаетслюбымиобъектамивDOM,которыеимеютSRC – 图像такработает,например,идажев的iframeможнозагрузитьhtml’ку,простосгенерировавеёизстроки。 Довольнокрутоигибко,ясчитаю。 Мытакжеможемуправлять工作者,простопередаваяемунашспециальносгенерированныйобъектизURL。 Мытакжеможемеготерминироватьиэтоужеработаеткакнамнадо,和мысоздалипервуюпесвчипесочницу。

Унасдальшеидутасинхронныевзаимодействия,потомучтолюбаяработас工人—этоасинхронность。 Какое-тосообщениемыотослали,инеможемсинхроннодождатьсяследующегосообщения,工人намвсеголишьвозвращает例如,имыможемподписатьсянасообщения。 МыловимсообщениеприпомощиRxJS,мысоздаемдвапотока:одиндляуспешногосообщенияиз工人,второ Двапотока,которымимыпотомуправлениемприпомощиих合并。

RxJSестьоператоры,которыепозволяютнамработатьспотоками。 Фактическиэтокакlodashдлясинхронныхопераций。 Мыможемуказатькакую-тофункциюинедумать,каконавнутриреализована,онаснимаетснасголовную。 Мыдолжныначатьмыслитьпотоками,оператор合并мержитнашипотоки,реагируетналюбоесообщение。 超时,消息。 Намнужнотолькосамоепервоесообщение,соответственно,послепервогосообщениямытытерминируем。 Вслучаеошибкивыводимэтуошибку,可以解决。

Тутвседовольнопросто。 Нашкодстановитсядекларативным,сложностьасинхронностикуда-тоуходит。 Главное—выучитьэтиоператоры。

ПUnitимернотакмыработаемс单位API。 Unitхотел,чтобыUnit APIбылустроеннастолькопросто,насколькоэтовозможно。 ГоворяпроJS,многиедумают,чтоэтосложно,надокуда-толезть,что-тоизучать。 Амнехотелосьсделатьмаксимальнопросто:单位: Вседляуправленияюнитами,дажеавтокомплит。

[Слайд15:20]Напрашиваетсярешение,与чтовтеможнозасунутьвтотсамыйзапрещённыйоператор在一起。 Давайтеразбираться,почемужеегозапрещают。

Деловтом,和естьсвоипроблемычтоу。 Например,具有,ксожалению,дырявыйзапределамитогоскоупа,которыймывнегопрокинули,потомучтоонпытаетсясмотретьглубже单位APIизаглядываетвглобальныйскоуп。

Воттутпоследнийпримерособенноклассный,потомучтодажечетверкаможетбытьопаснадлянашегокода,посколькувсеэтифункциимогутвыполнятьпользовательскийкод。 Пользовательможетделатьвсе,чтоугодно。 Этоиградляпрограммистов,以及其他онилюбятисследоватьпроблемыипутивозможноговзломачего-то。

Какяужесказал,скоупыустроеныоченьдыряво,соответственно,глобальныйскоупвсегдадоступен。 Сколькобымыскоуповнеподсовываликнашемупользовательскомукоду,восколькобыскоуповмыегонеоборачивали,глобальнаяобластьвидимостивсеравнобудетвидна。 Ивсёиз-за与。

Фактическионничегонеизолирует,онпростодобавляетнамновыйслойабстракции,новыйглобальный。 代理中的Номыможемизменитьэтоповедениеприпомощи。

Деловтомчто代理смотритзавсеминашимиобращениямикобъекту,которыепроксируютсячерезновыйAPI,имыможемуправлятьтем,какбудутвестисебязапросыновыхданныхвэтомобъекте。

Фактически与работаетдовольнопросто。 Когдамыскармливаемемукакую-топеременную,онподкапотомпроверяет,естьлиэтапеременнаявобъекте(тоестьонвыполняетоператор中),иеслиесть,товыполняетеёвобъекте,аеслинет,товыполняетвверхнемскоупе,в нашемслучаевглобальном。 Тутдовольнопросто。 Главное,чемнампоможет代理-мыможемпереопределитьэтоповедение。

В代理естьтакаявещькакхуки。 Замечательнаяштука,котораяпозволяетнампроксироватьлюбыезапросыкобъекту。 Мыможемизменитьповедениезапросаатрибута,изменитьповедениезаданияатрибута,аглавное – можемизменитьповедениеэтогооператора在Таместьхук了,которомумыможемвернутьтолько真的。 Такимобразом,мывознемиполностьюобманемнашоператор与делаянашAPIужекудасохраоное,чемб。

Еслимыпопробуемзапуститьeval(),онсначаласпросит,éстьлиэтотeval()或unitApi,因为它是功能性的,但未定义。 Кажется,этопервыйслучай,когдаярадуюсьэтойошибке! —таошибка—именното,чтомыдолжныбылиполучить。 Мывзялиисказалипользователю:«Извини,забудьпровсё,чтотызналобобъекте窗口,этогобольшен。 Мыужеушлиотчастипроблем,ноэтоещеневсё。

Деловтом,чтооператор与все-такиизJS,JS —динамичныйинемногостранноватый。 Странноватыйвтом,чтоневсёработаеттак,какхотелосьбы,беззаглядываниявспецификацию。 Деловтом,和работаетещёисосвойствамипрототипачто。 Тоестьмыбанальноможемскормитьемумассив,выполнитьэтотнепонятныйкод。 Всефункциимассивадоступныкакглобальныевэтомскоупе,чтовыглядитнемногостранно。

Намважнонеэто,намважното,чтопользовательможетвыполнитьvalueOf()иполучитьвесьнаш沙箱。 Прямовзятьизабрать,посмотреть,чтотамвнёместь。 ,тоготоженехотелось,поэтомувсспецификациизавелиинтереснуюштуку:Symbol.unscopables。 ТоестьвновойспецификациипосимволамзавелиSymbol.unscopablesспециальнодляоператора与которыйзапрещё。 Потомучтоониверят,чтоегокто-тоещёиспользует。 Например,я!

Такимобразом,мысделаемещеодинперехватчик, Еслинет,товозвращаемего,以及一个вотеслида—тогдаизвините,невозвращаем。 Мыеготоженеиспользуем。 И,такимобразом,с和мынеможемполучитьдажепрототипнашегосэндбокса。

Унасосталосьещеокружение工人。 ,точто-тотакое,чтовиситвглобальнойобластиивсёравнодоступно。 Деловтом,чтоеслипростопереопределить,这是онобудетдоступновпрототипе。 JSможновытащитьпрактическивеёеепрототип。 Удивительно,новсеэтиметодывсеравнодоступнычерезпрототип。

Пришлосьпростовзятьивычиститьвесь。 Мыпроходимсяповсемключамивсеэточистим。

Адальшемыоставляеммаленькуюпасхалкудляпользователя,которыйвсе-такипопробуемвызвать。 Мыберемобычнуюфункцию,главное,чтонестрелочную,укоторойестьскоуп,именяемеескоупнанашобъект,вкоторомоставляеммаленькуюпасхалкудляособолюбопытногопользователя,которыйзахочетвывестивконсоликакой-нибудь这или自我。 ,считаю,чтопасхалки—этозамечательно,инужноихоставлятьвкоде。

Далееоказывается,чтоосталисьтолькоснашимUnit API。 Мыполностьювсезаблокировали—посути,оставили白名单。 НамнужнодобавитьтеAPI,即которыеполезныинужны。 Например,API数学,которыйимеетполезнуюфункцию随机,которуюмногиеиспользуютвовремянаписаниякода。

Такженамнужна控制台имногиедругиеутилитарныефункции,которыененесутникакойразрушительнойфункции。 在列表длянашихAPI时进行Мысоздаем。 Этохорошо,потомучтоеслибымысоздали黑名单,мыбызависелиотлюбогообновлениябраузера,кото

Создав白名单,是try-catch的выможемначатьиспользовать。 Нашобёрнутыйкодужеловитошибкииможетотправлятьихпользователю,чтооченьважнодлядебага。

Ноделовтом,чтоконсольныеметодыизWorkerникакнепроявляютсебявпользовательскомкоде。 Тоесть,еслиоткрытьконсольиперейтивокружение工人,тоонибудутдоступны,ноговоритьпользователю«откройконсольипосмотри,чтоутебяпроизошло»былобынеправильно。 JavaScriptрешилсделатьдружественнууконсольдляигрока,гдеигрокдажебезопытавнервидеть

Емупишут,чтовкодеошибка,что-топошлонетак。 Всёэтоунасвконсоли,поэтомунамнужноловитьошибки。 Влюбомслучаенужнофильтроватьсообщения,чтобынепоказыватьпользователюпутикфайламизwebpackи。

ДляэтогояиспользуюмагическийpatchMethod(),которыйпростопатчитконсольныеметоды,замннияихнаобы。 控制台日志,错误,警告,信息。 Мыпропатчиливсеконсольныеметодыимызнаем,когдапользовательвызываетконсоль。 Этонужно,чтобывыводитьэтовсёвобычный

,которыйбудеткрасивовсёэтопоказывать,когдаупользователяошибка,когдакодвыполнилсяикогданет,чтобывсегдадаватьпользователюфидбек,чтопроизошлосигройвконкретныймоментвремени。

,многоговорилпроасинхронность,чтовседействияупользователяасинхронны。 Вседействияуюнитатакжеасинхронны:какой-нибудьпроходккакой-нибудьклетке – этообязательноанимация,этопроходчерезнесколькоклеток,спустякакое-товремянужновыполнятьследующеедействие。 Я,скажем,вообщенеиспользую许诺。 Деловтом,чтовнутриэтихфункцийуменябанально动作,которыеввидеобъектовпередаютданныедал。

Послевыполнениявсегопользовательскогокодауменяполучаетсямассив动作。 Почемуименнотак,почемуменяне实时битва? Деловтом,что实时битвасччастиемworker,чтонужнонастраиватьобщениемеждукли ,реализовалэтомаксимальнобыстроиболее-менеекачественно,чтобыничегонеотваливалось。 Основнаячастьэтойигрушки,накоторойвсёдержится,работала。 Поэтомувеськод,которыйвыпишетенаэкранеигрока,выполняетсядобитвы。 Ипотомвсябитваужеидетпосценарию。

Уменяполучаютсяизолированные工人,которыеделаютсценариидлякаждогоконкретногоюнита。 Этиworkerизолированы,чтобыошибкавкожекаждогоконкретногоюнитанебилаподругим。 Еслиуодногоюнитакодотвалился,остальныепродолжаютходить。 Этонужно,чтобыеслиигрокнаписалкод,которыйневыполняется(какделалинекоторыестуденты,тестировавшиеигру),оппонентвсеравноисполнялсвойкодимогпобедитьвэтойбитве。 Моральпроста:пишетеплохойкод—проигрываете。

РазрушительныйMath.random()

Всёбылохорошо,явсёсделал,您меняосталсябуквальноодинвечердопервойконференциекот ИтутявспомнилпроMath.random()。

Вродеонработаеткакнадо,ноявспомнил,чтоигрушкавыполняетсятольконаклиенте,аклиентовунасможетбытьнесколькоинанесколькихклиентахможетбытьзапущенаоднаитажебитва。 Аэтозначит,чMath.random()каждыйразбудетвыдаватьчто-торазное。

Тоесть,еслиигрокпытаетсянаписатькод,которыйстреляетпоюнитамврандомномпорядке(иэтоабсолютнонормально),JSвыдаётразныецифры,нотакиежецифрывыдаютсянаразныхклиентах。 Тоестьуразныхигроковполучаетсяразныйисходбитвы。

Аеслиучесть,чтомыустраивалитурнирусебявкомпанииидавализавсёэтопризы,выпредставляете,сколькочеловексвиламиифакеламизамнойбыпобежало。 ,быимничегонесмогдоказать,мненужнобылочто-тонайти。

Ивитогеябуквальнозаодинвечерполучилсразумногопроблем,которыемоглисерьезноподкоси。 Конечно,можнобылосделатькостыльввидезапретаrandom(),以及ноянанаёллучшийспособ。

Язнаю,что随机()неявляетсяполностьюслучайным – для«честногорандома»всёещёищутдостаточнонедорогоерешение,подходящеедляиспользованиявперсональныхкомпьютерах。 Витогеяпонял,чтонужнонайтикакую-тоуникальнуюсоль,котораябысделалаэтотаенолон Кактолькоигрокчто-томеняетиперезапускаеткод,ондолженвыдаватьслучайноечисло。 Новслучае,когдаонаитежебитвазапускаетсянаразныхклиентах,этотrandom()долженработатьпо。

Витогеяиспользоваллинейныйконгруэнтныйметод。 Этосамаяпростаяфункция,которуюянашёл,длясозданияrandom()сссолью。 Мыкидаемкакой-то种子ипутёмнехитрыхрасчетовделаемизнегослучайноечисло(втомсмысле,чтомынеможемегопредугадатьбезрасчётов,которыемысовершаем)。

Сольполучаетсяизпользовательскогокода,以及енядокидываютудаюниты。 Мысуммируемвсеиндексысимволоввкодеполучаемнекуюсоль,изкоторойпотомде。 Этопозволяетработатьпрозрачнодляменяинепрозрачнодляпользователейиизбавляетнасоткучипроблемстем,что随机()наразныхклиентахисполняетсяпо-разному。

Поссылкевеськод,которыйотправляетсяв工人,оннужендлятого,чтобысделатьJSполностьбезопа。 Оранжевая«вставка»—этототсамыйпользовательскийкод。 которыйтудаинжектится。 Вотнаскольконемалокудно,чтобыпростосделатьJSбезопасным。 标记random()单元API。 Путеминжектовяполучаюещёбольшийкод,которыйотправляетсяв工人。

状态共享:RxJS,сервериклиенты

Такмыразобрали,чтоунассклиентом。 Сейчаспоговоримпро状态共享,зачемэтонужноикакбылоорганизовано。 Усснасравнения,сервердолженшаритьегоподключеннымклиентам。 [Слайд28:48]

Унасестьчетыреролиразныхклиентов,которыемогутподключатьсяксерверу:«левыйпользователь»,«правыйпользователь»,зритель,которыйсмотритнаглавныйэкран,иадминистратор,которыйможетделатьчтоугодно。

Левыйэкраннеможетизменять状态правогоигрока,зрительнеможетменятьничего,аамминможетд。

Почемуэтобылопроблемой? Всеустроенодовольнопросто。 Любойподключенныйклиентможеткидатьсессию, Оншаритлюбыеизменения,которыевнегоприходят。 Нужнобылоэтокак-тофильтровать。

Дляначаласкажу,почемунасерверетожеRxJS。 Всевзаимодействиясдвумяиболееподключеннымипользователямистановятсяасинхронными。 Надождатьрезультатовотобоихпользователей。 Например,обапользователянажаликнопку«Готово»,надодождаться,покаобанажмут,итолькопотов。 使用RxJS的кокамиспособом:

Сноваоперируемпотоками,естьпотокотсокета,которыйтакиназван套接字。 Чтобысделатьодинпоток,которыйследиттолькозалевымигроком,мыпростоберёмифильтруемсообщенияизэтогосокетаполевомуигроку(ианалогичносправым)。 ДальшемыможемобъединитьихприпомощиоператораforkJoin(),которыйработаеткакPromise.all(оиявлете)。 setState(),添加到“准备好”的位置。 Получается,чтомыждёмобоихигроковименяемсостояниесервера。 НаRxJSэтополучаетсямаксимальнодекларативно,поэтомуяегоиииспользовал。

Остаётсяпроблемастем,чтоигрокимогутменять州другдругу。 Надоимзапретитьэтоделать。 Всё-такионипрограммисты,былипрецеденты,чтокто-топытался。 Создадимдлянихотдельныеклассы,которыеунаследованыот客户。

Унихбудетбазоваялогикасгерентальныйкожкое

客户端—этофактическипул连接,соединенийсклиентами。

ОнпростоиххранитиунегоетьпотокonUnsafeMessage,которыйполностью不安全:емунельзядоверять Мыэтисырыесообщениязаписываемвпоток。

ДальшеприреализацииконкретногоигрокамыберемэтотonUnsafeMessageифильтруемего。

Намнужнофильтроватьтолькотеданные,которыемыможемполучитьотэтогоигрока,которыемымы。 Левыйигрокможетизменять状态тольколевогоигрока,соответственномыберёмизвсехоаон Еслинеприслал—ладно。 Еслиприслал—берём。 Такимобразоммыизполностью不安全сообщениймыполучаемsafeсообщения,которыммыможемдоверятьпри。

Унасестьигровыекомнаты,которыеобъединяютигроков。 Внутрикомнатымыможемпинать,которыемогутизменять州 Мыабстрагировалисьоткучипроверок。 Мысделалипроверки,завязанныенаролях,иназвалиихотдельнымиклассами。 Разделиликодтакимобразом,чтовнутриконтроллера,гдевыполняютсяважныефункциисмены州

ТакжеRxJSиспользуетсянаклиенте,онподключенксокетусобратнойстороны,эмиттитсобытив

Вданномслучаехотелбыразобратьпример,когдамненужноизменитьармиюправогопротивника。

,тобынанеёподписаться,мысоздаёмпотокизтогожесокетаифильтруемего。 Убеждаемся,чтоэтодействительноправыйигрок,иберёмунегосообщениеотом,какаяунегоар。 Еслисообщениятакогоневененениодногосообщения,онбуде Мысразудекларативнорешаемпроблемуфильтрациисобытий,您在сабанальнонесуществует。

Акогдаизпотокаужечто-топришло,设置为setState()。 Этодовольнопросто,тотсамыйподход,которыйпозволяетнамделатьвсепрозрачноидекларативно。 Тосамое,радичегоявзялнапроектRxJSивчемонмнеотличнопомог。

Ясоздаюпотоки,которыеуменядовольнопонятноназваны,скоторымипонятнокакработать,всёдекларативно,вызываютсянужныефункции,нетвознисбольшимколичеством如果ифильтрациейсобытий,всёэтоделаетRxJS。

История:изсинглплееравмультиплеер

Итак,перваяверсиямоейигрушкибыланаписана。 Можносказать,чтоэтобылсинглплеер,потомучтовнеёмоглиигратьтолькодваигроке Унасбыллевыйигрок,правыйигрокиэкранпозади,以及напрямуюксерверу。 Всебылозахардкожено,всё-такизатринеделиделалось。

Мнепоступилоновоепредложение: ,тобыунасполучилсясписоклидеров,мультиплеер,чтобыонимоглиигратьвместе。 Тутяпонял,чтомнепредстоитбольшойрефакторинг。

Витогеоказалосьнетаксложно。 ппростообъединилвсесущности,которыеуменябыли,вотдельныекомнаты。 Уменяпоявиласьсущность«Комната»,котораямоглаобъединятьвсероли。 Теперьнапрямуюссерверомобщаютсянесамиигроки,以及其他版本。 Комнатыужепроксировализапросынапрямуюксерверу,州,заменяя,истейтсталукаждойкомнатыотдельно。

,взялипереписалвсе,добавилсписоклидеров,лучшихмынаграждалипризами。 Нужнобылопростобольчостколичествопользователей,

JS Gamedevиегопроблемы

ТакимобразомяужесерьёзнеепознакомилсясJS-геймдевом。 Прошлыйпроектявразвалочкуделалоколотрёхлет,периодическиотдыхая。 Атутуменяобаразабылопотринедели。 Якаждыйденьсиделичто-тоделалвечерами。

КкакиежепроблемыестьвразработкеигрнаJS? Всёотличаетсяотнашихбизнес-приложений,гденепроблеманаписатьчто-тоснуля。 Болеетого,многогдеэтодажеприветствуется:сделаемвсёсвоё,самипомнитеисториисNPMи左键盘。

ВJS Gamedevтакпоступитьневозможно,потомучтовсетехнологиидлявыводаграфикиявляютсянастольконизкоуровневыми,чтописатьчто-тонанихбанальноэкономическиневыгодно。 ЕслибыявзялсязаэтуигрушкуиначалписатьеёснулянаWebGL的,ябытожепросиделоколополугодазаней,простопытаясьразбиратьсявкаких-тостранныхбагах。 СамыйпопулярныйигровойдвижокPhaserснялсменяэтипроблемы…

…идобавилмненовые:5мегабайтвбандле。 Исэтимничегонельзябылосделать,онвообщенезнает,чтотакое摇树。 Болеетого,ПолькопоследняяверсияPhaserумеетработатьсwebpackибандлами。 ДоэтогоPhaser使用html-теге脚本этобылостраннодляменяподключалсятолько。

Яприхожуизвсякихвебпаков-тайпскриптов,以及JS-геймдевепочтиничеговэтонеумеет。 Всякиемодулиимеюткрайнескуднуютипизациюилинеимеютеовообще, Какоказалось,Ace编辑器,它是Webpack的一部分。 Чтобыначалработать,нужноскачиватьотдельныйпакет,гдеонужеобёрнут(大括号)。

Примернотакжераньшебылос移相器,новновойверсиисделалиболее-менеенормально。 Япродолжалписатьна移相инашел,каксделатьтак,чтобывсеработалос的WebPackтак,какмыпривыкли:чтобыбылаитипизация,итестыможнобылоприкрутитькэтомувсему。 Нашел,чтоможновзятьотдельноPixiJS,которыйявляетсярендеромуwebpack,инайтидлянеготаоеоодуле

PixiJS —和WebGL,和Canvas一起使用。 WebGL中的Болеетого,можнодажеписатькодбудтодля画布。以及WebGL中的ионбудетрендериться。 2табиблиотекаумееточеньбыстрорендерить2D。 Главноезнать,каконаработаетспамятью,чтобынепопастьвположение,когдапамятьзакончилась。

GitHub上的GitHubрепозиторийawesome-pixijs,来自можнонайтиразныемодули。 React-pixi的Большевсегомнепонравился。 Мыможемпростоабстрагироватьсяотрешенияпроблемсвьюхой,когдамыпрямовконтроллерепишемимперативныефункциидлярисованиягеометрическихфигур,спрайтов,анимацииипрочего。 JSX的Мывсёможемразметить。 МыпришлиизмираJSXснашимбизнес-приложениемиможемиспользоватьихдальше。 Тосамое,зачтоялюблюабстракции。 React-pixi添加了一个даётнамэтузнакомуюабстракцию。

Такжесоветуювзятьtween.js – тотсамыйзнаменитыйдвижоканимациииз相位,которыйпозволяетделатьдекларативноанимацию,чем-топохожуюнаCSS-анимацию:делаемпереходмеждусостояниями,аtween.jsрешаетзанас,какимименнообразомподвинутьобъект。

标记:ктоониикакснимиподружиться

,столкнулсясразнымиигроками,ихотелбыещёрассказатьвампротестированиеигрушки。 ,собиралколлегводнойзакрытойиневыпускал,покаонинедоиграют。 Ксожалению,доигратьсмоглиневсе,потомучтовсамомначалеуменябыломногобагов。 Ксчастью,яначалтестирование,кактолькопоявилсяхотькакой-торабочийпрототип。 Честноговоря,первоетестированиезавалилось,потомучтоупарыигроковничегонезавелось。 Былообидно,ноэтодаломнепинок,которыйпозволилдвигатьсядальше。

Когдавашаигрушкаготова,васмогутпринятьоченьхорошо,以及могутсвиламиифакелами。 Вселюдиждутотигркакого-тофана,ждутсчастья,котороевыимдадите。 Авыимдаётечто-то,чтовообщенеработает,хотяувасвродеработало。 Когдаувасонлайн-игрушка,тотакихбаговстановитсяещебольше。

Витогесамыеприятныелюдиизтех, Ониприятномогутдополнитьеевсякимимелочами,подсказавтебечто-тодобавить。 Но,ксожалению,обэениесэтимилюдьминедаваловажного–图库图片

Естьрядовыеигроки,которыеприходятисключительнорадифана。 Онимогутиногдадаженазамечатьбагов,как-топроскакиваячерезнихнасвоёмпутикудовольствию。

Ещёоднакатегория—собирателибагов,在которыхпрактическивсёнеработает。 Стакимилюдьминадодружить,хотяонибудутговоритькучунегатива。 Сниминужнозавязатьстранныеотношения:ониделаютвамбольно,авыпытаетесьунихвзятьчто-тополезноедлясебя,«давайпосидимзатвоимкомпом,посмотрим»。 Нужноработатьсними,потомучтовитогеименноэтилюдисделаютвашуигрукачественной。

Тестироватьнужнотольконаживыхлюдях。 Вашглаззамыливается,以及тестированиеобязательнопокажетто,чтоскрыто。 Выразрабатываетеигрушкуипогружаетесьвсёглубже,пилитькакие-тофичи,аони,возможно,да。 Выидетенапрямуюквашимпотребителям,показываетеимисмотрите,каконииграют,накакиеклави。 сттодаётвамстимулделатьименното,чтонужно。 Видишь, что некоторые люди постоянно нажимают Ctrl+S, потому что привыкли сохранять код — ну сделай хотя бы запуск кода по Ctrl+S, игрок почувствует себя комфортнее. Нужно создавать комфортную среду для игрока, для этого нужно любить его и следить за ним.

Работает правило 80/20: вы делаете демку 20% времени от всей разработки игры, а для игрока это выглядит как на 80% завершённая игра. Восприятие работает так, что основная механика готова, всё двигается и работает, значит, игра почти готова, и разработчик скоро допилит. Но на самом деле разработчику ещё предстоит путь из 80%. Как я уже говорил, довольно долго пришлось работать над документацией, чтобы она была понятна для всех. Я показывал её многим людям, которые говорили свои комментарии, я их фильтровал, пытаясь понять суть высказываний. И много времени у меня ушло на поиск багов.

Так что в геймдеве я бы мог вам посоветовать делать только демки: они всех радуют, не требуют много времени, и от демок никто ничего особо не ждет. Доделывать игры — скучный процесс, а вот начинать — замечательный.

Ссылки

  • Репозиторий с игрой и инструкцией по запуску (буду рад пул-реквестам, если вы найдёте баги)
  • Phaser
  • awesome-pixijs
  • Colyseus multiplayer game server (я писал мультиплеер сам, а потом увидел готовый сервер с комнатами)
  • Ace Editor
  • Презентация этого доклада
  • Русскоязычные конференции, на которые можно подаваться с докладом