ゲームライブラリ構築までの道「ブロック崩し編」#2 : ボールを動かす

2020/07/05

Javascript テクノロジー プログラミング 特集

t f B! P L
eyecatch プログラミングでは、どうしてもスピードにこだわってしまう、ユゲタです。 いろいろな便利なライブラリを試す時に、どうしても処理速度が、遅く、パフォーマンスが出ない時に、ギアの再発明をしてしまいます。 「できりゃあ、良い」というテスト・パイロット的な考え方と相反して、効率的に安定運用ができるという製品レベルの思考は必ず必要になります。 これは、エンジニアの独特の観点なのかもしれないけれど、企業では優先順位が上位では無い場合が多いので、エンジニアがしっかりと考える必要があることを経験で学びました。 そして、安定性を度外視したシステムで、問題が発生した時に責任を負わされるのは、それを構築したエンジニアでもありますからね。

本日のIT謎掛け

「システムの安定性」と、かけまして・・・ 「貴重なキャビアの物価」と、ときます。 そのココロは・・・ フカ(負荷と、サメの鱶)が、高くなります。

本日の目的

前回作った、基本画面の描画に対して、表示だけさせているボールを動かしてみたいと思います。 アニメーションなので、随時再描画を繰り返す事になりますが、効率のいいアニメーションのさせ方を追求してみたいと思います。

ソースコード

