25 个版本 (16 个破坏性版本)
| 0.17.0 | 2024 年 4 月 15 日 |
|---|---|
| 0.16.1 | 2024 年 3 月 28 日 |
| 0.15.0 | 2024 年 2 月 21 日 |
| 0.12.0 | 2023 年 11 月 30 日 |
| 0.5.3 | 2023 年 3 月 26 日 |
#60 in 游戏开发
每月 213 次下载
在 2 个存储库中使用 (通过 lettuces)
5.5MB
5K SLoC
Rust 的六边形工具库。
受此
RedBlobGames文章 和 Sander Evers 的工作启发
此库允许您
- 操作六边形坐标
- 生成具有自定义布局和方向的六边形地图
- 生成六边形网格(平面或列)
出于性能和实用性的原因,我选择了使用 轴向坐标,但 Hex 类型具有与 立方、双倍、hexmod 和 偏移 坐标的转换工具。
参见 六边形坐标系
安装
在您的项目中运行 cargo add hexx 或将以下行添加到您的 Cargo.toml
hexx= "0.17"
Cargo 功能
hexx 支持使用 serde 对大多数类型的序列化和反序列化,通过 serde 功能门。要启用它,请将以下行添加到您的 Cargo.toml
hexx= {version= "0.17",features= ["serde"] }
默认情况下,Hex 使用 Rust 经典内存布局,如果您想通过 FFI 使用 hexx 或希望 Hex 无任何内存填充存储,则 packed 功能会将 Hex repr(C)。要启用此行为,请将以下行添加到您的 Cargo.toml
hexx= {version= "0.17",features= ["packed"] }
hexx 通过 bevy_reflect 功能支持 Bevy Reflection。要启用它,请将以下行添加到您的 Cargo.toml
hexx= {version= "0.17",features= ["bevy_reflect"] }
hexx支持使用Hex作为面、GridVertex作为顶点和GridEdge作为边来处理Face/Vertex/Edge网格。要启用它,请将以下行添加到您的Cargo.toml
hexx= {version= "0.17",features= ["网格"] }
功能
hexx提供带有以下内容的Hex坐标
- 距离
- 邻居和方向
- 线
- 范围
- 环
- 边
- 楔
- 螺旋
- 旋转
- 对称性
- 向量操作
- 转换为其他坐标系
- 立方坐标
- 偏移坐标
- 双倍坐标
- Hexmod坐标
- 多分辨率
基本用法
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();
布局用法
HexLayout是您的世界/屏幕/像素坐标系和六边形坐标系之间的桥梁。
use hexx::*;
// Define your layout
let layout = HexLayout {
hex_size: 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);
包装
HexBounds定义了围绕中心坐标的边界六边形。它可以用于边界和交叉检查,也可以用于包装坐标。坐标包装将点转换为边界内的点。这允许无缝或重复包装地图。
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));
分辨率和块
Hex支持多分辨率坐标。在实践中,这意味着您可以转换坐标到不同的分辨率
- 到较低的分辨率,即获取父坐标
- 到较高的分辨率,即获取中心子坐标
分辨率是抽象的,唯一有用的信息是分辨率<强>半径强>。
例如,如果您使用一个大网格,半径为100,您可能希望将网格均匀分割成包含10个半径坐标的大六边形,并可能在这些块内进行本地操作。
因此,您可以直接使用一个大范围
use hexx::*;
const MAP_RADIUS: u32 = 100;
// Our big grid with hundreds of hexagons
let big_grid = Hex::ZERO.range(MAP_RADIUS);
您可能定义一个较小的网格,然后将它分割到更高的分辨率
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);
}
}
另一种用法可能是绘制一个无限六边形网格,显示不同分辨率,根据用户缩放级别动态更改。
在Bevy中的使用
如果您想在bevy中生成3D六边形网格并使用它,您可以这样做
use bevy::{
prelude::Mesh,
render::{
mesh::Indices, render_asset::RenderAssetUsages, render_resource::PrimitiveTopology,
},
};
use hexx::MeshInfo;
pub fn hexagonal_plane(mesh_info: MeshInfo) -> Mesh {
Mesh::new(
PrimitiveTopology::TriangleList,
// Means you won't edit the mesh 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))
}
MeshInfo可以从PlaneMeshBuilder或ColumnMeshBuilder生成。
有关bevy使用的示例,请参阅示例
问答
为什么不在
PartialOrd, Ord上派生?
将这些特质添加到Hex意味着要定义一个绝对规则来解决这个问题
let a = hex(-10, 20);
let b = hex(1, 2);
a > b
根据您如何看待这个问题,至少有3种可能的规则
a.y大于b.y所以它是truea.x小于b.x因此它是falsea的长度大于b的长度,所以它是true
如果我想要在
BtreeMap、BTreeSet或BinaryHeap中使用它怎么办?
使用带有 Ord 和 PartialOrd 特性的包装器。您可以复制并粘贴以下代码片段到您的项目中
/// [`Ordering`] wrapper around [`Hex`], comparing [`Hex::y`] then [`Hex::x`].
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OrdByYX(pub Hex);
impl Ord for OrdByYX {
fn cmp(&self, other: &Self) -> Ordering {
self.0.y.cmp(&other.0.y).then(self.0.x.cmp(&other.0.x))
}
}
impl PartialOrd for OrdByYX {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
示例
hexx 提供了展示各种功能的交互式示例
六边形网格

cargo运行 --示例hex_grid
此示例展示了六边形范围、环、楔形、旋转和线条
六边形区域

cargo运行 --示例hex_area
此示例展示了如何使用网格工具和组件生成六边形区域,以及如何在同一网格上使用两种布局。
滚动地图

cargo运行 --示例scroll_map
此示例展示了用于滚动地图的 HexMap 结构
包装地图

cargo运行 --示例wrap_map
此示例展示了用于循环/包装地图的 HexMap 结构
A 星路径查找

cargo运行 --示例a_star
此示例展示了 A 星算法,您可以通过交互式路径查找在起点和光标之间进行路径查找。点击图块可以切换其可用性
视野

cargo运行 --示例field_of_view
此示例展示了视野算法,展示了围绕光标的交互式范围视野。点击图块可以切换其可见性。
移动区域

cargo运行 --示例field_of_movement
此示例展示了移动区域算法,交互式显示光标周围的可用移动范围。
3d 列

cargo运行 --示例3d_columns
此示例展示了 3d 六边形列的生成
网格构建器

cargo运行 --示例mesh_builder --featuresbevy_reflect
此示例展示了如何使用网格构建器定制六边形列的生成
块

cargo运行 --示例chunks
此示例展示了六边形分辨率系统,允许在均匀大小的块中进行瓦片坐标
合并块

cargo运行 --示例merged_columns --featuresbevy_reflect
此示例展示了如何构建一个简单的六边形块系统,每个块都是一个单独的网格
精灵图集
![]()
cargo运行 --示例sprite_sheet
此示例展示了如何使用 hexx 与 2D 精灵图集
形状

cargo运行 --示例shapes --featuresbevy_reflect
此示例展示了如何使用 hexx 形状模块