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
所以它是true
a.x
小于b.x
因此它是false
a
的长度大于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 形状模块