【问题标题】:Setting a correct angular velocity to a canvas object为画布对象设置正确的角速度
【发布时间】:2014-12-27 00:29:04
【问题描述】:

我正在构建一个太空射击游戏,并希望飞船向光标所在方向发射火箭。因此,我获取了它应该射击的角度的弧度值,乘以船的速度并分别设置它的 x 和 y 速度。

我有这个作为子弹类:

function Bullet(x, y) {
    this.x = x;
    this.y = y;
    this.rotation = 0;
    this.width = 6;
    this.height = 3;
    this.color = utils.getRandomColor();
    this.speed = 80;
}

这里是更新子弹类所有实例运动的函数:

function drawBullet(bullet) {
    var dx = mouse.x - bullet.x,
        dy = mouse.y - bullet.y,
        angle = Math.atan2(dy, dx);
    bullet.vx = Math.cos(angle) * bullet.speed;
    bullet.vy = Math.sin(angle) * bullet.speed;
    bullet.x += bullet.vx;
    bullet.y += bullet.vy;
    bullet.draw(ctx);
}

开始没问题,朝着正确的方向和速度等方向前进。但是一旦它到达鼠标,它就会停在那里并开始闪烁。现在,我意识到这是因为我获得角度的方式,使用鼠标位置作为一个值 - 问题是我无法找到一种方法来使用速度的角度,而不是距离鼠标位置。所以它不会变慢。

欢迎所有建议,提前致谢!

【问题讨论】:

  • 当子弹到达目标(鼠标)时你想发生什么?
  • 没什么,这就是问题所在。我希望子弹以恒定的 x 和 y 速度直接穿过鼠标并飞出屏幕(发生这种情况时,我会将其拼接出数组)
  • 我明白了……也许可以这样做:当 dx+dy 接近于零时,子弹与鼠标相撞。当撞击发生时,只需将最后一个“非撞击”角度从子弹对象中拉出,而不是重新计算新角度。在 drawBullet() 中使用 bullet.lastNonImpactAngle=angle; 保存最后一个非冲击角度。
  • 我不明白,子弹应该像寻的导弹一样,总是跟随你的鼠标光标吗?
  • 不,当单击鼠标时,我想以与当前鼠标位置相对应的角度以固定速度发射子弹。当它被发射时,如果它没有击中任何东西,它就会从画布中消失,然后我将其移除。不要跟随鼠标或类似这样的花哨的东西

标签: html animation canvas


【解决方案1】:

bullet 上添加一个存储运动角度的新属性,将其初始化为-1。然后,在第一次drawBullet 调用中,检查它是否已被首先初始化。如果没有,请设置角度...

function Bullet(x, y) {
    this.x = x;
    this.y = y;
    this.rotation = 0;
    this.width = 6;
    this.height = 3;
    this.color = utils.getRandomColor();
    this.speed = 80;
    this.angle = -1;                // New, angle property initialized to -1
}

function drawBullet(bullet) {
    if (bullet.angle === -1) {      // Only pull the mouse cursor and get an angle
      var dx = mouse.x - bullet.x,  // If it hasn't already done so.
          dy = mouse.y - bullet.y,
          angle = Math.atan2(dy, dx);
      bullet.angle = angle;
    }
    bullet.vx = Math.cos(bullet.angle) * bullet.speed;  // Re-use the angle value.
    bullet.vy = Math.sin(bullet.angle) * bullet.speed;
    bullet.x += bullet.vx;
    bullet.y += bullet.vy;
    bullet.draw(ctx);
}

【讨论】:

  • 你无法理解保存角度并重新使用它背后的逻辑?
  • 我的错,伙计,它完美无瑕!不过,你能解释一下这背后的逻辑吗?
  • 如果每次绘制,您都会再次拉动鼠标光标,这可能意味着每次移动鼠标时,子弹都会跟随它。此外,这意味着一旦子弹穿过鼠标位置,角度会立即向后翻转以返回到现在位于它后面的鼠标,所以它会转身......一遍又一遍
  • 我明白了,所以基本上通过将角度设置为 - 1 并只检查一次鼠标位置,子弹就朝这个方向发射,目标是固定的,对吧?
  • 不是固定的目标,而是固定的方向。它最初获得了指向目标的方向,但随后它不再关心目标,它只关心前进。您不希望这样做的唯一原因是,如果您真的想要一个可以不断改变方向以跟随移动目标的寻的子弹。
