【问题标题】:How to move image on canvas using arrow keys in javascript如何使用javascript中的箭头键在画布上移动图像
【发布时间】:2016-04-19 08:23:28
【问题描述】:

我尝试了几种不同的方式,我在这里看到过,但我无法让我的图像移动。每当我尝试为箭头按键调整代码时,它似乎只是让我的画布缩小并且我的玩家模型(太空人)消失了。

这是我不断返回的“绘图板”,以及我目前所拥有的。

// Get the canvas and context
var canvas = document.getElementById("space"); 
var ctx = canvas.getContext("2d");
canvas.width = 1920;
canvas.height = 700;


// Create the image object
var spaceperson = new Image();

// Add onload event handler
spaceperson.onload = function () {
   // Done loading, now we can use the image
   ctx.drawImage(spaceperson, 280, 300);
};


// artwork by Harrison Marley (using make8bitart.com)
spaceperson.src = "http://i.imgur.com/Eh9Dpq2.png";`

我对 javascript 很陌生,我只是想弄清楚如何使用箭头键移动 specperson 图像。我试图为太空人创建一个类来访问他们的 x,y 值,但如果不使用.onload

,我似乎无法绘制图像

【问题讨论】:

  • 我做了一个jsbin,它应该适合你!

标签: javascript html image canvas keypress


【解决方案1】:

这里有一个更完整的例子:

//just a utility
function image(url, callback){
    var img = new Image();
    if(typeof callback === "function"){
        img.onload = function(){
            //just to ensure that the callback is executed async
            setTimeout(function(){ callback(img, url) }, 0)
        }
    }
    img.src = url;
    return img;
}

//a utility to keep a value constrained between a min and a max
function clamp(v, min, max){
    return v > min? v < max? v: max: min;
}

//returns a function that can be called with a keyCode or one of the known aliases 
//and returns true||false wether the button is down
var isKeyDown = (function(aliases){
    for(var i=256, keyDown=Array(i); i--; )keyDown[i]=false;
    var handler = function(e){ 
        keyDown[e.keyCode] = e.type === "keydown";
        e.preventDefault();  //scrolling; if you have to suppress it
    };

    addEventListener("keydown", handler, false);
    addEventListener("keyup", handler, false);

    return function(key){
        return(true === keyDown[ key in aliases? aliases[ key ]: key ])
    }
})({
    //some aliases, to be extended
    up: 38,
    down: 40,
    left: 37,
    right: 39
});



// Get the canvas and context
var canvas = document.getElementById("space"); 
canvas.width = 1920;
canvas.height = 700;
var ctx = canvas.getContext("2d");

//the acutal image is just a little-part of what defines your figue
var spaceperson = {
    image: image("//i.imgur.com/Eh9Dpq2.png", function(img){ 
        spaceperson.width = img.naturalWidth;
        spaceperson.height = img.naturalHeight;

        //start the rendering by calling update
        update();
    }),

    //position
    x: 60, y: 310,
    width: 0, height: 0,

    speed: 200  // 200px/s
};

var lastCall = 0;  //to calculate the (real) time between two update-calls
//the render-fucntion
function update(){
    //taking account for (sometimes changing) framerates
    var now = Date.now(), time = lastCall|0 && (now-lastCall)/1000;
    lastCall = now;
    requestAnimationFrame(update);

    var sp = spaceperson,
        speed = sp.speed;

    //checking the pressed buttons and calculates the direction
    //two opposite buttons cancel out each other, like left and right
    var dx = (isKeyDown('right') - isKeyDown('left')) * time, 
        dy = (isKeyDown('down') - isKeyDown('up')) * time;

    //fix the speed for diagonals
    if(dx && dy) speed *= 0.7071067811865475;   // * 1 / Math.sqrt(2)

    if(dx) { //there is some movement on the x-axes
        sp.x = clamp(
            //calculate the new x-Position
            //currentPos + direction * speed
            sp.x + dx * sp.speed, 

            //restraining the result to the bounds of the map
            0, canvas.width - sp.width
        );
    }

    //same for y
    if(dy) sp.y = clamp(sp.y + dy * sp.speed, 0, canvas.height - sp.height);

    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.drawImage(sp.image, sp.x, sp.y);
}

编辑:

一个简单的问题(我希望);如果我以后要添加其他对象,我会在 update() 中检查冲突吗?

这仍然只是一个非常基本的示例。 update()-function 的主要目的应该是作为主事件循环。 触发所有必须按照必须发生的顺序在每一帧发生的事件。

var lastCall = 0;
function update(){
    //I always want a next frame
    requestAnimationFrame(update);

    //handle timing
    var now = Date.now(), 
        //time since the last call in seconds
        //cause usually it's easier for us to think in 
        //tems like 50px/s than 0.05px/ms or 0.8333px/frame
        time = lastCall|0 && (now-lastCall) / 1000;

    lastCall = now;

    movePlayer(time);
    moveEnemies(time);
    moveBullets(time);

    collisionDetection();

    render();
}

function render(){
    ctx.clear(0, 0, canvas.width, canvas.height);
    drawBackground(ctx);
    for(var i=0; i<enemies.length; ++i)
        enemies[i].render(ctx);
    player.render(ctx);
}

并不是说您现在必须实现所有这些功能,而是让您了解可能的结构。 不要害怕将大任务(函数)分解为子任务。
给每个敌人一个move()-function 可能是有意义的,这样你就可以为每个敌人实现不同的运动模式, 或者你说每个敌人的模式都是(并且将是)相同的,最好是参数化的,然后你可以在一个循环中处理它。
渲染也是一样,正如我在代码的最后一部分中展示的那样。

【讨论】:

  • 这正是我一直在寻找的,而且我确实学到了一些东西。这里最重要的是将可爱的 spacePerson 作为一个类,我可以访问它的变量。谢谢。
  • 一个简单的问题(我希望);如果我以后要添加其他对象,我会在 update() 中检查冲突吗?
  • 这有点解释,所以我扩展了答案。
  • 分解成子任务是我真正需要做的更多事情。这是一个非常详细的答案,我希望我能给你加分。代码不仅可以工作,而且可读性也很好,这正是我试图学习的方法。
【解决方案2】:

这是我不久前在玩的一款游戏中经过略微修改的代码。如果您想查看更多代码,请查看complete JS on GitHub。游戏不完整,但您应该收集一些有用的线索,了解如何在画布上移动图像。

var spaceperson = {
      speed: 256,
      other_stuff: ''
    },
    keysDown = [],
    update,
    main;

addEventListener("keydown", function (e) {
  keysDown[e.keyCode] = true;
}, false);

update = function (modifier) {
  if (38 in keysDown && spaceperson.y > 0) { // UP
    spaceperson.y -= spaceperson.speed * modifier;
  }
  if (40 in keysDown && spaceperson.y < CANVAS_HEIGHT - SPACEPERSON_HEIGHT) { // DOWN
    spaceperson.y += spaceperson.speed * modifier;
  }
  if (37 in keysDown && spaceperson.x > 0) { // LEFT
    spaceperson.x -= spaceperson.speed * modifier;
  }
  if (39 in keysDown && spaceperson.x < CANVAS_WIDTH - SPACEPERSON_WIDTH) { // RIGHT
    spaceperson.x += spaceperson.speed * modifier;
  }
}

【讨论】:

  • 谢谢,这好多了,我会检查你的代码以获得一些想法。谢谢!
【解决方案3】:

我不确定,但我认为这会有所帮助。

// Get the canvas and context
var canvas = document.getElementById("space"); 
var ctx = canvas.getContext("2d");
canvas.width = 1920;
canvas.height = 700;
var x = 280;
var y = 300;

// Create the image object
var spaceperson = new Image();

spaceperson.addEventListener("keypress", press);

// Add onload event handler
spaceperson.onload = function () {
   // Done loading, now we can use the image
   ctx.drawImage(spaceperson, x, y);
};

function press(event) {
  if(event.keyCode == 37) {//LEFT
    x = x - 1;
  } else if(event.keyCode == 38) {//UP
    y = y - 1;
  } else if(event.keyCode ==39) {//RIGHT
    x = x + 1;
  } else if(event.keyCode == 40) {//DOWN
    y = y + 1;
  }
  draw();
}

function draw(){
  ctx.drawImage(spaceperson,x,y);
}



// artwork by Harrison Marley (using make8bitart.com)
spaceperson.src = "http://i.imgur.com/Eh9Dpq2.png";

【讨论】:

  • 这比我最终得到的结果要整洁得多,但由于某种原因并不能很好地工作。我不太明白为什么。非常感谢
【解决方案4】:

我找到了解决办法!

// Get the canvas and context
var canvas = document.getElementById("space"); 
var ctx = canvas.getContext("2d");
canvas.width = 1920;
canvas.height = 700;
var xPos = 60;
var yPos = 310;

// Create the image object
var spaceperson = new Image();

// Add onload event handler
spaceperson.onload = function () {
// Done loading, now we can use the image
ctx.drawImage(spaceperson, xPos, yPos);
};

function move(e){

if(e.keyCode==39){
    xPos+=10;
}
if(e.keyCode==37){
    xPos-=10;
}
if(e.keyCode==38){
    yPos-=10;
}
if(e.keyCode==40){
    yPos+=10;
}

canvas.width=canvas.width;
ctx.drawImage(spaceperson, xPos, yPos);

}

document.onkeydown = move;

// artwork by Harrison Marley
spaceperson.src = "http://i.imgur.com/Eh9Dpq2.png";

【讨论】:

    猜你喜欢
    • 2023-03-08
    • 2013-04-01
    • 1970-01-01
    • 2020-10-19
    • 2016-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-15
    相关资源
    最近更新 更多