Canvas - onClick移动对象以指定的速度单击[x,y]

时间:2017-07-17 20:14:38

标签: canvas

我正在寻找一个解决方案,但是找不到任何好的东西并且写得很简单,我希望你能帮我解决这个问题。

我只想实现:   - - - onClick完美地点击指定速度的[x,y]坐标(存储在变量中,例如速度;),

我在这里看到了类似的问题,但是我无法理解它们,如果您知道解决方案,请以最简单的方式编写。提前谢谢。



var ctx = document.getElementById('canvas').getContext('2d');
var cHeight = 500;
var cWidth = 500;

ctx.font = '30px Arial';

var enemyList = {};

var player = {
    x: 50,
    y: 50,
    spdX: 1,
    spdY: 1,
    name: 'P',
    hp: 10
}; 

getDistanceBetweenEntity = function(entity1, entity2) {
    var vx = entity1.x - entity2.x;
    var vy = entity1.y - entity2.y;
    return Math.sqrt(vx*vx+vy*vy);
}

testCollisionEntity = function(entity1, entity2) {
    var distance = getDistanceBetweenEntity(entity1, entity2);
    return distance < 30;
}


enemy = function(id, x, y, spdX, spdY) {
    var enemy = {
        x: x,
        spdX: spdX,
        y: y,
        spdY: spdY,
        name: 'E',
        id: id
    }
    enemyList[id] = enemy;
}


updateEntity = function(entity){
    updateEntityPosition(entity);
    drawEntity(entity);
}

updateEntityPosition = function(entity) {
    entity.x += entity.spdX;
    entity.y += entity.spdY;
    

    if (entity.x < 0 || entity.x > cWidth) {
        entity.spdX = -entity.spdX;
    }
    if (entity.y < 0 || entity.y > cHeight) {
        entity.spdY = -entity.spdY;
    }
}


drawEntity = function(entity) {
    ctx.fillText(entity.name, entity.x, entity.y);
}


 update = function() {

    ctx.clearRect(0, 0, cWidth, cHeight);
    
    for(var key in enemyList) { 
        updateEntity(enemyList[key]);
        var isColliding = testCollisionEntity(player, enemyList[key]);
        if(isColliding) {
            // console.log("Colliding!");
        }
    }

    drawEntity(player);

}

enemy('E1', 150, 350, 10, 15);
enemy('E2', 250, 350, 10, -15);
enemy('E3', 250, 150, 10, -8);

setInterval(update, 1000/30);


document.onclick = function(mouse) {
    var mouseX = mouse.clientX;
    var mouseY = mouse.clientY;
    
    while ( mouseX !== player.x && mouseY !== player.y ) {

        if ( mouseX <= player.x ) {
            player.x -= player.spdX;
        } else if ( mouseX >= player.x ) {
            player.x += player.spdX;
        }

        if ( mouseY <= player.y ) {
            player.y -= player.spdY;
        } else if ( mouseY >= player.y ) {
            player.y += player.spdY;
        }

    }
} 
&#13;
/*
  I just wanted to achieve:
    - onClick go to clicked [x, y] with SPECIFIED speed which will be stored in variable eg. var speed;
*/
&#13;
<canvas id="canvas" width="500" height="500" style="margin: 0 auto; border: 1px solid black;"></canvas>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:0)

以固定速度移动

为游戏添加两个属性,即当前目标x,y。如果没有目标

