Code Monkey home page Code Monkey logo

Comments (25)

ManevilleF avatar ManevilleF commented on June 10, 2024 2

I want to remove the direction enums, not the direction concept.
I will open a PR next week and we will discuss what could be missing. I don't want to reduce the amount of features from hexx, only the confusion.
The point on the direction/angle is noted, I'll keep in mind to have iso functionality

from hexx.

alice-i-cecile avatar alice-i-cecile commented on June 10, 2024 1

I like that last solution: I think that this is a much clearer way to approach the fundamental problem being solved here without coupling as tightly to "what direction is the camera facing".

from hexx.

ManevilleF avatar ManevilleF commented on June 10, 2024 1

@dmlary @f-hoenix @asibahi Could you review #156 ? I think it's a good solution to the direction problem

from hexx.

dmlary avatar dmlary commented on June 10, 2024 1

@dmlary @f-hoenix @asibahi Could you review #156 ? I think it's a good solution to the direction problem

I’ve been trying to get to this, but won’t have time until this weekend. It’s still on my plate.

from hexx.

dmlary avatar dmlary commented on June 10, 2024

Bah, but even PointyDirection & FlatDirection wouldn't resolve the issue as Hex::all_neighbors() would need to know orientation to start at PointyDirection::East or FlatDirection::NorthEast because they have different coordinate changes.

from hexx.

ManevilleF avatar ManevilleF commented on June 10, 2024

I think the direction enum approach is not the way, I added it as a utility and a separate notion from Hex coordinates but ultimately it is confusing.
One solution could be to rename the variants in a more abstract way than cardinal directions, I tried finding different names without success.

Thank you for opening an issue, I've been thinking about it for some time now. #110 also had a direction related issue, so it will be my next priority.

@alice-i-cecile what do you think ?

from hexx.

dmlary avatar dmlary commented on June 10, 2024

I also haven't been able to come up with non-ambiguous names for each edge because of how much different they are. If you do them by angle (0tau/6, 1tau/6, 2tau/6, ...) does the angle refer to the middle of the edge, or the start of the edge?

Although, we know angle 0 is East, and East is (1,0) in pointy orientation. The equivalent direction (1,0) in flat orientation is SouthEast. That would mean if naming were based on angle, then in flat orientation the angle would refer to the counter-clockwise end of the edge. Horribly phrased, and probably even more confusing to visualize Direction::Zero in flat orientation goes SouthWest 😵‍💫.

This kind of leads me back to thinking splitting Direction into FlatDirection & PointyDirection makes sense, but perhaps it needs to bubble up to PointyHex and FlatHex with some sort of use hexx::pointy::*/use hexx::flat::* magic to allow for the use of Hex and Direction names.

This is the work-around I'm using for the moment just as an additional data point (below). I defined a PointyDirection enum and a Hex::pointy_neighbors() method. I am able to move forward using these, but the integration (PointyDirection::to_hex) isn't the smoothest.

/// Pointy orientation hex directions in east counter-clockwise order
#[repr(u8)]
#[derive(Debug, Clone, Copy, Default)]
pub enum PointyDirection {
    #[default]
    East = 0,
    NorthEast = 1,
    NorthWest = 2,
    West = 3,
    SouthWest = 4,
    SouthEast = 5,
}

impl HexDirection {
    pub fn to_hex(&self) -> hexx::Hex {
        match self {
            Self::East => hexx::Hex::new(1, 0),
            Self::NorthEast => hexx::Hex::new(1, -1),
            Self::NorthWest => hexx::Hex::new(0, -1),
            Self::West => hexx::Hex::new(-1, 0),
            Self::SouthWest => hexx::Hex::new(-1, 1),
            Self::SouthEast => hexx::Hex::new(0, 1),
        }
    }
}

// specialize the type of Direction we're using
pub type Direction = PointyDirection;

// add a trait so we can specify things on `Hex`
pub trait HexPointyDirections {
    fn pointy_neighbors(self) -> [(Direction, Hex); 6];
}

impl HexPointyDirections for Hex {
    // similar to all_neighbors(), but pointy and include direction
    fn pointy_neighbors(self) -> [(Direction, Hex); 6] {
        [
            // This can be switched to use `self + Direction::to_hex`
            (Direction::East, self + Hex::X),
            (Direction::NorthEast, self + Hex::new(1, -1)),
            (Direction::NorthWest, self + Hex::NEG_Y),
            (Direction::West, self + Hex::NEG_X),
            (Direction::SouthWest, self + Hex::new(-1, 1)),
            (Direction::SouthEast, self + Hex::Y),
        ]
    }
}

from hexx.

ManevilleF avatar ManevilleF commented on June 10, 2024

The thing is that the directions are identical no matter the orientation you are using. The orientation is purely for layout purposes, all arithmetic is the same either way, even the angles would be the same as they are relative to a purely virtual axis.

