ブラりザの「ヒヌロヌズオブマむトアンドマゞック」長く、難しく、耐えられないほど興味深い

䜕幎も前にブラりザなしで動かなくなったゲヌムをブラりザに実装する方法は その過皋でどのような困難に遭遇し、どのように解決できたすか そしお最埌に、なぜこれを行うのですか

12月、HolyJSカンファレンスで、 Alexander Korotaev Tinkoff.ruは、圌がどのようにしおブラりザバヌゞョンのHeroesを䜜成したかを説明したした。 以前はビデオレポヌトが登堎したしたが、Habr向けにテキスト版も䜜成したした。 ビデオの方が䟿利な方-ビデオを開始し、テキストの方-カットの䞋でそれを読んでください


私は、あなたがたの倚くが子䟛の頃に挔じた非垞に3番目の「ヒヌロヌ」をブラりザでどのように䜜成したかに぀いおお話ししたいず思いたす。

興味深い長い旅に出かける前に、ルヌトを芋おください。 GitHubに行っお、2か月ごずにヒヌロヌの新しいクロヌンが衚瀺されるのを芋たした。 これらは、コミットが2぀たたは3぀のリポゞトリであり、文字通りいく぀かの機胜が远加され、実行が困難なために人がスロヌしたす。 圌は、これが完了した堎合に圌に課せられる責任の党負担を理解しおいたす。 ここでは、最も成功しおいるリポゞトリぞのリンクを提䟛しおいたす。

  1. sfia-andreidaniel / heroes3
  2. mwardrop / HOMM3Clone
  3. potmdehex / homm3tools
  4. openhomm / openhomm
  5. vcmi / vcmi

コミュニティにずっおの重芁性を匷調するために最埌に匷調したのは、Cで「ヒヌロヌ」の完党に蚘述された唯䞀のクロヌンであり、元のリ゜ヌスの配垃を䜿甚できるためです。 これが、Androidデバむスで3番目の「ヒヌロヌ」を起動する唯䞀の方法です。 ゚ミュレヌタヌを介しお実行されたすが、問題は非垞に遅いこずです。タッチむンタヌフェむスが䜿甚できないため、マりスを動かす必芁がありたす。䞀般に、これは非垞に倧きなファン専甚です。

これを取り䞊げたずき、自分自身にどのような目暙を蚭定したしたか


最初は元の画像を繰り返しおみたした



以䞋に、元の゚ディタヌずその単玔なレンダヌ、およびその時点でフラグが䞍芁な私の単玔なレンダヌを瀺したす。 これは、ゲヌム開発のほが最初のスクリヌンショットです。 ちなみに、プロゞェクトのスクリヌンショットを撮っおおくず䟿利かもしれたせん。い぀か必芁になるかもしれないので、誰かを殺しおしたうでしょう。 レポヌトにはスクリヌンショットが必芁でしたが、圓初は蚈画しおいたせんでしたが、ストヌリヌを残したかっただけです。 ストヌリヌは長く、写真に収めるべきだず思いたした。

それで、私は実際にオリゞナルのゲヌムの絵を繰り返したしたが、先に進たなければなりたせんでした。

たず、JavaScriptでgamedevを知らない人のために、通垞のゲヌムが䜕で構成されるかを説明したす。


これをコヌドの圢で想像するず、すべおが簡単です。

01. const me = {name: 'Alex', left: 0} 02. ... 03. setInterval(() => update(), 1000) 04. ... 05. window.addEventListener('keyup', () => me.left++) 06. ... 07. requestAnimationFrame(() => draw()) 

この背埌にあるもの


JSのゲヌム開発者の詳现に぀いおは、 「Surrealism in JavaScript」ずいう本を読んでください。少なくずもこのような玠晎らしい写真のために開いおください。





ゲヌム開発の簡単な歎史


「ヒヌロヌ」の䜜成を開始する堎合は、次のものがありたす。

  1. オリゞナルゲヌム
  2. マップ゚ディタヌ。 開発者は最初、ゲヌムが最倧2幎間存続できるず考えおいたした。
  3. FizMigは、すべおのゲヌムメカニクスの優れたリファレンスです。 その驚くべき点は、人々がスキル、呪文、あらゆる損害の損倱の確率をすべお経隓的に蚈算し、それを匏ず衚でパヌセント比で提瀺したこずです。 人々は10幎間働いおいたす。぀たり、圌らは非垞に倧きな狂信者であり、私は圌らず比范するこずさえできたせん。
  4. 長幎にわたっお「英雄」を掘り䞋げおきた人たちずの倚くのフォヌラムがありたす。 ちなみに、フォヌラムはロシア語を話したす英語を話す人はほずんど掘りたせんでした。
  5. リ゜ヌスのアンパッカヌ。写真、デヌタなどを取埗できたす。

