程序员游戏
ВыможетепомнитьАлександраКоротаевапобраузернойверсии«ГероевМечаиМагии»:расшифровкаегодокладаонейсобраланаХабрегромадноеколичествопросмотров。 Атеперьонсделалигру,ориентированнуюнапрограммистов:игратьвнеёнадо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
- Презентация этого доклада
- Русскоязычные конференции, на которые можно подаваться с докладом
Related Content
More Interesting