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

2020年7月4日

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

t f B! P L
やっぱりゲームを作るのは楽しいな〜と、つぶやいている、ユゲタです。 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 今回は初期表示のみのバージョンなので、あまり面白くないですが、今後バージョンアップさせていく予定なので、楽しんでもらえる方は引き続き読んでくださいませ。

このブログを検索

プロフィール

自分の写真
プログラミングとサーバーを心の底から楽しむクリエーターです。 経営者であり、開発者でもありますが、得意としているのは、アイデア創出で、出来高は無限大です。

ブログ アーカイブ

QooQ