Therefore it would not be a good solution to duplicate the orientation concept in directions as it would become error prone, and redundant data-wise.

The confusion comes from the naming, and I even think that the enums should be entirely removed.
Just like in square grids, any coordinate can represent a point or a vector. Hex should be able (and is) to represent both.
The neighbours of the origin are the direction vectors already! But it's a bit harder to grasp because of the strangeness of the hexagonal coordinate system.

The fact than you can convert a direction to a coordinate vector is proof of the redundancy in my opinion.

I created the direction enums to represent wedges just like what the redblobgames article represents, but I think it was a naive implementation. I don't have the perfect solution in mind yet, but I think there is potential in some kind of normalize method which could transform any coordinate to its "unit" wedge direction vector.
Therefore we could easily identify directions, don't be confused by naming them, and "reduce" coordinates to their wedge vector.
What would you think about such a solution ?

from hexx.

dmlary avatar dmlary commented on June 10, 2024

So I keep coming back to this. It seems like the simple solution to just remove the concept of Direction from hexx is the right answer, but does that actually remove the need for Direction in projects using hexx?

If it doesn’t, removing Direction means projects need to implement their own Direction, which will be largely similar across all of the projects.

I’m hung up on trying to determine common scenarios where direction is needed.

I know for my use case, I absolutely need direction as I’m doing non-Euclidean tricks so each cell has a set of exits ordered by direction. This is an edge case that most people won’t need.

One possibly common situation is napping dual-axis input into a hex movement direction. Actually I think even if we remove direction this scenario has the same problem when using vectors.

What vector does 15 degrees map to? The answer is different if you’re pointy oriented or flat.

(edited 31 to 15 because it’s a better example)

from hexx.

asibahi avatar asibahi commented on June 10, 2024

Re: The direction enum naming. My personal use for the Direction enum was for a Depth First Search where I needed to keep going "forward". (Here is the untested code )

the same functionality could've been gained by 6 constants in the Hex struct. You can rotate them just fine with the existing functionality in Hex, but you don't need the enum for that.

Which brings me to the X, Y etc constants in Hex, which are perplexing to use tbh, and their utility isn't clear to me, (especially that Z is defined as Neg_Y). My idea of a better naming scheme for directions, independently of cardinal directions, is to mark which coordinate is stationary and which is increasing (out of X, Y, Z).

So the direction currently marked with:

  • X, (1, 0) would be YX to indicate Y doesn't change but X increases
  • Neg_X (-1, 0) would be YZ
  • Y (0, 1) would be XY
  • Neg_Y (0, -1) would be XZ

Which leaves

  • (1, -1) as ZX
  • (-1, 1) as ZY.

just an idea.

from hexx.

ManevilleF avatar ManevilleF commented on June 10, 2024

Re: The direction enum naming. My personal use for the Direction enum was for a Depth First Search where I needed to keep going "forward". (Here is the untested code )

the same functionality could've been gained by 6 constants in the Hex struct. You can rotate them just fine with the existing functionality in Hex, but you don't need the enum for that.

I agree that the enum is not very useful in that case (You can also rotate the Hex coordinate), but I didn't find a better way to represent non zero normalized directions because of the Diagonal Directions, which are quite tricky and also have specific features like finding the adjacent directions and vice versa.

There are two solutions I think:

  • Either remove the enums and have an other way to represent unit directions and diagonal directions (maybe a wrapper, through some Hex::normalize_to_dir and Hex::nornalize_to_diag methods)
  • Rename the enums to remove the subjective directional language

Maybe something like

XNegY, // (1, -1)
NegY, // (0, -1)
NegX, // (-1, 0)
NegXY // (-1, 1)
Y // (0, 1)
X // (1, 0)

But I'm not sure if it's really more clear this way anyway

Which brings me to the X, Y etc constants in Hex, which are perplexing to use tbh, and their utility isn't clear to me, (especially that Z is defined as Neg_Y). My idea of a better naming scheme for directions, independently of cardinal directions, is to mark which coordinate is stationary and which is increasing (out of X, Y, Z).

So the direction currently marked with:

* `X`, (1, 0) would be `YX` to indicate `Y` doesn't change but `X` increases

* `Neg_X` (-1, 0) would be `YZ`

* `Y` (0, 1) would be `XY`

* `Neg_Y` (0, -1) would be `XZ`

Which leaves

* (1, -1) as `ZX`

* (-1, 1) as `ZY`.

just an idea.

The const values are indeed not very clear, should Hex::X represent the x axis or a unity vector increasing X, same for Y and Z. Which bring the Z issue, which can be represented by different vectors to increase or decrease in the Z axis.

from hexx.

lishaoxia1985 avatar lishaoxia1985 commented on June 10, 2024

