JSのTiny Tron(30行のコード)

画像



実際、今週のトレンドを続けています。



初めて小さなエクセルを読んだとき、そのようなものを書きたかったのです。小さくてクールです。 ヘビを見る-ゲームを書く価値があることに気付きました。 「会社の音でパックマンが欲しい」というコメントを読んだ後、私はキャンバスに「サイトマン」を書き、ウェブオーディオAPI(およびwaka-waka-waka)でページをむさぼり食うことにしました。



しかし、これは実現する運命ではありませんでした。



このすべてを読むことに興味がない人のために:コントロール-矢印を使用すると、任意のページで実行できます:

jsfiddle 、ソース。

ソースコード
siteman = { 'settings':{'size' : 10, 'speed' : 5, 'time':new Date().getTime(), 'width':window.innerWidth, 'height':window.innerHeight}, 'coord':{'x' : 0 + 20, 'y' : 0 + 20}, // plus siteman size 'direction':{ 'current':{'x': 0.75 * Math.PI, 'y' : 1.75 * Math.PI, 'clock' : false, 'calc_x' : function(){ return siteman.coord.x + siteman.settings.speed}, 'calc_y' : function(){return siteman.coord.y}}, 37:{'x': 0.75 * Math.PI, 'y' : 1.75 * Math.PI, 'clock' : true, 'calc_x' : function(){ return siteman.coord.x - siteman.settings.speed}, 'calc_y' : function(){return siteman.coord.y}}, 38:{'x': 1.75 * Math.PI, 'y' : 0.75 * Math.PI, 'clock' : false, 'calc_x' : function(){ return siteman.coord.x}, 'calc_y' : function(){return siteman.coord.y - siteman.settings.speed}}, 39:{'x': 0.75 * Math.PI, 'y' : 1.75 * Math.PI, 'clock' : false, 'calc_x' : function(){ return siteman.coord.x + siteman.settings.speed}, 'calc_y' : function(){return siteman.coord.y}}, 40:{'x': 1.75 * Math.PI, 'y' : 0.75 * Math.PI, 'clock' : true, 'calc_x' : function(){ return siteman.coord.x}, 'calc_y' : function(){return siteman.coord.y + siteman.settings.speed}} }, 'ctx':document.body.appendChild((function(element){element.width=window.innerWidth; element.height=window.innerHeight; element.style.cssText='background:rbga(60, 40, 20, 1); position:absolute; top:0; z-index: 100000000;'; return element;})(document.createElement('canvas'))).getContext("2d"), 'h_ctx':new function(){this.chain = function(method, args){siteman.ctx[method].apply(siteman.ctx, args); return this;}}, 'checkCollision':function(data){return data[0] == 128 && data[1] == 128 && data[2] == 128;} }; siteman.ctx.fillStyle = "rgb(128, 128, 128)"; siteman.h_ctx.chain('beginPath').chain('fillRect', [0, 0, window.innerWidth, window.innerHeight]); (function game_loop(){ siteman.coord = {'x':siteman.direction.current.calc_x(), 'y':siteman.direction.current.calc_y()}; siteman.ctx.fillStyle = "rgb(255, 255, 0)"; siteman.h_ctx.chain('beginPath').chain('arc', [siteman.coord.x, siteman.coord.y, siteman.settings.size, 0.25 * Math.PI, 1.25 * Math.PI, siteman.direction.current.clock]).chain('fill') siteman.h_ctx.chain('beginPath').chain('arc', [siteman.coord.x, siteman.coord.y, siteman.settings.size, siteman.direction.current.x, siteman.direction.current.y, siteman.direction.current.clock]).chain('fill'); var offset_x = siteman.settings.size * (siteman.coord.x != siteman.direction.current.calc_x() ? (siteman.direction.current.clock ? -1 : 1) : 0), offset_y = siteman.settings.size * (siteman.coord.y != siteman.direction.current.calc_y() ? (siteman.direction.current.clock ? 1 : -1) : 0); if(!siteman.checkCollision(siteman.ctx.getImageData(siteman.coord.x + offset_x, siteman.coord.y + offset_y,1,1).data)){ alert('Game over. Your score is: '+(new Date().getTime() - siteman.settings.time)+'. Siteman size: '+siteman.settings.size+' and speed:'+siteman.settings.speed+', map width: '+siteman.settings.width+' and height: '+siteman.settings.height); }else{ setTimeout(function(){game_loop();}, 1000 / 60); //requestAnimationFrame(game_loop); } })(); document.addEventListener('keydown', function (e) {siteman.direction.current=siteman.direction[e.keyCode] || siteman.direction.current}, false);
      
      









どのようにすべてが始まりましたか?



「jsでの30個の小文字アプリケーションのマラソン」のずっと前に、新しい技術を習得し、「ゲーム乙女に加わる」ために、自分のミニゲームを書きたかったのです。 しかし、結果のコードは悪臭に満ちていて、書き直す必要があることを理解したため、キャンバスを操作するスキルはまだありますが、どういうわけか継続する意欲を失いました。 はい、私は継続する希望を決して残しません。



そして今、小さな、面白いことをするチャンスが訪れました。 その選択は、サイトをむさぼり食う人に任せられ、黒さを残しましたが、結果は一人のプレイヤーのためのトロントレーニングルームでした。



これは何についてですか?



数学の小さなヒープについて(キャンバス上で必要な長さのセグメントを3日間作成したのは初めて)、衝突の計算、目的の形状の描画、および正常および異常なプログラミングの他のトリック。 要するに、ほとんどのコードは簡単だからです。



同意します。たとえば、canvasの作成行(11)など、一部の行が長すぎます。 しかし、これは「サイトマンを描く」、「キャンバスを構築する」、「結果を出力する」などの抽象化であると考えてください。 一部の変数の長さを短くすることも可能ですが、JS1Kをプレイしていませんよね?



このコードが興味深いのはなぜですか?



0)ロジック:

