1
\$\begingroup\$

I'm working on an open source game for 2 years but I'm very bad at math. The game permits moving a character on an octagonal basis. When the character reaches the border coordinate (colored in yellow), I permit him to travel to another octagon:

enter image description here

The map is a simple 2d array of x, y coordinates. The goal is to know if an x, y tile coordinate is on a "yellow" tile, and which direction it represents (north, northeast, east etc.) depending on map width and height.

I wrote this algorithm many times and in two different language, example with Rust:

pub fn get_corner(width: i16, height: i16, new_row_i: i16, new_col_i: i16) -> Option<CornerEnum> {
    let left_col_i_end = width / 3;
    let right_col_i_start = (width / 3) * 2;
    let top_row_i_end = height / 3;
    let bottom_row_i_start = (height / 3) * 2;
    let mut more = if new_row_i >= 0 { new_row_i } else { 0 };
    #[allow(unused_assignments)]
    let mut right_col_i = 0;
    #[allow(unused_assignments)]
    let mut left_col_i = 0;

    if new_row_i < top_row_i_end {
        right_col_i = right_col_i_start + more;
        left_col_i = left_col_i_end - more;
    } else {
        if new_row_i >= bottom_row_i_start {
            more = (height / 3) - (new_row_i - bottom_row_i_start + 1);
            more = if more >= 0 { more } else { 0 };
            right_col_i = right_col_i_start + more;
            left_col_i = left_col_i_end - more;
        } else {
            left_col_i = left_col_i_end;
            right_col_i = right_col_i_start;
        }
    }

    if new_col_i < left_col_i && new_row_i < top_row_i_end {
        return Some(CornerEnum::TopLeft);
    }
    if new_row_i < 0 && left_col_i <= new_col_i {
        return Some(CornerEnum::Top);
    }
    if new_col_i >= right_col_i && new_row_i < top_row_i_end {
        return Some(CornerEnum::TopRight);
    }
    if new_col_i > width - 1 && top_row_i_end <= new_row_i {
        return Some(CornerEnum::Right);
    }
    if new_col_i >= right_col_i && new_row_i >= bottom_row_i_start {
        return Some(CornerEnum::BottomRight);
    }
    if new_row_i > height - 1 && left_col_i_end <= new_col_i {
        return Some(CornerEnum::Bottom);
    }
    if new_col_i < left_col_i && new_row_i >= bottom_row_i_start {
        return Some(CornerEnum::BottomLeft);
    }
    if new_col_i < 0 && top_row_i_end <= new_row_i {
        return Some(CornerEnum::Left);
    }

    None
}

But it is not working too well: it works only for some borders, but not for others, apparently depending on width/height odd/even... I curse my math. I'm sure it's not that complicated but I've failed for two years. So, I'm here to ask for a solution... which would be greatly appreciated!

\$\endgroup\$
  • 1
    \$\begingroup\$ Remember, we have never seen your game before. Be more explicit about how it is not working... telling us that "it's not working well" is not very helpful to us, and thus not helpful to you, if you want answers. \$\endgroup\$ – Engineer May 22 at 15:10
  • \$\begingroup\$ Hello Enginneer. I just add some detail in question. Thanks for you remark. \$\endgroup\$ – bux May 23 at 11:30
  • \$\begingroup\$ Hello @bux. You're welcome. I have also edited your grammar to make it easier to read. Please check using a translator that I have not changed your meaning! \$\endgroup\$ – Engineer May 23 at 15:15
1
+50
\$\begingroup\$

I assume you are storing map information in some kind of 2D array or something similar where you can easily check neighboring tile information. Any border tile will be missing at least 1 neighbor. You can then tell what direction based on which neighbors are missing, for example if you are missing neighbor tiles to the south and west you know it is the south-west border. If you are missing a neighbor to the north only then it is the north border, etc. This should work for an octagon no matter what size. Hope this helps.

Edit: The corner tiles between directions may require special edge case logic because you could classify them in two directions potentially (as pointed out by Zibelas below). Depends on how you would classify those, but you can see any corner tile always has two missing neighbors. So any tile with two missing neighbors you should check to see if it has a neighboring border tile and if so use that tile's direction instead.

Also when I say neighbor, I mean only to the west/east/north/south, not diagonally.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ From his picture, the most left and right tiles of the north border would be according to your logic than north-west and east when I guess they should be just north (but they have each two missing tiles) \$\endgroup\$ – Zibelas May 22 at 17:50
  • \$\begingroup\$ Ah yes I neglected the corner points, thanks for pointing it out. I guess it depends on how he wants to classify those corner points but I will edit the answer to specify that. \$\endgroup\$ – twitchturk May 22 at 18:13
  • \$\begingroup\$ Hello, this is a very good idea ! I will implement it in next days and give you the result ! \$\endgroup\$ – bux May 23 at 11:32
  • \$\begingroup\$ And this is working ! github.com/buxx/rollgui/blob/… Thanks a lot for your idea \$\endgroup\$ – bux May 23 at 20:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.