Перемещение объекта по прямой с постоянной скоростью из точки A В точку B
Я знаю, что это было задано несколько раз раньше, но не было ответа, который действительно работает, что я могу найти. Есть похожие, но скорость варьируется в зависимости от расстояния.
Итак, моя проблема в том, что я пытаюсь заставить объект (в данном случае игрока) перемещать длинную прямую из точки A в B с постоянной скоростью. Это делается путем нажатия на игрока и перетаскивания туда, куда я хочу, чтобы он шел, поэтому он может быть в любом направлении и на любом расстоянии.
У меня есть код, который почти работает, но игрок всегда немного сбивается с курса, тем больше, чем больше расстояние он путешествует. Вот этот код:
window.addEventListener('mouseup', function(e) {
selectedPlayer.moveX = e.pageX;
selectedPlayer.moveY = e.pageY;
movePlayer(selectedPlayer);
});
function movePlayer(player) {
var xDistance = player.moveX - player.x;
var yDistance = player.moveY - player.y;
var travelDistance = Math.sqrt((xDistance * xDistance) + (yDistance * yDistance));
var timeToTravel = travelDistance; //This may seem pointless, but I will add a speed variable later
var playerAngle = Math.atan2(yDistance, xDistance) * (180 / Math.PI);
var xRatio = Math.atan2(xDistance, travelDistance);
var yRatio = Math.atan2(yDistance, travelDistance);
//This function is called in another part of code that repeats it 60 times a second
walkPlayer = function() {
setTimeout(function(){
player.x = player.moveX;
player.y = player.moveY;
selectedPlayer = undefined;
walkPlayer = undefined;
}, timeToTravel * 20)
player.angle = playerAngle;
player.x += xRatio;
player.y += yRatio;
};
}
Я надеюсь, что это имеет смысл, мне пришлось включить только часть кода, которая имеет отношение. Я думаю, что моя проблема, вероятно, связана с частями xRatio и yRatio, но я не могу понять это; я полностью в тупике.
EDIT: я хотел бы добавить, что playerAngle делает игрок посмотрел в направлении перетаскивания, и эта часть работает нормально.
2 ответов
Ниже приведены основы, необходимые для получения того, что вам нужно работать,
var tx = targetX - x,
ty = targetY - y,
dist = Math.sqrt(tx*tx+ty*ty),
rad = Math.atan2(ty,tx),
angle = rad/Math.PI * 180;;
velX = (tx/dist)*thrust;
velY = (ty/dist)*thrust;
player.x += velX
player.y += velY
Это демо я сделал некоторое время назад, который звучит как то, что вы ищете, я добавил возможность нажать, чтобы изменить цель на основе вашей проблемы.
window.addEventListener('mouseup', function(e) {
targetX = e.pageX;
targetY = e.pageY;
});
var ctx = document.getElementById("canvas").getContext("2d"),
x = 300,
y = 0,
targetX = Math.random()*300,
targetY = Math.random()*300,
velX = 0,
velY = 0,
thrust = 5;
function draw(){
var tx = targetX - x,
ty = targetY - y,
dist = Math.sqrt(tx*tx+ty*ty),
rad = Math.atan2(ty,tx),
angle = rad/Math.PI * 180;;
velX = (tx/dist)*thrust;
velY = (ty/dist)*thrust;
// stop the box if its too close so it doesn't just rotate and bounce
if(dist > 1){
x += velX;
y += velY;
}
ctx.fillStyle = "#fff";
ctx.clearRect(0,0,400,400);
ctx.beginPath();
ctx.rect(x, y, 10, 10);
ctx.closePath();
ctx.fill();
ctx.fillStyle = "#ff0";
ctx.beginPath();
ctx.rect(targetX, targetY, 10, 10);
ctx.closePath();
ctx.fill();
setTimeout(function(){draw()}, 30);
}
draw();
ваша проблема, похоже, в том, что xRatio
и yRatio
углы, а не координаты. Это должно сработать:
document.addEventListener('mouseup', function(e) {
movePlayer(selectedPlayer, {x:e.pageX, y:e.pageY});
});
function movePlayer(player, target) {
var start = {
x: player.x,
y: player.y,
t: Date.now()
},
distance = Math.sqrt(distance.x*distance.x + distance.y*distance.y),
time = distance; //This may seem pointless, but I will add a speed variable later
difference = {
x: target.x - player.x,
y: target.y - player.y,
t: time
};
player.angle = Math.atan2(distance.y, distance.x) * (180 / Math.PI);
//This function is called in another part of code that repeats it 60 times a second
walkPlayer = function(curTime) { // we need timing information here: Date.now()
var elapsed = curTime - start.t,
ratio = elapsed / difference.t;
player.x = start.x + difference.x * ratio;
player.y = start.y + difference.y * ratio;
if (ratio >= 1) {
player.x = target.x;
player.y = target.y;
// end calling of walkPlayer
}
};
}