それは簡単です-サイトマンを初期化し、プロパティを定義し、ページの上部にキャンバスを描画し、すべてのキーを押すことにバインドして特定のキーのみを「リッスン」し、サイトマンを表示し、メインループで衝突をカウントします。



1)連鎖を実装することにより:



 //    source 'h_ctx':new function(){this.chain = function(method, args){siteman.ctx[method].apply(siteman.ctx, args); return this;}} /*     this    -   --,  this     window,       .  ,  this      ,   h_ctx     ,        - siteman.ctx[method].apply(siteman.ctx, args)     "  ", .apply -  ,    this   .  ""  */ siteman.h_ctx.chain('beginPath').chain('arc'... /*    */ siteman.ctx.beginPath(); siteman.ctx.arc(... /*   30         */
      
      







2)サイトマンの図面。 塗りつぶされた2つの垂直半円で構成されます( この記事のヒントのおかげで、1つは「静的」です(塗りつぶしの順序のみが時計回りまたは反時計回りに変更されます)。右側)、実際にはこのようにして、すべての方向に見えるパックマンの絵に対応するために非常にコンパクトであることが判明しました。



最初は通常の動きの状態を説明したかったのですが、動きの方向を含むオブジェクトに必要なすべての式を直接書き込んだため、スペースを取りすぎることがわかりました。 その結果、私たちは持っているものを手に入れました



 /*  -   -*/ siteman.h_ctx.chain('beginPath') .chain('arc', [siteman.coord.x, siteman.coord.y, siteman.settings.size, 0.25 * Math.PI, 1.25 * Math.PI, siteman.direction.current.clock]) .chain('fill') /*        */ siteman.h_ctx.chain('beginPath') .chain('arc', [siteman.coord.x, siteman.coord.y, siteman.settings.size, siteman.direction.current.x, siteman.direction.current.y, siteman.direction.current.clock]) .chain('fill');
      
      







