身体动画不流畅

时间:2015-09-03 01:18:27

标签: javascript html5 animation canvas

以下代码中的“spaceShip”在按住任何箭头键的开头都没有顺利移动。它移动一步,冻结一瞬间,然后“平稳地”移动​​。如何从一开始就让它顺利移动,而不是“冻结”?

我的代码:

<!doctype html>
<html>
<head>
    <meta http-content="Content-type" charset="utf-8">
    <title>Make body move smoothly</title>
    <style type="text/css">
        body {
        }

        canvas {
            margin: auto;
            position: absolute;
            left: 0;
            top: 0;
            right: 0;
            bottom: 0;
            border: 1px solid black;
        }

    </style>
</head>
<body>
<canvas id="canvas" width="400" height="600"></canvas>
<script type="text/javascript">

// Set up requestAnimationFrame and cancelAnimationFrame
(function() {
    var lastTime =0;
    var vendors=['ms', 'moz', 'webkit', 'o'];
    for(var x=0; x<vendors.length && !window.requestAnimationFrame; ++x) {
        window.requestAnimationFrame=window[vendors[x]+'RequestAnimationFrame'];
        window.cancelAnimationFrame =
        window[vendors[x]+ 'CancelAnimationFrame'] ||
        window[vendors[x] +'CancelRequestAnimationFrame'];
    }
    if (!window.requestAnimationFrame)
    window.requestAnimationFrame=function(callback, element) {
        var currTime =new Date().getTime();
        var timeToCall =Math.max(0, 16 - (currTime - lastTime));
        var id =window.setTimeout(function() { callback(currTime+timeToCall); },
        timeToCall);
        lastTime =currTime + timeToCall;
        return id;
    };
    if (!window.cancelAnimationFrame)
    window.cancelAnimationFrame=function(id) {
        clearTimeout(id);
    };
}());


    var canvas;
    var ctx;
    // ship data
    var shipPositionX = document.getElementById('canvas').width/2;
    var shipPositionY = document.getElementById('canvas').height - 30;
    var deltaShipPositionX = 10;
    var deltaShipPositionY = 10;

    function init() {
        canvas = document.getElementById('canvas');
        ctx = canvas.getContext('2d');

        draw();
    }

    function draw(){
        clear();
        createRectangleToCoverCanvas();
        createSpaceShip(shipPositionX, shipPositionY, 10);

        requestAnimationFrame(draw);
    }

    function clear(){
        ctx.clearRect(0, 0, document.getElementById('canvas').width, document.getElementById('canvas').height);
    }

    function createRectangleToCoverCanvas(){
        ctx.fillStyle = 'black';
        ctx.strokeStyle = 'black';
        ctx.beginPath();
        ctx.rect(0, 0, canvas.width, canvas.height);
        ctx.closePath();
        ctx.fill();
        ctx.stroke();
    }

    function createSpaceShip(x, y, radius) {
        ctx.fillStyle = 'white'
        ctx.strokeStyle = 'white'
        ctx.beginPath();
        ctx.rect(x, y, 20, 20);
        ctx.closePath();
        ctx.fill();
        ctx.stroke();
    }

    function moveSpaceShip(event){
        switch(event.keyCode){
            // left
            case 37:
                if(shipPositionX - deltaShipPositionX + 15 > 0){
                    shipPositionX -= deltaShipPositionX;
                }
            break;

            // up
            case 38:
                if(shipPositionY - deltaShipPositionY + 15 > 0){
                    shipPositionY -= deltaShipPositionY;
                }
            break;

            // right
            case 39:
                if(shipPositionX + deltaShipPositionX < document.getElementById('canvas').width){
                    shipPositionX += deltaShipPositionX;
                }
            break;

            //down
            case 40:
                if(shipPositionY + deltaShipPositionY < document.getElementById('canvas').height){
                    shipPositionY += deltaShipPositionY;
                }
            break;
        }

    }

    window.addEventListener('load', init);
    window.addEventListener('keydown', moveSpaceShip, true);
</script>
</body>
</html>

请注意我的代码与此示例之间的区别:http://atomicrobotdesign.com/blog_media/sprite_sheet/spritesheet.html

看看这个例子是如何顺利的,但我的“太空船”不是? 为什么会发生这种情况?我该如何解决?是因为该示例使用精灵(但这似乎没有多大意义)?

