在js中返回精确的向量分量canvas
Returning precise vector components in js canvas
我一直在努力渲染从 "enemy" 节点到 2D 11:11 网格中的 "player" 节点(0:0 = 顶部-左)在 JS/Canvas。 After a lot of reading up 我已经设法让镜头接近,但不是很成功。我认为我的速度函数有点出问题,但我真的不知道为什么。这是三角函数:
this.getVelocityComponents = function(speed){
// loc (location of enemy actor) = array(2) [X_coord, Y_coord]
// des (destination (ie. player in this instance)) = array(2) [X_coord, Y_coord]
var i, sum, hyp, output = [], dis = [];
var higher = false;
for (i in loc) {
sum = 0;
if (loc[i] > des[i])
sum = loc[i] - des[i];
if (loc[i] < des[i])
sum = des[i] - loc[i];
dis.push(sum);
}
hyp = Math.sqrt(Math.pow(dis[X], 2) + Math.pow(dis[Y], 2));
if (dis[X] > dis[Y]) {
output[X] = (speed * Math.cos(dis[X]/hyp))
output[Y] = (speed * Math.sin(dis[Y]/hyp))
} else if (dis[X] < dis[Y]) {
output[X] = (speed * Math.cos(dis[Y]/hyp))
output[Y] = (speed * Math.sin(dis[X]/hyp))
}
return output;
}
这是让弹丸框架的X和Y前进的指令:
var distance = [];
for (i in loc) {
var sum = 0;
if (loc[i] > des[i])
sum = loc[i] - des[i];
if (loc[i] < des[i])
sum = des[i] - loc[i];
distance.push(sum);
}
if (distance[X] > distance[Y]) {
frm[X] += (loc[X] < des[X]) ? v[X] : -v[X];
frm[Y] += (loc[Y] < des[Y]) ? v[Y] : -v[Y];
} else {
frm[Y] += (loc[Y] < des[Y]) ? v[X] : -v[X];
frm[X] += (loc[X] < des[X]) ? v[Y] : -v[Y];
}
下面是截图。蓝色是玩家,粉色是敌人,黄色圆圈是弹丸
如您所见,快到目标了。
我是不是做错了什么?我需要做什么?
解决方案比这简单得多。
你应该怎么办?
1) 计算从敌人到玩家的向量。那将是拍摄方向。
2) 归一化向量:这意味着您构建一个长度为 1 且方向相同的向量。
3) 将该向量乘以你的速度:现在你有一个正确的速度向量,具有正确的范数,针对玩家。
下面的一些代码可以帮助您理解:
function spawnBullet(enemy, player) {
var shootVector = [];
shootVector[0] = player[0] - enemy[0];
shootVector[1] = player[1] - enemy[1];
var shootVectorLength = Math.sqrt(Math.pow(shootVector[0], 2) + Math.pow(shootVector[1],2));
shootVector[0]/=shootVectorLength;
shootVector[1]/=shootVectorLength;
shootVector[0]*=bulletSpeed;
shootVector[1]*=bulletSpeed;
// ... here return an object that has the enemy's coordinate
// and shootVector as speed
}
然后,由于您在计算中不使用时间 (!!wrooong!!;-) ),您将使子弹直接移动:
bullet[0] += bullet.speed[0];
bullet[1] += bullet.speed[1];
现在,固定步长的问题是您的游戏 运行 在 30fps 设备上比在 60fps 设备上慢两倍。解决方案是计算自上次刷新以来经过了多少时间,我们称这个时间为 'dt'。使用那个时间将引导您进行更新,例如:
bullet[0] += dt * bullet.speed[0];
bullet[1] += dt * bullet.speed[1];
现在您将与帧速率无关,您的游戏在任何设备上的感觉都一样。
要计算从敌人到玩家的方向,您可以稍微简化计算。
求方向角
var diffX = Player.x - Enemy.x, // difference in position
diffY = Player.y - Enemy.y,
angle = Math.atan2(diffY, diffX); // atan2 will give the angle in radians
请注意,对于 atan2,Y 的差异首先出现,因为 canvas 的方向为 0°,指向右侧。
速度矢量
然后使用角度和速度计算速度矢量:
// calculate velocity vector
var speed = 8,
vx = Math.cos(angle) * speed, // angle x speed
vy = Math.sin(angle) * speed;
如果时间很重要,您可能要考虑将时间作为一个因素。你可以在这里看到 my answer 的例子。
演示
使用这些计算,您将始终能够 "hit" 拥有射弹的玩家(重新加载演示以将敌人位置更改为随机 y):
var ctx = document.querySelector("canvas").getContext("2d"),
Player = {
x: 470,
y: 75
},
Enemy = {
x: 100,
y: Math.random() * 150 // reload demo to change y-position
};
// calculate angle
var diffX = Player.x - Enemy.x,
diffY = Player.y - Enemy.y,
angle = Math.atan2(diffY, diffX);
// calculate velocity vector
var speed = 8,
vx = Math.cos(angle) * speed, // angle x speed
vy = Math.sin(angle) * speed,
x = Enemy.x, // projectil start
y = Enemy.y + 50;
// render
(function loop() {
ctx.clearRect(0, 0, 500, 300);
ctx.fillRect(Player.x, Player.y, 30, 100);
ctx.fillRect(Enemy.x, Enemy.y, 30, 100);
ctx.fillRect(x - 3, y -3, 6, 6);
x += vx;
y += vy;
if (x < 500) requestAnimationFrame(loop);
})();
<canvas width=500 height=300></canvas>
我一直在努力渲染从 "enemy" 节点到 2D 11:11 网格中的 "player" 节点(0:0 = 顶部-左)在 JS/Canvas。 After a lot of reading up 我已经设法让镜头接近,但不是很成功。我认为我的速度函数有点出问题,但我真的不知道为什么。这是三角函数:
this.getVelocityComponents = function(speed){
// loc (location of enemy actor) = array(2) [X_coord, Y_coord]
// des (destination (ie. player in this instance)) = array(2) [X_coord, Y_coord]
var i, sum, hyp, output = [], dis = [];
var higher = false;
for (i in loc) {
sum = 0;
if (loc[i] > des[i])
sum = loc[i] - des[i];
if (loc[i] < des[i])
sum = des[i] - loc[i];
dis.push(sum);
}
hyp = Math.sqrt(Math.pow(dis[X], 2) + Math.pow(dis[Y], 2));
if (dis[X] > dis[Y]) {
output[X] = (speed * Math.cos(dis[X]/hyp))
output[Y] = (speed * Math.sin(dis[Y]/hyp))
} else if (dis[X] < dis[Y]) {
output[X] = (speed * Math.cos(dis[Y]/hyp))
output[Y] = (speed * Math.sin(dis[X]/hyp))
}
return output;
}
这是让弹丸框架的X和Y前进的指令:
var distance = [];
for (i in loc) {
var sum = 0;
if (loc[i] > des[i])
sum = loc[i] - des[i];
if (loc[i] < des[i])
sum = des[i] - loc[i];
distance.push(sum);
}
if (distance[X] > distance[Y]) {
frm[X] += (loc[X] < des[X]) ? v[X] : -v[X];
frm[Y] += (loc[Y] < des[Y]) ? v[Y] : -v[Y];
} else {
frm[Y] += (loc[Y] < des[Y]) ? v[X] : -v[X];
frm[X] += (loc[X] < des[X]) ? v[Y] : -v[Y];
}
下面是截图。蓝色是玩家,粉色是敌人,黄色圆圈是弹丸
如您所见,快到目标了。
我是不是做错了什么?我需要做什么?
解决方案比这简单得多。
你应该怎么办?
1) 计算从敌人到玩家的向量。那将是拍摄方向。
2) 归一化向量:这意味着您构建一个长度为 1 且方向相同的向量。
3) 将该向量乘以你的速度:现在你有一个正确的速度向量,具有正确的范数,针对玩家。
下面的一些代码可以帮助您理解:
function spawnBullet(enemy, player) {
var shootVector = [];
shootVector[0] = player[0] - enemy[0];
shootVector[1] = player[1] - enemy[1];
var shootVectorLength = Math.sqrt(Math.pow(shootVector[0], 2) + Math.pow(shootVector[1],2));
shootVector[0]/=shootVectorLength;
shootVector[1]/=shootVectorLength;
shootVector[0]*=bulletSpeed;
shootVector[1]*=bulletSpeed;
// ... here return an object that has the enemy's coordinate
// and shootVector as speed
}
然后,由于您在计算中不使用时间 (!!wrooong!!;-) ),您将使子弹直接移动:
bullet[0] += bullet.speed[0];
bullet[1] += bullet.speed[1];
现在,固定步长的问题是您的游戏 运行 在 30fps 设备上比在 60fps 设备上慢两倍。解决方案是计算自上次刷新以来经过了多少时间,我们称这个时间为 'dt'。使用那个时间将引导您进行更新,例如:
bullet[0] += dt * bullet.speed[0];
bullet[1] += dt * bullet.speed[1];
现在您将与帧速率无关,您的游戏在任何设备上的感觉都一样。
要计算从敌人到玩家的方向,您可以稍微简化计算。
求方向角
var diffX = Player.x - Enemy.x, // difference in position
diffY = Player.y - Enemy.y,
angle = Math.atan2(diffY, diffX); // atan2 will give the angle in radians
请注意,对于 atan2,Y 的差异首先出现,因为 canvas 的方向为 0°,指向右侧。
速度矢量
然后使用角度和速度计算速度矢量:
// calculate velocity vector
var speed = 8,
vx = Math.cos(angle) * speed, // angle x speed
vy = Math.sin(angle) * speed;
如果时间很重要,您可能要考虑将时间作为一个因素。你可以在这里看到 my answer 的例子。
演示
使用这些计算,您将始终能够 "hit" 拥有射弹的玩家(重新加载演示以将敌人位置更改为随机 y):
var ctx = document.querySelector("canvas").getContext("2d"),
Player = {
x: 470,
y: 75
},
Enemy = {
x: 100,
y: Math.random() * 150 // reload demo to change y-position
};
// calculate angle
var diffX = Player.x - Enemy.x,
diffY = Player.y - Enemy.y,
angle = Math.atan2(diffY, diffX);
// calculate velocity vector
var speed = 8,
vx = Math.cos(angle) * speed, // angle x speed
vy = Math.sin(angle) * speed,
x = Enemy.x, // projectil start
y = Enemy.y + 50;
// render
(function loop() {
ctx.clearRect(0, 0, 500, 300);
ctx.fillRect(Player.x, Player.y, 30, 100);
ctx.fillRect(Enemy.x, Enemy.y, 30, 100);
ctx.fillRect(x - 3, y -3, 6, 6);
x += vx;
y += vy;
if (x < 500) requestAnimationFrame(loop);
})();
<canvas width=500 height=300></canvas>