You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

视线检测(LOS)出现异常视觉效果,求替代算法建议

视觉异常的地图效果

左侧存在一些视觉效果不佳的奇怪点,这些点逻辑上正确,但不符合视觉预期。我使用了一种带有拐角环绕和横竖差异额外检测的直线算法。

注:右侧视觉也有异常,但这是地图边界导致的(:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#define MAP_WIDTH 60
#define MAP_HEIGHT 60
int map[MAP_WIDTH][MAP_HEIGHT];

void init_map()
{
    for (int y = 0; y < MAP_HEIGHT; y++) {
        for (int x = 0; x < MAP_WIDTH; x++) {
            map[x][y] = 1;
        }
    }
}

void generate_dungeon(int open_tiles_percentage)
{
    int total_tiles = MAP_WIDTH * MAP_HEIGHT;
    int open_tiles = (total_tiles * open_tiles_percentage) / 100;
    int carved_tiles = 0;
    int preDir = 0;
    int x = rand() % MAP_WIDTH;
    int y = rand() % MAP_HEIGHT;
    while (carved_tiles < open_tiles) {
        if (map[x][y] == 1) {
            map[x][y] = 0;
            carved_tiles++;
        }
        int direction = rand() % 24;
        if (direction > 4) {
            direction = (preDir) % 24;
        }
        preDir = direction;
        switch (direction) {
            case 0: if (x > 0) x--; break;
            case 1: if (x < MAP_WIDTH - 1) x++; break;
            case 2: if (y > 0) y--; break;
            case 3: if (y < MAP_HEIGHT - 1) y++; break;
        }
    }
}

int is_within_bounds(int x, int y)
{
    return (x >= 0 && x < MAP_WIDTH && y >= 0 && y < MAP_HEIGHT);
}

int line_of_sightV(int x0, int y0, int x1, int y1)
{
    int dx = abs(x1 - x0);
    int dy = abs(y1 - y0);
    int sx = (x0 < x1)? 1 : -1;
    int sy = (y0 < y1)? 1 : -1;
    int err = dx - dy;
    int blockedL = 0;
    int blockedR = 0;
    int blockedT = 0;
    int blockedD = 0;
    int start = 1;
    while (1) {
        if (x0 == x1 && y0 == y1) return 1;
        if ((map[x0][y0] == 1) && (!start)) return 0;
        if (!is_within_bounds(x0, y0)) return 0;
        if (!start) {
            if (map[x0-1][y0] == 1) blockedL = 1;
            if (map[x0+1][y0] == 1) blockedR = 1;
            if (map[x0][y0-1] == 1) blockedT = 1;
            if (map[x0][y0+1] == 1) blockedD = 1;
        }
        int e2 = err * 2;
        if (e2 <= dx) {
            err += dx;
            y0 += sy;
            if (sy > 0 && blockedD == 1) return 0;
            if (sy < 0 && blockedT == 1) return 0;
        } else if (e2 >= -dy) {
            err -= dy;
            x0 += sx;
            if (sx > 0 && blockedR == 1) return 0;
            if (sx < 0 && blockedL == 1) return 0;
        }
        start = 0;
    }
}

int line_of_sightH(int x0, int y0, int x1, int y1)
{
    int dx = abs(x1 - x0);
    int dy = abs(y1 - y0);
    int sx = (x0 < x1)? 1 : -1;
    int sy = (y0 < y1)? 1 : -1;
    int err = dx - dy;
    int blockedL = 0;
    int blockedR = 0;
    int blockedT = 0;
    int blockedD = 0;
    int start = 1;
    while (1) {
        if (map[x0][y0] == 1) return 0;
        if (!is_within_bounds(x0, y0)) return 0;
        if (x0 == x1 && y0 == y1) return 1;
        if (!start) {
            if (map[x0-1][y0] == 1) blockedL = 1;
            if (map[x0+1][y0] == 1) blockedR = 1;
            if (map[x0][y0-1] == 1) blockedT = 1;
            if (map[x0][y0+1] == 1) blockedD = 1;
        }
        int e2 = err * 2;
        if (e2 >= -dy) {
            err -= dy;
            x0 += sx;
            if (sx > 0 && blockedR == 1) return 0;
            if (sx < 0 && blockedL == 1) return 0;
        } else if (e2 <= dx) {
            err += dx;
            y0 += sy;
            if (sy > 0 && blockedD == 1) return 0;
            if (sy < 0 && blockedT == 1) return 0;
        }
        start = 0;
    }
}

int line_of_sight(int x0, int y0, int x1, int y1)
{
    int h = line_of_sightH(x0, y0, x1, y1) || line_of_sightH(x1, y1, x0, y0);
    int v = line_of_sightV(x0, y0, x1, y1) || line_of_sightV(x1, y1, x0, y0);
    return (h && v);
}

void print_map_with_los(int px, int py, int tx, int ty)
{
    system("cls");
    char buffer[(MAP_WIDTH * 2 + 1) * MAP_HEIGHT + 1];
    int buffer_index = 0;
    for (int y = 0; y < MAP_HEIGHT; y++) {
        for (int x = 0; x < MAP_WIDTH; x++) {
            char tile;
            if (x == px && y == py) {
                tile = '@';
            } else if (x == tx && y == ty) {
                tile = 'T';
            } else if (map[x][y] == 1 && (line_of_sight(x, y, px, py) || line_of_sight(x-1, y, px, py) || line_of_sight(x+1, y, px, py) || line_of_sight(x, y-1, px, py) || line_of_sight(x, y+1, px, py))) {
                tile = '#';
            } else if (map[x][y] == 0 && (line_of_sight(x, y, px, py) || line_of_sight(x-1, y, px, py) || line_of_sight(x+1, y, px, py) || line_of_sight(x, y-1, px, py) || line_of_sight(x, y+1, px, py))) {
                tile = '.';
            } else {
                tile = ' ';
            }
            buffer[buffer_index++] = tile;
            buffer[buffer_index++] = ' ';
        }
        buffer[buffer_index++] = '\n';
    }
    buffer[buffer_index] = '\0';
    printf("%s", buffer);
}

void move_player(int *px, int *py, char direction)
{
    int new_x = *px, new_y = *py;
    switch (direction) {
        case 'w': new_y--; break;
        case 's': new_y++; break;
        case 'a': new_x--; break;
        case 'd': new_x++; break;
    }
    if (is_within_bounds(new_x, new_y) && map[new_x][new_y] == 0) {
        *px = new_x;
        *py = new_y;
    }
}

int main()
{
    srand(320000);
    init_map();
    generate_dungeon(72);
    int player_x = 5, player_y = 5;
    int target_x = 15, target_y = 10;
    char input;
    while (1) {
        print_map_with_los(player_x, player_y, target_x, target_y);
        printf(" q to quit: ");
        input = getch();
        if (input == 'q') break;
        move_player(&player_x, &player_y, input);
        print_map_with_los(player_x, player_y, target_x, target_y);
    }
    return 0;
}

我已尝试了一些方案:

  • 将直线算法拆分为优先水平和优先垂直两种,这在很多场景下有效,但无法解决当前问题;
  • 添加了墙体检测以避免直线“绕过”拐角,但也没有效果。

内容的提问来源于stack exchange,提问作者studio-MM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 17:44:54