ゲームライブラリ構築までの道「ブロック崩し編」#1 : 仕様決定と基盤構築

2020年7月4日

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

やっぱりゲームを作るのは楽しいな〜と、つぶやいている、ユゲタです。 gameを構築するイメージがまあまあ見えてきたんですが、少し規模の大きいgameを作る時に、 フレームワークを使ってgameを作ってもいいんですが、できるだけ無駄とブラックボックス箇所を無くしたいので、 フルスクラッチでcanvasを使って構築をしたいと思った時に、いろいろなライブラリが必要になる事もイメージできます。 そんなライブラリを作り込んで行きたいと思って、小さなゲームプログラムを作り重ねていき、最終的に自分ライブラリを作ってみたいと思います。 ブログでは、そんなプログラムの解説をしつつ、Githubで都度のバージョンを公開して行く予定です。

本日のIT謎掛け

「ゲームライブラリ」と、かけまして・・・ 「公園の遊具」と、ときます。 そのココロは・・・ 遊ぶ時に、無いとまあまあ困るもの。

本日の目的

以前に作った三目並べのcanvasライブラリを参照しつつ、データ管理や、表示まわりの効率的な書き方などがまとまっていないので、とりあえず、今回はまだ手を付けていなかった、アニメーションに関するかんたんなライブラリを作ってみたいと思います。 そこで、BASICを学習した時の一番最初に作った「壁打ちテニス」にTRYします。 仕様は、三方壁に囲まれたbox内で直線的に動くボールを、手前のラケット(棒)で、返すだけですが、以下のような処理が必要になります。
・基本描画処理 ・開始時の「start」ボタンのクリックイベント処理 ・ボールと、ラケットが動くアニメーション描画処理(全体書き換え) ・マウス動作によるラケット移動 ・ボールが壁に当たって跳ね返る当たり判定 ・ボールがラケットに当たって跳ね返るコリジョン処理 ・ボールが画面外に言ってしまった時のGameOver処理
これを簡易仕様として、構築していきます。

基本描画処理

まず始めに、基本の画面表示をしてみます。 画面サイズを決めて、3方の壁の表示です。 初期構築という事で、htmlも含めたソースコードも合わせて掲載しておきます。

ソースコード

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>TicTacToe</title> <style> #mycanvas{ display:block; margin:10px auto; } </style> <script src="common.js"></script> </head> <body> <canvas id="mycanvas">not canvas</canvas> </body> </html>   (function(){ var __options = { canvas : "#mycanvas", width : 400, height : 600, wall : { w : 400 , h : 600 , color_stroke : "transparent" , color_fill : "#382B8C" , size : 20 }, ball : { r : 10 , color_stroke : "transparent" , color_fill : "#F2B5A7" }, 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(); }; 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.draw = function(){ 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(); ctx.arc(__options.wall.w / 2, __options.wall.h / 2, __options.ball.r, 0, Math.PI * 2); ctx.fill(); }; 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.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(); })();

Github

https://github.com/yugeta/game_block 今回は初期表示のみのバージョンなので、あまり面白くないですが、今後バージョンアップさせていく予定なので、楽しんでもらえる方は引き続き読んでくださいませ。

このブログを検索

ごあいさつ

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