Skip to content

Commit

Permalink
avian support (#41)
Browse files Browse the repository at this point in the history
* avian2d support

* make the avian2d example nicer

* support avian 3d

* support many colors of gizmos debug

* fix gizmo debugging

* clippy

* more clippy

* add tests on features

* flag some items

* simplify website build

* update screenshots

* fix CI deploy job

* cleanup html

* fit to canvas in wasm

* fix plugin

* 🤦

* remove unused import

* build and deploy in separate tasks

* set dependency
  • Loading branch information
mockersf authored Aug 1, 2024
1 parent 3d4c78a commit d5ead6e
Show file tree
Hide file tree
Showing 33 changed files with 1,023 additions and 328 deletions.
19 changes: 18 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,25 @@ jobs:

- name: Run clippy
run: |
cargo clippy -- -D warnings
cargo clippy --all-features -- -D warnings
checks:
name: Checks
strategy:
matrix:
features: ["--no-default-features", "--features avian2d", "--features avian3d", "--features debug-with-gizmos"]
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Install stable toolchain
uses: dtolnay/rust-toolchain@stable

- name: Run clippy
run: |
cargo check ${{ matrix.features }}
tests:
name: Tests
runs-on: ubuntu-latest
Expand Down
54 changes: 23 additions & 31 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ permissions:
id-token: write

jobs:
deploy:
build:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
Expand All @@ -23,45 +23,30 @@ jobs:
with:
target: wasm32-unknown-unknown

- name: Install wasm-bindgen
- name: install tools
run: |
cargo install cargo-quickinstall
cargo quickinstall wasm-bindgen-cli
cargo install wasm-bindgen-cli
sudo apt-get install -y binaryen
- name: Build
run: |
cargo build --target wasm32-unknown-unknown --release --example moving --features bevy/webgl2
wasm-bindgen --no-typescript --out-dir wasm --target web target/wasm32-unknown-unknown/release/examples/moving.wasm
cargo build --target wasm32-unknown-unknown --release --example lines --features bevy/webgl2
wasm-bindgen --no-typescript --out-dir wasm --target web target/wasm32-unknown-unknown/release/examples/lines.wasm
cargo build --target wasm32-unknown-unknown --release --example many --features bevy/webgl2
wasm-bindgen --no-typescript --out-dir wasm --target web target/wasm32-unknown-unknown/release/examples/many.wasm
cargo build --target wasm32-unknown-unknown --release --example gltf --features bevy/webgl2
wasm-bindgen --no-typescript --out-dir wasm --target web target/wasm32-unknown-unknown/release/examples/gltf.wasm
cargo build --target wasm32-unknown-unknown --release --example random_obstacles --features bevy/webgl2
wasm-bindgen --no-typescript --out-dir wasm --target web target/wasm32-unknown-unknown/release/examples/random_obstacles.wasm
cargo build --target wasm32-unknown-unknown --release --example auto_navmesh_aabb --features bevy/webgl2
wasm-bindgen --no-typescript --out-dir wasm --target web target/wasm32-unknown-unknown/release/examples/auto_navmesh_aabb.wasm
cargo build --target wasm32-unknown-unknown --release --example auto_navmesh_primitive --features bevy/webgl2
wasm-bindgen --no-typescript --out-dir wasm --target web target/wasm32-unknown-unknown/release/examples/auto_navmesh_primitive.wasm
cargo build --target wasm32-unknown-unknown --release --example primitive_3d --features bevy/webgl2
wasm-bindgen --no-typescript --out-dir wasm --target web target/wasm32-unknown-unknown/release/examples/primitive_3d.wasm
cargo build --target wasm32-unknown-unknown --release --example demo --features bevy/webgl2
wasm-bindgen --no-typescript --out-dir wasm --target web target/wasm32-unknown-unknown/release/examples/demo.wasm
for example in "auto_navmesh_aabb" "auto_navmesh_primitive" "primitive_3d" "demo" "auto_navmesh_avian2d" "auto_navmesh_avian3d" "many" "lines" "moving" "gltf" "random_obstacles"
do
echo "Building $example"
cargo build --target wasm32-unknown-unknown --release --example $example --features "bevy/webgl2,avian2d,avian3d"
wasm-bindgen --no-typescript --out-dir wasm --target web target/wasm32-unknown-unknown/release/examples/$example.wasm
wasm-opt -Oz wasm/${example}_bg.wasm --output wasm/${example}-opt.wasm
rm wasm/${example}_bg.wasm
mv wasm/${example}-opt.wasm wasm/${example}_bg.wasm
cp wasm/example.html wasm/${example}.html
sed -i'' "s/name-of-example/${example}/g" wasm/${example}.html
done
- name: Copy Assets
run: cp -r assets wasm/

- name: Copy Screenshots
run: cp screenshots/* wasm/
run: cp -r screenshots wasm/

- name: Setup Pages
uses: actions/configure-pages@v5
Expand All @@ -71,6 +56,13 @@ jobs:
with:
path: "wasm"

deploy:
needs: build
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
21 changes: 19 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,18 @@ categories = ["game-development"]
itertools = "0.13"
tracing = { version = "0.1", optional = true }

[dependencies.avian2d]
version = "0.1"
features = ["2d", "f32", "parry-f32"]
default-features = false
optional = true

[dependencies.avian3d]
version = "0.1"
features = ["3d", "f32", "parry-f32"]
default-features = false
optional = true

[dependencies.polyanya]
version = "0.7.1"

Expand Down Expand Up @@ -52,5 +64,10 @@ default = ["debug-with-gizmos"]
linuxci = ["bevy/x11"]
debug-with-gizmos = ["bevy/bevy_gizmos"]

[profile.dev.package."*"]
opt-level = 3
[[example]]
name = "auto_navmesh_avian2d"
required-features = ["avian2d"]

[[example]]
name = "auto_navmesh_avian3d"
required-features = ["avian3d"]
1 change: 1 addition & 0 deletions examples/auto_navmesh_aabb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ fn main() {
DefaultPlugins.set(WindowPlugin {
primary_window: Some(Window {
title: "Navmesh with Polyanya".to_string(),
fit_canvas_to_parent: true,
..default()
}),
..default()
Expand Down
225 changes: 225 additions & 0 deletions examples/auto_navmesh_avian2d.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
use avian2d::{math::*, prelude::*};
use bevy::{color::palettes, math::vec2, prelude::*, sprite::MaterialMesh2dBundle};
use rand::Rng;
use vleue_navigator::prelude::*;

#[derive(Component)]
enum Obstacle {
Peg,
Wall,
}

fn main() {
App::new()
.add_plugins((
DefaultPlugins.set(WindowPlugin {
primary_window: Some(Window {
title: "Navmesh with Polyanya".to_string(),
fit_canvas_to_parent: true,
..default()
}),
..default()
}),
PhysicsPlugins::default().with_length_unit(20.0),
VleueNavigatorPlugin,
NavmeshUpdaterPlugin::<Collider, Obstacle>::default(),
))
.insert_resource(ClearColor(Color::srgb(0.05, 0.05, 0.1)))
.insert_resource(Gravity(Vector::NEG_Y * 9.81 * 100.0))
.add_systems(Startup, setup)
.add_systems(
PreUpdate,
(puck_back_to_start, move_puck, display_puck_path),
)
.insert_resource(NavMeshesDebug(palettes::tailwind::RED_800.into()))
.run();
}

fn setup(
mut commands: Commands,
mut materials: ResMut<Assets<ColorMaterial>>,
mut meshes: ResMut<Assets<Mesh>>,
) {
commands.spawn(Camera2dBundle::default());

let square_sprite = Sprite {
color: Color::srgb(0.7, 0.7, 0.8),
custom_size: Some(Vec2::splat(50.0)),
..default()
};

// Left wall
commands.spawn((
SpriteBundle {
sprite: square_sprite.clone(),
transform: Transform::from_xyz(-50.0 * 9.5, 0.0, 0.0)
.with_scale(Vec3::new(1.0, 15.0, 1.0)),
..default()
},
RigidBody::Static,
Collider::rectangle(50.0, 50.0),
Obstacle::Wall,
));
// Right wall
commands.spawn((
SpriteBundle {
sprite: square_sprite,
transform: Transform::from_xyz(50.0 * 9.5, 0.0, 0.0)
.with_scale(Vec3::new(1.0, 15.0, 1.0)),
..default()
},
RigidBody::Static,
Collider::rectangle(50.0, 50.0),
Obstacle::Wall,
));

let marble_radius = 15.0;
let step = 10;
let marble_mesh = meshes.add(Circle::new(marble_radius));
let marble_material = materials.add(Color::srgb(0.2, 0.7, 0.9));

for x in (-50..50).step_by(step).skip(1) {
for (yi, y) in (-50..50).step_by(step).skip(1).enumerate() {
commands.spawn((
MaterialMesh2dBundle {
mesh: marble_mesh.clone().into(),
material: marble_material.clone(),
transform: Transform::from_xyz(
(x as f32
+ if yi % 2 == 0 {
-(step as f32 / 4.0)
} else {
step as f32 / 4.0
}
+ rand::thread_rng().gen_range(-1.0..1.0))
* 9.5,
(y as f32 + rand::thread_rng().gen_range(-1.0..1.0)) * 6.0,
0.0,
),
..default()
},
RigidBody::Static,
Collider::circle(marble_radius as Scalar),
Obstacle::Peg,
));
}
}

let mesh = meshes.add(Circle::new(5.0));
let material = materials.add(Color::srgb(0.7, 0.9, 0.2));
for x in (-50..50).step_by(5).skip(1) {
let start = Vec3::new(x as f32 * 9.5, 300.0, 0.0);
commands.spawn((
MaterialMesh2dBundle {
mesh: mesh.clone().into(),
material: material.clone(),
transform: Transform::from_translation(start),
..default()
},
RigidBody::Dynamic,
LinearVelocity(
Vec2::new(
rand::thread_rng().gen_range(-1.0..1.0),
rand::thread_rng().gen_range(-1.0..1.0),
)
.normalize()
* 200.0,
),
Collider::circle(5.0 as Scalar),
Puck(start),
));
}

commands.spawn(NavMeshBundle {
settings: NavMeshSettings {
// Define the outer borders of the navmesh.
fixed: Triangulation::from_outer_edges(&vec![
vec2(-500.0, -500.0),
vec2(500.0, -500.0),
vec2(500.0, 500.0),
vec2(-500.0, 500.0),
]),
..default()
},
update_mode: NavMeshUpdateMode::Direct,
..default()
});
}

#[derive(Component)]
struct Puck(Vec3);

fn puck_back_to_start(
mut commands: Commands,
query: Query<(Entity, Ref<Transform>, &Puck), Without<Path>>,
navmeshes: Res<Assets<NavMesh>>,
navmesh: Query<&Handle<NavMesh>>,
) {
let Some(navmesh) = navmeshes.get(navmesh.single()) else {
return;
};

for (entity, transform, puck) in query.iter() {
if transform.translation.y < -300.0 {
let Some(path) = navmesh.transformed_path(transform.translation, puck.0) else {
continue;
};

if let Some((first, remaining)) = path.path.split_first() {
let mut remaining = remaining.to_vec();
remaining.reverse();

commands.entity(entity).insert((
RigidBody::Static,
Path {
current: first.clone(),
next: remaining,
},
));
}
}
}
}

#[derive(Component)]
pub struct Path {
current: Vec3,
next: Vec<Vec3>,
}

pub fn move_puck(
mut commands: Commands,
mut navigator: Query<(&mut Transform, &mut Path, Entity, &mut LinearVelocity)>,
time: Res<Time>,
) {
for (mut transform, mut path, entity, mut linvel) in navigator.iter_mut() {
let move_direction = path.current - transform.translation;
transform.translation += move_direction.normalize() * time.delta_seconds() * 200.0;

if transform.translation.distance(path.current) < 10.0 {
if let Some(next) = path.next.pop() {
path.current = next;
}
}
if transform.translation.distance(path.current) < 50.0 && path.next.is_empty() {
commands
.entity(entity)
.insert(RigidBody::Dynamic)
.remove::<Path>();
linvel.0 = (path.current - transform.translation).xy() * 10.0;
continue;
}
}
}

pub fn display_puck_path(navigator: Query<(&Transform, &Path)>, mut gizmos: Gizmos) {
for (transform, path) in &navigator {
let mut to_display = path.next.iter().map(|v| v.xy()).collect::<Vec<_>>();
to_display.push(path.current.clone().xy());
to_display.push(transform.translation.xy());
to_display.reverse();
if to_display.len() >= 1 {
gizmos.linestrip_2d(to_display, palettes::tailwind::YELLOW_400);
}
}
}
Loading

0 comments on commit d5ead6e

Please sign in to comment.