3)衝突の計算:



 /* .  ""   -   ""    ,  ,  siteman              ,     "" ,                  */ var offset_x = siteman.settings.size * (siteman.coord.x != siteman.direction.current.calc_x() ? (siteman.direction.current.clock ? -1 : 1) : 0), offset_y = siteman.settings.size * (siteman.coord.y != siteman.direction.current.calc_y() ? (siteman.direction.current.clock ? 1 : -1) : 0); /*   ,          128( ,   ).       ,    -.      ,     */ if(!siteman.checkCollision(siteman.ctx.getImageData(siteman.coord.x + offset_x, siteman.coord.y + offset_y,1,1).data))
      
      





それはどのように機能し、なぜそのような式を正確にしていますか? xまたはyに沿った座標が変化する場合、この座標に沿ったオフセットを考慮する必要があります(ところで、合成の動きを追加することもできます)。そうでない場合は考慮しません。 円を(時計回りまたは反時計回りに)塗りつぶす方法により、移動方向を理解し、サイズによるオフセットを減算または加算します。

最後に、座標に取得したものを追加します。なぜなら、目の前にあるものに興味があるからです(後で取り去ります)。

座標を計算するための式は、ループを作成するために最初に使用したものと非常に似ています。



4)まあ、キャンバスの作成は少しですが、これは歪曲されているため、説明しません。決して良い習慣ではありません。



このコードは、requestAnimationFrameとsetTimeoutの両方から機能します。 setTimeoutがデフォルトの価値があるのはなぜですか? Linuxでは「polyfil」を1行で実行できなかったため、より安定しています。



このコードが悪いのはなぜですか?



1)サイトマンのクローンを作成することはできません。 可能であれば、100%小規模なサイトマンの工場を詰めることができ、少なくともいくつかの敵がいるでしょう。 今、私はそれを見るが、私は3度目にすべてを書き直したくない。

2)空白のページを運転するのは少し退屈です。 それは、トロンよりも早く食べる脂肪ヘビであることが判明しました。

3)一部の行には、(あらゆる意味で)抽象化が多すぎます。

4)それでも、過去時制からデルタをカウントし、サイトマンが「できる」ときにのみサイトマンを移動する方が正しいでしょう。

5)まあ、角の絵は少し奇妙に見えますが、ここではパックマンではなく円全体を描くか、座標でさらに変質する必要があります。

6)はい、自分で食べることができます。 動きの反対側のキーを押すと。 移動の方向はどこにも明示的に示されていないため、キーバインディングのある重い文字列が取得されますが、これは非常に可能です。

7)リセットが不十分



はい、そして長い間、私は通常のループを表示しようとしましたが、方向を考慮に入れると(そして常に棚の後ろにある「単純な」ループを作らないで)、あなたはあまりにも多くのコードと式を得ます。 オーディオでも同じですが、少なくとも3行を費やす必要があります。

 siteman.audio = new Audio(data:wav/base64); siteman.audio.loop=true; siteman.audio.play();
      
      





しかし、ほとんどの場合、彼らがすぐに働き始めるという事実ではありません。



それでは、次は何ですか?



しかし、何も。 目標は、キャンバスを使用してjs上で30行でゲームを作成することでした-完了しました。 コードはUGではないことが判明しましたが、最良ではありませんでした。 しかし、私は多くの経験を得て、それでも何らかのゲームを作りました。



確かに、私はまだもっとうまくいきます、特に壁から跳ね返ってランダムに移動する単純なAIを追加したいと思いますが、このためにコードを真剣に書き直さなければなりません。コード。 さて、またはそれでも私はサイトを食べる人でアイデアを終了します。 しかし、それは残念なことです。このプロジェクトに合計5時間を費やし、それ以上の夜を過ごしたくありませんでした。



PS私は皮肉な記事「js-code in only line」を読んで、私見-ポイントは正確にN行にすることではありません(ほとんどの言語では少なくとも1行を圧縮できます)が、ポイントは何かを書くことです面白くて小さい。



All Articles