user7530757
user7530757

Reputation:

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

Upvotes: 0

Views: 59

Answers (1)

SergGr
SergGr

Reputation: 23788

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

i.e. the first term shuold be something about Y rather than X. Unfortunately with your looping logic it should be the Y of the point that has the smaller X. 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. This is obviously not so when dy > dx. Moreover in case of a vertical line when dx is 0, the code will fail. 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. SetCursorPosition call with a negative value or a value larger than the buffer size will crash your app.

Upvotes: 1

Related Questions