You should consider the edges and corners directions of Hex, sometimes we want to get the position of corners.
If you research this, you will find:
The edge directions of pointy hex are the corners direction of flat hex.
Because of this, we can define the enum of Direction contains 8 direction. And define 2 array [Direction; 6], they can be used for pointy and flat hex's edges and corners, respectively.

from hexx.

ManevilleF avatar ManevilleF commented on June 10, 2024

You should consider the edges and corners directions of Hex, sometimes we want to get the position of corners. If you research this, you will find: The edge directions of pointy hex are the corners direction of flat hex. Because of this, we can define the enum of Direction contains 8 direction. And define 2 array [Direction; 6], they can be used for pointy and flat hex's edges and corners, respectively.

In world space it is indeed correct, but Hex coordinates and directions are the same in either pointy or flat orientation. The arithmetic is identic, it's just the world/pixel representation that changes.
This confusion is why the current enums are a problem as they represent cardinal directions and not what they should represent: Hex unit vectors

from hexx.

lishaoxia1985 avatar lishaoxia1985 commented on June 10, 2024

OK, if you delete the enum Direction, replace Direction with (X, Y...), my suggestion is:

  1. if X is related to Pointy hex's Top angel and Flat hex's edge, you should write the necessary comments with "///".
  2. Implement the enum Direction in example code, it will help someone who want to implement the Direction by himself.

from hexx.

ManevilleF avatar ManevilleF commented on June 10, 2024

I'm still not sure what the ideal solution is, but I won't remove the directions, they may not be an enum anymore but the feature will stay. But tbh I'm not sure what is the best way to handle this in a good way, all solutions I mentioned in this issue have flaws

from hexx.

dmlary avatar dmlary commented on June 10, 2024

Yea, having DiagonalDirection for pointy orientation does seem like the best available solution. Users of the crate can type alias whichever one they need to Direction.

from hexx.

ManevilleF avatar ManevilleF commented on June 10, 2024

Yea, having DiagonalDirection for pointy orientation does seem like the best available solution. Users of the crate can type alias whichever one they need to Direction.

What do you mean ? DiagonalDirection is not related to orientation

from hexx.

dmlary avatar dmlary commented on June 10, 2024

Ah, I misread the diff on #144 when it closed this issue. Thought you just broke out a second enum for pointy directions and just used an odd name.

from hexx.

ManevilleF avatar ManevilleF commented on June 10, 2024

Aha no, I still haven't figured out a good new approach for the direction enums, they are such a useful abstraction over Hex. So I justed added some expressive const values that might be useful until then

from hexx.

f-hoenix avatar f-hoenix commented on June 10, 2024

If I might suggest: the current Directions are confusing because they depend on the layout too much while being too generic in their use.
Moving them behind the layout whould IMO solve this issue and provide a very useful api.

Rough attempt usign traits (I haven't found a convincing way to nest const):

trait GridLayout {
    fn get_north_offset(&self) -> Option<Hex>;
}

struct PointyLayout;
impl GridLayout for PointyLayout {
    fn get_north_offset(&self) -> Option<Hex> {
        None
    }
}

struct FlatLayout;
impl GridLayout for FlatLayout {
    fn get_north_offset(&self) -> Option<Hex> {
        Some(hex(0, 0))
    }
}

impl Hex {
    fn get_north(&self, layout: &dyn GridLayout) -> Option<Hex> {
        if let Some(offset) = layout.get_north_offset() {
            Some(offset + *self)
        }
        None
    }
}

This opens a lot of useful access to other coordinates too : diagonal neighbors, edges, vertexes, ...

from hexx.

ManevilleF avatar ManevilleF commented on June 10, 2024

Direction and orientation are unrelated, the naming of the direction variants is confusing

from hexx.

f-hoenix avatar f-hoenix commented on June 10, 2024

Not entirely sure I get what you mean, it would seem that cardinal points and grid orientation are dependent ?
'Going north' in Flat means following the [(0,0) ; (0,-1)] vector
'Going north' in Pointy means following the [(0,0) ; (+1,-2)] vector

from hexx.

ManevilleF avatar ManevilleF commented on June 10, 2024

Pointy and flat orientation is a purely visual concept, meaning a 30 degrees rotation.
Coordinate wise there is no impact. You can check the documentation for Direction and DiagonalDirection for more details.

This issue is about finding another way to represent directions, without cardinal names which create this confusion

from hexx.

f-hoenix avatar f-hoenix commented on June 10, 2024

I agree with the coordinates being orientation-agnostic yes

My suggestion was indeed not on the main issue here (the way to represent directions) but rather a way to keep the cardinal names (which can be useful in some circumstances) by having an explicit dependancy on orientation, as an alternative to entirely removing them like you mentioned

from hexx.

ManevilleF avatar ManevilleF commented on June 10, 2024

We can always add orientation specific cardinal constants

from hexx.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.