,则为null
const player = {
    x: 50,
    y: 50,
    name: 'P',
    hp: 10,        
    targetX : null, // null for no target
    targetY : null,

以每帧像素(60Fps)为单位添加速度值,因此每秒10像素为10/60

    speed : 10 / 60,

添加一个功能,如果有目标集

,将移动玩家
    update(){
        if(this.targetX !== null){

获取目标的x,y距离,然后获得线性距离。如果距离小于速度,那么你就在那里设置位置并使目标为空

            var xd = this.targetX - this.x;
            var yd = this.targetY - this.y;
            var distToTarget = Math.sqrt(xd*xd+yd*yd);
            if(distToTarget<= this.speed){
                 this.x = this.targetX;
                 this.y = this.targetY;
                 this.targetX = this.targetY = null;
            }else {

如果不存在,则将x,y距离除以线性距离,得到一个单位长的向量。

                 xd /= distToTarget;
                 yd /= distToTarget;

向量xd,yd的长度是1个像素。我们可以将它乘以速度并获得在x和y中移动的像素数以此速度移动

                 xd *= this.speed;
                 yd *= this.speed;

更新播放器位置和功能结束并关闭对象播放器

                 this.x += xd;
                 this.y += yd;
             }
         }
   }

你可以为敌人做同样的事情,因为他们在追逐玩家你可以使用相同的功能,但你只需将目标设置为玩家。让它们哑一点可能是值得的,所以只设置每隔这么多帧的目标,或者使用随机赔率测试。 (见代码)

最好使用requestAnimationFrame而不是setInterval制作动画。

我在下面重写了你的代码。

var ctx = document.getElementById('canvas').getContext('2d');
var cHeight = 500;
var cWidth = 500;

ctx.font = '30px Arial';

// As you are sharing some functionality I put the shared functions in a separate object
var sharedBehaviour = {
  x: 50,
  y: 50,
  targetX: null, // null for no target
  targetY: null,
  speed: 100 / 60,
  update() {
    if (this.targetX !== null) {
      var xd = this.targetX - this.x;
      var yd = this.targetY - this.y;
      var distToTarget = Math.sqrt(xd * xd + yd * yd);
      if (distToTarget <= this.speed) {
        this.x = this.targetX;
        this.y = this.targetY;
        this.targetX = this.targetY = null;
      } else {
        xd /= distToTarget;
        yd /= distToTarget;
        xd *= this.speed;
        yd *= this.speed;
        this.x += xd;
        this.y += yd;
      }
    }
  },
  draw() {
    ctx.fillText(this.name, this.x, this.y);
  }
}

var enemyList = [];

// to create the player with the shared properties you use Object.assign

var player = Object.assign({}, sharedBehaviour, { // add the unique properties last
  x: 50, // you can overwrite shared properties
  y: 50,
  name: 'P',
  hp: 10
});

// function to create an enemy with the shard properties
// use the for function functionName(  rather than functionName = function
// It is safer and has other benefits as well
// you had enemy = function(id, x, y, spdX, spdY) {
function createEnemy(id, x, y, speed) {
  enemyList.push(Object.assign({}, sharedBehaviour, {
    x,
    y,
    speed,
    id, // You can use shorthand properties rather than x:x,y:y
    name: id,
    setTarget() { // will set the player as a target with a random so its not to hard
      this.targetX = player.x + (Math.random() - 0.5) * 100;
      this.targetY = player.y + (Math.random() - 0.5) * 100;;
    },
    isOnPlayer() {
      var xd = player.x - this.x;
      var yd = player.y - this.y;
      return Math.sqrt(xd * xd + yd * yd) < 30;
    }
  }));
}

function update() {
  ctx.clearRect(0, 0, cWidth, cHeight);

  enemyList.forEach(enemy => {
    if (Math.random() < (1 / 300)) { // 1 in 500 chance to look for player about once every 5 seconds
      enemy.setTarget();
    }
    enemy.update();
    if (enemy.isOnPlayer()) {
      // do what you need to do here
      player.hp -= 0.1;
      enemy.x = Math.random() * canvas.width;
      enemy.y = Math.random() * canvas.height;
      enemy.targetX = null;
    }
  })
  player.update();

  // best to update all then draw all
  enemyList.forEach(enemy => {
    enemy.draw()
  });
  player.draw();
  requestAnimationFrame(update);

}
requestAnimationFrame(update);

createEnemy('E1', 150, 350, 60 / 60);
createEnemy('E2', 250, 350, 60 / 60);
createEnemy('E3', 250, 150, 60 / 60);




document.onclick = function(mouse) {
  player.targetX = mouse.clientX;
  player.targetY = mouse.clientY;
}
<canvas id="canvas" width="500" height="500" style="margin: 0 auto; border: 1px solid black;"></canvas>