Javascript很慢的玩家运动

时间:2015-09-15 14:33:04

标签: javascript canvas

更新 将其更改为以下内容并注意到速度提升。现在的问题是玩家只需在没有动画帧的情况下滑动。

    var animator, frames;
    animator = window.setInterval(function(){
    if(currentFrame == totalFrames){
        clearInterval(animator);
        currentFrame = 0;
        update();
        isMoving = 0;
        return;
    }
    xPosition += x;
    yPosition += y;
    frames = window.requestAnimationFrame(animator);
    currentFrame++;
    update();   

},frames);

我目前面临的一些问题是:地图边缘代码部分完全被破坏了。我只是试图让玩家无法超越canvas.width / canvas.height。此外,我的球员运动非常缓慢且反应迟钝。我认为这是因为我添加了isMoving检查。我希望能够更顺畅地移动。现在这个角色需要很长时间才能移动,我觉得我好像在滞后。此外,由于某种原因,有时它会移动不止一次。它发生时完全随机。任何帮助将不胜感激

var playerSprite = new Image();
playerSprite.src = "male.png";

var playerWidth = 64;
var playerHeight = 64;
var currentFrame = 0;
var totalFrames = 8;

var moveDistance = 4; // move 4 pixels
var xPosition = 300;
var yPosition = 200;
var direction = 2; // south, options: 0 - 3

var isMoving = 0;

var canvas, context;
window.addEventListener("load", function(){
    canvas = document.getElementById('map');
    context = canvas.getContext('2d');
 })


function draw(){
    context.drawImage(playerSprite,currentFrame * playerWidth, direction*  playerHeight ,playerWidth,playerHeight,xPosition,yPosition,playerWidth,playerHeight);
}

function update()
{
    clearMap();
    draw();
}

function move(x, y){

    if(isMoving)return;
    isMoving = 1;

    if(x > 0) direction = 3;
    else if(x < 0) direction = 1;
    if(y > 0) direction = 2;
    else if(y < 0) direction = 0;

    //update direction no matter what, implemented 
    // in order for directions to update
    // when changing directions in map edges
    //update();

/*      Broken

    if(xPosition + playerWidth + x > canvas.width)return; //works
    else if(xPosition - x < 0)return; // player gets stuck

    if(yPosition + playerHeight + y > canvas.height)return; //works
    else if(yPosition - y < 0)return; // player gets stuck

    //xPosition += x;
    //yPosition += y;
*/
    //actual animation update
    var animator;
    animator = window.setInterval(function(){
        if(currentFrame == totalFrames){
            clearInterval(animator);
            currentFrame = 0;
            update();
            isMoving = 0;
            return;
        }
        xPosition += x;
        yPosition += y;
        currentFrame++;
        update();

    },1000/16);
}
function clearMap(){
    context.clearRect(0, 0, canvas.width, canvas.height);
}

function keyPress(e)
{

    if(currentFrame == totalFrames){
        currentFrame = 0;
    }

    switch(e.keyCode){
        case 38: move(0, -moveDistance); break;
        case 40: move(0, +moveDistance); break;
        case 39: move(+moveDistance, 0); break;
        case 37: move(-moveDistance, 0); break;
    }

}

window.addEventListener("load", update, false);
window.addEventListener("keydown",keyPress);

2 个答案:

答案 0 :(得分:3)

我改变了要点:

  • 在任何地方都不使用setInterval。相反,我们让浏览器以可以使用requestAnimationFrame
  • 处理的速率处理FPS
  • 一个中心游戏循环update())。在此之前,您每次按一个键时都会进行一系列计算并启动新的背景循环。那很糟糕。如果有人要混合箭头键,浏览器必须在后台处理100 + setInterval个。
  • 我们不是在关键事件中进行任何计算,而是使用变量来跟踪按下哪些按钮。然后在每个帧发生的游戏循环中,如果按住箭头键,我们可以将玩家移动几个像素。

练习:

  • 动画非常快,因为玩家框架在每个游戏框架都是先进的。放慢速度!
  • 如果更快的计算机以60fps运行,则播放器将每秒移动60 * 4 = 240像素。如果较慢的计算机以20fps运行,则播放器每秒仅移动20 * 4 = 80像素。这实际上是一个巨大的差异。无论平台如何,为了让您的游戏始终如一地运行,您应该根据游戏的运行速度或多或少地移动玩家。 Here's a good article让您入门。此外,requestAnimationFrame文档也会有所帮助。

以下是代码:

var playerSprite = new Image();
playerSprite.src = "male.png";

var playerWidth = 64;
var playerHeight = 64;
var currentFrame = 0;
var totalFrames = 8;

var direction = 2; // south, options: 0 - 3
var moveDistance = 4; // move 4 pixels
var xPosition = 300;
var yPosition = 200;

var left = 0,
    right = 0,
    up = 0,
    down = 0;

var canvas, context;

window.addEventListener("keydown", keyPress);
window.addEventListener("keyup", keyRelease);
window.addEventListener("load", function(){
    canvas = document.getElementById('map');
    context = canvas.getContext('2d');

    // tells the browser to call update() as soon as it's ready
    // this prevents lockups, and also the browser regulates the FPS
    window.requestAnimationFrame(update);
});

function update() {
    // EVERYTHING game related happens in update (except listening for key events).
    // This keeps everything organized, and prevents any lag/slowdown issues

    // handles player movement and animation
    movePlayer();

    // handles all drawing
    draw();

    // lets the browser know we're ready to draw the next frame
    window.requestAnimationFrame(update);
}

function movePlayer() {
    if(left) {
        xPosition -= moveDistance;
        direction = 1;
    }
    if(right) {
        xPosition += moveDistance;
        direction = 3;
    }
    if(up) {
        yPosition -= moveDistance;
        direction = 0;
    }
    if(down) {
        yPosition += moveDistance;
        direction = 2;
    }

    // all this code happens every frame
    // in english: if we're moving, advance to the next frame
    if(left || right || up || down) {
        currentFrame ++;
        if(currentFrame == totalFrames) currentFrame = 0;
    }
}

function draw() {
    // clear the map
    context.clearRect(0, 0, canvas.width, canvas.height);

    // draw the next frame
    context.drawImage(playerSprite, currentFrame * playerWidth, direction * playerHeight,
                                    playerWidth, playerHeight,
                                    xPosition, yPosition,
                                    playerWidth, playerHeight);
}

// keyPress and keyRelease ensure that the variables are
//  equal to 1 if pressed and 0 otherwise.
function keyPress(e)
{
    switch(e.keyCode){
        case 38: up = 1; break;
        case 40: down = 1; break;
        case 39: right = 1; break;
        case 37: left = 1; break;
    }
}

function keyRelease(e)
{
    switch(e.keyCode){
        case 38: up = 0; break;
        case 40: down = 0; break;
        case 39: right = 0; break;
        case 37: left = 0; break;
    }
}

答案 1 :(得分:0)

编辑:忘记提及我选择在我的播放器移动中包含delta而不是我的更新()重绘以防止整个游戏以20 fps运行。

忘记发布我修订过的功能齐全的代码。谢谢@Entity帮我解决了&lt; 3。正如你所看到的,我已经开始采取更多的自由和实验。

var fps = 20, fpsInterval = 1000/fps, now, then = Date.now(), delta;
var moving = {38:0, 40:0, 39:0, 37:0} // north, south, east, west

function move(direction, toggle){moving[direction] = toggle}
function keyDown(e){move(e.keyCode,1)}
function keyUp(e){move(e.keyCode,0)}

function playerMovement(){
    now = Date.now();
    delta = now - then;
    if(delta > fpsInterval){
        then = now - (delta % fpsInterval);
        // north = 38, south = 40, east = 39, west = 37
        // stop movement stall from opposite directions
        if(moving[38] && moving[40]){move(40,0)}
        if(moving[39] && moving[37]){move(37,0)}
        // flip order to change diagonal rendering mode
        if(moving[38]) {direction = 0; yPosition -= moveDistance};
        if(moving[40]) {direction = 2; yPosition += moveDistance};  
        if(moving[39]) {direction = 3; xPosition += moveDistance};
        if(moving[37]) {direction = 1; xPosition -= moveDistance};  

        if(moving[38] || moving[40] || moving[39] || moving[37]) currentFrame++;
        if(currentFrame == totalFrames) currentFrame = 0;
    }

}