Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <math.h>
- #include <float.h> // Для DBL_MAX
- #include <stdbool.h>
- #include <stdlib.h>
- #include <stdio.h>
- #define PI 3.14159
- #define RIGHT 0
- #define UP 1
- #define LEFT 2
- #define DOWN 3
- // Шаблон для комнат
- struct room_struct {
- bool* map;
- int width;
- int height;
- };
- struct unit_struct {
- double x;
- double y;
- double angle;
- double rotate_speed;
- };
- //=========================================================================================
- // Стандартные мат. функции
- double sqr(double value) {
- return value*value;
- }
- double point_distance(double x_start, double y_start, double x_end, double y_end) {
- return sqrt( sqr(x_end - x_start) + sqr(y_end - y_start) );
- }
- double min(double value_1, double value_2) {
- return (value_1 < value_2) ? value_1 : value_2;
- }
- double max(double value_1, double value_2) {
- return (value_1 > value_2) ? value_1 : value_2;
- }
- //=========================================================================================
- // Проверка на существование горизонтальной или вертикальной стены
- bool wall_check(int tile_number_x, int tile_number_y, int wall_side, struct room_struct room) {
- // Если какая то из начальных координат выходит за границы карты
- if (tile_number_x < 0 || tile_number_x >= room.width || tile_number_y < 0 || tile_number_y >= room.height) {
- return true;
- }
- int index = 0;
- switch(wall_side) {
- case RIGHT: if (++tile_number_x < room.width) {
- index = tile_number_x + (room.width * tile_number_y);
- return room.map[index];
- }
- break;
- case UP: if (--tile_number_y >= 0) {
- index = tile_number_x + (room.width * tile_number_y);
- return room.map[index];
- }
- break;
- case LEFT: if (--tile_number_x >= 0) {
- index = tile_number_x + (room.width * tile_number_y);
- return room.map[index];
- }
- break;
- case DOWN: if (++tile_number_y < room.height) {
- index = tile_number_x + (room.width * tile_number_y);
- return room.map[index];
- }
- break;
- default:
- abort();
- break;
- }
- return true; // Стена при достижении границы карты по дефолту
- }
- // Поиск расстояния до ближайшей горизонтальной стены (вверхние и нижние)
- double find_horizontal_wall_distance(double x_start, double y_start, double angle, struct room_struct room, double max_view_distance, int wall_spacing, int side) {
- int left_border_num = (int)floor( x_start / wall_spacing);
- int up_border_num = (int)floor( y_start / wall_spacing);
- int offset;
- int current_border_num;
- bool wall_exist;
- double distance;
- const int max_border_check = (int)ceil(max_view_distance);
- if (side == UP) {
- offset = -1;
- current_border_num = up_border_num;
- }
- else if (side == DOWN) {
- offset = 1;
- current_border_num = up_border_num + 1;
- }
- else {
- abort();
- }
- for(int i = 0; i < max_border_check; i++) {
- double y_intersection = ( current_border_num + i*offset ) * wall_spacing; // Константно для номера(индекса) стены
- double x_intersection = ( (y_intersection - y_start) / (-tan(angle)) ) + x_start; // Зависит от угла обзора
- // ВАЖНО :
- // передаются координаты того тайла, на котором стоял бы юнит, если бы
- // смотрел на стену по направлению side
- int y_intersection_tile = up_border_num + i*offset;
- int x_intersection_tile = (int)floor(x_intersection / wall_spacing);
- wall_exist = wall_check(x_intersection_tile, y_intersection_tile, side, room);
- // Если обнаружена стена или эта итерация последняя
- if (wall_exist || i + 1 >= max_border_check) {
- distance = point_distance(x_start, y_start, x_intersection, y_intersection);
- if ( distance > max_view_distance) {
- distance = max_view_distance;
- }
- break;
- }
- }
- return distance;
- }
- // Поиск расстояния до ближайшей вертикальной стены (правые и левые)
- double find_vertical_wall_distance(double x_start, double y_start, double angle, struct room_struct room, double max_view_distance, int wall_spacing, int side) {
- int left_border_num = (int)floor( x_start / wall_spacing);
- int up_border_num = (int)floor( y_start / wall_spacing);
- int offset;
- int current_border_num;
- bool wall_exist;
- double distance = max_view_distance;
- const int max_border_check = (int)ceil(max_view_distance);
- if (side == LEFT) {
- offset = -1;
- current_border_num = left_border_num;
- }
- else if (side == RIGHT) {
- offset = 1;
- current_border_num = left_border_num + 1;
- }
- else {
- abort();
- }
- for(int i = 0; i < max_border_check; i++) {
- double x_intersection = ( current_border_num + i*offset ) * wall_spacing; // Константа от номера(индекса) стены
- double y_intersection = ( -tan(angle) * (x_intersection - x_start) ) + y_start; // Зависит от угла обзора
- // ВАЖНО :
- // передаются координаты того тайла, на котором стоял бы юнит, если бы
- // смотрел на стену по направлению side
- int x_intersection_tile = left_border_num + i*offset;
- int y_intersection_tile = (int)floor(y_intersection / wall_spacing);
- wall_exist = wall_check(x_intersection_tile, y_intersection_tile, side, room);
- // Если обнаружена стена или эта итерация последняя
- if (wall_exist || i + 1 >= max_border_check) {
- distance = point_distance(x_start, y_start, x_intersection, y_intersection);
- if ( distance > max_view_distance) {
- distance = max_view_distance;
- }
- break;
- }
- }
- return distance;
- }
- //=========================================================================================
- // Тяжёлая артиллерия
- double ray_length_to_wall(double x_start, double y_start, double angle, struct room_struct room, double max_view_distance, int wall_spacing) {
- if (angle >= (3*PI)/2) { // 1) Для угла >270
- //=======================================================================================================
- double down_wall_distance = find_horizontal_wall_distance(x_start, y_start, angle, room, max_view_distance, wall_spacing, DOWN);
- double right_wall_distance = find_vertical_wall_distance(x_start, y_start, angle, room, max_view_distance, wall_spacing, RIGHT);
- return min(down_wall_distance, right_wall_distance);
- }
- else if (angle >= PI) { // 2) Для угла >180
- //=======================================================================================================
- double left_wall_distance = find_vertical_wall_distance(x_start, y_start, angle, room, max_view_distance, wall_spacing, LEFT);
- double down_wall_distance = find_horizontal_wall_distance(x_start, y_start, angle, room, max_view_distance, wall_spacing, DOWN);
- return min(left_wall_distance, down_wall_distance);
- }
- else if (angle >= PI/2) { // 3) Для угла >90
- //=======================================================================================================
- double up_wall_distance = find_horizontal_wall_distance(x_start, y_start, angle, room, max_view_distance, wall_spacing, UP);
- double left_wall_distance = find_vertical_wall_distance(x_start, y_start, angle, room, max_view_distance, wall_spacing, LEFT);
- return min(up_wall_distance, left_wall_distance);
- }
- else if (angle < PI/2) { // 4) Для угла <90
- //=======================================================================================================
- double right_wall_distance = find_vertical_wall_distance(x_start, y_start, angle, room, max_view_distance, wall_spacing, RIGHT);
- double up_wall_distance = find_horizontal_wall_distance(x_start, y_start, angle, room, max_view_distance, wall_spacing, UP);
- return min(right_wall_distance, up_wall_distance);
- }
- return -1;
- } // Конец функции
- int main(void) {
- //=======================================================================================================
- // Создание начальной комнаты
- struct room_struct main_room;
- main_room.width = 3;
- main_room.height = 3;
- main_room.map = malloc( sizeof(*main_room.map) * main_room.width * main_room.height );
- if (main_room.map == NULL) {
- abort();
- }
- else {
- /////////////////////////////////////////////////////////////////
- main_room.map[0] = 0; main_room.map[1] = 0; main_room.map[2] = 0;
- main_room.map[3] = 0; main_room.map[4] = 0; main_room.map[5] = 0;
- main_room.map[6] = 0; main_room.map[7] = 0; main_room.map[8] = 0;
- /////////////////////////////////////////////////////////////////
- }
- struct room_struct* current_room = &main_room; // Мейн рум устанавливается как стартовая
- //=======================================================================================================
- // Преднастройка параметров рендеринга
- double max_view_distance = max(current_room -> width, current_room -> height);
- int wall_spacing = 1;
- //=======================================================================================================
- // Создание персонажа
- struct unit_struct player;
- player.x = 1.01;
- player.y = 1.01;
- player.angle = 0.01;
- player.rotate_speed = PI/30;
- //=======================================================================================================
- printf("%f\n", ray_length_to_wall( player.x, player.y, player.angle, *current_room, max_view_distance, wall_spacing) );
- printf("%f\n", ray_length_to_wall( player.x, player.y, player.angle + PI/2, *current_room, max_view_distance, wall_spacing) );
- printf("%f\n", ray_length_to_wall( player.x, player.y, player.angle + PI, *current_room, max_view_distance, wall_spacing) );
- printf("%f\n", ray_length_to_wall( player.x, player.y, player.angle + (3*PI)/2, *current_room, max_view_distance, wall_spacing) );
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement