Как точно рассчитать диагональное движение?

Извините за повторяющиеся вопросы, но я все еще сталкивался с проблемами много дней. Это вызвано функцией расчета диагонального движения. Я уже искал и пробовал, но это работает только для нескольких плиток, и после этого мой персонаж идет другими путями .У меня есть поиск в той же проблеме и может быть ее причиной по координате, которая должна нормализовать вектор, но я не уверен, что это правда или не моя проблема здесь?

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 ссылка

Я попробовал перо и не понял про диагональ, которую вы указали в вопросе? Вы хотите, чтобы персонаж мог двигаться по диагонали? Или можно, пожалуйста, подробнее?

Dhana D. 19.12.2022 11:18

да, я хочу, чтобы он двигался по диагонали в точных координатах плиток, которые создаются звездными алгоритмами, из всего, что я знаю, мне нужно плюс/минус [x y] с радианом

chew 19.12.2022 11:19

Вы хотите, чтобы движение было таким, как будто вы сейчас находитесь на плитке (0,0), тогда вы можете перейти на плитку (1,1) только на один ход, а не на два, верно? И какую клавишу вы ожидаете, чтобы персонаж двигался по диагонали? Комбинированные нажатия клавиш со стрелками?

Dhana D. 19.12.2022 11:24

Во втором и третьем случае вы изменяете координаты таким же образом. Второй случай неверен: он должен иметь -= для координаты x, так как это движение влево, и он должен иметь += для координаты y, так как это движение вниз.

trincot 19.12.2022 11:25

@Dhana D да, это именно то, что я хочу, чтобы первая кнопка создавала путь, а вторая кнопка с именем «GO» запускала движение персонажа.

chew 19.12.2022 11:27

@trincot извините за это из-за этого, но я верю, что даже если я исправлю минус или плюс, это все еще будет похоже на эту проблему

chew 19.12.2022 11:30

Я вижу некоторые проблемы с тригонометрией. Грех управляет y, а cos должен управлять x. /16 сложно... технически это вопрос умножения на радиус, который должен быть расстоянием между начальной точкой и пунктом назначения. rad должно быть значением между 0-2Pi в полном круге

Diego D 19.12.2022 11:31

поэтому я еще пробовал, я заменяю угол const rad = angle * (Math.PI / 360); 360 не 180 и делаю y грехом, а x cos, но все еще получаю эту проблему

chew 19.12.2022 11:42

@chew, пожалуйста, отредактируйте свой вопрос. Это должно быть воспроизводимо для нас. Ссылка на кодовую базу с более чем 1800 строками не помогает. И явно что-то не так (см. мой предыдущий комментарий), поэтому, пожалуйста, исправьте и это в своем вопросе. Я предлагаю вам сделать новый образец программы без всей графики, который печатает только некоторые координаты и демонстрирует проблему. Требуется не более 100 строк кода. См. Как создать минимальный воспроизводимый пример

trincot 19.12.2022 11:43

PS: целые числа для this.player_direction не имеют смысла. Что они представляют? Почему вы используете те же целые числа, что и для направлений up, left, down, right?

Roko C. Buljan 19.12.2022 12:25
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
10
83
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Как я объяснил в своем комментарии, возникли некоторые проблемы с тем, как вы использовали тригонометрию для определения смещения 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.

chew 19.12.2022 12:56

это просто вопрос понимания условий. Демонстрация показывает, какой смысл использовать sin и cos для перемещения значений x и y, при этом точка перемещается на заданную величину. Это просто пиагорейский подход к проблеме с использованием тригонометрии. То, как вы его использовали, было довольно сложно понять и неправильно с точки зрения математики. Есть шанс, что, поскольку вы используете плитки, вам следует «квантовать» домены функций. Во всяком случае, я не понял, что вы имели в виду в своем комментарии. Но еще раз хочу подчеркнуть, что вы использовали математику неправильно. Не код.. математика

Diego D 19.12.2022 13:25
Ответ принят как подходящий

Поскольку вы не используете контроллер джойстика (который возвращает более широкий диапазон значений угла), а только клавиши со стрелками на клавиатуре для перемещения вашего персонажа по диагонали, вам не нужно ничего особенного, кроме

// 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 19.12.2022 14:11

@chew, пожалуйста! Рад, что у тебя получилось

Roko C. Buljan 19.12.2022 14:55

Другие вопросы по теме