无法让精灵在圆形路径中移动

Can't get sprite to move in a circle path

本文关键字:路径 移动 精灵      更新时间:2023-09-26

我有一个叫做飞贼的精灵,我试图让它绕圈移动,中心在画布/2(画布被命名为空间)和半径30。我正在使用以下代码,但它似乎没有做任何事情,"告密者"只是站在那里对坐标 (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);

对于许多问题,所以我做了重写。已经经历了并解释了我做了什么以及我为什么这样做。

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

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

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

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

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

// 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

这应该会让飞贼四处走动。

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

 Math.sin()

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

 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

你在 Moves 函数上有一个告密者参数。当它被没有参数的间隔刻度调用时,它会作为未定义的对象妨碍。

如果要全局使用它,只需删除参数即可。

或者你可以这样做

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