(function(){ var __options = { canvas : "#mycanvas", width : 400, height : 600, wall : { w : 400 , h : 600 , color_stroke : "transparent" , color_fill : "#382B8C" , size : 20 }, ball : { x : 50 , y : 50 , r : 10 , color_stroke : "transparent" , color_fill : "#F2B5A7" , moveX : 2 , moveY : 2 }, bar : { w: 50 , h: 10 , color_stroke : "transparent" , color_fill : "#958ABF" }, $:0 }; var MAIN = function(){ if(!this.check()){ alert("htmlに指定のcanvasがありません。"); return; } this.init(); this.draw(); this.animation_set(); }; MAIN.prototype.getCanvas = function(){ if(typeof this.canvas === "undefined"){ this.canvas = document.querySelector(__options.canvas); } return this.canvas; }; MAIN.prototype.getContext = function(){ if(typeof this.ctx === "undefined"){ var canvas = this.getCanvas(); if(!canvas){return null;} this.ctx = canvas.getContext("2d"); } return this.ctx; }; MAIN.prototype.check = function(){ var ctx = this.getContext(); if(ctx){ return true; } else{ return false; } }; MAIN.prototype.init = function(){ // 画面サイズ調整 var canvas = this.canvas; canvas.setAttribute("width" , __options.wall.w); canvas.setAttribute("height" , __options.wall.h); }; MAIN.prototype.ctx_clear = function(){ this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); }; MAIN.prototype.draw = function(){ this.ctx_clear(); this.draw_wall(); this.draw_bar(); this.draw_ball(); }; MAIN.prototype.draw_wall = function(){ var ctx = this.ctx; ctx.strokeStyle = __options.wall.color_stroke; ctx.strokeWidth = __options.wall.color_stroke === "transparent" ? 0 : 1; ctx.fillStyle = __options.wall.color_fill; ctx.beginPath(); ctx.moveTo(0,0); ctx.lineTo(__options.wall.w , 0); ctx.lineTo(__options.wall.w , __options.wall.h); ctx.lineTo(__options.wall.w - __options.wall.size , __options.wall.h); ctx.lineTo(__options.wall.w - __options.wall.size , __options.wall.size); ctx.lineTo(__options.wall.size , __options.wall.size); ctx.lineTo(__options.wall.size , __options.wall.h); ctx.lineTo(0 , __options.wall.h); ctx.lineTo(0 , 0); ctx.stroke(); ctx.fill(); }; MAIN.prototype.draw_bar = function(){ var ctx = this.ctx; ctx.strokeStyle = __options.bar.color_stroke; ctx.strokeWidth = __options.bar.color_stroke === "transparent" ? 0 : 1; ctx.fillStyle = __options.bar.color_fill; ctx.fillRect(__options.wall.size + 10 , __options.wall.h - __options.bar.h - 30 , __options.bar.w , __options.bar.h); }; MAIN.prototype.draw_ball = function(){ var ctx = this.ctx; ctx.strokeStyle = __options.ball.color_stroke; ctx.strokeWidth = __options.ball.color_stroke === "transparent" ? 0 : 1; ctx.fillStyle = __options.ball.color_fill; ctx.beginPath(); __options.ball.x = __options.ball.x || __options.wall.w / 2; __options.ball.y = __options.ball.y || __options.wall.h / 2; ctx.arc( __options.ball.x , __options.ball.y , __options.ball.r, 0, Math.PI * 2 ); ctx.fill(); }; MAIN.prototype.animation_set = function(){ new LIB().anim((function(e){this.animation(e)}).bind(this) , 50); }; MAIN.prototype.animation = function(timestamp){ if (!this.time_start){ this.time_start = timestamp; } if(timestamp - this.time_start > 30000){return;} this.ball_move(); this.draw(); this.animation_set(); }; MAIN.prototype.ball_move = function(){ __options.ball.x += __options.ball.moveX; __options.ball.y += __options.ball.moveY; // コリジョン判定(壁)----- // <- : left if(__options.ball.x - __options.ball.r < __options.wall.size){ __options.ball.x = __options.wall.size + __options.ball.r; __options.ball.moveX = __options.ball.moveX * -1; } // ^ : top if(__options.ball.y - __options.ball.r < __options.wall.size){ __options.ball.y = __options.wall.size + __options.ball.r; __options.ball.moveY = __options.ball.moveY * -1; } // -> : right if(__options.ball.x + __options.ball.r > __options.wall.w - __options.wall.size){ __options.ball.x = __options.wall.w - __options.wall.size - __options.ball.r; __options.ball.moveX = __options.ball.moveX * -1; } // v : bottom (test用) if(__options.ball.y + __options.ball.r > __options.wall.h - __options.wall.size){ __options.ball.y = __options.wall.h - __options.wall.size - __options.ball.r; __options.ball.moveY = __options.ball.moveY * -1; } }; var LIB = function(){}; LIB.prototype.event = function(target, mode, func , flg){ flg = (flg) ? flg : false; if (target.addEventListener){target.addEventListener(mode, func, flg)} else{target.attachEvent('on' + mode, function(){func.call(target , window.event)})} }; LIB.prototype.anim = function(func , time){ if(window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame){ window.requestAnimationFrame(func); } else{ anim_flg = setTimeout(func , time); } }; LIB.prototype.construct = function(){ switch(document.readyState){ case "complete" : new MAIN();break; case "interactive" : this.event(window , "DOMContentLoaded" , (function(){new MAIN()}).bind(this));break; default : this.event(window , "load" , (function(){new MAIN()}).bind(this));break; } }; new LIB().construct(); })(); 全体的に書き直した箇所があったので、jsファイル全部掲載しておきました。 ポイントは、アニメーション処理に、通常であれば、setIntervalやsettimeoutを使うところを、"requestAnimationFrame"という命令を使うと、デバイスのCPU処理に適した値で処理が進められるため、無駄に負荷が増えないというメリットがあります。 使い方は、かんたんで、setTimeoutの時間していをしないバージョンだと考えるとわかりやすいでしょう。 参考 : https://developer.mozilla.org/ja/docs/Web/API/Window/requestAnimationFrame 普通に関数を数珠つなぎするのと何が違うのかと言うと、プログラムが止まらないと、アクセスを一切受け付けなくなるので、こうしたプログラムの切れ目を入れてあげるのがjavascriptでは必要なので、繰り返しの処理をする際などに、こうしたテクニックを覚えておくと良いでしょうね。

本日のまとめ

今回は、ボールの挙動を作りたかったので、画面の下を壁に見立てていますが、カーソル操作を受け付けるようにすると、下に到着するとゲームオーバーになりますね。 次回は、そのカーソル操作をやりたいと思います。お楽しみに。 全体のソースは、githubにpushしているので、そちらから取得してください。 https://github.com/yugeta/game_block

人気の投稿

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。

ブログ アーカイブ