commit
09b7c0228c
@ -0,0 +1,9 @@
|
|||||||
|
# Unwanted files
|
||||||
|
target
|
||||||
|
|
||||||
|
# Backup files
|
||||||
|
.DS_Store
|
||||||
|
thumbs.db
|
||||||
|
*~
|
||||||
|
*.rs.bk
|
||||||
|
*.swp
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,15 @@
|
|||||||
|
[package]
|
||||||
|
name = "amethyst-cli-starter-2d"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = []
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
amethyst = "0.11.0"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["vulkan"]
|
||||||
|
empty = ["amethyst/empty"]
|
||||||
|
metal = ["amethyst/metal"]
|
||||||
|
vulkan = ["amethyst/vulkan"]
|
||||||
|
nightly = ["amethyst/nightly"]
|
@ -0,0 +1,26 @@
|
|||||||
|
# amethyst-cli-starter-2d
|
||||||
|
|
||||||
|
## How to run
|
||||||
|
|
||||||
|
To run the game, use
|
||||||
|
|
||||||
|
```
|
||||||
|
cargo run --features "vulkan"
|
||||||
|
```
|
||||||
|
|
||||||
|
on Windows and Linux, and
|
||||||
|
|
||||||
|
```
|
||||||
|
cargo run --features "metal"
|
||||||
|
```
|
||||||
|
|
||||||
|
on macOS.
|
||||||
|
|
||||||
|
For building without any graphics backend, you can use
|
||||||
|
|
||||||
|
```
|
||||||
|
cargo run --features "empty"
|
||||||
|
```
|
||||||
|
|
||||||
|
but be aware that as soon as you need any rendering you won't be able to run your game when using
|
||||||
|
the `empty` feature.
|
@ -0,0 +1,4 @@
|
|||||||
|
(
|
||||||
|
title: "amethyst-cli-starter-2d",
|
||||||
|
dimensions: Some((800, 600)),
|
||||||
|
)
|
@ -0,0 +1,176 @@
|
|||||||
|
use amethyst::{
|
||||||
|
assets::{AssetStorage, Handle, Loader, Processor},
|
||||||
|
core::transform::{Transform, TransformBundle},
|
||||||
|
ecs::prelude::{ReadExpect, Resources, SystemData},
|
||||||
|
prelude::*,
|
||||||
|
renderer::{
|
||||||
|
pass::DrawFlat2DDesc,
|
||||||
|
rendy::{
|
||||||
|
factory::Factory,
|
||||||
|
graph::{
|
||||||
|
render::{RenderGroupDesc, SubpassBuilder},
|
||||||
|
GraphBuilder,
|
||||||
|
},
|
||||||
|
hal::{format::Format, image},
|
||||||
|
},
|
||||||
|
types::DefaultBackend,
|
||||||
|
Camera, GraphCreator, ImageFormat, RenderingSystem, SpriteSheet, SpriteSheetFormat,
|
||||||
|
Texture,
|
||||||
|
},
|
||||||
|
utils::application_root_dir,
|
||||||
|
window::{ScreenDimensions, Window, WindowBundle},
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MyState;
|
||||||
|
|
||||||
|
impl SimpleState for MyState {
|
||||||
|
fn on_start(&mut self, data: StateData<'_, GameData<'_, '_>>) {
|
||||||
|
let world = data.world;
|
||||||
|
|
||||||
|
init_camera(world);
|
||||||
|
|
||||||
|
// TODO(happens): Add entity for this
|
||||||
|
let _spritesheet = load_sprites(world);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> amethyst::Result<()> {
|
||||||
|
amethyst::start_logger(Default::default());
|
||||||
|
|
||||||
|
let app_root = application_root_dir()?;
|
||||||
|
|
||||||
|
let resources = app_root.join("resources");
|
||||||
|
let display_config = resources.join("display_config.ron");
|
||||||
|
|
||||||
|
let render_graph = RenderGraph::default();
|
||||||
|
let render_system = RenderingSystem::<DefaultBackend, _>::new(render_graph);
|
||||||
|
|
||||||
|
// TODO(happens): Add UI example
|
||||||
|
let game_data = GameDataBuilder::default()
|
||||||
|
.with_bundle(WindowBundle::from_config_path(display_config))?
|
||||||
|
.with_bundle(TransformBundle::new())?
|
||||||
|
.with(
|
||||||
|
Processor::<SpriteSheet>::new(),
|
||||||
|
"sprite_sheet_processor",
|
||||||
|
&[],
|
||||||
|
)
|
||||||
|
.with_thread_local(render_system);
|
||||||
|
|
||||||
|
let mut game = Application::new(resources, MyState, game_data)?;
|
||||||
|
game.run();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_camera(world: &mut World) {
|
||||||
|
let mut transform = Transform::default();
|
||||||
|
transform.set_translation_xyz(100., 100., 1.);
|
||||||
|
|
||||||
|
world
|
||||||
|
.create_entity()
|
||||||
|
.with(Camera::standard_2d(200., 200.))
|
||||||
|
.with(transform)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_sprites(world: &mut World) -> Handle<SpriteSheet> {
|
||||||
|
// TODO(happens): Add sprite assets
|
||||||
|
let texture_handle = {
|
||||||
|
let loader = world.read_resource::<Loader>();
|
||||||
|
let texture_storage = world.read_resource::<AssetStorage<Texture>>();
|
||||||
|
loader.load(
|
||||||
|
"sprites/ayaya.png",
|
||||||
|
ImageFormat::default(),
|
||||||
|
(),
|
||||||
|
&texture_storage,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let sheet_handle = {
|
||||||
|
let loader = world.read_resource::<Loader>();
|
||||||
|
let sheet_storage = world.read_resource::<AssetStorage<SpriteSheet>>();
|
||||||
|
loader.load(
|
||||||
|
"sprites/ayaya.ron",
|
||||||
|
SpriteSheetFormat(texture_handle),
|
||||||
|
(),
|
||||||
|
&sheet_storage,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
sheet_handle
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(happens): Can we provide this with a few parameters,
|
||||||
|
// for the most common cases? The fields could still be exposed
|
||||||
|
#[derive(Default)]
|
||||||
|
struct RenderGraph {
|
||||||
|
dimensions: Option<ScreenDimensions>,
|
||||||
|
surface_format: Option<Format>,
|
||||||
|
dirty: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(happens): Add explanations
|
||||||
|
impl GraphCreator<DefaultBackend> for RenderGraph {
|
||||||
|
fn rebuild(&mut self, res: &Resources) -> bool {
|
||||||
|
// Rebuild when dimensions change, but wait until at least two frames have the same.
|
||||||
|
let new_dimensions = res.try_fetch::<ScreenDimensions>();
|
||||||
|
use std::ops::Deref;
|
||||||
|
if self.dimensions.as_ref() != new_dimensions.as_ref().map(|d| d.deref()) {
|
||||||
|
self.dirty = true;
|
||||||
|
self.dimensions = new_dimensions.map(|d| d.clone());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.dirty
|
||||||
|
}
|
||||||
|
|
||||||
|
fn builder(
|
||||||
|
&mut self,
|
||||||
|
factory: &mut Factory<DefaultBackend>,
|
||||||
|
res: &Resources,
|
||||||
|
) -> GraphBuilder<DefaultBackend, Resources> {
|
||||||
|
use amethyst::renderer::rendy::{
|
||||||
|
graph::present::PresentNode,
|
||||||
|
hal::command::{ClearDepthStencil, ClearValue},
|
||||||
|
};
|
||||||
|
|
||||||
|
self.dirty = false;
|
||||||
|
let window = <ReadExpect<'_, Window>>::fetch(res);
|
||||||
|
let surface = factory.create_surface(&window);
|
||||||
|
// cache surface format to speed things up
|
||||||
|
let surface_format = *self
|
||||||
|
.surface_format
|
||||||
|
.get_or_insert_with(|| factory.get_surface_format(&surface));
|
||||||
|
let dimensions = self.dimensions.as_ref().unwrap();
|
||||||
|
let window_kind =
|
||||||
|
image::Kind::D2(dimensions.width() as u32, dimensions.height() as u32, 1, 1);
|
||||||
|
|
||||||
|
let mut graph_builder = GraphBuilder::new();
|
||||||
|
let color = graph_builder.create_image(
|
||||||
|
window_kind,
|
||||||
|
1,
|
||||||
|
surface_format,
|
||||||
|
Some(ClearValue::Color([0.34, 0.36, 0.52, 1.0].into())),
|
||||||
|
);
|
||||||
|
|
||||||
|
let depth = graph_builder.create_image(
|
||||||
|
window_kind,
|
||||||
|
1,
|
||||||
|
Format::D32Sfloat,
|
||||||
|
Some(ClearValue::DepthStencil(ClearDepthStencil(1.0, 0))),
|
||||||
|
);
|
||||||
|
|
||||||
|
let opaque = graph_builder.add_node(
|
||||||
|
SubpassBuilder::new()
|
||||||
|
.with_group(DrawFlat2DDesc::new().builder())
|
||||||
|
.with_color(color)
|
||||||
|
.with_depth_stencil(depth)
|
||||||
|
.into_pass(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let _present = graph_builder
|
||||||
|
.add_node(PresentNode::builder(factory, surface, color).with_dependency(opaque));
|
||||||
|
|
||||||
|
graph_builder
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue