3000ms で、800pixcel を水平移動する。その4

昨日のプログラムを見て、整理しようと思った。
「余りを次の処理に繰り越す」という考えを、apos さんの説明は、理解しやすくするために、余りを整数で例えている。


実際に自分のプログラムは変数 err に少数部分を誤差として代入している。もしゲームならスピード優先。整数で考えるべきだ。


その考えの前に、「遅延が発生した場合、補正が必要だ」ということは理解した。本来、移動するプログラムが個々に遅延を考慮するべきなのだろうか?そこで強引ではあるが、遅延を補間するようなコードの下で走らせてはどうか?と考えた。
遅延がある程度解消されるまでコールバック関数を数回呼び出す。

そしてインターバルのタイミングを1ドット移動するための時間とする。
さすれば加算値は整数になる。

<!DOCTYPE html>
<title>遅延時間を考えて移動する</title>
<meta charset="UTF-8">
<style>
#invader {
  list-style : none;
  position: absolute;
  margin : 0;
  padding: 0;
  top : 0px;
  left: 3px;
}

#invader li {
  margin : 0;
  padding : 0;
  display : none;
}


</style>


<ol id ="invader">
  <li class="type1 v">
    <img id ="inv3"
         alt="インベーダ"
         src="data:image/gif;base64,
              R0lGODlhMAAYAIAAAP8ntf///yH5BAEAAAEALAAAAAAwABgAAAJijI95wO2sopzqWUCzXtft
              34Vi8yHjeZUcymJgC3tZTLtUHWth9fDp3PGREjvgz9QjBo04lK7JekJPKkMReaxiLcKkdutd
              cb+BMdgmhlTNabQ1/JKdu24VW3L/5unkOVNNUQAAOw==">
  <li class="type2">
    <img id="inv3o"
         alt="インベーダ"
         src="data:image/gif;base64,
              R0lGODlhMAAYAIAAAP8ntf///yH5BAEAAAEALAAAAAAwABgAAAJmjI95wO2sopzqWUCzXtft
              34Vi8yHjeZUcymJgC3tZTLtUHWth9fDp3PGREjvgz9QjBo04lK7JekJPKqUMea3ektihdps1
              WL6SMRNCXnkn5nSgzeaW4NZ1HQ22d/FCfll+Z9MnaFAAADs=">
</ol>

<canvas id="hoge" width="800" height="200"></canvas>
<p>時間:<input type="text" value="0" id="fuga"></p>


<script>

var changePattern =
  (function () {
    
    var pattern = document.querySelectorAll ('#invader > li');
    var state = 0;
    var max = 2;
    
    Array.prototype.forEach.call (
      pattern,
      function (e) {
        e.style.display = 'none';
      }
    );
    
    function change () {
      pattern[state].style.display = 'none';
      state = (state + 1) % max;
      pattern[state].style.display = 'inline';
    }
    
    change ();
    
    return change;

  }) ();

setInterval (changePattern, 200);

//_______________

(function () {

  function IntervalCompletion (cbFunc, interval, maxCompletion) {
    this.cbFunc    = cbFunc;
    this.interval  = interval;
    this.maxCompletion = maxCompletion;

    this.startTime = null;
    this.count     = null;
  }
  
  
  var loop =
    (function () {

      var now = (new Date).getTime ();
      var delay = (now - this.startTime) - this.interval * this.count;
      var completion = 0;
      var result;
      
      if (0 < delay) {
        completion = Math.floor (delay / this.interval);
        if (this.maxCompletion < completion) {
          completion = this.maxCompletion;
        }
      }

      do {
        result = this.cbFunc ((new Date).getTime ());
        this.count++;
        if (! result)
          break;

      } while (completion--);
      
      if (result)
        setTimeout (loop.bind (this), this.interval);
    });
  
  
  IntervalCompletion.prototype.start =
    (function () {
      this.startTime = (new Date).getTime ();
      this.count = 0;
      loop.call (this);
    });


  IntervalCompletion.create =
    (function (cbFunc, interval) {
      if (1 > arguments.length)
        throw new Error;
      return new IntervalCompletion (cbFunc, interval);
    });
  
  this.IntervalCompletion = IntervalCompletion;
}) ();

//_______________

var moveInvader =
  (function (time, distance) {

    var style = document.querySelector ('#invader').style;
    var x = 0;
    var y = 30;
    var step = 1;
    
    var t = +new Date;//debug

    function move () {
      x += step;
      
      if (distance < x)
        return false;
      
      document.getElementById('fuga').value=+(new Date)-t;//debug

      setPosition ();
      return true;
    }
    
    function setPosition () {
      style.left = x + 'px';
      style.top = y + 'px';
    }
    
    return move;

  }) (3000, 800);


var obj = new IntervalCompletion (moveInvader, 3000/800, 4);
obj.start();

</script>