コアダンプの数だけ強くなれるよ

見習いエンジニアの備忘log

canvasで少しずつ作るブロック崩し(2/5)

前回はマウスで動くバーを作成しました。今回はボールを打てるようにしていきます。

バーとボール


追加要素

ボールの描画と座標の更新処理、壁、床・天井、バーと接触時にボールを反発させる処理を追加しました。

  var BALL = {
    'X'      : 0,   // ボールのX座標
    'Y'      : 0,   // ボールのY座標
    'Vx'     : 100, // ボール速度(X成分)
    'Vy'     : 0,   // ボール速度(Y成分)
    'Vy0'    : 100, // ボールの最低速度
    'E'      : 0.7, // 床の反発係数
    'E0'     : 10,  // 反発時のバタつき防止
    'RADIUS' : 5,   // ボールの半径
  };
  
  var FIELD = {
    'GRAVITY' :588, // 重力加速度(0.9 * FPS)
    'FPS'     : 60, // frame per second
  };

  // ボールの座標更新
  function calcBallPosition() {
    // 縦計算
    BALL.Vy += FIELD.GRAVITY * (1/FIELD.FPS);
    BALL.Y  += BALL.Vy * (1/FIELD.FPS);
    
    // 床・天井接触
    if (BALL.Y <= 0 || height <= BALL.Y) {
      if (BALL.Y <= 0) {
        BALL.Y = BALL.E0;
        BALL.Vy = BALL.Vy * BALL.E * (-1)
      } else {
        BALL.Y = height-BALL.E0;
        BALL.Vy = BALL.Vy * BALL.E * (-1) - BALL.Vy0;
      }
      
    }
    
    // 横計算
    BALL.X += BALL.Vx * (1/FIELD.FPS);
    
    // 壁接触
    if (BALL.X <= 0 || width <= BALL.X) {
      if (BALL.X <= 0) {
        BALL.X = BALL.E0;
      } else {
        BALL.X = width - BALL.E0;
      }
      
      BALL.Vx = BALL.Vx * (-1);
    }
    
    // バー接触
    if (BAR.X <= BALL.X && BALL.X <= BAR.X + BAR.WIDTH) {
      if (Math.abs(BALL.Y - (height - BAR.UNDER)) <= BAR.HEIGHT) {
        BALL.Y += - BALL.E0;
        BALL.Vy = BALL.Vy  * (-1) - BALL.Vy0;
      }
    }
  };

  // ボールの描画
  function drawBall() {
    
    // ボールの座標更新
    //calcBallPosition()
    
    ctx.save();
    ctx.fillStyle = 'rgba(0, 0, 0, 0.1)';
    ctx.fillRect(0, 0, width, height);
    
    // 円の描画設定
    ctx.beginPath();
    ctx.arc(BALL.X, BALL.Y, BALL.RADIUS, 0, 2*Math.PI, true);
    ctx.closePath();
    
    // 色設定
    hue += 0.5;
    ctx.strokeStyle = 'hsl(' + hue + ', 50%, 50%)';
    ctx.fillStyle = 'hsl(' + hue + ', 50%, 50%)';
    ctx.shadowColor = 'hsl(' + hue + ', 50%, 50%)';
    ctx.shadowBlur = 10;
    
    // 描画実行
    ctx.stroke();
    ctx.fill();
    ctx.restore();
  };


ソースコード

