【问题标题】:Restarting a canvas animation using OOP method使用 OOP 方法重新启动画布动画
【发布时间】:2016-11-01 17:08:08
【问题描述】:

我正在创建一个网页,您在键盘上按下的每个键都会生成一个新的声音/动画。我现在只在我的第一个键上,但我遇到了一个问题,在按下第一个键后,动画就卡住了。而不是重新开始动画或根据按下的键开始新的动画,矩形(在这种情况下)将开始闪烁。下面是我的一些代码。

class Drawable{
constructor(context, x = 0, y = 0, fillStyle = "#000", strokeStyle = "transparent", lineWidth = 0){
this.context = context;
if(!(this.context instanceof CanvasRenderingContext2D)){
  throw new Error("You must provide a valid canvas context to Drawables.");
}
this.x = x;
this.y = y;
this.fillStyle = fillStyle;
this.strokeStyle = strokeStyle;
this.lineWidth = lineWidth;
this.deltas = new Map();

this.limits = {
    max: new Map(),
    min: new Map()
};
}
draw(){
   this.context.save();
   this.context.translate(this.x, this.y);
   this.context.scale(2,1.5);
   this.context.fillStyle = this.fillStyle;
   this.context.strokeStyle = this.strokeStyle;
   this.context.lineWidth = this.lineWidth;
}
afterDraw(){
   this.context.restore();
}
 applyAnimation(secondsElapsed){
  for(const[propertyName, valueChangePerSecond] of this.deltas){
      const changedAmount = secondsElapsed * valueChangePerSecond;
      this[propertyName] += changedAmount;
      if(this.limits.max.has(propertyName)){
          this[propertyName] =     Math.min(this[propertyName],this.limits.max.get(propertyName));
      } else if(this.limits.min.has(propertyName)){
          this[propertyName] = Math.max(this[propertyName],this.limits.min.get(propertyName));
      }
   }  
   }
 }
  class Rectangle extends Drawable{  
constructor(context, x = 0, y = 0, fillStyle = "#000", strokeStyle = "transparent", lineWidth = 0, deltas = new Map(), width = 100, height = 100){
super(context, x, y, fillStyle, strokeStyle, lineWidth, deltas);
this.width = width;
this.height = height;
}

draw(){
super.draw();
this.context.fillRect( this.width / -2, this.height / -2, this.width, this.height);
this.context.strokeRect( this.width / -2, this.height / -2, this.width, this.height);
super.afterDraw();
}
loopDraw(){
    super.draw();
    let rectSize = 30;
    for(let i = 0; i < 3; i++){
        let yPos = (rectSize - 10)*i;
        for(let j = 0; j < 6; j++){
              this.context.fillRect((rectSize+10)*j,yPos,this.width/-2,this.height/-2);
            this.context.strokeRect(this.width / -2, this.height / -2, this.width, this.height);
        }
    }
    super.afterDraw();
}
}
const canvas = document.getElementById("soundBoardCanvas");
const context = canvas.getContext("2d");
  const animationAObjects = new Set();
 // Creating the rectangle and setting the animation properties of the rectangle
let animationARect = new Rectangle(context,canvas.width/1.5,canvas.height/2, randomColour(), "transparent", 0, new Map() ,50,50);

animationARect.deltas.set("y",100);
animationARect.deltas.set("height",50);
animationARect.deltas.set("width",50);
animationARect.deltas.set("x",100);
animationARect.limits.max.set("y", canvas.height/2);
animationARect.limits.max.set("x", canvas.width/2.5);
animationARect.limits.max.set("height",randomBetween(100,170));
animationARect.limits.max.set("width",randomBetween(100,170));

animationAObjects.add(animationARect);


function randomBetween(min,max){
let range = max - min;

let random = Math.random();
random = random * (range + 1);
random = random + min;

return random;
}

// Animates all of the objects in the selected set
function animationA(){
    requestAnimationFrame(animationA);
    context.clearRect(0,0,canvas.width,canvas.height);

    const diffSeconds = (Date.now() - lastTime) / 1000;
    lastTime = Date.now();

    if(diffSeconds > 0){
        for(const animationAObject of animationAObjects){
            animationAObject.applyAnimation(diffSeconds);
            animationAObject.draw();
        }
    }
}
document.addEventListener("keydown", (e) => {
e.preventDefault();
cancelAnimationFrame(requestId);
if(e.keyCode == 65){
    window.requestAnimationFrame(animationA);
}
});

【问题讨论】:

  • 缺少代码。从您所提供的内容来看,您描述的问题没有任何理由。顺便说一句,requestAnimationFrame 作为第一个参数传递给回调一个高分辨率时间 1/1,000,000 秒,以毫秒(1/1000 秒)为单位,最小值 0.001 毫秒。 function animationA(time){
  • @Blindman67 我现在已将所有代码添加到上面的编辑中。希望这应该更好地解释它。您能否详细说明您对 requestAnimationFrame 的评论,我不太关注您。
  • 当浏览器调用你传递给requestAnimationFrame的“回调”函数时,传递给回调的第一个参数是时间。例如function callback(time){ // time argument passed by RAFrequestAnimationFrame(callback); // set the RAF callback function

标签: javascript oop animation canvas ecmascript-6


【解决方案1】:

您永远不会创建requestId(甚至在任何地方声明它),因此应该会引发错误(至少在严格模式下)。然后你只是在每次按下 a 时创建一个新动画,这可能会相互干扰并导致闪烁(尽管我无法确切说明原因)。

let requestId = 0; // declare this!
let lastTime = Date.now(); // important initialisation

function animationA(){
    requestId = requestAnimationFrame(animationA);
//  ^^^^^^^^
    …
}
document.addEventListener("keydown", (e) => {
    e.preventDefault();
    cancelAnimationFrame(requestId);
    if (e.keyCode == 65) {
        requestId = window.requestAnimationFrame(animationA);
//      ^^^^^^^^^
    }
});

【讨论】:

  • 我刚刚对我的代码进行了这些更改,但仍然没有任何区别。当我重复按键时,形状不会重绘,动画也不会重复。相反,形状只是静止不动。
  • @seanrs97 你有什么错误吗?你调试过动画吗? animationA 是否定期调用? applyAnimation 做你想做的事吗?为什么loopDraw 从来没有在任何地方被调用过?添加一些日志以查看您的对象发生了什么,而不仅仅是画布上发生了什么。
  • 我检查了错误,根本没有。 LoopDraw 是一个单独的绘制方法,目前还不需要。它不会影响代码。据我所知,应用动画正在做我想做的事情。我会放一些 console.logs 看看这是否有帮助。
猜你喜欢
  • 2016-08-20
  • 1970-01-01
  • 2017-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多