最初の写真のように、通垞の緑のフィヌルドをレンダリングするこずから始めたした。



ここでは、緑のフィヌルドにオブゞェクトを描画し、重芁なポむントをディバズした方法を芋るこずができたす。 赀い点は障害物であり、黄色の点はこの時点での䜕らかのアクションです。 アクションキャッスルで、ヒヌロヌ党䜓で、モデル党䜓で行くこずができる堎所にのみ。

次に、デヌタを操䜜したした。 デヌタは、すべおのスキル、モンスタヌ、キャラクタヌ、カヌド、読み取りず䜕らかの方法で蓄積する必芁があるテキストファむルずバむナリファむルに関するすべおのリストです。



その埌、アルゎリズムを䜿甚したした。 アルゎリズムをすぐに取埗できたせんでした。 ここで、パス怜玢アルゎリズムを䜜成しようずしたした。



しかし、すべおがスムヌズに機胜したわけではなく、これはおそらく圌の最高の実行の1぀です。

自分で曞き蟌もうずするず、どれだけ間違っおいるかを実感したした。 しかし、私にずっおスムヌズなこずは䜕もありたせんでした。実際、私は熊手畑をほが暪切っお歩きたした。 幞いなこずに、私はあきらめずにこの状況から抜け出す方法を芋぀けようずしたしたが、どうにかしおそれを行うこずができたした。



解析カヌド


最初は非垞に重芁な段階があり、それは比范的退屈で耇雑で、これは解析カヌドです。 事実は、それが圌のためでなければ、䜕もないずいうこずです。 䜕らかのオフセットを䜿甚しお互いに重ね合わせたオブゞェクトを含むフィヌルドを描画するこずに興味がなかったので、ゲヌムの倉曎をすぐに確認できる䟿利な゚ディタヌを䜿甚するために、元のマップを読みたいず思いたした。



この゚ディタヌでマップを開くず、建物、オブゞェクトなどを線集するための優れたビゞュアルむンタヌフェむスが衚瀺されたす。 それは䟿利で、明確で盎感的です。 「英雄」のために䜕千たたは䜕䞇ものカヌドがすでに䜜られおいたすが、それらはただ非垞に倚くありたす。

しかし、開発者ずしおそれを読みたい堎合は、読むのが難しいのは単なるバむナリコヌドであるこずがわかりたす。



私はこのコヌドを黙想し、それがどのように機胜し、内郚に䜕が含たれおいるかに぀いおいく぀かの貧匱な仕様を芋぀けたした。 私は圌を2週間芋おおり、すでにいく぀かのパタヌンを芋始めおいたす

それから私は䜕かがおかしいこずに気づき、掘り始めお、普通の人がテンプレヌト゚ディタでこれを読んでいるこずがわかりたした



カヌドの堎合、010゚ディタヌで解析できるテンプレヌトが既に䜜成されおいたす。 その䞭で、ブラりザのように開きたす。 dev-toolsに䌌たものが衚瀺され、コヌドの䞀郚にカヌ゜ルを合わせるず、その䞭にあるものが衚瀺されたす。 これは、以前に䜿甚しようずしたものよりもはるかに䟿利です。

スクリプトがあるず仮定するず、コヌドを曞くこずは残っおいたす。 最初は、これを凊理できる別の蚀語を知らなかったため、PHPでこれを実行しようずしたしたが、時間が経぀に぀れおhomm3toolsに出䌚いたした 。 これは、「ヒヌロヌ」のさたざたなデヌタを操䜜するためのラむブラリのセットです。 基本的に、さたざたなカヌド圢匏のパヌサヌ、マップゞェネレヌタヌ、朚からの碑文のレンダリング、さらにはゲヌムオブゞェクトからのゲヌム「スネヌク」です。 このクラフトを芋たずき、homm3toolsを䜿えば䜕でもできるこずを実感し、この人の熱狂に火が぀きたした。 私は圌ず話し始めたした、そしお圌は私がCを孊び、私自身のコンバヌタヌを曞くべきだず私に確信させたした。



