use std::f32::consts::FRAC_PI_2;
use bevy::{core_pipeline::tonemapping::Tonemapping, prelude::*};
use bevy_hanabi::prelude::*;
mod texutils;
mod utils;
use texutils::make_anim_img;
use utils::*;
const DEMO_DESC: &str = include_str!("circle.txt");
fn main() -> Result<(), Box<dyn std::error::Error>> {
let app_exit = utils::DemoApp::new("circle")
.with_desc(DEMO_DESC)
.build()
.add_systems(Startup, setup)
.run();
app_exit.into_result()
}
fn setup(
asset_server: Res<AssetServer>,
mut commands: Commands,
mut images: ResMut<Assets<Image>>,
mut effects: ResMut<Assets<EffectAsset>>,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
commands.spawn((
Transform::from_xyz(3.0, 3.0, 5.0).looking_at(Vec3::new(0.0, 1.0, 0.0), Vec3::Y),
Camera3d::default(),
Tonemapping::None,
));
let sprite_size = UVec2::new(64, 64);
let sprite_grid_size = UVec2::new(8, 8);
let anim_img = make_anim_img(sprite_size, sprite_grid_size, Vec3::new(0.1, 0.1, 0.1));
let texture_handle = images.add(anim_img);
let texture_handle2 = asset_server.load("ramp.png");
let frame_count = sprite_grid_size.x * sprite_grid_size.y;
let mut gradient = bevy_hanabi::Gradient::new();
gradient.add_key(0.0, Vec4::ONE);
gradient.add_key(0.5, Vec4::ONE);
gradient.add_key(1.0, Vec3::ONE.extend(0.));
let writer = ExprWriter::new();
let age = writer.rand(ScalarType::Float).expr();
let init_age = SetAttributeModifier::new(Attribute::AGE, age);
let lifetime = writer.lit(5.).expr();
let init_lifetime = SetAttributeModifier::new(Attribute::LIFETIME, lifetime);
let init_pos = SetPositionCircleModifier {
center: writer.lit(Vec3::Y * 0.1).expr(),
axis: writer.lit(Vec3::Y).expr(),
radius: writer.lit(0.4).expr(),
dimension: ShapeDimension::Surface,
};
let init_vel = SetVelocityCircleModifier {
center: writer.lit(Vec3::ZERO).expr(),
axis: writer.lit(Vec3::Y).expr(),
speed: (writer.lit(1.) + writer.lit(0.5) * writer.rand(ScalarType::Float)).expr(),
};
let sprite_index = writer
.attr(Attribute::AGE)
.mul(writer.lit(0.1))
.fract()
.mul(writer.lit(2.))
.sub(writer.lit(1.))
.abs()
.mul(writer.lit(frame_count as f32))
.cast(ScalarType::Int)
.rem(writer.lit(frame_count as i32))
.expr();
let update_sprite_index = SetAttributeModifier::new(Attribute::SPRITE_INDEX, sprite_index);
let texture_slot = writer.lit(0u32).expr();
let texture_slot2 = writer.lit(1u32).expr();
let mut module = writer.finish();
module.add_texture_slot("color");
module.add_texture_slot("shape");
let effect = effects.add(
EffectAsset::new(
32768,
SpawnerSettings::burst(32.0.into(), 8.0.into()),
module,
)
.with_name("circle")
.init(init_pos)
.init(init_vel)
.init(init_age)
.init(init_lifetime)
.update(update_sprite_index)
.render(ParticleTextureModifier {
texture_slot,
sample_mapping: ImageSampleMapping::ModulateOpacityFromR,
})
.render(ParticleTextureModifier {
texture_slot: texture_slot2,
sample_mapping: ImageSampleMapping::ModulateRGB,
})
.render(FlipbookModifier { sprite_grid_size })
.render(ColorOverLifetimeModifier::new(gradient))
.render(SizeOverLifetimeModifier {
gradient: bevy_hanabi::Gradient::constant([0.5; 3].into()),
screen_space_size: false,
}),
);
commands.spawn((
Transform::from_rotation(Quat::from_rotation_x(-FRAC_PI_2)),
Mesh3d(meshes.add(Rectangle {
half_size: Vec2::splat(2.0),
})),
MeshMaterial3d(materials.add(utils::COLOR_BLUE)),
Name::new("ground"),
));
commands.spawn((
Transform::from_translation(Vec3::Y),
Mesh3d(meshes.add(Sphere { radius: 1.0 })),
MeshMaterial3d(materials.add(utils::COLOR_CYAN)),
Name::new("sphere"),
));
commands.spawn((
ParticleEffect::new(effect),
EffectMaterial {
images: vec![texture_handle, texture_handle2],
},
Name::new("effect"),
));
}