无法精灵在圆圈路径中移动

时间:2016-01-17 01:29:59

标签: javascript animation canvas path geometry

我有这个名为snitch的精灵,我试图让它在一个圆圈中移动,画布中心/ 2(画布命名为空格)和半径30.我使用以下内容代码,但它似乎没有做任何事情," snitch"只是站在那里坐标(0,0)上什么都不做。我尝试从MySprite2函数中删除这些(0,0)坐标,但是当我这样做时,它甚至不会出现。

var ctx = space.getContext("2d"); 
var FPS = 40;
var snitch= new MySprite2("http://i.imgur.com/IgNKTbW.png");

function MySprite2 (img_url) {
  var x = this.x = 0;
  var y = this.y = 0; 
  this.visible= true;
  var img = this.MyImg2 = new Image();
  this.MyImg2.src = img_url;
}

MySprite2.prototype.Do_Frame_Things = function() {
  if (this.visible) ctx.drawImage(this.MyImg2, this.x, this.y);
}; 

function Do_a_Frame () {
  ctx.clearRect(0, 0, space.width, space.height);
  snitch.Do_Frame_Things();
}

function theMoves(snitch){
  var theta = 0;
  for (theta = 0; theta < 2 * Math.PI; theta+=0.1) { 
     snitch.x = (space.width/2) + Math.sin(theta)*30;
     snitch.y = (space.height/2) + Math.cos(theta)*30;
  }
}
setInterval(theMoves, 1000/FPS);
setInterval(Do_a_Frame, 1000/FPS);

知道出了什么问题吗? 确定它正在移动但现在它只是以直线而不是圆形运行。下面的新代码。

function MySprite (img_url) {
  var x = this.x = (space_x/2);
  var y = this.y = (space_y/2);
  var angle = this.angle = 0;
  this.visible= true;
  var img = this.MyImg = new Image();
  this.MyImg.src = img_url;
}

MySprite.prototype.Do_Frame_Things = function() {
  if (this.visible) ctx.drawImage(this.MyImg, this.x, this.y);
};  

function theMoves(){
  snitch.x += Math.cos(snitch.angle)*2;
  snitch.y += Math.sin(snitch.angle)*2;
}
setInterval(theMoves, 40);

3 个答案:

答案 0 :(得分:1)

很多问题所以我做了重写。已经完成并解释了我做了什么以及为什么要这样做。

第一行所有好但不需要FPS,因为这将由浏览器来决定。对于游戏,除非您拥有专用硬件和确定性操作系统,否则您永远无法保证任何帧速率。只有专用游戏机提供此功能。

var ctx = space.getContext("2d"); 

使用newprototypes对游戏设计不利,因为它们会产生大量不需要的额外开销。事实上,完全避免使用这种类型的构造函数通常是一个好主意。

使用生成器功能,不要直接触摸原型

首先在生成器BTW之前声明你的方法在变量开头的Javascript大写字母为类类型对象保留,但这不再是个人风格选择

// draw the sprite is visible
var doFrameThings = function() {
    if (this.visible) { // though you don't have to put the curly braces here
                        // you should make it a habit  to always use them
        ctx.drawImage(this.myImg , this.x, this.y);
    }
}; 

创建一个更新精灵的函数,如果帧速率下降,则使用最后一帧时间来确保速度一致

var updateSprite = function(frameTime){
    this.theta += this.deltaTheta * frameTime;
    this.x = (space.width/2) + Math.sin(this.theta)*30;
    this.y = (space.height/2) + Math.cos(this.theta)*30;
}

创建一个精灵。这种方法几乎与原型方法没有区别,但它提供了更好的性能

function createSprite(imgURL){
    var sprite = {  // create the sprite
        x:0,
        y:0,
        theta: 0,
        deltaTheta: Math.PI/40,
        visible:false,           // not visible until it has loaded.
        draw : doFrameThings,    // add the draw function
        update : updateSprite,   // add the update function
        myImg : (function(){     // call a annon function that creates the 
                                 // image returning it to myImg
            var image = new Image();
            image.src = imgUrl;
            image.onload = function(){  // flag it as visible only when it has loaded.
                sprite.visible = true;
            };
            return image;
        })()
    };
    return sprite; // return the created sprite
                   // this is exactly the same as new does except new returns
                   // this instead of the named object.
}        

创建一个精灵。现在您不必调用使用New和使用原型系统的所有开销。

var snitch = createSprite("http://i.imgur.com/IgNKTbW.png");