【解决方案2】:

如果您不需要寻的导弹类型行为,只需在创建子弹时传递鼠标坐标。

示例:

new Bullet(shooterX, shooterY, mouseX, mouseY)

我包含了一个过度设计的堆栈 sn-p,但相关部分如下。

var Bullet = function(x,y,tx,ty){
    this.speed = 15;

    this.x = x;
    this.y = y;

    var radians = Math.atan2(ty-y, tx-x);
    // we now have our velX and velY we can just refer to
    this.velX = Math.cos(radians) * this.speed;
    this.velY = Math.sin(radians) * this.speed;

}

Bullet.prototype.update = function(){
    // just update by our previous calculated velX and velY.
    this.x += this.velX;
    this.y += this.velY;
};

var canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d"),
    width = 250,
    height = 250,
    output = document.getElementById("radians"),
    output2 = document.getElementById("degrees"),
    cX = 0,
    cY = 0,
    mX = 0,
    mY = 0,
    bullets = [];

canvas.width = width;
canvas.height = height;

canvas.addEventListener("mousemove", function (e) {
    mX = e.pageX;
    mY = e.pageY;
});

var Ball = function (x, y, radius, color) {    
    this.x = x || 0;
    this.y = y || 0;
    this.radius = radius || 10;
    
    // makes our x and y the center of the circle.
    this.x = (this.x-this.radius/2);
    this.y = (this.y-this.radius/2);
    
    // how far out do we want the point
    this.pointLength = 50;
    this.px = 0;
    this.py = 0;
    
    this.color = color || "rgb(255,0,0)";
}

Ball.prototype.shoot = function(tx, ty){
    bullets.push(new Bullet(this.x, this.y, tx, ty));
}

Ball.prototype.update = function (x, y) {
    // get the target x and y
    this.targetX = x;
    this.targetY = y;
    
    var x = this.x - this.targetX,
        y = this.y - this.targetY,
        radians = Math.atan2(y,x);
    
    this.px = this.x - this.pointLength * Math.cos(radians);
    this.py = this.y - this.pointLength * Math.sin(radians);
    
    // -y will make 0 the top, y will 0 us at the bottom.
    output.textContent = radians;
    output2.textContent = radians/Math.PI * 180
};

Ball.prototype.render = function () {
    ctx.fillStyle = this.color;
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
    ctx.closePath();
    ctx.fill();
    
    ctx.strokeStyle = "rgb(0,0,255)";
    ctx.beginPath();
    ctx.moveTo(this.x, this.y);
    ctx.lineTo(this.px, this.py);
    ctx.closePath();
    ctx.stroke();
};

var Bullet = function(x,y,tx,ty){
    this.speed = 15;
    
    this.x = x;
    this.y = y;
    
    var radians = Math.atan2(ty-y, tx-x);
    this.velX = Math.cos(radians) * this.speed;
    this.velY = Math.sin(radians) * this.speed;

}

Bullet.prototype.update = function(){
    this.x += this.velX;
    this.y += this.velY;
};

Bullet.prototype.render = function(){
    ctx.fillStyle = '#000';
    ctx.beginPath();
    ctx.arc(this.x, this.y, 2, 0, Math.PI * 2);
    ctx.closePath();
    ctx.fill();
};

var ball1 = new Ball(width/2, height/2, 10);

canvas.addEventListener("click", function (e) {
    ball1.shoot(e.pageX, e.pageY);
});

function render() {
    ctx.clearRect(0, 0, width, height);
    ball1.update(mX, mY);
    ball1.render();
    
    bullets.forEach(function(b){
        b.update();
        b.render();
    });
    requestAnimationFrame(render);
}

render();
ol{list-style:none;}
<canvas id="canvas"></canvas>
<div>
    <ol>
        <li>
            <span>Radians : </span><span id="radians"></span>
        </li>
        <li>
            <span>Degrees : </span><span id="degrees"></span>
        </li>
    </ol>
</div>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-22
    • 2019-06-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多