Crate hexx

Source
Expand description

Hexagonal tools lib in rust.

Inspired by this RedBlobGames article and Sander Evers work

This lib allows you to:

  • Manipulate hexagon coordinates
  • Generate hexagonal maps with custom layouts and orientation
  • Generate hexagon meshes (planes or columns)

I made the choice to use Axial Coordinates for performance and utility reasons, but the Hex type has conversion utilities with cubic, doubled, hexmod and offset coordinates.

See the hexagonal coordinate systems

§Installation

Run cargo add hexx in your project or add the following line to your Cargo.toml:

  • hexx = "0.20"

§Cargo features

hexx supports serialization and deserialization of most types using serde, through the serde feature gate. To enable it add the following line to your Cargo.toml:

  • hexx = { version = "0.20", features = ["serde"] }

By default Hex uses rust classic memory layout, if you want to use hexx through the FFI or have Hex be stored without any memory padding, the packed feature will make Hex repr(C). To enable this behaviour add the following line to your Cargo.toml:

  • hexx = { version = "0.20", features = ["packed"] }

hexx supports Bevy Reflection through the bevy_reflect feature. To enable it add the following line to your Cargo.toml:

  • hexx = { version = "0.20", features = ["bevy_reflect"] }

hexx supports Face/Vertex/Edge grid handling using Hex as Face, GridVertex as vertex and GridEdge as edge. To enable it add the following line to your Cargo.toml:

  • hexx = { version = "0.20", features = ["grid"] }

§Features

hexx provides the Hex coordinates with:

  • Distances
  • Neighbors and directions
  • Lines
  • Ranges
  • Rings
  • Edges
  • Wedges
  • Spirals
  • Rotation
  • Symmetry
  • Vector operations
  • Conversions to other coordinate systems:
    • Cubic coordinates
    • Offset coordinates
    • Doubled coordinates
    • Hexmod coordinates
  • Multiple hex resolution

§Basic usage

 use hexx::*;

 // Declare points in hexagonal spaces
 let point_a = hex(10, -5); // Equivalent of `Hex::new(10, -5)`
 let point_b = hex(-8, 15);
 // Find distance between them
 let dist = point_a.unsigned_distance_to(point_b);
 // Compute a line between points
 let line: Vec<Hex> = point_a.line_to(point_b).collect();
 // Compute a ring from `point_a` containing `point_b`
 let ring: Vec<Hex> = point_a.ring(dist).collect();
 // Rotate `point_b` around `point_a` by 2 times 60 degrees clockwise
 let rotated = point_b.rotate_cw_around(point_a, 2);
 // Find the direction between the two points
 let dir_a = point_a.main_direction_to(point_b);
 let dir_b = point_b.main_direction_to(point_a);
 assert!(dir_a == -dir_b);
 // Compute a wedge from `point_a` to `point_b`
 let wedge = point_a.wedge_to(point_b);
 // Get the average value of the wedge
 let avg = wedge.average();

§Layout usage

HexLayout is the bridge between your world/screen/pixel coordinate system and the hexagonal coordinates system.

 use hexx::*;

 // Define your layout
 let layout = HexLayout {
     scale: Vec2::new(1.0, 1.0),
     orientation: HexOrientation::Flat,
     ..Default::default()
 };
 // Get the hex coordinate at the world position `world_pos`.
 let world_pos = Vec2::new(53.52, 189.28);
 let point = layout.world_pos_to_hex(world_pos);
 // Get the world position of `point`
 let point = hex(123, 45);
 let world_pos = layout.hex_to_world_pos(point);

§Wrapping

HexBounds defines a bounding hexagon around a center coordinate. It can be used for boundary and interesection checks but also for wrapping coordinates. Coordinate wrapping transform a point outside of the bounds to a point inside. This allows for seamless or repeating wraparound maps.

use hexx::*;

let center = hex(23, -45);
let radius = 5;
let bounds = HexBounds::new(center, radius);
let outside_coord = hex(12345, 98765);
assert!(!bounds.is_in_bounds(outside_coord));
let wrapped_coord = bounds.wrap(outside_coord);
assert!(bounds.is_in_bounds(wrapped_coord));

§Resolutions and chunks

