Извините за повторяющиеся вопросы, но я все еще сталкивался с проблемами много дней. Это вызвано функцией расчета диагонального движения. Я уже искал и пробовал, но это работает только для нескольких плиток, и после этого мой персонаж идет другими путями .У меня есть поиск в той же проблеме и может быть ее причиной по координате, которая должна нормализовать вектор, но я не уверен, что это правда или не моя проблема здесь?
if (obj[i].direction == "topleft") {
this.player_x -= Math.sin(rad) / 16 ;
this.player_y -= Math.cos(rad) / 16 ;
this.player_walking = 1;
this.player_direction = 0;
} else if (obj[i].direction == "bottomleft") {
this.player_x += Math.sin(rad) / 16 ;
this.player_y -= Math.cos(rad) / 16 ;
this.player_walking = 1;
this.player_direction = 2;
} else if (obj[i].direction == "topright") {
this.player_x += Math.sin(rad) / 16 ;
this.player_y -= Math.cos(rad) / 16 ;
this.player_walking = 1;
this.player_direction = 1;
}else if (obj[i].direction == "bottomright") {
this.player_x += Math.sin(rad) / 16 ;
this.player_y += Math.cos(rad) / 16 ;
this.player_walking = 1;
this.player_direction = 3;
}
Это мое утверждение, в котором вычисляется диагональ направления. Я очень ценю любую помощь и благодарю всех за помощь.
Это мой codepen ссылка
да, я хочу, чтобы он двигался по диагонали в точных координатах плиток, которые создаются звездными алгоритмами, из всего, что я знаю, мне нужно плюс/минус [x y] с радианом
Вы хотите, чтобы движение было таким, как будто вы сейчас находитесь на плитке (0,0), тогда вы можете перейти на плитку (1,1) только на один ход, а не на два, верно? И какую клавишу вы ожидаете, чтобы персонаж двигался по диагонали? Комбинированные нажатия клавиш со стрелками?
Во втором и третьем случае вы изменяете координаты таким же образом. Второй случай неверен: он должен иметь -= для координаты x, так как это движение влево, и он должен иметь += для координаты y, так как это движение вниз.
@Dhana D да, это именно то, что я хочу, чтобы первая кнопка создавала путь, а вторая кнопка с именем «GO» запускала движение персонажа.
@trincot извините за это из-за этого, но я верю, что даже если я исправлю минус или плюс, это все еще будет похоже на эту проблему
Я вижу некоторые проблемы с тригонометрией. Грех управляет y, а cos должен управлять x. /16 сложно... технически это вопрос умножения на радиус, который должен быть расстоянием между начальной точкой и пунктом назначения. rad должно быть значением между 0-2Pi в полном круге
поэтому я еще пробовал, я заменяю угол const rad = angle * (Math.PI / 360); 360 не 180 и делаю y грехом, а x cos, но все еще получаю эту проблему
@chew, пожалуйста, отредактируйте свой вопрос. Это должно быть воспроизводимо для нас. Ссылка на кодовую базу с более чем 1800 строками не помогает. И явно что-то не так (см. мой предыдущий комментарий), поэтому, пожалуйста, исправьте и это в своем вопросе. Я предлагаю вам сделать новый образец программы без всей графики, который печатает только некоторые координаты и демонстрирует проблему. Требуется не более 100 строк кода. См. Как создать минимальный воспроизводимый пример
PS: целые числа для this.player_direction не имеют смысла. Что они представляют? Почему вы используете те же целые числа, что и для направлений up, left, down, right?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Как я объяснил в своем комментарии, возникли некоторые проблемы с тем, как вы использовали тригонометрию для определения смещения x и y на основе угла и расстояния.
Вы сделали это:
this.player_x += Math.sin(rad) / 16 ;
this.player_y -= Math.cos(rad) / 16 ;
Но это не имело смысла, потому что sin и cos — это соответственно y и x.
Во всяком случае, я сделал очень маленькую демонстрацию, которая покажет концепцию небольшого ящика, который можно перемещать в направлениях TL, TR, BL и BR на величину radius, определенную как постоянную.
Позже я реорганизовал ваш код, чтобы было бессмысленно иметь if для каждого направления, поскольку вам всегда нужно просто добавлять значения sin и cos к координатам. Углы исходят из объекта, отображающего каждое направление в соответствующий угол и радиус, а не предопределяются заранее, они исходят из значения ввода distance и могут быть установлены в любое время перед выполнением движения.
Поскольку, чтобы сделать это более понятным, я также сопоставляю эти координаты с позицией элемента dom, мне пришлось преобразовать координату y, выполняя * -1 в соответствии с тем, как работает свойство top css (сверху вниз).
Углы заранее определены для каждого направления как доля PI.
Есть лучшие способы сделать его более эффективным, но это просто ради демонстрации концепции:
//const radius = 30;
const p1 = new player('#p1');
function player(target){
const pi_tr = Math.PI*(1/4); //45deg
const pi_tl = Math.PI*(3/4); //135deg
const pi_bl = Math.PI*(5/4); //225deg
const pi_br = Math.PI*(7/4); //315deg
this.target = document.querySelector(target);
this.player_x = 0;
this.player_y = 0;
this.logCoords = ()=>{
console.info(`X: ${this.player_x}, Y: ${this.player_y}`);
}
this.showPosition = ()=>{
this.target.style.left = `${this.player_x}px`;
this.target.style.top = `${this.player_y*-1}px`;
}
this.move = (direction)=>{
const anglesByDirection = {
'topleft': {
rad: pi_tl,
directionCode: 0
},
'bottomleft': {
rad: pi_bl,
directionCode: 2
},
'topright': {
rad: pi_tr,
directionCode: 1
},
'bottomright': {
rad: pi_br,
directionCode: 3
}
}
const radius = parseInt( document.getElementById('distance').value );
const angle = anglesByDirection[direction];
this.player_x += Math.cos(angle.rad) * radius;
this.player_y += Math.sin(angle.rad) * radius;
this.player_walking = 1;
this.player_direction = angle.directionCode;
this.logCoords();
this.showPosition();
}
}body{
display: flex;
justify-content: space-evenly;
}
.controls{
border: solid 1px lightgray;
text-align: center;
padding: 1em;
font-family: sans-serif;
}
.controls button{
cursor: pointer;
width: 2em;
margin-bottom: 5px;
}
.controls .distance{
margin-top: 2em;
}
.controls #distance{
width: 2em;
}
.controls #distance+span{
margin-left: 5px;
}
#game{
position: relative;
width: 50vw;
height: 50vh;
border: dashed 2px gray;
}
#p1{
position: absolute;
width: 20px;
height: 20px;
background: red;
}<div class = "controls">
<button class = "TL" onclick = "p1.move('topleft');">TL</button>
<button class = "TR" onclick = "p1.move('topright');">TR</button>
<br>
<button class = "BL" onclick = "p1.move('bottomleft');">BL</button>
<button class = "BR" onclick = "p1.move('bottomright');">BR</button>
<br>
<div class = "distance">
<label for = "distance">Distance</label>
<input type = "text" id = "distance" data-default = "30" value = "30"><span>px</span>
</div>
</div>
<div id = "game">
<div id = "p1"></div>
</div>извините за беспорядок в коде, потому что я только начинаю с него несколько дней, но кажется, что если я умножу на угол, как вы говорите, это будет хуже, чем больше. Я просто подумал, что он разделится на x и y и сделает их с минимальным углом больше, потому что я установил размер каждой плитки всего 16 пикселей 16 пикселей, поэтому каждый мой персонаж имеет размер около 0,5.
это просто вопрос понимания условий. Демонстрация показывает, какой смысл использовать sin и cos для перемещения значений x и y, при этом точка перемещается на заданную величину. Это просто пиагорейский подход к проблеме с использованием тригонометрии. То, как вы его использовали, было довольно сложно понять и неправильно с точки зрения математики. Есть шанс, что, поскольку вы используете плитки, вам следует «квантовать» домены функций. Во всяком случае, я не понял, что вы имели в виду в своем комментарии. Но еще раз хочу подчеркнуть, что вы использовали математику неправильно. Не код.. математика
Поскольку вы не используете контроллер джойстика (который возвращает более широкий диапазон значений угла), а только клавиши со стрелками на клавиатуре для перемещения вашего персонажа по диагонали, вам не нужно ничего особенного, кроме
// If single arrow key:
distance = 1
// If combo arrow keys:
distance = 1 / Math.sqrt(2) // ~0.707
что даст вам необходимое расстояние движения по диагонали ~0.707
и как только вы определили значение расстояния, умножьте его на скорость:
distance *= speed;
остальное тогда довольно просто:
if (K[37]) Player.x -= distance;
if (K[38]) Player.y -= distance;
if (K[39]) Player.x += distance;
if (K[40]) Player.y += distance;
Демонстрационный пример:
const Player = {
el: document.getElementById('player'),
x: 200,
y: 100,
speed: 2,
move() {
// You will use canvas, this is for demo only
this.el.style.transform = `translate(${this.x}px, ${this.y}px)`;
}
};
const K = {
fn(ev) {
const k = ev.which;
if (k >= 37 && k <= 40) { // If is arrow
ev.preventDefault();
K[k] = ev.type === "keydown";
}
}
};
const update = () => {
let dist = K[38] && (K[37] || K[39]) || K[40] && (K[37] || K[39]) ? 0.707 : 1;
dist *= Player.speed;
if (K[37]) Player.x -= dist;
if (K[38]) Player.y -= dist;
if (K[39]) Player.x += dist;
if (K[40]) Player.y += dist;
Player.move();
}
document.addEventListener('keydown', K.fn);
document.addEventListener('keyup', K.fn);
(function engine() {
update();
requestAnimationFrame(engine);
}());#player{ position: absolute; left: 0; top: 0; width: 20px; height: 20px; background: #000; border-radius: 50%; }Click here to focus, and use arrows
<div id = "player"></div>о, большое спасибо, я сделал это, и все стало правильно, я поставил, как вы говорите, и разделил на 16, и это сработало, мне нечего сказать и выразить, но еще раз большое спасибо
@chew, пожалуйста! Рад, что у тебя получилось
Я попробовал перо и не понял про диагональ, которую вы указали в вопросе? Вы хотите, чтобы персонаж мог двигаться по диагонали? Или можно, пожалуйста, подробнее?