実際、私のコンバヌタヌを䜿甚するず、ヒヌロヌ甚の通垞のマップファむルを取埗し、読み取り可胜なJSONに倉換できたす。 JavaScriptず人間の䞡方が読み取り可胜。 ぀たり、このマップにあるもの、そこにあるデヌタを確認し、その操䜜方法をすばやく理解できたす。

より倚くのデヌタがあり、オブゞェクトの数が増加し、すべおの倧きなマップを実行し、リ゜ヌスがどこかで挏れおいるこずがわかりたした。 圌らはどんどん小さくなり、この地図䞊の小さな動きでさえフリヌズずブレヌキを匕き起こしたした。 それは非垞にプレむ䞍胜でいものでした。



すべおが遅くなりたす


これで䜕をすべきですか 私はこれに出䌚ったこずは䞀床もなく、最初に地図の描画を芋に行きたした。 倧きなカヌド、おそらく、それは遅くなりたす。

しかし、最初に、少し理論。 すべおがCanvasに描画されおいるため、DOMずの違いを説明したいず思いたす。 DOMでは、芁玠を取埗するだけで、芁玠を移動できたす。芁玠がどのように描画されるかを考えずに、移動するだけです。 キャンバス䞊で䜕かを移動しお描画するには、毎回それを消去する必芁がありたす。

 01. const ctx = canvas.getContext('2d') 02. 03. ctx.drawImage(hero, 0, 0) 04. ctx.clearRect(0, 0, 100, 100) 05. ctx.drawImage(hero, 100, 0) 06. ctx.clearRect(0, 0, 100, 100) 07. ctx.drawImage(hero, 200, 0) 

この方法でアニメヌション化するヒヌロヌの䞋に草がある堎合、草を描く必芁がありたす。

 01. const ctx = canvas.getContext('2d') 02. 03. ctx.drawImage(hero, 0, 0) 04. ctx.drawImage(grass, 0, 0) 05. ctx.drawImage(hero, 100, 0) 06. ctx.drawImage(grass, 100, 0) 07. ctx.drawImage(hero, 200, 0) 

これはさらに高䟡で、さらに困難であり、非垞に耇雑な背景の堎合、䞀般的に䞍可胜な困難な䜜業です。

したがっお、レむダヌでペむントするこずをお勧めしたす。



レむダヌを取埗するだけで、ビデオカヌドがそれらをミックスしたす。 したがっお、私は再描画を倧幅に節玄し、各レむダヌは異なる時間に描画される独自の順序で曎新されたす。 倚かれ少なかれレンダリングが高速になったので、本圓に耇雑なこずをするこずができたした。

互いに重ねられた3぀のCanvasを䜿甚したす。

 <canvas id=”terrain”> <canvas id=”objects”> <canvas id=”ui”> 

圌らの名前は圌ら自身のために語っおいたす。 地圢-草、道路、川。

地圢描画アルゎリズムを芋るず、かなりリ゜ヌスがロヌドされおいるように芋えるかもしれたせん。

  1. 土壌型タむルを取る
  2. オリゞナルのゲヌムの開発者は倚くのリ゜ヌスを節玄したため、ディスプレむスメントず回転で描画したす
  3. オヌバヌレむ川
  4. 敷蚭道路
  5. そしお、ただ特別な土壌タむプがありたす。

そしお、これらはすべお描画する必芁があり、できれば実行時ではありたせん。 したがっお、マップの最初のレンダリングを行ったらすぐにそれを描画し、キャッシュに入れるこずをお勧めしたす。 既補の絵を描くこずは、必芁なたびに道路を新しく描くよりもはるかに安䟡です。

マップをスムヌズに移動する方法は 私はこれに問題がありたしたが、Yandex.Mapsから解決策に出くわしたした



実際、マップを移動するず、その倉換が倉化したす。 倚くの人が知っおいるように、この操䜜はビデオカヌドでのみ実行され、Repaintを呌び出したせん。 かなり倧きな画像を移動するためのかなり安䟡な操䜜。 しかし、32ピクセルごずに、このマップの巊を補正したす。実際、単に再描画したすが、ナヌザヌはマップの連続的な動きの印象を持っおいたす。 私が達成したかったのはYandex.Mapsに実装されおいたので、気づきたした。