Hex support multi-resolution coordinates. In practice this means that you may convert a coordinate to a different resolution:

  • To a lower resolution, meaning retrieving a parent coordinate
  • to a higher resolution, meaning retrieving the center child coordinate

Resolutions are abstract, the only useful information is the resolution radius.

For example, if you use a big grid, with a radius of a 100, you might want to split that grid evenly in larger hexagons containing a 10 radius of coordinates and maybe do operations locally inside of these chunks.

So instead of using a big range directly:

use hexx::*;

const MAP_RADIUS: u32 = 100;

// Our big grid with hundreds of hexagons
let big_grid = Hex::ZERO.range(MAP_RADIUS);

You may define a smaller grid you will then divide to a higher resolution

use hexx::*;

const CHUNK_RADIUS: u32 = 10;
const MAP_RADIUS: u32 = 20;

let chunks = Hex::ZERO.range(MAP_RADIUS);
for chunk in chunks {
    // We can retrieve the center of that chunk by increasing the resolution
    let center = chunk.to_higher_res(CHUNK_RADIUS);
    // And retrieve the other coordinates in the chunk
    let children = center.range(CHUNK_RADIUS);
    // We can retrieve the chunk coordinates from any coordinate..
    for coord in children {
        // .. by reducing the resolution
        assert_eq!(coord.to_lower_res(CHUNK_RADIUS), chunk);
    }
}

An other usage could be to draw an infinite hex grid, with different resolutions displayed, dynamically changing according to user zoom level.

§Dense map storage

Hex implements Hash, and most users store hexagonal maps in a HashMap. But for some cases hexx provides dense storage collections with more performant accessors:

§Procedural meshes

hexx provides 3 built-in procedural mesh construction utilies:

All those builders have a lot of customization options and will output a MeshInfo struct containing vertex positions, normals and uvs

§Usage in Bevy

If you want to integrate the procedural meshes in bevy you may do it this way:

 use bevy::{
     prelude::Mesh,
     render::{
         mesh::Indices, render_asset::RenderAssetUsages, render_resource::PrimitiveTopology,
     },
 };
 use hexx::MeshInfo;

 pub fn hexagonal_mesh(mesh_info: MeshInfo) -> Mesh {
     Mesh::new(
         PrimitiveTopology::TriangleList,
         // Means you won't interact with the mesh on the CPU afterwards
         // Check bevy docs for more information
         RenderAssetUsages::RENDER_WORLD,
     )
     .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, mesh_info.vertices)
     .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, mesh_info.normals)
     .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, mesh_info.uvs)
     .with_inserted_indices(Indices::U16(mesh_info.indices))
 }

Re-exports§

pub use mesh::*;

Modules§

algorithms
Non exhaustive collection of classic algorithms.
angles
Angle constants used for directions
bounds
Hexagonal range bounds module
conversions
Hexagonal coordinates conversion module
direction
Hexagonal directions module
hex
Hexagonal coordinates module
layout
Hexagonal layout module
mesh
Mesh generation utils module
orientation
Hexagon oritentation module
shapes
Map shapes generation functions
storage
Optimized storage module inspired by this article

Structs§

EdgeDirection
All 6 possible neighbor/edge directions in hexagonal space.
GridEdge
Hexagonal grid orientated edge representation
GridVertex
Hexagonal grid orientated vertex representation.
Hex
Hexagonal axial coordinates
HexBounds
Hexagonal bounds utils, represented as a center and radius. This type can be defined manually or from a Hex iterator.
HexLayout
Hexagonal layout. This type is the bridge between your world/pixel coordinate system and the hexagonal coordinate system.
VertexDirection
All 6 possible diagonal/vertex directions in hexagonal space.

Enums§

DirectionWay
Describes a direction way, which can be a Single direction or a Tie betwen two directions.
DoubledHexMode
Layout mode for doubled coordinates conversion. See Hex::to_doubled_coordinates and Hex::from_doubled_coordinates.
HexOrientation
Hexagonal orientation, either Pointy-Topped or Flat-Topped
OffsetHexMode
Layout mode for offset coordinates conversion. See Hex::to_offset_coordinates and Hex::from_offset_coordinates.

Traits§

HexIterExt
Extension trait for iterators of Hex

Functions§

hex
Instantiates a new hexagon from axial coordinates