init
This commit is contained in:
442
Cargo.lock
generated
442
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@ authors = ["Hilmar Wiegand <me@hwgnd.de>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
amethyst = "0.13.0"
|
amethyst = "0.13.2"
|
||||||
log = { version = "0.4.8", features = ["serde"] }
|
log = { version = "0.4.8", features = ["serde"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|||||||
6
resources/bindings.ron
Normal file
6
resources/bindings.ron
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
(
|
||||||
|
axes: {},
|
||||||
|
actions: {
|
||||||
|
"flap": [[Key(Space)]],
|
||||||
|
},
|
||||||
|
)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
(
|
(
|
||||||
title: "amethyst-cli-starter-2d",
|
title: "test",
|
||||||
dimensions: Some((800, 600)),
|
dimensions: Some((432, 768)),
|
||||||
)
|
)
|
||||||
|
|||||||
BIN
resources/sprites/flappy.png
Normal file
BIN
resources/sprites/flappy.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
42
resources/sprites/flappy.ron
Normal file
42
resources/sprites/flappy.ron
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
(
|
||||||
|
texture_width: 512,
|
||||||
|
texture_height: 512,
|
||||||
|
sprites: [
|
||||||
|
( // Daytime background
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: 144,
|
||||||
|
height: 256,
|
||||||
|
),
|
||||||
|
( // Nighttime background
|
||||||
|
x: 146,
|
||||||
|
y: 0,
|
||||||
|
width: 144,
|
||||||
|
height: 256,
|
||||||
|
),
|
||||||
|
( // Down Pipe
|
||||||
|
x: 56,
|
||||||
|
y: 323,
|
||||||
|
width: 26,
|
||||||
|
height: 160,
|
||||||
|
),
|
||||||
|
( // Up Pipe
|
||||||
|
x: 84,
|
||||||
|
y: 323,
|
||||||
|
width: 26,
|
||||||
|
height: 160,
|
||||||
|
),
|
||||||
|
( // Ground
|
||||||
|
x: 292,
|
||||||
|
y: 0,
|
||||||
|
width: 168,
|
||||||
|
height: 56,
|
||||||
|
),
|
||||||
|
( // Floppy
|
||||||
|
x: 3,
|
||||||
|
y: 490,
|
||||||
|
width: 17,
|
||||||
|
height: 13,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
38
src/components.rs
Normal file
38
src/components.rs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
use amethyst::{
|
||||||
|
core::transform::TransformBundle,
|
||||||
|
core::transform::Transform,
|
||||||
|
prelude::*,
|
||||||
|
renderer::{
|
||||||
|
plugins::{RenderFlat2D, RenderToWindow},
|
||||||
|
types::DefaultBackend,
|
||||||
|
RenderingBundle,
|
||||||
|
},
|
||||||
|
utils::application_root_dir,
|
||||||
|
core::SystemDesc,
|
||||||
|
derive::SystemDesc,
|
||||||
|
ecs::prelude::{Component, DenseVecStorage, Entity},
|
||||||
|
ecs::prelude::{Join, ReadStorage, System, SystemData, WriteStorage},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Falling object component to bucket us into something the system can manipulate
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct TiledScroller {
|
||||||
|
pub speed: f32,
|
||||||
|
pub width: f32,
|
||||||
|
pub height: f32,
|
||||||
|
pub position: f32,
|
||||||
|
}
|
||||||
|
impl Component for TiledScroller {
|
||||||
|
type Storage = DenseVecStorage<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Falling object component to bucket us into something the system can manipulate
|
||||||
|
pub struct Birb {
|
||||||
|
pub vertical_speed: f32,
|
||||||
|
pub starting_height: f32,
|
||||||
|
pub position: f32,
|
||||||
|
}
|
||||||
|
impl Component for Birb {
|
||||||
|
type Storage = DenseVecStorage<Self>;
|
||||||
|
}
|
||||||
30
src/main.rs
30
src/main.rs
@@ -1,5 +1,10 @@
|
|||||||
|
mod components;
|
||||||
|
mod systems;
|
||||||
|
mod state;
|
||||||
use amethyst::{
|
use amethyst::{
|
||||||
|
input::{InputBundle, StringBindings},
|
||||||
core::transform::TransformBundle,
|
core::transform::TransformBundle,
|
||||||
|
core::transform::Transform,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
renderer::{
|
renderer::{
|
||||||
plugins::{RenderFlat2D, RenderToWindow},
|
plugins::{RenderFlat2D, RenderToWindow},
|
||||||
@@ -7,20 +12,38 @@ use amethyst::{
|
|||||||
RenderingBundle,
|
RenderingBundle,
|
||||||
},
|
},
|
||||||
utils::application_root_dir,
|
utils::application_root_dir,
|
||||||
|
core::SystemDesc,
|
||||||
|
derive::SystemDesc,
|
||||||
|
ecs::prelude::{Component, DenseVecStorage, Entity},
|
||||||
|
ecs::prelude::{Join, ReadStorage, System, SystemData, WriteStorage},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod state;
|
use crate::components::*;
|
||||||
|
use crate::systems::*;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
fn main() -> amethyst::Result<()> {
|
fn main() -> amethyst::Result<()> {
|
||||||
amethyst::start_logger(Default::default());
|
|
||||||
|
|
||||||
let app_root = application_root_dir()?;
|
//amethyst::start_logger(Default::default());
|
||||||
|
|
||||||
|
// Gets the root directory of the application
|
||||||
|
let mut app_root = PathBuf::from_str("/home/mrh/source/amethyst-starter-2d/")?;
|
||||||
|
|
||||||
|
// join on the resources path, and the config.
|
||||||
let resources = app_root.join("resources");
|
let resources = app_root.join("resources");
|
||||||
let display_config = resources.join("display_config.ron");
|
let display_config = resources.join("display_config.ron");
|
||||||
|
let binding_path = resources.join("bindings.ron");
|
||||||
|
|
||||||
|
let input_bundle = InputBundle::<StringBindings>::new()
|
||||||
|
.with_bindings_from_file(binding_path)?;
|
||||||
|
|
||||||
|
//
|
||||||
let game_data = GameDataBuilder::default()
|
let game_data = GameDataBuilder::default()
|
||||||
.with_bundle(TransformBundle::new())?
|
.with_bundle(TransformBundle::new())?
|
||||||
|
.with_bundle(input_bundle)?
|
||||||
|
.with(ScrollScrollables, "scroll", &[])
|
||||||
|
.with(BirbGravity{ fired: false }, "gravity", &["input_system"])
|
||||||
.with_bundle(
|
.with_bundle(
|
||||||
RenderingBundle::<DefaultBackend>::new()
|
RenderingBundle::<DefaultBackend>::new()
|
||||||
.with_plugin(
|
.with_plugin(
|
||||||
@@ -30,6 +53,7 @@ fn main() -> amethyst::Result<()> {
|
|||||||
.with_plugin(RenderFlat2D::default()),
|
.with_plugin(RenderFlat2D::default()),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
// Creates the app with the startup state and bound game data
|
||||||
let mut game = Application::new(resources, state::MyState, game_data)?;
|
let mut game = Application::new(resources, state::MyState, game_data)?;
|
||||||
game.run();
|
game.run();
|
||||||
|
|
||||||
|
|||||||
116
src/state.rs
116
src/state.rs
@@ -1,17 +1,22 @@
|
|||||||
use amethyst::{
|
use amethyst::{
|
||||||
assets::{AssetStorage, Loader},
|
assets::{AssetStorage, Loader},
|
||||||
core::transform::Transform,
|
core::transform::Transform,
|
||||||
|
core::math::Vector3,
|
||||||
input::{get_key, is_close_requested, is_key_down, VirtualKeyCode},
|
input::{get_key, is_close_requested, is_key_down, VirtualKeyCode},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
renderer::{Camera, ImageFormat, SpriteRender, SpriteSheet, SpriteSheetFormat, Texture},
|
renderer::{Camera, ImageFormat, SpriteRender, SpriteSheet, SpriteSheetFormat, Texture},
|
||||||
window::ScreenDimensions,
|
window::ScreenDimensions,
|
||||||
|
ecs::prelude::{Component, DenseVecStorage, Entity},
|
||||||
};
|
};
|
||||||
|
|
||||||
use log::info;
|
use log::info;
|
||||||
|
use crate::components::*;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub struct MyState;
|
pub struct MyState;
|
||||||
|
|
||||||
impl SimpleState for MyState {
|
impl SimpleState for MyState {
|
||||||
|
|
||||||
// On start will run when this state is initialized. For more
|
// On start will run when this state is initialized. For more
|
||||||
// state lifecycle hooks, see:
|
// state lifecycle hooks, see:
|
||||||
// https://book.amethyst.rs/stable/concepts/state.html#life-cycle
|
// https://book.amethyst.rs/stable/concepts/state.html#life-cycle
|
||||||
@@ -23,7 +28,9 @@ impl SimpleState for MyState {
|
|||||||
// pass the world mutably to the following functions.
|
// pass the world mutably to the following functions.
|
||||||
let dimensions = (*world.read_resource::<ScreenDimensions>()).clone();
|
let dimensions = (*world.read_resource::<ScreenDimensions>()).clone();
|
||||||
|
|
||||||
|
|
||||||
// Place the camera
|
// Place the camera
|
||||||
|
/// function sets size of camera window
|
||||||
init_camera(world, &dimensions);
|
init_camera(world, &dimensions);
|
||||||
|
|
||||||
// Load our sprites and display them
|
// Load our sprites and display them
|
||||||
@@ -36,6 +43,7 @@ impl SimpleState for MyState {
|
|||||||
mut _data: StateData<'_, GameData<'_, '_>>,
|
mut _data: StateData<'_, GameData<'_, '_>>,
|
||||||
event: StateEvent,
|
event: StateEvent,
|
||||||
) -> SimpleTrans {
|
) -> SimpleTrans {
|
||||||
|
|
||||||
if let StateEvent::Window(event) = &event {
|
if let StateEvent::Window(event) = &event {
|
||||||
// Check if the window should be closed
|
// Check if the window should be closed
|
||||||
if is_close_requested(&event) || is_key_down(&event, VirtualKeyCode::Escape) {
|
if is_close_requested(&event) || is_key_down(&event, VirtualKeyCode::Escape) {
|
||||||
@@ -44,7 +52,7 @@ impl SimpleState for MyState {
|
|||||||
|
|
||||||
// Listen to any key events
|
// Listen to any key events
|
||||||
if let Some(event) = get_key(&event) {
|
if let Some(event) = get_key(&event) {
|
||||||
info!("handling key event: {:?}", event);
|
// info!("handling key event: {:?}", event);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If you're looking for a more sophisticated event handling solution,
|
// If you're looking for a more sophisticated event handling solution,
|
||||||
@@ -55,6 +63,10 @@ impl SimpleState for MyState {
|
|||||||
// Keep going
|
// Keep going
|
||||||
Trans::None
|
Trans::None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, data: &mut StateData<'_, GameData<'_, '_>>) -> SimpleTrans {
|
||||||
|
Trans::None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_camera(world: &mut World, dimensions: &ScreenDimensions) {
|
fn init_camera(world: &mut World, dimensions: &ScreenDimensions) {
|
||||||
@@ -70,7 +82,7 @@ fn init_camera(world: &mut World, dimensions: &ScreenDimensions) {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_sprites(world: &mut World) -> Vec<SpriteRender> {
|
fn load_sprites(world: &mut World) -> HashMap<String, SpriteRender> {
|
||||||
// Load the texture for our sprites. We'll later need to
|
// Load the texture for our sprites. We'll later need to
|
||||||
// add a handle to this texture to our `SpriteRender`s, so
|
// add a handle to this texture to our `SpriteRender`s, so
|
||||||
// we need to keep a reference to it.
|
// we need to keep a reference to it.
|
||||||
@@ -78,7 +90,7 @@ fn load_sprites(world: &mut World) -> Vec<SpriteRender> {
|
|||||||
let loader = world.read_resource::<Loader>();
|
let loader = world.read_resource::<Loader>();
|
||||||
let texture_storage = world.read_resource::<AssetStorage<Texture>>();
|
let texture_storage = world.read_resource::<AssetStorage<Texture>>();
|
||||||
loader.load(
|
loader.load(
|
||||||
"sprites/logo.png",
|
"sprites/flappy.png",
|
||||||
ImageFormat::default(),
|
ImageFormat::default(),
|
||||||
(),
|
(),
|
||||||
&texture_storage,
|
&texture_storage,
|
||||||
@@ -91,40 +103,96 @@ fn load_sprites(world: &mut World) -> Vec<SpriteRender> {
|
|||||||
let loader = world.read_resource::<Loader>();
|
let loader = world.read_resource::<Loader>();
|
||||||
let sheet_storage = world.read_resource::<AssetStorage<SpriteSheet>>();
|
let sheet_storage = world.read_resource::<AssetStorage<SpriteSheet>>();
|
||||||
loader.load(
|
loader.load(
|
||||||
"sprites/logo.ron",
|
"sprites/flappy.ron",
|
||||||
SpriteSheetFormat(texture_handle),
|
SpriteSheetFormat(texture_handle),
|
||||||
(),
|
(),
|
||||||
&sheet_storage,
|
&sheet_storage,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create our sprite renders. Each will have a handle to the texture
|
let sprite_map = vec![
|
||||||
// that it renders from. The handle is safe to clone, since it just
|
(0, "day-background".to_string()),
|
||||||
// references the asset.
|
(1, "night-background".to_string()),
|
||||||
(0..3)
|
(2, "down-pipe".to_string()),
|
||||||
.map(|i| SpriteRender {
|
(3, "up-pipe".to_string()),
|
||||||
|
(4, "ground".to_string()),
|
||||||
|
(5, "floppy".to_string()),
|
||||||
|
];
|
||||||
|
|
||||||
|
sprite_map.iter()
|
||||||
|
.map(|i| (i.1.clone(), SpriteRender {
|
||||||
sprite_sheet: sheet_handle.clone(),
|
sprite_sheet: sheet_handle.clone(),
|
||||||
sprite_number: i,
|
sprite_number: i.0,
|
||||||
})
|
}))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_sprites(world: &mut World, sprites: &[SpriteRender], dimensions: &ScreenDimensions) {
|
fn init_sprites(world: &mut World, sprites: &HashMap<String, SpriteRender>, dimensions: &ScreenDimensions) {
|
||||||
for (i, sprite) in sprites.iter().enumerate() {
|
|
||||||
// Center our sprites around the center of the window
|
let background_sprite = sprites.get("day-background").unwrap();
|
||||||
let x = (i as f32 - 1.) * 100. + dimensions.width() * 0.5;
|
|
||||||
let y = (i as f32 - 1.) * 100. + dimensions.height() * 0.5;
|
|
||||||
let mut transform = Transform::default();
|
let background_object = TiledScroller {
|
||||||
transform.set_translation_xyz(x, y, 0.);
|
speed: -75.0,
|
||||||
|
position: 1.0,
|
||||||
|
width: 144.0 * 3.0,
|
||||||
|
height: 256.0 * 3.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut transform = Transform::default();
|
||||||
|
transform.set_scale(Vector3::new(3.0, 3.0, 3.0));
|
||||||
|
transform.set_translation_xyz(background_object.width/2.0, background_object.height/2.0, 0.0);
|
||||||
|
|
||||||
|
|
||||||
// Create an entity for each sprite and attach the `SpriteRender` as
|
|
||||||
// well as the transform. If you want to add behaviour to your sprites,
|
|
||||||
// you'll want to add a custom `Component` that will identify them, and a
|
|
||||||
// `System` that will iterate over them. See https://book.amethyst.rs/stable/concepts/system.html
|
|
||||||
world
|
world
|
||||||
.create_entity()
|
.create_entity()
|
||||||
.with(sprite.clone())
|
.with(background_sprite.clone()) // Sprite Render
|
||||||
|
.with(background_object.clone())
|
||||||
|
.with(transform.clone())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
transform.set_translation_xyz(3.0*144.0/2.0*3.0, 3.0*256.0/2.0, 0.0);
|
||||||
|
|
||||||
|
world
|
||||||
|
.create_entity()
|
||||||
|
.with(background_sprite.clone()) // Sprite Render
|
||||||
|
.with(TiledScroller {
|
||||||
|
speed: -75.0,
|
||||||
|
position: 2.0,
|
||||||
|
width: 0.0,
|
||||||
|
height: 0.0
|
||||||
|
})
|
||||||
|
.with(transform.clone())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let ground_sprite = sprites.get("ground").unwrap();
|
||||||
|
transform.set_translation_xyz(3.0*168.0/2.0*3.0, 3.0*56.0/2.0, 0.1);
|
||||||
|
|
||||||
|
world
|
||||||
|
.create_entity()
|
||||||
|
.with(ground_sprite.clone()) // Sprite Render
|
||||||
|
.with(TiledScroller {
|
||||||
|
speed: -100.0,
|
||||||
|
position: 2.0,
|
||||||
|
width: 0.0,
|
||||||
|
height: 0.0,
|
||||||
|
})
|
||||||
|
.with(transform.clone())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let birb_sprite = sprites.get("floppy").unwrap();
|
||||||
|
transform.set_translation_xyz(dimensions.width()/2.0, dimensions.height()/2.0, 0.2);
|
||||||
|
|
||||||
|
|
||||||
|
world
|
||||||
|
.create_entity()
|
||||||
|
.with(birb_sprite.clone()) // Sprite Render
|
||||||
|
.with(Birb {
|
||||||
|
vertical_speed: 0.0,
|
||||||
|
position: 0.0,
|
||||||
|
starting_height: 0.0
|
||||||
|
})
|
||||||
.with(transform)
|
.with(transform)
|
||||||
.build();
|
.build();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
62
src/systems.rs
Normal file
62
src/systems.rs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
use amethyst::{
|
||||||
|
core::SystemDesc,
|
||||||
|
core::timing::Time,
|
||||||
|
core::transform::{Transform, TransformBundle},
|
||||||
|
derive::SystemDesc,
|
||||||
|
ecs::prelude::{},
|
||||||
|
ecs::prelude::{
|
||||||
|
Component, DenseVecStorage, Entity, Join, Read,
|
||||||
|
ReadStorage, System, SystemData, WriteStorage
|
||||||
|
},
|
||||||
|
input::{InputHandler, StringBindings},
|
||||||
|
};
|
||||||
|
|
||||||
|
use log::info;
|
||||||
|
use crate::components::*;
|
||||||
|
|
||||||
|
pub struct ScrollScrollables;
|
||||||
|
|
||||||
|
// This system iterates all the objects with transform (and falling object) component
|
||||||
|
impl<'a> System<'a> for ScrollScrollables {
|
||||||
|
type SystemData = (
|
||||||
|
WriteStorage<'a, Transform>,
|
||||||
|
WriteStorage<'a, TiledScroller>,
|
||||||
|
Read<'a, Time>,
|
||||||
|
);
|
||||||
|
|
||||||
|
fn run(&mut self, (mut transforms, mut scrolling, time): Self::SystemData) {
|
||||||
|
for (mut transform, mut object) in (&mut transforms, &mut scrolling).join() {
|
||||||
|
|
||||||
|
// I need to tile it by it's width
|
||||||
|
transform.prepend_translation_x(object.speed * time.delta_seconds());
|
||||||
|
if transform.translation().x+144.0*1.5 < 0.0 {
|
||||||
|
transform.set_translation_x(144.0*3.0/2.0*3.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BirbGravity {
|
||||||
|
pub fired: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
// This system iterates all the objects with transform (and falling object) component
|
||||||
|
impl<'a> System<'a> for BirbGravity {
|
||||||
|
type SystemData = (
|
||||||
|
WriteStorage<'a, Transform>,
|
||||||
|
WriteStorage<'a, Birb>,
|
||||||
|
Read<'a, Time>,
|
||||||
|
Read<'a, InputHandler<StringBindings>>,
|
||||||
|
);
|
||||||
|
|
||||||
|
fn run(&mut self, (mut transforms, mut scrolling, time, input): Self::SystemData) {
|
||||||
|
for (mut transform, mut object) in (&mut transforms, &mut scrolling).join() {
|
||||||
|
|
||||||
|
if input.action_is_down("flap").expect("No action") {
|
||||||
|
object.vertical_speed = 500.0;
|
||||||
|
}
|
||||||
|
object.vertical_speed -= 1000.0 * time.delta_seconds();
|
||||||
|
transform.prepend_translation_y(object.vertical_speed * time.delta_seconds());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user