<canvas id="canvas_area"></canvas>
    
html,body {
   width: 100%;
   margin: 0;
   padding: 0;
 }
#canvas_area {
  display: block;
}
//Drawの読み込み
window.addEventListener('load', function(e) {
  new Draw();
});

//描画
function Draw() {
  var self = this;
  //共通変数
  this.timeout_MOVE; //setIntervalを代入する用の変数(動作時)
  this.timeout_EXP; //setIntervalを代入する用の変数(拡大時)
  this.windowSizeW = window.innerWidth; // ウィンドウの横幅
  this.windowSizeH = window.innerHeight; // ウィンドウの高さ

  this.fps = 35;  // 1秒あたりのフレーム数
  this.MpPX = 100;  // 1メートルを何ピクセルとするか
  this.ga = 9.8 * this.MpPX;  // 重力加速度
  this.gh2 = this.ga * Math.pow( ( 1 / self.fps ), 2 );  // 重力加速度 × フレーム表示間隔(秒)の2乗


  //キャンバスの読み込み(認識できなければ、return)
  var canvas = document.getElementById('canvas_area');
  if( !canvas || !canvas.getContext ){
     return false;
  }

  //2Dで表示します。
  this.ctx = canvas.getContext('2d');
  //キャンバスの横幅を代入
  canvas.width = this.windowSizeW;
  //キャンバスの高さを代入
  canvas.height = this.windowSizeH;


  /*-----------------------------------------
    画像の読み込み
  -----------------------------------------*/

  //背景画像
  this.img = new Image();
  this.img.src = 'https://drive.google.com/uc?export=view&id=1AcgAW0NX0E7Lc6rcU3abLLoY050BBw76';

  //マスク画像
  this.maskImg = new Image();
  this.maskImg.src = 'https://drive.google.com/uc?export=view&id=1-ay1ixlyCDuG8R0LYn2pmZyu4bqSzuX2';

  //画像を読み込んだタイミングでロード
  this.img.onload = function() {
    // 画面表示
    self.init();
    self.timeout_MOVE = window.setInterval( self.jumpFun.bind(self), 1000 / self.fps );

  }

}


/*----------------------------------
  Drawの初期設定
----------------------------------*/
Draw.prototype.init = function() {
  //thisの値を格納
  var self = this;
  //変数一覧
  this.imgR = this.maskImg.width / 2; //画像の半径
  this.firstX = this.windowSizeW / 4 - this.imgR * 2;  // 中心のx座標初期値
  this.firstY = this.windowSizeH / 1.9 - this.imgR;  // 中心のy座標初期値
  this.peakY = 2 * this.imgR + 5;  // ジャンプピーク時のy座標

  this.v0 = -1 * Math.sqrt(2 * this.ga * Math.abs(this.firstY - this.peakY)); // 初速度
  this.vfirst = this.v0; // 初速度(保存用)
  this.jumping = true;  // マスクの移動(ジャンプ)時の判定用flag
  this.increaseX = 0; //マスクのX軸の移動力を指定
  this.countUp = 0; //マスク拡大用のカウント

  // 中心の座標 (x0,y0)は前回の座標
  this.imgObj = {
    x0: this.firstX,
    y0: this.firstY,
    x: this.firstX,
    y: this.firstY
  };
}

/*----------------------------------
  キャンバスの描画(リセット)
----------------------------------*/
Draw.prototype.canvasResetFun = function(){
  //thisの値を格納
  var self = this;

  // canvasに描画を保存したときの状態に戻す
  this.ctx.restore();
  // canvasの状態を保存
  this.ctx.save();

  // canvasをリセット
  this.ctx.clearRect(0, 0, self.windowSizeW, self.windowSizeH);

  //背景の合成方法を指定
  this.ctx.globalCompositeOperation = 'source-over';

  //キャンバスに背景を描画
  this.ctx.drawImage(self.img, 0, 0, self.windowSizeW, self.windowSizeH);

  //マスクの合成方法を指定
  this.ctx.globalCompositeOperation = 'destination-in';
}

/*----------------------------------
  ジャンプ処理
----------------------------------*/
Draw.prototype.jumpFun = function(){
  //thisの値を格納
  var self = this;

  //キャンバスの状態を背景ありの状態でリセット
  this.canvasResetFun();


  //キャンバスにマスクをかけた状態を反映します。
  this.ctx.drawImage(self.maskImg, self.imgObj.x, self.imgObj.y, self.maskImg.width, self.maskImg.height);

  //マスクの移動(ジャンプ)を停止
  if(!this.jumping){
    //self.timeout_MOVEの処理をリセット
    window.clearInterval(self.timeout_MOVE);
    //マスクの拡大を実行
    self.timeout_EXP = window.setInterval( self.scaleFun.bind(self), 1000 / self.fps );
  }

  //マスクの位置を計測します
  self.jampPosition();

}


/*----------------------------------
  マスクが移動(ジャンプ)する位置を計算
 ----------------------------------*/
Draw.prototype.jampPosition = function(){

  var self = this; //thisをselfに格納
  var backy = this.imgObj.y;  // 前回のy座標を代入

  //マスクy座標が前回と現在で一致するとき
  if( this.imgObj.y0 == this.imgObj.y){

    this.imgObj.y = this.ga / ( 2 * Math.pow( self.fps,2 ) ) + this.v0 / self.fps + this.firstY;

  //マスクy座標が前回と現在で一致しないとき
  }else{

    this.imgObj.y += this.imgObj.y - this.imgObj.y0 + this.gh2;

    if(this.increaseX < 10){
      this.increaseX += 2;
    }else{
      this.increaseX--;
    }

    if(this.vfirst / 2  > this.v0){
      this.imgObj.x += this.increaseX;
    }else{
      this.imgObj.x -= this.increaseX;
    }
  }


  //前回の座標格納
  this.imgObj.y0 = backy;

  // 現在のy座標が初期値を上回ったら、反発係数をかけて、減速します。
  if(this.imgObj.y >= this.firstY){

    this.v0 *= 0.8; // 反発係数をかける

    //初速度が値を下回る時
    if(this.v0 >= -25){
      this.imgObj.y = this.firstY;
      // ジャンプ終了
      this.jumping = false;
    }else{

      this.imgObj.y = this.ga / (2 * Math.pow( self.fps,2 )) + this.v0 / self.fps + this.firstY;
      this.imgObj.y0 = this.firstY;
    }
  }
}


/*----------------------------------
  マスク画像の拡大
----------------------------------*/
Draw.prototype.scaleFun = function(){
  //thisの値を格納
  var self = this;
  //変数一覧
  this.countUp += 100;
  this.maskImgWidth = this.maskImg.width + this.countUp;
  this.maskImgHeight = this.maskImg.height + this.countUp;
  this.countUp_Harf = this.countUp / 2;

  //キャンバスの状態を背景ありの状態でリセット
  this.canvasResetFun();

  //マスクを描画します。停止位置からthis.countUp分だけ拡大します。
  this.ctx.drawImage(
    self.maskImg,
    self.imgObj.x - this.countUp_Harf,
    self.imgObj.y - this.countUp_Harf,
    self.maskImgWidth,
    self.maskImgHeight
  );

  //キャンバスの縦横サイズより、3倍マスク画像が大きくなった場合
  if( self.windowSizeW < this.maskImgWidth / 10 && self.windowSizeH < this.maskImgHeight / 10  ){
    //self.timeout_EXPの処理を停止し、マスクの拡大は停止します。
    window.clearInterval(self.timeout_EXP);
  }
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.