使用setInterval是一种非常糟糕的动画制作方法。首先,你有两个setInterval他们会不同步,并且无法保证它们会在请求的时间间隔内发生。它们也不与显示硬件同步,因此您将受到剪切。另外,因为它们未与浏览器的渲染系统同步,您可能会出现闪烁或更糟的情况。

如果您的渲染时间大于间隔时间,最终会导致您的应用崩溃,并且没有简单的方法可以知道是否发生了这种情况

所以永远不要使用setInterval。个人永远不要使用setInterval任何危险的方法,应该从Javascript中删除。

使用requestAnimationFrame获得稳定的60 fps并同步到显示硬件和浏览器的渲染系统。因为它与显示器同步,所以帧之间的时间将以1/60秒为单位。如果你错过第一帧,你将不得不等待下一次刷新,这将是1/60秒。

创建一个主循环/更新函数,并从同一个函数调用所有动画。

var lastTime = new Date().valueOf();  // for tracking the frame time
function update(time){  // requestAnimationFrame provides the current time
    var frameTime = time-lastTime;
    // clear the canvas
    ctx.clearRect(0, 0, space.width, space.height);

    snitch.update(frameTime); // update sprite
    snitch.draw(); // draw the sprite


    requestAnimationFrame(update); // request the next animation frame
    lastTime = time;  // save the time this frame was called 
}

requestAnimationFrame(update); // start the animation

这应该让这个小报很好地运转。

答案 1 :(得分:0)

我看到的第一个错误是你的sin函数将返回undefined,因为你需要使用以下语法调用它:

 Math.sin()

第二个错误是你的snitch变量未定义。以下代码行引发错误。

 snitch.x = (space.width/2) + Math.sin(theta)*30;

您的第三个错误是:

snitch.y = (space.height/2) + cos(theta)*30;

我创建了一种更模块化的方法来帮助您完成圆形动画。

现场演示:http://codepen.io/larryjoelane/pen/obGPwY

HTML:

     <canvas width ="500" height="500" id="canvasOne"></canvas>

JavaScript的:

 var canvas = new Canvas("canvasOne");

 var thisCanvas = canvas.instance("canvasOne");

 var imageURL = "http://bytewarestudios.com/assets/images/sphere.png";

 var image = canvas.createImage(imageURL);

 var context = canvas.context2D("canvasOne");

 /* Formula to determine x and y points on the circumference of a    
  * circle
  * cx and cy = (origin or center of the circle)
  * r = radius of the circle
  * a = angle in radians(360deg = 6.285714285714285714285714285714 radian) or 2 * PI
  *  Formulas examples below for x and y points
  *   var x = cx + r * Math.cos(a);
  *   var y = cy + r * Math.sin(a);
  */

 //initialize the degree variable
 var deg = 0;

 //frames per second
 var fps = 45;

 window.requestAnimationFrame(drawCircle); // start the animation

 function drawCircle() { //begin function

   setTimeout(function() {

     //increment the degrees
     deg = deg + 1;

     //used to offset the circle radius to bring the circle in from the border of 
     //the canvas
     var offset = 120;

     //radius of the circle
     var r = ((thisCanvas.width - offset) / 2);

     //x coordinate of the circle origin
     var cx = ((thisCanvas.width) / 2);

     //y coordinate of the circle origin
     var cy = ((thisCanvas.height) / 2);

     //store the angle in radians
     var a = canvas.toRadians(deg);

     var x = cx + r * Math.cos(a);
     var y = cy + r * Math.sin(a);

     //clear the canvas  
     context.clearRect(0, 0, thisCanvas.width, thisCanvas.height);

     //draw the first image
     context.drawImage(image, x, y);

     //start the animation
     window.requestAnimationFrame(drawCircle);

   }, 1000 / fps);

 } //end function

 function Canvas() { //begin canvas constructor    

   Canvas.prototype.createImage = function(imageURL) {

     //create a new image
     var image = new Image();

     //set the image source
     image.src = imageURL;

     //return the image object
     return image;

   };

   Canvas.prototype.context2D = function(id) {

     var canvas = document.getElementById(id);

     var context = canvas.getContext("2d");

     return context;

   };

   Canvas.prototype.instance = function(id) {

     var canvas = document.getElementById(id);

     return canvas;

   };

   Canvas.prototype.toRadians = function(angle) {

     return angle * (Math.PI / 180);

   };

 } //end canvas constructor

答案 2 :(得分:0)

你有一个关于动作功能的snitch参数。当它被没有参数的间隔tick调用时,它会作为未定义的对象受到阻碍。

如果您想全局使用它,只需删除参数。

或者你可以这样做

setInterval(function(){theMoves(snitch)}, 1000/FPS);