<html>
<head>
<meta charset="UTF-8">
<script type="text/javascript">
(function() {

  var canvas;
  var ctx;
  var width;
  var height;
  var mouseX;
  var mouseY;
  
  var BAR = {
    'HEIGHT' : 10,  // バーの高さ
    'WIDTH'  : 50,  // バーの幅
    'UNDER'  : 20,  // バーのY座標(床からの高さ)
    'X'      : 0,   // バーのX座標
  };
  
  var BALL = {
    'X'      : 0,   // ボールのX座標
    'Y'      : 0,   // ボールのY座標
    'Vx'     : 100, // ボール速度(X成分)
    'Vy'     : 0,   // ボール速度(Y成分)
    'Vy0'    : 100, // ボールの最低速度
    'E'      : 0.7, // 床の反発係数
    'E0'     : 10,  // 反発時のバタつき防止
    'RADIUS' : 5,   // ボールの半径
  };
  
  var FIELD = {
    'GRAVITY' :588, // 重力加速度(0.9 * FPS)
    'FPS'     : 60, // frame per second
  };
  
  // 初期化処理
  function initialize() {
    canvas = document.getElementById('canvas');
    if(!canvas && !canvas.getContext) {
      return false;
    }
    
    ctx = canvas.getContext('2d');
    width = ctx.canvas.width ;
    height = ctx.canvas.height;
    
    // バーの初期位置は中心
    mouseX = width/2;
    BAR.X = mouseX;
    
    
    // ボールの初期位置は中心
    BALL.X = width/2;
    BALL.Y = height/2;
    
    canvas.addEventListener('mousemove', getMousePosition, false);
    setInterval(drawBar, 1000/FIELD.FPS);
    setInterval(drawBall, 1000/FIELD.FPS);
    setInterval(calcBallPosition, 1000/FIELD.FPS);
  };
  
  
  // マウス座標の更新
  function getMousePosition(e) {
    var rect = e.target.getBoundingClientRect();
    mouseX = Math.floor(e.clientX - rect.left);
    mouseY = Math.floor(e.clientY - rect.top);
  };
  
  
  // ボール位置計算
  function calcBallPosition() {
    // 縦計算
    BALL.Vy += FIELD.GRAVITY * (1/FIELD.FPS);
    BALL.Y  += BALL.Vy * (1/FIELD.FPS);
    
    // 床・天井接触
    if (BALL.Y <= 0 || height <= BALL.Y) {
      if (BALL.Y <= 0) {
        BALL.Y = BALL.E0;
        BALL.Vy = BALL.Vy * BALL.E * (-1)
      } else {
        BALL.Y = height-BALL.E0;
        BALL.Vy = BALL.Vy * BALL.E * (-1) - BALL.Vy0;
      }
      
    }
    
    // 横計算
    BALL.X += BALL.Vx * (1/FIELD.FPS);
    
    // 壁接触
    if (BALL.X <= 0 || width <= BALL.X) {
      if (BALL.X <= 0) {
        BALL.X = BALL.E0;
      } else {
        BALL.X = width - BALL.E0;
      }
      
      BALL.Vx = BALL.Vx * (-1);
    }
    
    // バー接触
    if (BAR.X <= BALL.X && BALL.X <= BAR.X + BAR.WIDTH) {
      if (Math.abs(BALL.Y - (height - BAR.UNDER)) <= BAR.HEIGHT) {
        BALL.Y += - BALL.E0;
        BALL.Vy = BALL.Vy  * (-1) - BALL.Vy0;
      }
    }
  };
  
  var hue = 0.5;
  
  function drawBall() {
    
    // ボールの座標更新
    //calcBallPosition()
    
    ctx.save();
    ctx.fillStyle = 'rgba(0, 0, 0, 0.1)';
    ctx.fillRect(0, 0, width, height);
    
    // 円の描画設定
    ctx.beginPath();
    ctx.arc(BALL.X, BALL.Y, BALL.RADIUS, 0, 2*Math.PI, true);
    ctx.closePath();
    
    // 色設定
    hue += 0.5;
    ctx.strokeStyle = 'hsl(' + hue + ', 50%, 50%)';
    ctx.fillStyle = 'hsl(' + hue + ', 50%, 50%)';
    ctx.shadowColor = 'hsl(' + hue + ', 50%, 50%)';
    ctx.shadowBlur = 10;
    
    // 描画実行
    ctx.stroke();
    ctx.fill();
    ctx.restore();
  };
  
  function drawBar() {
    var delay = 1;
    
    BAR.X = (mouseX + delay * BAR.X) / (delay+1);
    
    ctx.save();
    ctx.fillStyle = 'rgba(0, 0, 0, 0.1)';
    ctx.fillRect(0, 0, width, height);
    
    // 色設定
    ctx.fillStyle = 'rgb(255,255,0)';
    // 円の描画設定
    ctx.fillRect(BAR.X, height-BAR.UNDER, BAR.WIDTH, BAR.HEIGHT);
    
    // 描画実行
    ctx.stroke();
    ctx.fill();
    ctx.restore();
  };
  
  
  // 初期化イベント
  window.addEventListener('load', initialize, false);
  
} ) ();
</script>
</head>
<body>
<canvas id='canvas' width=500 height=300></canvas>
</body>
</html>


後はブロックを作ればひとまず形になりそう。

関連ページ

canvasで少しずつ作るブロック崩し(1/5) - Segmentation Fault
canvasで少しずつ作るブロック崩し(3/5) - Segmentation Fault
canvasで少しずつ作るブロック崩し(その4) - Segmentation Fault
canvasで少しずつ作るブロック崩し(5/5) - Segmentation Fault