Опыт работы с нейронными сетями и простой код на Ассемблере.

Тема в разделе "WASM.BEGINNERS", создана пользователем dcc0, 17 май 2026.

Метки:
  1. dcc0

    dcc0 Active Member

    Публикаций:
    2
    Регистрация:
    22 дек 2022
    Сообщения:
    130
    who_know777,
    Оно хорошо, но строк уже за 500.
    А я хотел выпилить всё так, чтобы идея рейкастинга и эффект 3D сохранились.
    Так, чтобы ухватить алгоритм и по шагам и в целом. Много графики и доп. эффекты отвлекают. Педагогический (для себя) смысл теряется .
     
  2. who_know777

    who_know777 Active Member

    Публикаций:
    2
    Регистрация:
    29 мар 2021
    Сообщения:
    125
    Адрес:
            
    Графическая версия показывает некоторые баги консольной:
    - неправильно считаются столкновения, игрок проваливается внутрь стены
    - игрок цепляется за стены

    Мне кажется у игрока должна быть форма чтобы правильно считать коллизии в 3d.
     
    dcc0 нравится это.
  3. dcc0

    dcc0 Active Member

    Публикаций:
    2
    Регистрация:
    22 дек 2022
    Сообщения:
    130
    who_know777, да за пределы стены можно выйти лучом.
    Тут есть проверка на это:
    Код (C):
    1.  if (testX < 0 || testX >= MAP_WIDTH || testY < 0 || testY >= MAP_HEIGHT) {
    --- Сообщение объединено, 6 июл 2026 в 19:53 ---
    Вот здесь, конечно, интересная математика. И тут бы хорошие комментарии:
    Зависимость, как я понял, такая:
    Угол игрока влияет на угол луча (что естественно).
    Код (Text):
    1.          
    2.   /*Пример: Угол луча равен. (0- (3.14159265358979323846/3)/2) + (x (двойной точности, на певрой итерации 0) / 80)*(3.14159265358979323846/3)*/
    3.             rayAngle = (playerAngle - FOV / 2.0) + ((double)x / (double)SCREEN_WIDTH) * FOV;    

    Угол луча влияет на взгляд (игрока) по x и y
    Код (Text):
    1.  eyeX = cos(rayAngle);
    2.             eyeY = sin(rayAngle);
    3.  
    Взгляд по x и y влияет на луч по x и y, понятно, что луч от позиции игрока.
    Код (Text):
    1.            
    2.  distanceToWall += 0.1;  /* шаг по лучу*/
    3.                  testX = (int)(playerX + eyeX * distanceToWall); /*переменная луча по X*/
    4.                  testY = (int)(playerY + eyeY * distanceToWall); /*по Y*/
    5.  
    А для вывода столбца оказывается важным только, где остановился
    distanceToWall (эффект рыбьего глаза не трогаю). На дистанцию до стены влиеят все оставльное по цепочке.
    Потолок = высота экрана / 2 - высотка экрана / дистанция до стены
    Пол = высотка экрана - потолок.

    Далее вывод: если y < потолка печатем пробел
    Если y > потолка и y <= пола, печатаем символы - стены с тенями.
    В остальном печатем пол - пробел.


    P.S.
    Вроде и просто. Алгоритм стал понятен.
    И даже почему так много отдельных переменных.
    Но угол луча (математически) не сказать, что очень очевидная вещь.
     
    Последнее редактирование: 6 июл 2026 в 19:55
    who_know777 нравится это.
  4. who_know777

    who_know777 Active Member

    Публикаций:
    2
    Регистрация:
    29 мар 2021
    Сообщения:
    125
    Адрес:
            
    Мне недавно дипсик выдал что есть проблема в рейкастинге связаная с коллизиями.
    И что она решается так то и так то. Потерял его ответ блин.

    Немного тупанул, надо было линии везде рисовать таким образом:
    Код (Pascal):
    1.  
    2. procedure DrawLine(hDC: HDC; X1, Y1, X2, Y2: Integer;
    3.                    Color: COLORREF; Thickness: Integer = 1;
    4.                    Style: TLineStyle = lsSolid);
    5. var
    6.   Pen: HPEN;
    7.   OldPen: HPEN;
    8.   PenStyle: DWORD;
    9. begin
    10.   // Инициализируем PenStyle значением по умолчанию
    11.   PenStyle := PS_SOLID;
    12.  
    13.   case Style of
    14.     lsSolid:   PenStyle := PS_SOLID;
    15.     lsDashed:  PenStyle := PS_DASH;
    16.     lsDotted:  PenStyle := PS_DOT;
    17.     lsDashDot: PenStyle := PS_DASHDOT;
    18.   end;
    19.  
    20.   Pen := CreatePen(PenStyle, Thickness, Color);
    21.   OldPen := SelectObject(hDC, Pen);
    22.  
    23.   MoveToEx(hDC, X1, Y1, nil);
    24.   LineTo(hDC, X2, Y2);
    25.  
    26.   SelectObject(hDC, OldPen);
    27.   DeleteObject(Pen);
    28. end;
    p.s. этот рейкастинг для меня открыл новый дивный мир в погромировании.
    Кроме него еще есть bsp деревья. В общем интересно это все, и не на один год.
     
    dcc0 нравится это.
  5. dcc0

    dcc0 Active Member

    Публикаций:
    2
    Регистрация:
    22 дек 2022
    Сообщения:
    130
    Я так понимаю, что для сокращения вот эти переменные можно закомментировать и перенести:
    Код (Text):
    1.  
    2. eyeX = cos(rayAngle);
    3. eyeY = sin(rayAngle);
    4.  
    Т.е. в этом фрагменте можно сократить так:

    Код (C):
    1. for (y = 0; y < SCREEN_HEIGHT; y++) {
    2.         for (x = 0; x < SCREEN_WIDTH; x++) {
    3.               /*Вычисляем угол для каждого луча*/
    4.              /*Угол луча равен. (0- (3.14159265358979323846/3)/2) + (x (двойной точности) / 80)*(3.14159265358979323846/3)*/
    5.             rayAngle = (playerAngle - FOV / 2.0) + ((double)x / (double)SCREEN_WIDTH) * FOV;
    6.             distanceToWall = 0.0;
    7.              hit = 0;
    8.             while (!hit && distanceToWall < MAX_DEPTH) {
    9.                 distanceToWall += 0.1;  /* шаг по лучу*/
    10.                  testX = (int)(playerX + cos(rayAngle) * distanceToWall); /*переменная луча по X*/
    11.                  testY = (int)(playerY + sin(rayAngle) * distanceToWall); /*по Y*/
    12.  
    13.                 if (testX < 0 || testX >= MAP_WIDTH || testY < 0 || testY >= MAP_HEIGHT) {
    14.                     hit = 1;  /*луч вышел за границы карты, считаем, что столкнулся с границей*/
    15.                     distanceToWall = MAX_DEPTH;
    16.                 } else {
    17.                     if (worldMap[testY][testX] == 1) {
    18.                         hit = 1; /*столкновение со стеной*/
    19.                     }
    20.                 }
    21.             }
    --- Сообщение объединено, 6 июл 2026 в 20:14 ---


    Кто хоть раз мерил углы и размеры помещения, или улицы (топографы), или пещеры (спелеологи) даже... тем, наверное, алгоритм более понятен. =)
    Я имею в виду, откуда берутся синусы с косинусами.

    Мне сейчас сильно больше стал понятен алгоритм, осталось с математикой разобраться в вычислении угла луча.

    Даже с ходу понятно, почему x до SCREEN_WIDTH. Так как лучом обходим всю видимую область, а этом и есть экран.
    Но в играх часто - это может быть и не весь экран.

    Мне кажется, но я не уверен, что игрок проваливается за стены по причине, что на каждой итерации угол луча считается с
    учетом x - а x тут - это всего лишь переменная для цикла.

    Он вообще переводит int x в (double)x. Можно сказать даже, что в общем, - это число с потолка взято. Определяет изменение угла луча для каждого броска.
    --- Сообщение объединено, 6 июл 2026 в 20:25 ---
    Т.е. если совсем в двух словах алгоритм такой:
    1) Посчитал угол луча от позиции игрока.
    2) Бросил луч.
    3) Получил дистанцию.
    Повторил все шаги для всей видимой области - ширины экрана.
    Вывод:
    1) Посчитал потолок и пол на основе дистнации для каждого стобца стены.
    2) Вывел каждый столбец стены.
    --- Сообщение объединено, 6 июл 2026 в 21:30 ---
    В стиле матрицы:

    Код (C):
    1. /*Модель 3D Raycasting на C(89). Написана нейронной сетью. Отредактирована by dcc0.
    2. Стены с помощью символов
    3. Компиляция и запуск gcc -o ray ray.c  -lm; ./ray
    4. * или gcc -std=c89  -o ray ray.c  -lm; ./ray
    5. Убран эффект рыбьего глаза*/
    6. #include <stdio.h>
    7. #include <math.h>
    8. #include <string.h>
    9. #include <stdlib.h>
    10. #include <time.h>
    11. /*Размеры карты и экрана*/
    12. #define MAP_WIDTH 16
    13. #define MAP_HEIGHT 16
    14. #define SCREEN_WIDTH 80
    15. #define SCREEN_HEIGHT 24
    16. #define M_PI 3.14159265358979323846
    17. #define FOV (M_PI / 3.0)
    18. #define MAX_DEPTH 16.0
    19.  
    20. /*Карта*/
    21. int worldMap[MAP_HEIGHT][MAP_WIDTH] = {
    22.   {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
    23.   {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
    24.   {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
    25.   {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
    26.   {1,0,0,0,1,1,1,0,0,1,1,1,0,0,0,1},
    27.   {1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,1},
    28.   {1,0,0,0,1,1,1,0,0,1,1,1,0,0,0,1},
    29.   {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
    30.   {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
    31.   {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
    32.   {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
    33.   {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
    34.   {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
    35.   {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
    36.   {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
    37.   {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
    38. };
    39.  
    40. double playerX = 3.0;  /*Начальные координаты игрока*/
    41. double playerY = 3.0;
    42. double playerAngle = 0.0;
    43.  
    44. void draw() {
    45.    int y, x, RayX, RayY, hit, ceiling, floor, rrandd;
    46.    double angleDifference;
    47.    double eyeX, eyeY, rayAngle, distanceToWall;
    48.   printf("\033[2J"); //Очистка экрана
    49.   printf("\033[H"); //И сброс курсора в начало
    50.   fflush(stdout);
    51.  
    52.   for (y = 0; y < SCREEN_HEIGHT; y++) {
    53.   for (x = 0; x < SCREEN_WIDTH; x++) {
    54.         /*Вычисляем угол для каждого луча*/
    55.   rayAngle = (playerAngle - FOV / 2.0) + ((double)x / (double)SCREEN_WIDTH) * FOV;
    56.   distanceToWall = 0.0;
    57.   hit = 0;
    58.   /*Можно удалить */
    59.   //eyeX = cos(rayAngle);
    60.   //eyeY = sin(rayAngle);
    61.   while (!hit && distanceToWall < MAX_DEPTH) {
    62.   distanceToWall += 0.1;  /* шаг по лучу*/
    63.   // testX = (int)(playerX + eyeX * distanceToWall); /*переменная луча по X*/
    64.   //testY = (int)(playerY + eyeY * distanceToWall); /*по Y*/
    65.   RayX = (int)(playerX + cos(rayAngle) * distanceToWall); /*переменная луча по X*/
    66.   RayY = (int)(playerY + sin(rayAngle) * distanceToWall); /*по Y*/
    67.  
    68.   if (RayX < 0 || RayX >= MAP_WIDTH || RayY < 0 || RayY >= MAP_HEIGHT) {
    69.   hit = 1;  /*луч вышел за границы карты, считаем, что столкнулся с границей*/
    70.   distanceToWall = MAX_DEPTH;
    71.   } else {
    72.   if (worldMap[RayY][RayX] == 1) {
    73.   hit = 1; /*столкновение со стеной*/
    74.   }
    75.   }
    76.   }
    77.  
    78.        /*Корректировка расстояния для устранения эффекта рыбьего глаза*/
    79.         angleDifference = rayAngle - playerAngle;
    80.        if (angleDifference > M_PI) angleDifference -= 2 * M_PI;
    81.        if (angleDifference < -M_PI) angleDifference += 2 * M_PI;
    82.  
    83.   ceiling = (int)((SCREEN_HEIGHT / 2.0) - SCREEN_HEIGHT / distanceToWall);
    84.   floor = SCREEN_HEIGHT - ceiling;
    85.  
    86.   srand(time(NULL));
    87.         rrandd = (rand() %10);
    88.  
    89.   if (y < ceiling) {
    90.   printf(" "); /*рисуем пробел - небо*/
    91.   } else if (y > ceiling && y <= floor) {
    92.   if (distanceToWall <= MAX_DEPTH / 4.0) {
    93.            printf("\033[0;32m");
    94.   printf("%d",  rrandd ); /*рисуем стены разной жирности*/
    95.   } else if (distanceToWall < MAX_DEPTH / 2.0) {
    96.   printf("+");
    97.   } else {
    98.   printf(".");
    99.   }
    100.   } else {
    101.          printf("\033[0;32m");
    102.   printf(" "); /*рисуем пол*/
    103.   }
    104.   }
    105.   printf("\n");
    106.   }
    107. }
    108.  
    109. int main() {
    110.   char command[10];
    111.   double newX,  newY;
    112.   char c;
    113. //Управление
    114.   while (1) {
    115.      //На каждое движение перерисовываем видимую область
    116.   draw();
    117.   printf("Введите  (W/A/S/D + enter, 'exit'  - выход): ");
    118.   if (!fgets(command, sizeof(command), stdin)) break;
    119.  
    120.   if (strncmp(command, "exit", 4) == 0) {
    121.   break; /*Выход из программы*/
    122.   }
    123.  
    124.   c = command[0];
    125.   if (c == 'w' || c == 'W') {
    126.   /*Вперед*/
    127.   newX = playerX + cos(playerAngle) * 0.2;
    128.   newY = playerY + sin(playerAngle) * 0.2;
    129.   if (worldMap[(int)newY][(int)newX] == 0) {
    130.   playerX = newX;
    131.   playerY = newY;
    132.   }
    133.   } else if (c == 's' || c == 'S') {
    134.   /*Назад*/
    135.   newX = playerX - cos(playerAngle) * 0.2;
    136.   newY = playerY - sin(playerAngle) * 0.2;
    137.   if (worldMap[(int)newY][(int)newX] == 0) {
    138.   playerX = newX;
    139.   playerY = newY;
    140.   }
    141.   } else if (c == 'a' || c == 'A') {
    142.   /*Поворот налево*/
    143.   playerAngle -= 0.1;
    144.   } else if (c == 'd' || c == 'D') {
    145.   /*Поворот направо*/
    146.   playerAngle += 0.1;
    147.   }
    148.   }
    149.   return 0;
    150. }
    151.  
     
    Последнее редактирование: 6 июл 2026 в 20:17
    who_know777 нравится это.
  6. who_know777

    who_know777 Active Member

    Публикаций:
    2
    Регистрация:
    29 мар 2021
    Сообщения:
    125
    Адрес:
            
    Мне иногда кажется целесообразно вообще сначала в 2d перейти. Ато хаос немного получается =)
    2d(вид сверху) типа фундамента для будущего понимания(качества будущих решений).

    Есть еще bsp-деревья, там как раз про графы вроде.
     
    Последнее редактирование: 6 июл 2026 в 22:46
    Mikl___ и dcc0 нравится это.
  7. dcc0

    dcc0 Active Member

    Публикаций:
    2
    Регистрация:
    22 дек 2022
    Сообщения:
    130
    Если вдуматься, то в общем все, как и в жизни. Т.е. дискретная модель описывает то, как мы это и видим:
    Луч выходит из позиции игрока (playerX и Y), под углом, который вычисляется для каждого заново (rayAngle),
    движется постепенно до встречи со стеной - инкременет (distanceToWall).
    Код (C):
    1.     RayX = (int)(playerX + cos(rayAngle) * distanceToWall); /*переменная луча по X*/
    2.                 RayY = (int)(playerY + sin(rayAngle) * distanceToWall); /*по Y*/
    3.  
    Один из самых, не сказать, что простых моментов - определение угла следующего луча:
    Код (C):
    1. rayAngle = (playerAngle - FOV / 2.0) + ((double)x / (double)SCREEN_WIDTH) * FOV;
    Тут объясние от нейронной сети вполне внятное:



    На вычислении потолка ещё тоже можно споткнуться (почему высота экрана делённая именно на 2?!):
    Код (C):
    1. ceiling = (int)((SCREEN_HEIGHT / 2.0) - SCREEN_HEIGHT / distanceToWall);
    Нейронная сеть (deepai) объяснила и это:

    --- Сообщение объединено, 7 июл 2026 в 08:11 ---
    who_know777, в bsp деревьях ничего не понимаю. Но вот переборная комбинаторика - интересная штука (если без рекурсии).
    Задачи типа найти алгоритм для любых n (хотя бы условно).
    Заодно поиск нестандартных приёмов.
    --- Сообщение объединено, 7 июл 2026 в 08:50 ---
    Вроде понятно стало: угол - минус половина обзора ( так как игрок смотрит вперед, а лучи от него слева и справа).
    + x столбец (из соотношения к шире) * FOV (которое есть Пи/ на три, потому что поле зрения - треть от 180, т.е. вычисление угла )
    Код (C):
    1. rayAngle = (playerAngle - FOV / 2.0) + ((double)x / (double)SCREEN_WIDTH) * FOV;
    2.  
    --- Сообщение объединено, 7 июл 2026 в 14:02 ---
    Кстати, вспомнил.
    Рейкастинг я пробовал писать даже на php:
    http://i92625up.beget.tech/raycastingModelPhp/main.php
    =)
    --- Сообщение объединено, 7 июл 2026 в 14:04 ---
    2д уже пробовал делать на php:
    http://i92625up.beget.tech/raycastingModelPhp/main.php
     
    Последнее редактирование: 7 июл 2026 в 08:23
  8. who_know777

    who_know777 Active Member

    Публикаций:
    2
    Регистрация:
    29 мар 2021
    Сообщения:
    125
    Адрес:
            
    Интересный эксперимент.

    Я думаю надо сначала на 2d движок написать:
    - Генерация карты.
    - Перемещение по карте.
    - Обработка коллизий с обьектами.
    - Интеллект врагов(враг всегда знает где игрок, но если игрок далеко враг блуждает по карте).
    - Угол поворота врагов относительно игрока для правильной установки 2d спрайтов(понадобится в будущем).
    - Полет пули игрока/врагов по карте(отдельная структура).
    - и т. д.
     
    dcc0 нравится это.
  9. dcc0

    dcc0 Active Member

    Публикаций:
    2
    Регистрация:
    22 дек 2022
    Сообщения:
    130

    Игру я уже один раз писал, давно.
    Она, правда, пвп. Примитив.
    Но там есть локация пещеры... Там ходишь, события при достижении опред. позиций. Можно сказать, коллизии.

    http://i92625up.beget.tech/chat/ind/index.php
    --- Сообщение объединено, 7 июл 2026 в 18:02 ---
    who_know777, имхо, если писать, то для терминала продолжить тему. Можно без аски, но лучше с ним... Так как для терминала графика должна быть максимально примитивная.
    Генерация уровней. Враги. Пушка. Счёт. В идеале, если это будет онлайн игра. Кто-то создаёт сервер, кто коннектится. Или сервер на сайте, карта подгружается из бд и к ней все игроки коннектятся... Регистрируются на карте... И играют.... Реализацию в общем виду, но таких игр много...
    --- Сообщение объединено, 7 июл 2026 в 20:27 ---
    Прошу прощения за опечатки, иногда в транспорте набираю.
     
    Последнее редактирование: 7 июл 2026 в 18:04
    Mikl___ и who_know777 нравится это.