简体   繁体   English

如何使用最小/最大的行拖曳算法? F#

[英]How to use a line draiwng algorithm with min/max? F#

Sorry if this question is not suited for this site, but I don't know where else too ask it. 抱歉,这个问题不适合该网站,但我不知道在哪里也要问这个问题。 I'm pretty confused, I use min and max I believe correctly. 我很困惑,我使用最小和最大我相信正确。 When I move the weapon with arrow keys the line seem to works find when its moving right or down. 当我使用箭头键移动武器时,在向右或向下移动时似乎可以找到该线。 If anybody knows how to fix it or just put me on the right track I'd greatly appreciate it. 如果有人知道如何解决它,或者只是把我放在正确的轨道上,我将不胜感激。 For anyone interested I am creating this program for a game which I need a line of sight in for the weapon. 对于有兴趣的人,我正在为一个游戏创建该程序,我需要将视线对准武器。

EDIT: 编辑:

I am trying to achieve a state where I can use w,a,s,d keys to move the C (character) and arrow keys to move W (weapon). 我试图达到一种状态,可以使用w,a,s,d键移动C(字符),使用箭头键移动W(武器)。 Eventually when I add enemies the line between the character and weapon will be used to see if they are in range to be attacked. 最终,当我添加敌人时,角色和武器之间的界线将用于查看它们是否在要攻击的范围内。 Like a gun shooting in any direction. 就像用枪向任何方向射击一样。 But when I move C in it's current state the line does not connect to C anymore. 但是,当我将C移到当前状态时,该线不再与C连接。 I'm not sure why this is. 我不确定为什么会这样。

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

I believe that are several issues with your code. 我相信这是您的代码的几个问题。 Probably the most important one is in the logic of the line: 可能最重要的是该行的逻辑:

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

Obviously it should have been something like 显然应该是这样的

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

ie the first term shuold be something about Y rather than X . 即,第一项shuold应该是关于Y而不是X东西。 Unfortunately with your looping logic it should be the Y of the point that has the smaller X . 不幸的是,根据您的循环逻辑,它应该是X较小的点的Y It is not that easy to say that. 这么说并不容易。 IMHO it is easier to fix looping using negative step. 恕我直言,使用负步更容易修复循环。

Another naive assumption is that you can always draw a line as having some y for each x . 另一种天真的假设是,你总是可以画一条线具有一些y每个x This is obviously not so when dy > dx . dy > dx时显然不是这样。 Moreover in case of a vertical line when dx is 0 , the code will fail. 此外,当dx0时出现垂直线时,代码将失败。 The most most popular Bresenham's line algorithm requires you to handle those cases as explicitly different. 最流行的布雷森汉姆线算法要求您将这些情况处理为明显不同。 Here is a simple implementation that handle those cases: 这是处理这些情况的简单实现:

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 "."

As for other issues, you probably want to restrict positions of your points to some visible area between 0 and some max value. 至于其他问题,您可能希望将点的位置限制在0到某个最大值之间的某个可见区域。 SetCursorPosition call with a negative value or a value larger than the buffer size will crash your app. 负值或大于缓冲区大小的SetCursorPosition调用将使您的应用程序崩溃。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM