代码之家  ›  专栏  ›  技术社区  ›  HYUTS

每次单击requestFrameAnimation时,我都想启动一个新的动画

  •  0
  • HYUTS  · 技术社区  · 7 年前

    我有很多问题。

    1. 解决了@Jorge Fuentes Gonzlez
    2. 每次我点击 解决@kaido

    我改变了我能想到的一切,但仍然是同一个问题。任何帮助都将不胜感激。谢谢!

        function drawFrame(frameX, frameY, canvasX, canvasY) {
          ctx.drawImage(img,
                        frameX * width, frameY * height,
                        width, height,
                        x_click, y_click,
                        scaledWidth, scaledHeight);
        }
    
        // Number of frames in animation
        var cycleLoop = [3, 2, 1, 0, 7, 6, 5];
        // Position of sprite in sheet
        var currentLoopIndex = 0;
        var frameCount = 0;
    
        function step() {
    
          frameCount++;
          if (frameCount < 30) {
            window.requestAnimationFrame(step);
            return;
          }
          frameCount = 0;
          // ctx.clearRect(0, 0, canvas.width, canvas.height);
          drawFrame(cycleLoop[currentLoopIndex++], 0, 0, 0);
          // Starts animation over
          if (currentLoopIndex >= cycleLoop.length) {
            // If you want to loop back in oposite direction after full animation
            cycleLoop.reverse();
            // Reseting position of which sprite to use
            currentLoopIndex = 0;
          }
          window.requestAnimationFrame(step);
        }
    
        canvas.addEventListener("mousedown", getPosition, false);
        function getPosition(event) {
           x_click = event.x;
           y_click = event.y;
    
           x_click -= canvas.offsetLeft * 10;
           y_click -= canvas.offsetTop * 10;
           step();
        }
    

    JS小提琴:

    https://jsfiddle.net/HYUTS/q4fazt6L/9/

    =======================================

    3 回复  |  直到 7 年前
        1
  •  1
  •   Kaiido NickSlash    7 年前

    在您的情况下,第一步是为每个 可动画 ,以便可以独立绘制和更新它们。

    一个基本的设置是有一个主循环在后台持续运行,它将调用所有高级对象更新函数,然后调用所有绘图函数。

    正是在这些高级方法中,您将检查它们是否应该被实际丢弃。主循环不需要处理它。

    动画特征 物体。这些对象现在将拥有自己的状态,并且能够独立于其他对象根据自己的意愿进行更新。

    // Our Animatable class (ES5 style...)
    // Each object as its own frameCount and its own loopIndex
    function Animatable(x, y) {
      this.x = x;
      this.y = y;
      this.frameCount = 0;
      this.loopIndex = 0;
      this.cycleLoop = [3, 2, 1, 0, 7, 6, 5];
    }
    Animatable.prototype = {
      update: function() {
        this.frameCount++;
        if (this.frameCount < 30) {
          return;
        }
        this.frameCount = 0;
        this.loopIndex++
          if (this.loopIndex >= this.cycleLoop.length) {
            // If you want to loop back in oposite direction after full animation
            this.cycleLoop.reverse();
            // Reseting position of which sprite to use
            this.loopIndex = 0;
          }
      },
      draw: function() {
        // check the image is loaded
        if (!img.naturalWidth) return;
        var frameX = this.cycleLoop[this.loopIndex];
        ctx.drawImage(img,
          frameX * width, 0,
          width, height,
          this.x - scaledWidth/2, this.y - scaledHeight/2,
          scaledWidth, scaledHeight);
      }
    };
    
    // the main anim loop, independent
    function startAnimLoop() {
    
      animloop();
      
      function animloop() {
        requestAnimationFrame(animloop);
        // updates
        animatables.forEach(update);
        // drawings
        ctx.clearRect(0,0,canvas.width, canvas.height);
        animatables.forEach(draw);
      }
    
      function update(animatable) {
        animatable.update();
      }
    
      function draw(animatable) {
        animatable.draw();
      }
    }
    
    
    
    // one image for all
    var img = new Image();
    img.src = 'https://imgur.com/u2hjhwq.png';
    img.onload = startAnimLoop;
    
    // here we will hold all our objects
    var animatables = [new Animatable(50, 50)]; // start with a single one
    
    var canvas = document.querySelector('canvas');
    var ctx = canvas.getContext('2d');
    
    // some constant from OP's fiddle
    var scale = 1.5;
    var width = 100; // Bigger numbers push left <-, smaller right ->
    var height = 100;
    var scaledWidth = scale * width;
    var scaledHeight = scale * height;
    
    
    canvas.onclick = function(evt) {
      var rect = canvas.getBoundingClientRect();
      var x = evt.clientX - rect.left;
      var y = evt.clientY - rect.top;
      // we simply create a new object ;-)
      animatables.push(new Animatable(x, y));
    };
    canvas{border:1px solid}
    <canvas id="canvas" width="500" height="500"></canvas>
        2
  •  2
  •   Jorge Fuentes González    7 年前

    每次你点击,你都会打电话 step(); ,它将调用 window.requestAnimationFrame(step); ,它将调用 step() 下一个动画帧。我看不到任何停止点,所以循环将被永远调用。

    步骤() 步骤() 将永远被召唤,如果你再次点击,另一个 “line”将被再次调用,它将调用 window.requestAnimationFrame(步骤); 永远,所以现在你将有两条“线”打电话 步骤() 步骤()

    你要做的是检查动画是否已经在运行(带有标志),不要再运行它,或者 window.cancelAnimationFrame(ID) 步骤() 再次循环。注意,每次单击都必须重新启动控制动画的变量,如 frameCount currentLoopIndex

    function drawFrame(frameX, frameY, canvasX, canvasY) {
      ctx.drawImage(img,
                    frameX * width, frameY * height,
                    width, height,
                    x_click, y_click,
                    scaledWidth, scaledHeight);
    }
    
    // Number of frames in animation
    var cycleLoop = [3, 2, 1, 0, 7, 6, 5];
    // Position of sprite in sheet
    var currentLoopIndex = 0;
    var frameCount = 0;
    
    var animationid = null;
    function step() {
    
      frameCount++;
      if (frameCount < 30) {
        animationid = window.requestAnimationFrame(step);
        return;
      }
      frameCount = 0;
      // ctx.clearRect(0, 0, canvas.width, canvas.height);
      drawFrame(cycleLoop[currentLoopIndex++], 0, 0, 0);
      // Starts animation over
      if (currentLoopIndex >= cycleLoop.length) {
        // If you want to loop back in oposite direction after full animation
        cycleLoop.reverse();
        // Reseting position of which sprite to use
        currentLoopIndex = 0;
      }
      animationid = window.requestAnimationFrame(step);
    }
    
    canvas.addEventListener("mousedown", getPosition, false);
    function getPosition(event) {
       x_click = event.x;
       y_click = event.y;
    
       x_click -= canvas.offsetLeft * 10;
       y_click -= canvas.offsetTop * 10;
       frameCount = currentLoopIndex = 0;
       window.cancelAnimationFrame(animationid);
       step();
    }
    
        3
  •  1
  •   WhiteMaple    7 年前

    https://developer.mozilla.org/en-US/docs/Web/API/Window/cancelAnimationFrame

    这样地:

    ...
    var animationID;
    
    //in step() save the id in every call
    function step() {
        ...
        animationID = window.requestAnimationFrame(step);
        ...
    }
    
    //In getPosition cancel the current animation
    function.getPosition(event) {
        ...
        window.cancelAnimationFrame(animationId);
        ...
    }
    

    window.requestAnimationFrame(this.step) 步骤内()。您还必须保存动画所需的每个变量,如 currentLoopIndex 作为物体的一部分。