1 个答案:

答案 0 :(得分:2)

问题是您等待每个keydown事件更新船位 keydown事件在再次触发之前会有一段延迟:您在开始时遇到的延迟以及每次重绘时遇到的跳跃。

此处的解决方案是触发keydown上的移动并在keyup上释放。这样,只要按下按钮,您的船就会顺利移动。

&#13;
&#13;
// Im' assuming most of visitors here have recent browsers, so I removed the rAF polyfill for readibility

// If you wrap it after the canvas element decalaration, you can already populate this variable, it will avoid that you make a lot of calls to document.getElementById()
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
// ship data
var shipPositionX = canvas.width / 2;
// Just for the snippet height
var shipPositionY = 0;
var deltaShipPositionX = 10;
var deltaShipPositionY = 10;

//Removed the init() function, since our elements are loaded.


function draw() {
  clear();
  createRectangleToCoverCanvas();
  createSpaceShip(shipPositionX, shipPositionY, 10);
}

function clear() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
}

function createRectangleToCoverCanvas() {
  ctx.fillStyle = 'black';
  ctx.strokeStyle = 'black';
  ctx.beginPath();
  ctx.rect(0, 0, canvas.width, canvas.height);
  ctx.fill();
  ctx.stroke();
}

function createSpaceShip(x, y, radius) {
  ctx.fillStyle = 'white'
  ctx.strokeStyle = 'white'
  ctx.beginPath();
  ctx.rect(x, y, 20, 20);
  ctx.fill();
  ctx.stroke();
}
// instantiate a variable that will store our animationFrame id, so we can cancel it further
var raf, 
// the direction object, with an x and y values
    direction = {
      x: 0,
      y: 0
    };
// we can set a speed variable
var speed = 2.5;
function triggerMoveSpaceShip(event) {
  switch (event.keyCode) {
    // left
    case 37:
      // update the direction object
      direction.x = -speed;
      // avoid the scroll in the snippet
      event.preventDefault();
      break;

      // up
    case 38:
      direction.y = -speed;
      event.preventDefault();
      break;

      // right
    case 39:
      direction.x = speed;
      event.preventDefault();
      break;

      //down
    case 40:
      direction.y = speed;
      event.preventDefault();
      break;
  }
  // if we haven't initiated the animation yet, and that our direction is not 0, then do it now
  if (!raf && (direction.x || direction.y)) moveSpaceShip();
}

function releaseMoveSpaceShip(event) {;
  switch (event.keyCode) {
    // left
    case 37:
      //reset this direction
      direction.x = 0;
      break;

      // up
    case 38:
      direction.y = 0;
      break;

      // right
    case 39:
      direction.x = 0;
      break;

      //down
    case 40:
      direction.y = 0;
      break;
  }
  if (!direction.x && !direction.y) {
    // if none of the directions is set, stop the animation
    cancelAnimationFrame(raf);
    raf = undefined;
  }
}

function moveSpaceShip() {
  // declare our animation function
  var move = function() {
    // update the positions without going out of the screen
    // Sorry, this is dirty...
    if(direction.x){
    	if(
	    	(shipPositionX > 0 && shipPositionX < canvas.width-20) ||
			(shipPositionX <= 0 && direction.x > 0) ||
			(shipPositionX >= canvas.width-20 && direction.x < 0))
				shipPositionX += direction.x;
		}
	if(direction.y){
    	if(
	    	(shipPositionY > 0 && shipPositionY < canvas.height-20) ||
			(shipPositionY <= 0 && direction.y > 0) ||
			(shipPositionY >= canvas.width-20 && direction.y < 0))
				shipPositionY += direction.y;
		}

    // finally draw ou ship
    draw();
    // update our raf id
    raf = requestAnimationFrame(move);
  };
  // let's go !
  raf = requestAnimationFrame(move);
}


draw();

window.addEventListener('keydown', triggerMoveSpaceShip, true);
window.addEventListener('keyup', releaseMoveSpaceShip, true);
&#13;
canvas {
  margin: auto;
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  border: 1px solid black;
}
body{
   overflow: none;
  }
&#13;
<canvas id="canvas" width="400" height="200"></canvas>
&#13;
&#13;
&#13;

uncommented fiddle