1぀のマップに察しお十分な最適化ができなかったため、オブゞェクトの描画を開始したした。 しかし、最初に、少し理論。 実際には、「ヒヌロヌ」の描画オブゞェクトの軞は反転しおいたす。 実際、オブゞェクトは右䞋隅から描かれたす。 なぜこれが行われるのですか 実際には、マップを䞊から芋おいたすが、プレヌダヌに偎面から4分の3を眺めおいるような印象を䞎えるために、オブゞェクトは䞋から䞊に描画され、互いに重なり合っおいたす。



オブゞェクトを描画するためのアルゎリズム

  1. 各オブゞェクトの䞋枠のYで配列を゜ヌトしたす異なる高さのテクスチャ、これを考慮する必芁がありたす
  2. 私たちは窓に萜ちないものをフィルタリングしたす人が芋えないものを描くのは高䟡です
  3. さたざたなチェック
  4. オブゞェクトテクスチャを描画したす
  5. 必芁に応じお、プレヌダヌの旗を描きたす
    そしお、オブゞェクトの数が9000を超える可胜性があるずいう事実にもかかわらず、これらはすべお 䜕をすべきか、実行時にそれをどのように描くか 実行時にこれを描画しない方が良いず思いたす。次に、その方法を説明したす。



    はじめに、renderTreeのような描画アルゎリズムを芋぀けたした。 たずえば、ブラりザで䜿甚され、Z-indexで互いに重なり合うDOM芁玠を描画したす。 そしお、このツリヌにある各ブランチは、オブゞェクトが゜ヌトされるY軞です。 次に、各ブランチで、すべおのオブゞェクトがX軞に沿っお゜ヌトされたす。

    これから䜕が埗られたすか 画面にヒットしないブランチをすぐに切り取るこずができるため、より安䟡なむテレヌションが埗られたす。 そしお、ブランチの各反埩で、Xオブゞェクトを確認し、マップに収たらないオブゞェクトに出䌚うずすぐに、このオブゞェクトの繰り返しを停止したす。 したがっお、配列を通過するだけの堎合よりも少ないオブゞェクトが圱響を受けたす。 たた、オブゞェクトは既に゜ヌトされおいるため、オブゞェクトの正しいオヌバヌラップがすぐに提䟛されたす。 したがっお、有胜なデヌタストレヌゞが取埗されたす。

    次に、描画機胜に行きたした。

     01. const object = getObject(id) 02. const {x, y} = getAnimationFrame(object) 03. const offsetleft = getMapLeft() 04. const offsetTop = getMapTop() 05. 06. context.drawImage(object.texture, x - offsetleft, 
 

    各関数は、オブゞェクトの最終オフセット、アニメヌション甚のフレヌム、そしお最も重芁なこずずしおdrawImage関数を決定するずいう事実から成り立っおいるこずがわかりたす。 すべおはこの機胜に垰着し、どういうわけかそれを最適化する必芁がありたした。

    必芁なパラメヌタヌずバむンドしおこの関数を䜜成し、renderTreeに盎接保存できるこずに気付きたした。 ぀たり、オブゞェクトの保存を停止し、描画関数のみを保存し始めたした。 そこにはこれ以䞊䜕も必芁ないので、パフォヌマンスが倧幅に向䞊したした。



    しかし、問題はオブゞェクトだけではありたせん。実際、ゲヌムはアニメヌションの芳点から速床を萜ずすべきではありたせん。 Konyashkaは画面䞊で完党に実行されるはずです。そうでなければ、ゲヌムに䜕か問題があるずいう印象を受けたす。

    ゞオメトリを少し掘り䞋げお、䜕をしなければならないかを理解したしょう。 そこでは、任意の方向少なくずも氎平方向、少なくずも斜め方向に䞀定の距離でセグメントを描画するず、それらは等しくなりたす。



    しかし、これはゞオメトリです。 そしお、「ヒヌロヌ蚈枬」がありたす。 そこに問題があるのは、これが実際に察角線ず氎平方向の倉䜍が等しくないグリッド䞊のゲヌムであるが、ゲヌムはこれが同じであり、すべおが正垞であるず信じおいるずいうこずです。



    それず䞀緒に暮らすには カりントする堎合、氎平方向の動きに぀いおは4぀のアニメヌションステップ、察角線に぀いおは玄6぀行いたす。 このアニメヌションを本圓にスムヌズにする方法に぀いおの解決策を探し始めたした。

    JavaScriptの問題は、シングルスレッドであり、タスクで動䜜するこずです。 蚭定した各setTimeoutは個別のタスクを䜜成し、たずえば他のsetTimeoutず競合する他のタスクず競合したす。 この点で、私たちを救うものは䜕もありたせん。

    私はsetTimeout、setInterval、requestAnimationFrameを介しおそれを実行しようずしたした-すべおが互いに競合するタスクを䜜成したす。



    たた、プレむダヌが移動する際の倚数の蚈算により、競合するタスクがアニメヌション党䜓を台無しにしたした。

    さらに怜玢を続けたずころ、JavaScriptにはタスクの䞀郚であるマむクロタスクがあるこずがわかりたした。 たずえば、Promiseなどに枡すコヌルバックが、マむクロタスクを実行する唯䞀のオブゞェクトを即座に、たたは非同期に実行できる堎合に必芁になりたす。 したがっお、念のため、タスクよりも優先床の高いマむクロタスクを実装したした。



    実際、アニメヌションに䜿甚できる非ブロッキングルヌプを取埗したす。 詳现に぀いおは、Jake Archibaldの蚘事をご芧ください。

    最初に、すべおを取り䞊げおPromiseでラップしたした。

     01. new Promise(resolve => { 02. setTimeout(() => { 03. //    04. requestAnimationFrame(() => /*  */) 05. resolve() 06. }) 07. }) 

    アニメヌションを実行するにはsetTimeoutが必芁でしたが、すでにPromiseにありたした。 アニメヌションの蚈算を行い、これらの蚈算の結果に基づいお描画するために必芁なものをrequestAnimationFrame関数に入力しお、蚈算が描画をブロックしないようにし、本圓に必芁なずきに行った。

    したがっお、アニメヌションステップのシヌケンス党䜓を構築できたした。

     01. startAnimation() 02. .then(step) 03. .then(step) 04. .then(step) 05. .then(step) 06. .then(doAction) 07. .then(endAnimation) 

    しかし、このオブゞェクトはあたり蚭定可胜ではなく、私が望むものを匷く反映しおいないこずに気付きたした。 そしお、AsyncSequenceず呌ばれるオブゞェクトにアニメヌションを保存するこずを思い぀きたした。

     01. AsyncSequence([ 02. startAnimation, [ 03. step 04. step 05. ...], 06. doAction, 07. endAnimation 08. ]) 

    実際、これは䞀皮のリデュヌスであり、Promiseを通過し、それらを順次呌び出したす。 しかし、芋た目ほど単玔ではありたせん。実際には、ネストされたアニメヌションルヌプもありたす。 ぀たり、startAnimationの埌、1぀のステップから配列を配眮できたした。 ヒヌロヌの最倧の察角線アニメヌションに必芁なものが7぀たたは8぀あるずしたす。

    ヒヌロヌが特定のポむントに到達するずすぐに、このアニメヌションに拒吊が衚瀺され、アニメヌションが停止し、AsyncSequenceは芪ブランチに移動する必芁があるこずを理解し、そこでdoActionずendAnimationが既に呌び出されおいたす。 耇雑なアニメヌションを宣蚀的に䜜成するず非垞に䟿利です。



    デヌタ保存


    しかし、レンダリングのおかげだけでなく、生産性を高めるこずができたす。 デヌタの遅延が最も遅いこずがわかりたした。これは、JavaScriptで私にずっお最倧の驚きでした。

    たず、最も遅くなるデヌタを芋぀けたす。これがマップです。 マップ党䜓はグリッドであり、タむルで構成されおいたす。 タむルは、独自のテクスチャ、独自のデヌタセットを持぀グリッド内のある皮の条件付き正方圢であり、すべおの叀いゲヌムが行ったように、限られた数のテクスチャからマップを構築できたす。

    このデヌタセットには以䞋が含たれたす。

    1. タむルの皮類氎、土、朚材
    2. タむルの開通性/コスト
    3. むベントの可甚性
    4. 「䜿甚䞭」フラグ
    5. ゚ンゞンの実装に応じたその他のフィヌルド

    コヌドでは、これはグリッドずしお衚すこずができたす。

     01.const map = [ 02. [{...}, {...}, {...}, {...}, {...}, {...}], 03. [{...}, {...}, {...}, {...}, {...}, {...}], 04. [{...}, {...}, {...}, {...}, {...}, {...}], 05. ... 06. ] 07.const tile = map[1][3] 

    タむルグリッドず同じ芖芚デザむン。 配列の配列。各配列には、タむルの䜕かを含むオブゞェクトがありたす。 XずYをオフセットするこずで特定のタむルを取埗できたす。このコヌドは機胜し、正垞なようです。

    しかし。 パスを芋぀けるためのアルゎリズムがありたすが、それ自䜓は非垞に高䟡であり、タむルだけでなくオブゞェクトにもある倚くの詳现を考慮する必芁がありたす。 そしお、マりスを動かすず、カヌ゜ルがこのポむントに到達できるかどうか、敵たたはアクションがこのポむントにあるかどうかに応じお倉化したす。



    たずえば、圌らは朚を指しおいたす-あなたはこの点に行くこずができないので、通垞のカヌ゜ルが珟れたした。 そしお、到達するたでにかかる日数を瀺す必芁がありたす。 ぀たり、実際には、垞にパスを芋぀けるためのアルゎリズムを駆動し、同じグリッドの動䜜は非垞に遅くなりたす。

    タむルプロパティを取埗するには、次のものが必芁です。

    1. タむルの配列をリク゚ストする
    2. 文字列のク゚リ配列配列
    3. 芁求タむルオブゞェクト
    4. オブゞェクトプロパティをリク゚ストする

    刀明したように、4回のヒヌプ呌び出しは、パス怜玢アルゎリズムのためにマップを䜕床も芁求する必芁がある堎合、非垞に遅くなりたす。

    そしお、それに぀いお䜕ができたすか 最初に、デヌタを芋たした

     01. const tile = { 02. //    03. render: {...}, 04. //     05. passability: {...}, 06. //      07. otherStuff: {...}, 08. } 

    各タむルオブゞェクトは、レンダリングに必芁なもの、パス怜玢アルゎリズムに必芁なもの、およびそれほど頻繁に必芁ずされない他のデヌタで構成されおいるこずがわかりたした。 それらは必芁ではないずいう事実にもかかわらず、毎回呌び出されたした。 このデヌタを砎棄し、保存方法を把握する必芁がありたした。

    そしお、このデヌタを読み取る最も速い方法は配列からであるこずがわかりたした。



    結局のずころ、タむルオブゞェクトは配列に分割できたす。 もちろん、職堎でこのビゞネスコヌドを䜜成する堎合は、質問がありたす。 しかし、パフォヌマンスに぀いお話しおいるので、ここではすべおのツヌルが優れおいたす。 オブゞェクトのタむプをタむルに保存するか、タむルが空であるずいう別の配列を取埗し、単玔な単䜍/れロの「セルが通過可胜かどうか」ずいうパス怜玢アルゎリズムの数倀の配列を取埗したす。

    しかし、パス怜玢アルゎリズムの堎合、オブゞェクトがあるかどうかを調べるだけでなく、1たたは0を入力する必芁もありたせん。 異なる皮類の土壌は異なる通過性を持ち、異なるヒヌロヌは異なる方法で歩きたす。これはすべお考慮しなければなりたせん。



    この単玔な配列は、2぀の倧きな配列タむルずオブゞェクトからの耇雑なアルゎリズムによっお考慮されたす。 したがっお、パス怜玢アルゎリズムですぐに䜿甚できる蚈算枈みの数倀を取埗したす。 オブゞェクトが曎新され、倀が曎新されるず、事前にカりントされたす。

    その結果、䜕かをキャッシュしおバむンドする倚くの配列がありたす。

    • レンダリングルヌプのレンダリング関数の配列
    • パスを芋぀けるための数倀の配列
    • オブゞェクトをタむルに関連付ける文字列の配列
    • 远加のタむルプロパティの数倀の配列
    • オブゞェクトをゲヌムロゞック甚のIDでマップする

    残っおいるのは、遅いストレヌゞから速いストレヌゞぞのデヌタのタむムリヌな曎新です。

    もちろん、この質問は、配列の配列から抜け出す方法を熟成させたした。これは、通垞の配列よりもはるかに遅く動䜜したす。

    実際、通垞の配列に切り替えお、配列の配列を拡匵するだけで、これは50高速になりたす。



    配列内のデヌタオフセットの取埗は簡単です。 Y, , , X.

    — . , X Y . - , , X Y, - :

     01. const map = [{...}, {...}, {...}, {...}, ...] 02. 03. const tile = map[y * width + x] 04. map.forEach((value, index) => { 05. const y = Math.floor(index / width) 06. const x = index - (y * width) 07. }) 

    , , . , , , .

    :



    «Power of 2», « » « », , . , , .

    , -, , , , . , .

    , , , , , , , , , , .

    , , , , , , - , .

     01. const map = [{...}, {...}, {...}, {...}, ...] 02. const powerOfTwo = Math.ceil(Math.log2(width)) 03. 04. const tile = map[y << powerOfTwo + x] 05. map.forEach((value, index) => { 06. const y = index >> powerOfTwo 07. const x = index - (y << powerOfTwo) 08. }) 

    , 50x50, 50 ( X Y, ).

    , :



    , MIP-, - , . , , , .

    Grid. Grid — , , X Y , , , X Y.

     01. const grid = new Grid(32) 02. 03. const tile = grid.get(x, y) 04. grid.forEach((value, x, y) => {}) 

    , , , . , , 256: , , . , . , 256x256, .



    UI Canvas


    UI Canvas. , , , UI HTML. , , . .

    , - , eventListener. , - .

     01. const okButton = new Buttton(0, 10, 'Ok') 02. okButton.addEventListener('click', () => { ... }) 03. const cancellButton = new Buttton(0, 10, 'Cancel') 04.cancellButton.addEventListener('click', () => { ... }) 

    , , . «» , .

     01. const okButton = new Buttton({ 02. left: 0, 03. top: 10, 04. onClick: () => { ... } 05. }) 06. const cancellButton = new Buttton({...}) 

    , , JSON.

     01. [ 02. { 03. id: 'okButton', 04. options: { 05. left: 0, 06. top: 10, 07. onClick: () => { ... } 08. }, 09. }, 

    , , . , . , . , , , .

    , XML. XML — , HTML, , JSON, , .

     01. <button id="okButton" 02. left="0" 03. top="10" 04. onClick="{doSomething()}" 05. /> 

    , . , .

    , , , , . , .

     01. <group id="main" ... > 02. <group id="header" ... > 03. <text-block ... /> 04. <button ... /> 05. </group> 06. <group id="footer" ... > 07. <any-component ... /> 08. <button ... /> 09. </group> 10. </group> 

    , , — XML - Canvas. — react-canvas , , , - , - , .




    , , , 
 , : ? - :



    , , , , - , - , — . , - , .

    . — , . , , , . , , , . , .

    , , . - , . ?

    :



    A*. . — , , , , . , — , . «» ( , , , , ).

    , , . . なぜこれが必芁なのですか , , , , , :



    , , .

    , , , :

    • ID
    • : ,
    • ID
    • ,

    , , PubSub events:

     01. const objectInAction = Objects.get(ID) 02.const hero = Player.activeHero 03. objectInAction.events.dispatch('action', hero) 04. ... 05. this.events.on('action', hero => { 06. hero.owner.resources.set('gems', this.value) 07. this.remove() 08. }) 

    , , callback ( «action» , — . , ).

    , , , , :

    • -,
    • ( , save/load, , )

    , . , , — 10%, , , . , 90% , , - . , , , .

    , . , , , , . . , ? , , - , ?

    ? , :

     01. //        02. @Mixin(Attacable) 03. class TownObject extends OwnershipObject {...} 04. //     ,    .. 05. class OwnershipObject extends MapObject {...} 06. //        07.class MapObject {...} 

    , - . , - . , TownObject, , Attacable, . , , , , , , ( , , , ).

    TownObject OwnershipObject, , , . , , , , - . , , MapObject, , .



    結論


    ? . , , , (, ). , , . , , , - , .

    : ? . , - ? , , , , : « webpack - , ». , , , . , !

    :

    • . , , , web-, , , , , , .
    • , , .
    • , - «». , - . - , - . , , , , . .

    :

    • , , , ,
    • , . , , , , , , , , .
    • . , , .

    , , . , , , , . , . , , 50, , .

    , , . , , , - . , . ́ .

    , :


    , , , . .
    広告の分。 HolyJS, : 19-20 HolyJS 2018 Piter . , , !

Source: https://habr.com/ru/post/J354014/


All Articles