extern crate amethyst;
extern crate amethyst_rhusics;
extern crate collision;
extern crate genmesh;
extern crate rand;
extern crate rhusics_core;
extern crate rhusics_ecs;
extern crate shred;
#[macro_use]
extern crate shred_derive;
use std::time::{Duration, Instant};
use amethyst::assets::{Handle, Loader};
use amethyst::core::cgmath::{Array, One, Point2, Quaternion, Vector3};
use amethyst::core::{GlobalTransform, Transform, TransformBundle};
use amethyst::ecs::prelude::{Builder, Entity, World};
use amethyst::input::{is_close_requested, is_key_down};
use amethyst::prelude::{
Application, Config, GameData, GameDataBuilder, SimpleState, SimpleTrans, StateData,
StateEvent, Trans,
};
use amethyst::renderer::{
Camera, DisplayConfig, DrawFlat, Material, MaterialDefaults, Mesh,
Pipeline, PosTex, RenderBundle, Stage, VirtualKeyCode,
};
use amethyst::ui::{DrawUi, UiBundle};
use amethyst::utils::fps_counter::FPSCounterBundle;
use amethyst_rhusics::{setup_2d_arena, time_sync, DefaultPhysicsBundle2};
use collision::primitive::{Primitive2, Rectangle};
use collision::Aabb2;
use rhusics_core::CollisionShape;
use rhusics_ecs::physics2d::BodyPose2;
use self::boxes::{
create_ui, update_ui, BoxSimulationBundle2, Emitter, Graphics, KillRate, ObjectType,
};
mod boxes;
#[derive(Default)]
pub struct Emitting {
fps: Option<Entity>,
num: Option<Entity>,
collision: Option<Entity>,
}
pub type Shape = CollisionShape<Primitive2<f32>, BodyPose2<f32>, Aabb2<f32>, ObjectType>;
impl<'a, 'b> SimpleState<'a, 'b> for Emitting {
fn on_start(&mut self, data: StateData<GameData>) {
let StateData { world, .. } = data;
world.write_resource::<KillRate>().0 = 0.01;
initialise_camera(world);
let g = Graphics {
mesh: initialise_mesh(world),
};
let (num_display, fps_display, collisions_display) = create_ui(world);
self.num = Some(num_display);
self.fps = Some(fps_display);
self.collision = Some(collisions_display);
world.add_resource(g);
setup_2d_arena(
Point2::new(-1., -1.),
Point2::new(1., 1.),
(
ObjectType::Wall,
ObjectType::Wall,
ObjectType::Wall,
ObjectType::Wall,
),
world,
);
initialise_emitters(world);
}
fn handle_event(&mut self, _: StateData<GameData>, event: StateEvent) -> SimpleTrans<'a, 'b> {
match event {
StateEvent::Window(ref event)
if is_close_requested(&event) || is_key_down(&event, VirtualKeyCode::Escape) =>
{
Trans::Quit
}
_ => Trans::None,
}
}
fn update(&mut self, data: &mut StateData<GameData>) -> SimpleTrans<'a, 'b> {
time_sync(&data.world);
update_ui::<Point2<f32>>(
data.world,
self.num.unwrap(),
self.fps.unwrap(),
self.collision.unwrap(),
);
data.data.update(data.world);
Trans::None
}
}
fn initialise_camera(world: &mut World) {
world
.create_entity()
.with(Camera::standard_2d())
.with(Transform {
rotation: Quaternion::one(),
scale: Vector3::from_value(1.),
translation: Vector3::new(0., 0., 5.),
}).with(GlobalTransform::default())
.build();
}
fn initialise_mesh(world: &mut World) -> Handle<Mesh> {
use genmesh::generators::Cube;
use genmesh::{MapToVertices, Triangulate, Vertices};
let vertices = Cube::new()
.vertex(|v| PosTex {
position: v.pos.into(),
tex_coord: [0.1, 0.1],
}).triangulate()
.vertices()
.collect::<Vec<_>>();
world
.read_resource::<Loader>()
.load_from_data(vertices.into(), (), &world.read_resource())
}
fn initialise_material(world: &mut World, r: f32, g: f32, b: f32) -> Material {
let albedo = world.read_resource::<Loader>().load_from_data(
[r, g, b, 1.0].into(),
(),
&world.read_resource(),
);
Material {
albedo,
..world.read_resource::<MaterialDefaults>().0.clone()
}
}
fn emitter(p: Point2<f32>, d: Duration, material: Material) -> Emitter<Point2<f32>> {
Emitter {
location: p,
emission_interval: d,
last_emit: Instant::now(),
material,
emitted: 0,
}
}
fn initialise_emitters(world: &mut World) {
let mat = initialise_material(world, 0.3, 1.0, 0.3);
world
.create_entity()
.with(emitter(
Point2::new(-0.4, 0.),
Duration::new(0, 50_000_000),
mat,
)).build();
let mat = initialise_material(world, 0.3, 0.0, 0.3);
world
.create_entity()
.with(emitter(
Point2::new(0.4, 0.),
Duration::new(0, 75_000_000),
mat,
)).build();
let mat = initialise_material(world, 1.0, 1.0, 1.0);
world
.create_entity()
.with(emitter(
Point2::new(0., -0.4),
Duration::new(0, 100_000_000),
mat,
)).build();
let mat = initialise_material(world, 1.0, 0.3, 0.3);
world
.create_entity()
.with(emitter(
Point2::new(0., 0.4),
Duration::new(1, 25_000_000),
mat,
)).build();
}
fn run() -> Result<(), amethyst::Error> {
amethyst::start_logger(amethyst::LoggerConfig::default());
let path = format!(
"{}/../resources/display_config.ron",
env!("CARGO_MANIFEST_DIR")
);
let config = DisplayConfig::load(&path);
let pipe = Pipeline::build().with_stage(
Stage::with_backbuffer()
.clear_target([0., 0., 0., 1.0], 1.0)
.with_pass(DrawFlat::<PosTex>::new())
.with_pass(DrawUi::new()),
);
let game_data = GameDataBuilder::default()
.with_bundle(FPSCounterBundle::default())?
.with_bundle(DefaultPhysicsBundle2::<ObjectType>::new().with_spatial())?
.with_bundle(BoxSimulationBundle2::new(Rectangle::new(0.1, 0.1).into()))?
.with_bundle(TransformBundle::new().with_dep(&["sync_system", "emission_system"]))?
.with_bundle(UiBundle::<String, String>::new())?
.with_bundle(RenderBundle::new(pipe, Some(config)))?;
let mut game = Application::new("./", Emitting::default(), game_data)?;
game.run();
Ok(())
}
fn main() {
if let Err(e) = run() {
println!("Error occurred during game execution: {}", e);
::std::process::exit(1);
}
}