
以前に作ったプログラムを見直すとどうしても書き直したくなってしまう、ユゲタです。
リファクタリングは重要な作業ですが、その時々で、コーディングルールが変わってきてしまい、どうしても、最新の自分のマイ・フェイバリットコーディングルールに思考が寄ってしまうので、書き直しをしたくなるんですね。
その中で書き直さなくても納得の行く書き方ができているのは、自分のプログラミングの型が決まっているものは、書き直しをしなくてもコードに安定感を感じるため、プログラミングにも武道の型のようなものが存在するということを、改めて理解することができました。
そして、壁打ちテニスも、操作性がつくことによって、ゲームっぽくなってきたので、今回は、ゲーム開始と終了の処理を追加してみたいと思います。
本日のIT謎掛け
「コーディング・ルール」と、かけまして・・・
「駐車テクニック」と、ときます。
そのココロは・・・
スペースにこだわる人が、多いでしょう。
ソースコード
$$gamekit_draw = (function(w,d,n){
  // default-set
  var __options = {
    flg_mouse : null,
    mouse_over : {
      color_bg  : "#7BA6A1",
    },
    mouse_down : {
      color_bg  : "#C5D9D2",
    },
    mouse_up : {
      color_bg  : "#7BA6A1",
    },
    color_bg  : "#58838C",
    color_txt : "#F2E6A7",
    color_stroke : "#3F6473",
    width_stroke : 0,
    align     : "center", // [ left , center , right ]
    valign    : "middle", // [ top , middle , bottom ]
    width     : 0,  // % or px *数値のみの場合はpx
    height    : 0,  // % or px *数値のみの場合はpx
    margin    : 0, // 全ての方向に対して一律指定 : %指定の場合はwidthに対しての% or px *数値のみの場合はpx
    padding   : "10px", // 全ての方向に対して一律指定 : %指定の場合はwidthに対しての% or px *数値のみの場合はpx
    radius    : 0,
    textAlign : "center",
    textFont  : "sans-serif",
    textColor : "white",
    textBase  : "top",
    textWeight: "bold",
    textSize  : "16px",
    x         : 0,  // 自動設定
    y         : 0,  // 自動設定
    tx        : 0,  // 自動設定
    ty        : 0,  // 自動設定
    click : function(e , options){},
    $:0
  };
  // -----
  // Object make
  var MAIN = function(canvas_selector){
    canvas_selector = canvas_selector || "canvas";
    var canvas = d.querySelector(canvas_selector);
    if(canvas){
      this.canvas = canvas;
      return 1;
    }
    else{
      this.canvas = null;
      return 0;
    }
  };
  // -----
  // Dialog
  // options : __options is default
  // texts   : array strings of text-line
  MAIN.prototype.dialog = function(options){
    if(!this.canvas){return;}
    var canvas = this.canvas;
    options = new $$gamekit_common().setOption(__options , options);
    options = this.dialogOptions_adjust(options);
    var ctx = canvas.getContext("2d");
    this.viewBase(ctx , options);
    this.viewMessage(ctx , options);
  };
  MAIN.prototype.dialogOptions_adjust = function(options){
    if(!this.canvas){return;}
    var canvas = this.canvas;
    // サイズ処理
    options.width    = this.px_per2num(options.width , canvas.offsetWidth);
    options.height   = this.px_per2num(options.height , canvas.offsetHeight);
    options.margin   = this.px_per2num(options.margin , canvas.offsetWidth);
    options.padding  = this.px_per2num(options.padding , canvas.offsetWidth);
    options.textSize = Number(String(options.textSize).replace("px",""));
    options.radius   = this.px_per2num(options.radius , canvas.offsetWidth);
    options.width_stroke = Number(String(options.width_stroke).replace("px",""));
    if(options.x === 0){
      switch(options.align){
        case "left":
          options.x = options.margin;
          break;
        case "right":
          options.x = canvas.offsetWidth - (options.width + options.margin);
          break;
        case "center":
        default:
          options.x = (canvas.offsetWidth / 2) - (options.width / 2);
          break;
      }
    }
    else{
      options.x = this.px_per2num(options.x , canvas.offsetWidth);
    }
    if(options.y === 0){
      switch(options.valign){
        case "top":
          optinos.y = options.margin;
          break;
        case "bottom":
          options.y = canvas.offsetHeight - (options.height + options.margin);
          break;
        case "middle":
        default:
          options.y = (canvas.offsetHeight / 2) - (options.height / 2);
          break;
      }
    }
    else{
      options.y = this.px_per2num(options.y , canvas.offsetHeight);
    }
    
    // text情報
    options.ty = options.y + options.padding;
    switch(options.textAlign){
      case "left":
        options.tx = options.x + options.padding;
        break;
      case "right":
        options.tx = canvas.offsetWidth - options.x - options.padding;
        break;
      case "center":
      default:
        options.tx = options.x + (options.width / 2);
        break;
    }
    return options;
  };
  // @px,@%を数値に変換する
  MAIN.prototype.px_per2num = function(data , max){
    if(String(data).match(/^([0-9]+?)%$/)){
      var num = Number(RegExp.$1);
      num = num <= 100 ? num : 100;
      return parseInt(max * (num / 100));
    }
    else if(String(data).match(/^([0-9]+?)px$/)){
      return Number(String(data).replace("px",""));
    }
    else{
      return Number(data);
    }
  };
  MAIN.prototype.viewBase = function(ctx , options){
    ctx.fillStyle   = options.color_bg;
    ctx.strokeStyle = options.color_stroke;
    ctx.lineWidth   = options.width_stroke * 2;
    if(options.radius === 0){
      ctx.strokeRect(options.x , options.y , options.width , options.height);
      ctx.fillRect(options.x , options.y , options.width , options.height);
    }
    else{
      var w = options.width;
      var h = options.height;
      var x = options.x;
      var y = options.y;
      var r = options.radius;
      ctx.beginPath();
      ctx.moveTo(x,y + r);
      ctx.arc(x+r , y+h-r , r , Math.PI , Math.PI*0.5 , true);
      ctx.arc(x+w-r , y+h-r , r , Math.PI*0.5,0 , 1);
      ctx.arc(x+w-r , y+r , r , 0 , Math.PI*1.5 , 1);
      ctx.arc(x+r , y+r , r , Math.PI*1.5 , Math.PI , 1);   
      ctx.closePath();
      ctx.stroke();
      ctx.fill();
    }
  };
  MAIN.prototype.viewMessage = function(ctx , options){
    // 文字
    ctx.fillStyle = options.color_txt;
    ctx.font      = options.textWeight +" "+ options.textSize +"px "+ options.textFont;
    ctx.textAlign = options.textAlign;
    ctx.textBaseline = options.textBase;
    options.texts = typeof options.texts === "string" ? [options.texts] : options.texts;
    for(var i=0; i<options.texts.length; i++){
      ctx.fillText(options.texts[i], options.tx, options.ty + (i * options.textSize + 4) , options.width);
    }
  };
  // -----
  // button
  MAIN.prototype.button = function(options){
    options = new $$gamekit_common().setOption(__options , options);
    options = this.dialogOptions_adjust(options);
    options.mouse_over = new $$gamekit_common().setOption(options , options.mouse_over);
    options.mouse_down = new $$gamekit_common().setOption(options , options.mouse_down);
    options.mouse_up   = new $$gamekit_common().setOption(options , options.mouse_up);
    this.button_draw(options);
    this.setButtonEvent(options);
  };
  MAIN.prototype.button_draw = function(options){
    if(!this.canvas){return;}
    var ctx = this.canvas.getContext("2d");
    options = options.flg_mouse === null ? options : options["mouse_"+options.flg_mouse];
    this.viewBase(ctx , options);
    this.viewMessage(ctx , options);
  };
  MAIN.prototype.setButtonEvent = function(options){
    if(!this.canvas){return;}
    new $$gamekit_common().event(this.canvas , "mousemove" , (function(options,e){this.event_button_mouse(e,options,"over")}).bind(this , options));
    new $$gamekit_common().event(this.canvas , "mousedown" , (function(options,e){this.event_button_mouse(e,options,"down")}).bind(this , options));
    new $$gamekit_common().event(this.canvas , "mouseup"   , (function(options,e){this.event_button_mouse(e,options,"up")}).bind(this , options));
    new $$gamekit_common().event(this.canvas , "click"     , (function(options,e){this.event_button_click(e,options)}).bind(this , options));
  };
  MAIN.prototype.event_button_mouse = function(e,options , flg){
    if(flg === "over" && options.flg_mouse === "down"){return;}
    if(flg === "over" && options.flg_mouse === "up"){return;}
    var canvas = e.currentTarget;
    var x = e.clientX - canvas.getBoundingClientRect().left;
    var y = e.clientY - canvas.getBoundingClientRect().top;
    // buttonエリア内
    if(options.x <= x && x <= options.x + options.width
      && options.y <= y && y <= options.y + options.height){
      options.flg_mouse = flg;
      this.button_draw(options);
    }
    else if(options.flg_mouse !== null){
      options.flg_mouse = null;
      this.button_draw(options);
    }
    if(options.flg_mouse === "down"
    || options.flg_mouse === "up"){
      // options.flg_mouse = null;
      setTimeout((function(options){options.flg_mouse = null;}).bind(this , options) , 100);
    }
  };
  
  MAIN.prototype.event_button_click = function(e,options){
    var canvas = e.currentTarget;
    var x = e.clientX - canvas.getBoundingClientRect().left;
    var y = e.clientY - canvas.getBoundingClientRect().top;
    // buttonエリア内
    if(options.x <= x && x <= options.x + options.width
      && options.y <= y && y <= options.y + options.height
      && options.click){
      options.click(e , {x:x,y:y});
    }
  };
  // -----
  // Image
  var __options_image = {
    src : null,
    x : 0,
    y : 0,
    width  : 0,
    height : 0
  };
  MAIN.prototype.view = function(options){
    if(!this.canvas){return;}
    if(!options){return;}
    options = new $$gamekit_common().setOption(__options_image , options);
    options = this.dialogOptions_adjust_image(options);
    var img = new Image();
    img.src = options.src;
    img.onload = (function(e){
      var img = e.target;
      var ctx = this.canvas.getContext("2d");
      ctx.drawImage(img , options.x, options.y ,options.w , options.h);
    }).bind(this);
    
  };
  MAIN.prototype.dialogOptions_adjust_image = function(options){
    if(!this.canvas){return;}
    var canvas = this.canvas;
    // サイズ処理
    options.width  = this.px_per2num(options.width  , canvas.offsetWidth);
    options.height = this.px_per2num(options.height , canvas.offsetHeight);
    options.x      = this.px_per2num(options.x      , canvas.offsetWidth);
    options.y      = this.px_per2num(options.y      , canvas.offsetWidth);
    return options;
  };
  console.log("- lib draw : loaded");
  return MAIN;
})(window,document,navigator); 
 
本日のまとめ
プログラムを起動した際に、ゲームタイトルダイアログを表示し、画面のどこかをクリックすると、ゲームスタートする仕様にしました。
あと、ボールが、画面下に落ちた場合に、ゲームオーバーダイアログを表示ます。
ゲームオーバー・ダイアログは、画面クリックをすると、何度でもゲーム再開できるようになっているので、無限に遊ぶことができます。
それから、カーソルを使ってラケットを移動するのが、非常にトロかったので、ロジックを作り直してスムーズにしました。
ゲームとしては、単純ですが、これで完成ですが、このあとブロック崩し要素を追加したいので、次回は、リファクタリングを行ってコードをスッキリさせてみますね。
お楽しみに。
全体のソースは、githubにpushしているので、そちらから取得してください。
https://github.com/yugeta/game_block
 
0 件のコメント:
コメントを投稿