algorithm - 如何使用带最小值/最大值的画线算法? F#

标签 algorithm f# line point

如果这个问题不适合这个网站,我很抱歉,但我不知道还有什么地方可以问。我很困惑,我使用 min 和 max 我相信是正确的。当我用箭头键移动武器时,当它向右或向下移动时,这条线似乎可以找到。如果有人知道如何修复它或只是让我走上正轨,我将不胜感激。对于任何感兴趣的人,我正在为一个游戏创建这个程序,我需要武器的视线。

编辑:

我正在尝试实现一种状态,我可以使用 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

最佳答案

我认为您的代码有几个问题。可能最重要的一个是行的逻辑:

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

显然它应该是这样的

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

即第一个术语应该是关于 Y 而不是 X 的东西。不幸的是,对于您的循环逻辑,它应该是具有较小 X 的点的 Y。说起来没那么容易。恕我直言,使用负步更容易修复循环。

另一个天真的假设是,您总是可以画一条线,因为每个 x 都有一些 ydy > dx 时显然不是这样。此外,当dx0 时出现垂直线,代码将失败。最受欢迎Bresenham's line algorithm要求您将这些情况视为明显不同。这是处理这些情况的简单实现:

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 会使您的应用崩溃。

关于algorithm - 如何使用带最小值/最大值的画线算法? F#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54261302/

相关文章:

php - 移除 Switch 语句

java - 如何构造我的程序以返回递归函数的成功输出?

inheritance - 受歧视的工会和继承

f# - 将捕获构造函数参数的闭包传递给基类构造函数

f# - 如何在 F# 中实现 “efficient generalized fold”?

c++ - Qt 代码编辑器在右侧区域显示行号

java - 使用缓存的斐波那契数列

c# - 查找列表中的元素并获取前面的元素(两者都需要快速)

javascript - 如何在 THREE.js 中克隆 Line 对象的 Mesh?

java - OpenGL 线条在屏幕中间相交而不是直线