Криво работает свой RayCasting.

aloyen
Offline
Зарегистрирован: 28.12.2021

Всех приветствую!

Недавно я решил сделать что-то наподобие 3D бродилки на Arduino, поискал немного на эту тему, далее все понял и начал кодить. Сперва получалось все хорошо, но когда дело дошло до угла обзора (FOV) возникла проблема.

Цикл, который высчитывает расстояние до объекта решил пускать столько лучей, сколько ему вздумается. Затем я путем "Научного Тыка" нашел закономерность: Чем больше переменная playerA (это угол между осью Х и основным лучём взгляда), тем меньше цикл пускает лучей.

Вот код:


const size_t kart_w = 16; //Ширина карты
const size_t kart_h = 16; //Высота карты
const char kart[] = "################"\
                   "#              #"\
                   "#      #####   #"\
                   "#     #        #"\
                   "#     #  #######"\
                   "#     #        #"\
                   "#   #####      #"\
                   "#   #   #####  #"\
                   "#   #   #      #"\
                   "#   #   #  #####"\
                   "#       #      #"\
                   "#       #      #"\
                   "#       #      #"\
                   "# #######      #"\
                   "#              #"\
                   "################"; //Сама карта
unsigned int playerX = 5; // Координаты
unsigned int playerY = 3; //          игрока
unsigned int playerA = 0; // Угол основного луча
const unsigned int fov = 128; //FOV или в моем случае, сколько будет кидаться лучей.

void setup() {
  Serial.begin(115200); // Ну тут понятно
  while (!Serial) {
    ;
  }
}

void loop() {
  float c = 0; //В будущем здесь будет расстояние
  unsigned int player_A = playerA; //НЕ основной луч
  for (unsigned int now = 0; now <= fov; now++) {  
    player_A = playerA + now; //Определяем угол луча, который будем обрабатывать.
    if (player_A >= 360) {player_A=360-player_A;} //Защита от углов, которые больше 360 градусов.
    for (; c<=20; c=c+0.05) { //Цикл определения расстояния от игрока до предмета по заданному лучу.
      float x = playerX + c*cos(player_A);
      float y = playerY + c*sin(player_A);
      if (kart[int(x)+int(y)*kart_w]!=' ') { //Если замечено столкновение
        Serial.print("Distance: "); //Здесь по идее должна распологаться функция отрисовки, но пока я оставил на выводе информации.
        Serial.print(c);
        Serial.print(". Player_A is now: ");
        Serial.print(player_A);
        Serial.print(". Now: ");
        Serial.print(now);
        Serial.print(".\n");
        break;
      }
    }
  }
}

Я получаю следующий лог:

18:03:59.231 -> Distance: 1.00. Player_A is now: 0. Now: 0.
18:03:59.231 -> Distance: 1.90. Player_A is now: 1. Now: 1.
18:03:59.271 -> Distance: 9.65. Player_A is now: 2. Now: 2.
18:03:59.311 -> Distance: 15.20. Player_A is now: 3. Now: 3.
18:03:59.311 -> Distance: 15.20. Player_A is now: 4. Now: 4.
18:03:59.311 -> Distance: 15.20. Player_A is now: 5. Now: 5.
18:03:59.311 -> Distance: 15.20. Player_A is now: 6. Now: 6.
18:03:59.311 -> Distance: 15.20. Player_A is now: 7. Now: 7.
18:03:59.351 -> Distance: 17.20. Player_A is now: 8. Now: 8.
18:03:59.351 -> Distance: 18.70. Player_A is now: 9. Now: 9.
18:03:59.351 -> Distance: 18.70. Player_A is now: 10. Now: 10.
18:03:59.351 -> Distance: 18.70. Player_A is now: 11. Now: 11.
18:03:59.351 -> Distance: 18.70. Player_A is now: 12. Now: 12.
18:03:59.351 -> Distance: 1.00. Player_A is now: 0. Now: 0.
18:03:59.391 -> Distance: 1.90. Player_A is now: 1. Now: 1.
18:03:59.431 -> Distance: 9.65. Player_A is now: 2. Now: 2.
18:03:59.471 -> Distance: 15.20. Player_A is now: 3. Now: 3.
18:03:59.471 -> Distance: 15.20. Player_A is now: 4. Now: 4.
18:03:59.471 -> Distance: 15.20. Player_A is now: 5. Now: 5.
18:03:59.471 -> Distance: 15.20. Player_A is now: 6. Now: 6.
18:03:59.471 -> Distance: 15.20. Player_A is now: 7. Now: 7.
18:03:59.471 -> Distance: 17.20. Player_A is now: 8. Now: 8.
18:03:59.471 -> Distance: 18.70. Player_A is now: 9. Now: 9.
18:03:59.471 -> Distance: 18.70. Player_A is now: 10. Now: 10.
18:03:59.471 -> Distance: 18.70. Player_A is now: 11. Now: 11.
18:03:59.511 -> Distance: 18.70. Player_A is now: 12. Now: 12.
18:03:59.511 -> Distance: 1.00. Player_A is now: 0. Now: 0.
18:03:59.511 -> Distance: 1.90. Player_A is now: 1. Now: 1.
18:03:59.551 -> Distance: 9.65. Player_A is now: 2. Now: 2.
18:03:59.591 -> Distance: 15.20. Player_A is now: 3. Now: 3.
18:03:59.591 -> Distance: 15.20. Player_A is now: 4. Now: 4.
18:03:59.591 -> Distance: 15.20. Player_A is now: 5. Now: 5.
18:03:59.591 -> Distance: 15.20. Player_A is now: 6. Now: 6.
18:03:59.591 -> Distance: 15.20. Player_A is now: 7. Now: 7.
18:03:59.631 -> Distance: 17.20. Player_A is now: 8. Now: 8.
18:03:59.631 -> Distance: 18.70. Player_A is now: 9. Now: 9.
18:03:59.631 -> Distance: 18.70. Player_A is now: 10. Now: 10.
18:03:59.631 -> Distance: 18.70. Player_A is now: 11. Now: 11.
18:03:59.631 -> Distance: 18.70. Player_A is now: 12. Now: 12.

*Бесконечный цикл*

Здесь цикл отрабатывает только 13 лучей из 128, хотя должен отработать все.

Я пытался исправить эту ошибку, но не смог. Помогите исправить пожалуйста.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

У Вас в цикле строки № 34 переменная "с" постоянно растёт и никогда не уменьшается. Когда она достигает 20.05 цикл в строке №39 просто перестаёт работать - в него программа не заходит. Всё, приплыли.

Вставьте печать "с" после строки №36 и после строки №50 и всё увидите.

aloyen
Offline
Зарегистрирован: 28.12.2021

Спасибо. Я даже не заметил этого.

Morroc
Offline
Зарегистрирован: 24.10.2016

Вы прям изображение решили строить с помощью обратной трассировки ? IMHO для дуины на меге жирноват этот вариант, есть же другие алгоритмы.