Как использовать алгоритм линейного рисования с мин / макс? F # - PullRequest
0 голосов
/ 18 января 2019

Извините, если этот вопрос не подходит для этого сайта, но я не знаю, где еще его задать. Я довольно смущен, я использую мин и макс, я верю правильно Когда я двигаю оружие клавишами со стрелками, кажется, что линия работает, когда она движется вправо или вниз. Если кто-нибудь знает, как это исправить или просто поставил меня на правильный путь, я был бы очень благодарен. Для всех, кто интересуется, я создаю эту программу для игры, в которой мне нужно иметь видимость оружия.

EDIT:

Я пытаюсь достичь состояния, в котором я могу использовать клавиши w, a, s, d для перемещения C (символ) и клавиши со стрелками для перемещения W (оружие). В конце концов, когда я добавлю врагов, будет использоваться линия между персонажем и оружием, чтобы увидеть, находятся ли они в пределах досягаемости для атаки. Как пистолет, стреляющий в любом направлении. Но когда я перемещаю C в его текущем состоянии, линия больше не соединяется с C. Я не уверен, почему это так.

open System

let [<Literal>] CharacterN = ConsoleKey.W
let [<Literal>] CharacterE = ConsoleKey.D
let [<Literal>] CharacterS = ConsoleKey.S
let [<Literal>] CharacterW = ConsoleKey.A

let [<Literal>] WeaponN = ConsoleKey.UpArrow
let [<Literal>] WeaponE = ConsoleKey.RightArrow
let [<Literal>] WeaponS = ConsoleKey.DownArrow
let [<Literal>] WeaponW = ConsoleKey.LeftArrow

type Point =
    { X : int
      Y : int }

let p1 = { X = 0; Y = 0 }
let p2 = { X = 10; Y = 10 }

let rec main p1 p2 =
    Console.Clear()

    let dx = min p1.X p2.X - max p1.X p2.X
    let dy = min p1.Y p2.Y - max p1.Y p2.Y

    for x in min p1.X p2.X .. max p1.X p2.X do
        let y = min p1.X p2.X + dy * (x - min p1.X p2.X) / dx
        Console.SetCursorPosition(x, y)
        printf "."

    Console.SetCursorPosition(p1.X, p1.Y)
    printf "C"

    Console.SetCursorPosition(p2.X, p2.Y)
    printf "W"

    match Console.ReadKey().Key with
    | CharacterN -> main { X = p1.X; Y = p1.Y - 1 } p2
    | CharacterE -> main { X = p1.X + 1; Y = p1.Y } p2
    | CharacterS -> main { X = p1.X; Y = p1.Y + 1 } p2
    | CharacterW -> main { X = p1.X - 1; Y = p1.Y } p2
    | WeaponN -> main p1 { X = p2.X; Y = p2.Y - 1 }
    | WeaponE -> main p1 { X = p2.X + 1; Y = p2.Y }
    | WeaponS -> main p1 { X = p2.X; Y = p2.Y + 1 }
    | WeaponW -> main p1 { X = p2.X - 1; Y = p2.Y }
    | _ -> ()

main p1 p2

Console.Read() |> ignore

1 Ответ

0 голосов
/ 19 января 2019

Я считаю, что есть несколько проблем с вашим кодом. Вероятно, наиболее важным является логика линии:

let y = min p1.X p2.X + dy * (x - min p1.X p2.X) / dx

Очевидно, это должно было быть что-то вроде

y = y0 + (x-x0)*dy/dx

т.е. первый термин должен быть чем-то вроде Y, а не X. К сожалению, с вашей логикой зацикливания это должна быть Y точки, которая имеет меньшую X. Это не так просто сказать. ИМХО, проще исправить цикл, используя отрицательный шаг.

Другое наивное предположение состоит в том, что вы всегда можете нарисовать линию, имеющую по y для каждого x. Это явно не так, когда dy > dx. Более того, в случае вертикальной линии, когда dx равен 0, код не будет выполнен. Самый популярный линейный алгоритм Брезенхама требует, чтобы вы обрабатывали эти случаи как явно отличающиеся. Вот простая реализация, которая обрабатывает эти случаи:

let drawLine p1 p2 = 
    let dx = p2.X - p1.X
    let dy = p2.Y - p1.Y
    if((dx <> 0) || (dy <> 0)) then
        if abs(dx) >= abs(dy) then
            let step = if (p1.X < p2.X) then 1 else -1
            for x in p1.X ..step.. p2.X do
                let y = p1.Y + dy * (x -  p1.X) / dx 
                Console.SetCursorPosition(x, y)
                printf "."
        else
            let step = if (p1.Y < p2.Y) then 1 else -1
            for y in p1.Y .. step .. p2.Y do
                let x = p1.X + dx * (y -  p1.Y) / dy
                Console.SetCursorPosition(x, y)
                printf "."

Что касается других вопросов, вы, вероятно, захотите ограничить позиции ваших точек какой-либо видимой областью между 0 и некоторым максимальным значением. SetCursorPosition вызов с отрицательным значением или значением, превышающим размер буфера, приведет к сбою приложения.

...