#graph #plane #2d #integer #geometry #game #2d-vector

gardiz

一个专注于游戏领域的二维平面整数几何库

2个版本

0.1.1 2021年10月30日
0.1.0 2021年8月9日

#2306 in 数据结构


用于andiskaz

自定义许可证

200KB
5.5K SLoC

gardiz

一个专注于游戏的二维整数几何库。支持泛型二维向量(作为实际向量、点或大小)、矩形、平面上点的数据映射、平面上点的集合、平面上点的简单图(可能是非平面图)。详见文档。

主分支文档

https://brunoczim.github.io/gardiz/gardiz/

特性

impl-serde

启用此功能可以使数据结构如Vec2Map实现serde序列化和反序列化特性。


lib.rs:

二维几何空间库(又称“平面”)。该库专注于整数几何,旨在用于离散二维游戏。

该库支持对二维泛型向量进行算术操作(包括点积和模长),这些向量可以表示点、大小、实际向量等。它还定义了平面中的“直线”基本方向(即上、左、下、右),使用轴作为索引和矩形。

它使用点作为键实现了专门的映射和集合。你可以将映射视为将数据与平面上的点关联起来,而集合可以被视为子平面的规范。两者都支持获取给定方向中的第一个或最后一个邻居。

最后,该库有简单的图,其顶点是平面上的点,并且它们可以连接(形成边)。这对于创建平面图(即没有边交叉)非常有用,但实现不会阻止你形成非平面图,尽管图仍然在二维平面上。图还实现了“A星”(或“A*”)算法,用于在两个点之间创建路径,仅使用给定区域(如果需要,则创建顶点)。

以下是一个A*算法的执行示例

use gardiz::{
    coord::Vec2,
    graph::Graph,
    direc::{Direction, DirecVector},
};
use std::collections::HashSet;

// `i64` is the type of the coordinate of the points.
let mut graph = Graph::<i64>::new();
// Initial and final points.
let start = Vec2 { x: -3, y: -3 };
let goal = Vec2 { x: 2, y: 4 };
graph.create_vertex(start);
graph.create_vertex(goal);

// Penalty whenever the path takes a turn.
let penalty = 2;

// Valid points to be used in the path.
let mut valid_points = HashSet::new();
for x in -3 .. 1 {
    for y in -3 .. 0 {
        valid_points.insert(Vec2 { x, y });
    }
}
for x in 0 .. 3 {
    for y in 0 .. 2 {
        valid_points.insert(Vec2 { x, y });
    }
}
for x in -1 .. 2 {
    for y in 2 .. 3 {
        valid_points.insert(Vec2 { x, y });
    }
}
for x in -2 .. 0 {
    for y in 3 .. 5 {
        valid_points.insert(Vec2 { x, y });
    }
}
for x in -3 .. 7 {
    for y in 5 .. 7 {
        valid_points.insert(Vec2 { x, y });
    }
}
for x in 1 .. 9 {
    for y in 4 .. 9 {
        valid_points.insert(Vec2 { x, y });
    }
}

// Cloning the graph before making the path (which will modify it).
let mut expected = graph.clone();

// Runs A*
let directions = graph.make_path(
    &start,
    &goal,
    &penalty,
    |point| valid_points.contains(&point)
);

// Checks whether the computed directions are correct.
assert_eq!(
    directions,
    Some(vec![
        // x = -3, y = -3
        DirecVector { direction: Direction::Right, magnitude: 3 },
        // x = 0, y = -3
        DirecVector { direction: Direction::Down, magnitude: 5 },
        // x = 0, y = 2
        DirecVector { direction: Direction::Left, magnitude: 1 },
        // x = -1, y = 2
        DirecVector { direction: Direction::Down, magnitude: 3 },
        // x = -1, y = 5
        DirecVector { direction: Direction::Right, magnitude: 3 },
        // x = 2, y = 5
        DirecVector { direction: Direction::Up, magnitude: 1 },
        // x = 2, y = 4
    ])
);

// Insert the vertices created when making the path.
expected.create_vertex(Vec2 { x: 0, y: -3 });
expected.create_vertex(Vec2 { x: 0, y: 2 });
expected.create_vertex(Vec2 { x: -1, y: 2 });
expected.create_vertex(Vec2 { x: -1, y: 5 });
expected.create_vertex(Vec2 { x: 2, y: 5 });

// Connect the vertices in the path.
expected
    .connect(Vec2 { x: -3, y: -3 }.as_ref(), Vec2 { x: 0, y: -3 }.as_ref());
expected
    .connect(Vec2 { x: 0, y: 2 }.as_ref(), Vec2 { x: 0, y: -3 }.as_ref());
expected
    .connect(Vec2 { x: 0, y: 2 }.as_ref(), Vec2 { x: -1, y: 2 }.as_ref());
expected
    .connect(Vec2 { x: -1, y: 5 }.as_ref(), Vec2 { x: -1, y: 2 }.as_ref());
expected
    .connect(Vec2 { x: -1, y: 5 }.as_ref(), Vec2 { x: 2, y: 5 }.as_ref());
expected
    .connect(Vec2 { x: 2, y: 4 }.as_ref(), Vec2 { x: 2, y: 5 }.as_ref());

// Test if the graph produced by `make_path` is the expected one we built.
assert_eq!(graph, expected);

依赖关系

~2MB
~31K SLoC