Cleanup my asset stupidity...?
This commit is contained in:
parent
7d2e46c263
commit
aaddc46c65
10 changed files with 259 additions and 320 deletions
|
@ -1,72 +0,0 @@
|
|||
use bevy::prelude::*;
|
||||
|
||||
#[derive(Resource, Debug, Default)]
|
||||
pub struct AssetLoader {
|
||||
pub layouts: Layouts,
|
||||
pub images: Images,
|
||||
pub sounds: Sounds,
|
||||
pub fonts: Fonts,
|
||||
}
|
||||
|
||||
#[derive(Resource, Debug, Default)]
|
||||
pub struct Layouts {
|
||||
pub player: Handle<TextureAtlasLayout>,
|
||||
pub statue: Handle<TextureAtlasLayout>,
|
||||
}
|
||||
|
||||
#[derive(Resource, Debug, Default)]
|
||||
pub struct Images {
|
||||
pub player: Handle<Image>,
|
||||
pub statue: Handle<Image>,
|
||||
}
|
||||
|
||||
#[derive(Resource, Debug, Default)]
|
||||
pub struct Sounds {
|
||||
pub meow: Handle<AudioSource>,
|
||||
}
|
||||
|
||||
#[derive(Resource, Debug, Default)]
|
||||
pub struct Fonts {
|
||||
pub iosevkalytemin: Handle<Font>,
|
||||
}
|
||||
|
||||
pub fn startup(
|
||||
mut assets: ResMut<AssetLoader>,
|
||||
asset_server: Res<AssetServer>,
|
||||
mut texture_atlases: ResMut<Assets<TextureAtlasLayout>>,
|
||||
) {
|
||||
let props = asset_server.load("img/Props.png");
|
||||
let player = asset_server.load("img/Player.png");
|
||||
|
||||
let player_atlas = TextureAtlasLayout::from_grid(
|
||||
UVec2::new(32, 64),
|
||||
3,
|
||||
1,
|
||||
Some(UVec2 { x: 0, y: 0 }),
|
||||
Some(UVec2 { x: 0, y: 0 }),
|
||||
);
|
||||
let statue_atlas =
|
||||
TextureAtlasLayout::from_grid(UVec2::new(40, 74), 1, 1, None, Some(UVec2::new(443, 20)));
|
||||
|
||||
let player_atlas_handle = texture_atlases.add(player_atlas);
|
||||
let statue_atlas_handle = texture_atlases.add(statue_atlas);
|
||||
|
||||
*assets = AssetLoader {
|
||||
images: Images {
|
||||
player,
|
||||
statue: props.clone(),
|
||||
},
|
||||
layouts: Layouts {
|
||||
player: player_atlas_handle,
|
||||
statue: statue_atlas_handle,
|
||||
},
|
||||
|
||||
sounds: Sounds {
|
||||
meow: asset_server.load("sfx/meow.wav"),
|
||||
},
|
||||
|
||||
fonts: Fonts {
|
||||
iosevkalytemin: asset_server.load("font/iosevka-lyteterm-regular.subset.ttf"),
|
||||
},
|
||||
};
|
||||
}
|
|
@ -2,8 +2,8 @@ use bevy::prelude::*;
|
|||
use bevy::render::camera::Camera;
|
||||
|
||||
pub fn startup(mut commands: Commands) {
|
||||
let bundle = (Camera2dBundle::default(), IsDefaultUiCamera);
|
||||
// bundle.0.projection.scale = 1;
|
||||
let mut bundle = (Camera2dBundle::default(), IsDefaultUiCamera);
|
||||
bundle.0.projection.scale = 1.;
|
||||
commands.spawn(bundle);
|
||||
}
|
||||
|
||||
|
|
4
src/game.rs
Normal file
4
src/game.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
use crate::prelude::*;
|
||||
|
||||
#[derive(Component, Default)]
|
||||
pub struct Gameobject;
|
53
src/input.rs
Normal file
53
src/input.rs
Normal file
|
@ -0,0 +1,53 @@
|
|||
use bevy::prelude::*;
|
||||
|
||||
#[derive(Resource, Default, Debug, Clone, PartialEq)]
|
||||
pub struct Input {
|
||||
pub movement: Vec2,
|
||||
pub angle: f32,
|
||||
pub action: bool,
|
||||
pub cancel: bool,
|
||||
}
|
||||
|
||||
pub fn process_input(
|
||||
mut input: ResMut<Input>,
|
||||
keys: Res<ButtonInput<KeyCode>>,
|
||||
// mouse: Res<ButtonInput<MouseButton>>,
|
||||
) {
|
||||
input.movement.x = 0.;
|
||||
input.movement.y = 0.;
|
||||
for key in keys.get_pressed() {
|
||||
match key {
|
||||
KeyCode::KeyA | KeyCode::ArrowLeft => {
|
||||
input.movement -= Vec2::X;
|
||||
}
|
||||
KeyCode::KeyD | KeyCode::ArrowRight => {
|
||||
input.movement += Vec2::X;
|
||||
}
|
||||
KeyCode::KeyW | KeyCode::ArrowUp => {
|
||||
input.movement += Vec2::Y;
|
||||
}
|
||||
KeyCode::KeyS | KeyCode::ArrowDown => {
|
||||
input.movement -= Vec2::Y;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
input.movement = input.movement.normalize_or_zero();
|
||||
// input.target // not set using keyboard, see mouse
|
||||
input.action = input.action || keys.any_pressed([KeyCode::Space, KeyCode::Enter]);
|
||||
input.cancel = input.cancel || keys.just_pressed(KeyCode::Escape);
|
||||
|
||||
info!("Input: {:#?}", input);
|
||||
}
|
||||
|
||||
// TODO: controller input: https://bevy-cheatbook.github.io/input/gamepad.html
|
||||
// Iterate controllers on startup and assign to players/units?
|
||||
// What logic for handling controller connection/disconnection?
|
||||
// Will we have splitscreen?
|
||||
// Once a controller is assigned to a player, we can handle its input
|
||||
// pub fn controller_input(
|
||||
// axes: Res<Axis<GamepadAxis>>,
|
||||
// buttons: Res<ButtonInput<GamepadButton>>,
|
||||
// my_gamepad: Option<Res<MyGamepad>>,
|
||||
// ) {
|
||||
// }
|
151
src/main.rs
151
src/main.rs
|
@ -1,15 +1,20 @@
|
|||
use bevy::audio::{AudioPlugin, SpatialScale};
|
||||
use bevy::diagnostic::{DiagnosticsStore, FrameTimeDiagnosticsPlugin};
|
||||
use bevy::prelude::{default, *};
|
||||
use bevy::window::{PrimaryWindow, WindowMode};
|
||||
|
||||
mod assets;
|
||||
mod camera;
|
||||
mod game;
|
||||
mod input;
|
||||
mod main_menu;
|
||||
mod movement;
|
||||
mod player;
|
||||
mod prelude;
|
||||
mod statue;
|
||||
|
||||
use bevy::asset::load_internal_binary_asset;
|
||||
use bevy::audio::{AudioPlugin, SpatialScale};
|
||||
use bevy::diagnostic::{DiagnosticsStore, FrameTimeDiagnosticsPlugin};
|
||||
use bevy::window::{PrimaryWindow, WindowMode};
|
||||
use input::Input;
|
||||
use prelude::*;
|
||||
use statue::SpawnStatueEvent;
|
||||
|
||||
#[derive(States, Default, Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Game {
|
||||
#[default]
|
||||
|
@ -39,7 +44,8 @@ fn main() -> AppExit {
|
|||
.set(WindowPlugin {
|
||||
primary_window: Some(Window {
|
||||
title: "Kodo Tag".into(),
|
||||
mode: bevy::window::WindowMode::BorderlessFullscreen,
|
||||
// mode: bevy::window::WindowMode::BorderlessFullscreen,
|
||||
mode: bevy::window::WindowMode::Windowed,
|
||||
// resolution: (640. * 2., 360. * 2.).into(),
|
||||
..default()
|
||||
}),
|
||||
|
@ -52,41 +58,57 @@ fn main() -> AppExit {
|
|||
})
|
||||
.set(ImagePlugin::default_nearest()),
|
||||
FrameTimeDiagnosticsPlugin,
|
||||
))
|
||||
.init_resource::<assets::AssetLoader>()
|
||||
.init_state::<View>()
|
||||
.init_state::<Game>()
|
||||
.add_systems(OnEnter(View::MainMenu), main_menu::startup)
|
||||
.add_systems(OnExit(View::MainMenu), main_menu::exit)
|
||||
.add_systems(OnEnter(View::InGame), (player::startup, statue::startup))
|
||||
.add_systems(OnExit(View::InGame), (player::exit, statue::exit))
|
||||
.add_systems(
|
||||
OnEnter(View::LoadingScreen),
|
||||
(startup, assets::startup, camera::startup),
|
||||
)
|
||||
.add_systems(
|
||||
));
|
||||
|
||||
load_internal_binary_asset!(
|
||||
app,
|
||||
TextStyle::default().font,
|
||||
"../assets/font/iosevka-lyteterm-regular.subset.ttf",
|
||||
|bytes: &[u8], _path: String| { Font::try_from_bytes(bytes.to_vec()).unwrap() }
|
||||
);
|
||||
|
||||
app.init_resource::<input::Input>()
|
||||
.init_state::<View>()
|
||||
.init_state::<Game>();
|
||||
|
||||
app.configure_sets(
|
||||
Update,
|
||||
(
|
||||
update,
|
||||
finish_setup.run_if(in_state(View::LoadingScreen)),
|
||||
(
|
||||
player::sprite_select,
|
||||
player::controls,
|
||||
movement::update_velocity_by_heading,
|
||||
movement::resolve_velocity.after(movement::update_velocity_by_heading),
|
||||
movement::ysort.after(movement::update_velocity_by_heading),
|
||||
camera::update
|
||||
.after(player::controls)
|
||||
.after(movement::resolve_velocity),
|
||||
)
|
||||
.in_set(InGameSet)
|
||||
.run_if(in_state(View::InGame)),
|
||||
(main_menu::update)
|
||||
.in_set(MainMenuSet)
|
||||
.run_if(in_state(View::MainMenu)),
|
||||
MainMenuSet.run_if(in_state(View::MainMenu)),
|
||||
InGameSet
|
||||
.run_if(in_state(View::InGame))
|
||||
.after(input::process_input),
|
||||
),
|
||||
)
|
||||
.insert_resource(ClearColor(Color::srgb(0.3, 0.1, 0.5)));
|
||||
);
|
||||
|
||||
app.add_event::<SpawnStatueEvent>();
|
||||
|
||||
app.add_systems(OnEnter(View::MainMenu), main_menu::startup)
|
||||
.add_systems(OnExit(View::MainMenu), main_menu::exit)
|
||||
.add_systems(OnEnter(View::InGame), (player::startup, statue::startup))
|
||||
.add_systems(OnExit(View::InGame), (player::exit, statue::exit))
|
||||
.add_systems(OnEnter(View::LoadingScreen), (startup, camera::startup))
|
||||
.add_systems(
|
||||
Update,
|
||||
(
|
||||
finish_setup.run_if(in_state(View::LoadingScreen)),
|
||||
input::process_input,
|
||||
(update,).after(input::process_input),
|
||||
(
|
||||
player::control,
|
||||
statue::spawn_statue,
|
||||
movement::update_velocity_by_heading,
|
||||
movement::resolve_velocity.after(movement::update_velocity_by_heading),
|
||||
movement::ysort.after(movement::update_velocity_by_heading),
|
||||
camera::update
|
||||
.after(player::control)
|
||||
.after(movement::resolve_velocity),
|
||||
)
|
||||
.in_set(InGameSet),
|
||||
(main_menu::update).in_set(MainMenuSet),
|
||||
),
|
||||
)
|
||||
.insert_resource(ClearColor(Color::srgb(0.3, 0.1, 0.5)));
|
||||
// NOTE: would need to add PBR feature I think?
|
||||
// Was intending to use this for day/night cycle type stuff a la V Rising?
|
||||
// app.insert_resource(AmbientLight {
|
||||
|
@ -97,14 +119,6 @@ fn main() -> AppExit {
|
|||
app.run()
|
||||
}
|
||||
|
||||
fn toggle_fullscreen(mut window: Mut<Window>) {
|
||||
if window.mode == WindowMode::Windowed {
|
||||
window.mode = WindowMode::BorderlessFullscreen
|
||||
} else {
|
||||
window.mode = WindowMode::Windowed
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
struct FpsText;
|
||||
|
||||
|
@ -112,22 +126,21 @@ fn finish_setup(mut app_state: ResMut<NextState<View>>) {
|
|||
app_state.set(View::MainMenu);
|
||||
}
|
||||
|
||||
fn startup(mut commands: Commands, assets: Res<assets::AssetLoader>) {
|
||||
fn startup(mut commands: Commands, mut ui_scale: ResMut<UiScale>) {
|
||||
commands.spawn((
|
||||
FpsText,
|
||||
TextBundle::from_sections([
|
||||
TextSection::new(
|
||||
"FPS: ",
|
||||
TextStyle {
|
||||
font: assets.fonts.iosevkalytemin.clone(),
|
||||
font_size: 60.,
|
||||
..default()
|
||||
},
|
||||
),
|
||||
TextSection::from_style(TextStyle {
|
||||
font: assets.fonts.iosevkalytemin.clone(),
|
||||
font_size: 60.,
|
||||
color: Color::hsla(0.5, 0.5, 0.5, 0.5),
|
||||
..default()
|
||||
}),
|
||||
])
|
||||
.with_style(Style {
|
||||
|
@ -137,19 +150,49 @@ fn startup(mut commands: Commands, assets: Res<assets::AssetLoader>) {
|
|||
..default()
|
||||
}),
|
||||
));
|
||||
|
||||
ui_scale.0 = 1.;
|
||||
}
|
||||
|
||||
fn update(
|
||||
view: Res<State<View>>,
|
||||
input: Res<Input>,
|
||||
mut next_state: ResMut<NextState<crate::View>>,
|
||||
diagnostics: Res<DiagnosticsStore>,
|
||||
mut query: Query<&mut Text, With<FpsText>>,
|
||||
keyboard: Res<ButtonInput<KeyCode>>,
|
||||
mut window: Query<&mut Window, With<PrimaryWindow>>,
|
||||
keys: Res<ButtonInput<KeyCode>>,
|
||||
mut app_exit_events: ResMut<Events<bevy::app::AppExit>>,
|
||||
) {
|
||||
if keyboard.just_pressed(KeyCode::Enter)
|
||||
&& (keyboard.pressed(KeyCode::AltLeft) || keyboard.pressed(KeyCode::AltRight))
|
||||
if input.cancel {
|
||||
match view.get() {
|
||||
View::InGame => {
|
||||
next_state.set(crate::View::MainMenu);
|
||||
}
|
||||
View::MainMenu => {
|
||||
app_exit_events.send(AppExit::Success);
|
||||
}
|
||||
View::LoadingScreen => {}
|
||||
}
|
||||
} else if input.action {
|
||||
match view.get() {
|
||||
View::InGame => {}
|
||||
View::MainMenu => {
|
||||
next_state.set(crate::View::InGame);
|
||||
}
|
||||
View::LoadingScreen => {}
|
||||
}
|
||||
}
|
||||
if keys.just_pressed(KeyCode::Enter)
|
||||
&& (keys.pressed(KeyCode::AltLeft) || keys.pressed(KeyCode::AltRight))
|
||||
{
|
||||
if let Ok(window) = window.get_single_mut() {
|
||||
toggle_fullscreen(window)
|
||||
let mut window = window;
|
||||
if window.mode == WindowMode::Windowed {
|
||||
window.mode = WindowMode::BorderlessFullscreen
|
||||
} else {
|
||||
window.mode = WindowMode::Windowed
|
||||
}
|
||||
}
|
||||
}
|
||||
for mut text in &mut query {
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
use bevy::prelude::*;
|
||||
|
||||
use crate::assets::AssetLoader;
|
||||
|
||||
#[derive(Component, Debug)]
|
||||
pub struct MainMenu;
|
||||
|
||||
pub fn startup(mut commands: Commands, assets: Res<AssetLoader>) {
|
||||
pub fn startup(mut commands: Commands) {
|
||||
commands
|
||||
.spawn((
|
||||
MainMenu,
|
||||
|
@ -25,7 +23,6 @@ pub fn startup(mut commands: Commands, assets: Res<AssetLoader>) {
|
|||
TextBundle::from_section(
|
||||
"Text Example\nPress ENTER to play",
|
||||
TextStyle {
|
||||
font: assets.fonts.iosevkalytemin.clone(),
|
||||
font_size: 100.0,
|
||||
..default()
|
||||
},
|
||||
|
@ -63,20 +60,4 @@ pub fn exit(mut commands: Commands, q: Query<Entity, With<MainMenu>>) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn update(
|
||||
keyboard: Res<ButtonInput<KeyCode>>,
|
||||
mut next_state: ResMut<NextState<crate::View>>,
|
||||
mut app_exit_events: ResMut<Events<bevy::app::AppExit>>,
|
||||
) {
|
||||
for key in keyboard.get_just_pressed() {
|
||||
match key {
|
||||
KeyCode::Escape => {
|
||||
app_exit_events.send(AppExit::Success);
|
||||
}
|
||||
KeyCode::Enter => {
|
||||
next_state.set(crate::View::InGame);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn update() {}
|
||||
|
|
|
@ -9,7 +9,7 @@ pub struct Heading(pub Vec2);
|
|||
#[derive(Component, Deref, DerefMut, Debug, Default)]
|
||||
pub struct Speed(pub f32);
|
||||
|
||||
#[derive(Component, Debug)]
|
||||
#[derive(Component, Debug, Default)]
|
||||
pub struct YSortable;
|
||||
|
||||
pub fn resolve_velocity(mut query: Query<(&Velocity, &mut Transform)>, time: Res<Time>) {
|
||||
|
|
189
src/player.rs
189
src/player.rs
|
@ -1,17 +1,19 @@
|
|||
use bevy::sprite::MaterialMesh2dBundle;
|
||||
use bevy::sprite::Mesh2dHandle;
|
||||
use bevy::{prelude::*, window::PrimaryWindow};
|
||||
|
||||
use crate::camera::Watched;
|
||||
use crate::movement::YSortable;
|
||||
use crate::statue;
|
||||
use crate::{
|
||||
assets::AssetLoader,
|
||||
movement::{Heading, Mover, Speed, Velocity},
|
||||
};
|
||||
use crate::movement::{Heading, Mover, Speed, Velocity, YSortable};
|
||||
use crate::prelude::*;
|
||||
use bevy::sprite::MaterialMesh2dBundle;
|
||||
|
||||
const PLAYER_SPEED: f32 = 1000.;
|
||||
|
||||
// #[derive(Resource, Default)]
|
||||
// pub struct Layout(Handle<TextureAtlasLayout>);
|
||||
|
||||
// #[derive(Resource)]
|
||||
// pub struct CrosshairMaterial(Handle<ColorMaterial>);
|
||||
|
||||
// #[derive(Resource)]
|
||||
// pub struct CrosshairMesh(Mesh2dHandle);
|
||||
|
||||
#[derive(Component, Debug)]
|
||||
pub struct Player;
|
||||
|
||||
|
@ -20,21 +22,28 @@ pub struct Crosshair;
|
|||
|
||||
pub fn startup(
|
||||
mut commands: Commands,
|
||||
assets: Res<AssetLoader>,
|
||||
assets: Res<AssetServer>,
|
||||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<ColorMaterial>>,
|
||||
) {
|
||||
let layout = assets.add(TextureAtlasLayout::from_grid(
|
||||
UVec2::new(32, 64),
|
||||
3,
|
||||
1,
|
||||
Some(UVec2 { x: 0, y: 0 }),
|
||||
Some(UVec2 { x: 0, y: 0 }),
|
||||
));
|
||||
commands
|
||||
.spawn((
|
||||
Player,
|
||||
YSortable,
|
||||
Watched,
|
||||
SpriteBundle {
|
||||
texture: assets.images.player.clone(),
|
||||
texture: assets.load("img/Player.png"),
|
||||
..default()
|
||||
},
|
||||
TextureAtlas {
|
||||
layout: assets.layouts.player.clone(),
|
||||
layout,
|
||||
..default()
|
||||
},
|
||||
Mover {
|
||||
|
@ -44,7 +53,7 @@ pub fn startup(
|
|||
},
|
||||
))
|
||||
.with_children(|player| {
|
||||
let mesh = Mesh2dHandle(meshes.add(Capsule2d::new(3.0, 25.0)));
|
||||
let mesh = meshes.add(Capsule2d::new(3.0, 25.0));
|
||||
let material = materials.add(Color::hsl(360. * 1 as f32 / 3 as f32, 0.95, 0.7));
|
||||
// let global_transform = GlobalTransform::from_xyz(
|
||||
// 0.0, 20.0,
|
||||
|
@ -62,138 +71,34 @@ pub fn startup(
|
|||
|
||||
player.spawn((
|
||||
Crosshair,
|
||||
// SpatialBundle::default(),
|
||||
// SpatialListener::new(1.),
|
||||
// MaterialMesh2dBundle {
|
||||
// // global_transform,
|
||||
// mesh,
|
||||
// material,
|
||||
// transform,
|
||||
// ..default()
|
||||
// },
|
||||
// Text2dBundle {
|
||||
// text: Text::from_section(
|
||||
// "You",
|
||||
// TextStyle {
|
||||
// font_size: 11.0,
|
||||
// font: assets.fonts.iosevkalytemin.clone(),
|
||||
// color: Color::WHITE,
|
||||
// ..default()
|
||||
// },
|
||||
// ),
|
||||
// transform: Transform::from_translation(Vec3::new(30.0, -30.0, 0.)),
|
||||
// ..default()
|
||||
// },
|
||||
// TODO: crosshair transform?
|
||||
MaterialMesh2dBundle {
|
||||
// global_transform,
|
||||
mesh: mesh.into(),
|
||||
material,
|
||||
transform,
|
||||
..default()
|
||||
},
|
||||
));
|
||||
player.spawn((SpatialBundle::default(), SpatialListener::new(1.)));
|
||||
player.spawn((Text2dBundle {
|
||||
text: Text::from_section(
|
||||
"You",
|
||||
TextStyle {
|
||||
font_size: 18.,
|
||||
color: Color::WHITE,
|
||||
..default()
|
||||
},
|
||||
),
|
||||
transform: Transform::from_translation(Vec3::new(30.0, -30.0, 0.)),
|
||||
..default()
|
||||
},));
|
||||
});
|
||||
}
|
||||
|
||||
pub fn controls(
|
||||
mut commands: Commands,
|
||||
mut player: Query<(&mut Sprite, &mut TextureAtlas, &mut Heading, Entity), With<Player>>,
|
||||
input: Res<ButtonInput<KeyCode>>,
|
||||
mouse_input: Res<ButtonInput<MouseButton>>,
|
||||
assets: Res<AssetLoader>,
|
||||
win: Query<&Window, With<PrimaryWindow>>,
|
||||
cam: Query<(&Camera, &GlobalTransform), With<Camera>>,
|
||||
mut next_state: ResMut<NextState<crate::View>>,
|
||||
mut crosshair: Query<&mut Transform, With<Crosshair>>,
|
||||
) {
|
||||
let (mut sprite, mut texture, mut heading, player_entity) =
|
||||
player.get_single_mut().expect("no player_q entities");
|
||||
let (camera, camera_transform) = cam.single();
|
||||
|
||||
let mouse_world_position = win
|
||||
.single()
|
||||
.cursor_position()
|
||||
.and_then(|cursor| camera.viewport_to_world(&GlobalTransform::from_xyz(0., 0., 0.), cursor))
|
||||
.map(|ray| ray.origin.truncate());
|
||||
|
||||
if let Some(pos) = mouse_world_position {
|
||||
if let Ok(mut t) = crosshair.get_single_mut() {
|
||||
t.look_at(Vec3::ZERO, pos.extend(0.));
|
||||
t.translation = camera_transform.translation();
|
||||
}
|
||||
}
|
||||
|
||||
**heading = Vec2::ZERO;
|
||||
for button in mouse_input.get_just_pressed() {
|
||||
match button {
|
||||
MouseButton::Left => {
|
||||
if let Some(world_position) = win
|
||||
.single()
|
||||
.cursor_position()
|
||||
.and_then(|cursor| camera.viewport_to_world(camera_transform, cursor))
|
||||
.map(|ray| ray.origin.truncate())
|
||||
{
|
||||
let spos = world_position.extend(-world_position.y);
|
||||
commands.spawn(statue::statue_at_position(&assets, spos));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
for key in input.get_just_pressed() {
|
||||
match key {
|
||||
KeyCode::Escape => next_state.set(crate::View::MainMenu),
|
||||
KeyCode::Enter => next_state.set(crate::View::MainMenu),
|
||||
KeyCode::Space => {
|
||||
let child = commands
|
||||
.spawn(AudioSourceBundle {
|
||||
source: assets.sounds.meow.clone(),
|
||||
settings: PlaybackSettings::DESPAWN.with_spatial(false),
|
||||
})
|
||||
.id();
|
||||
commands.entity(player_entity).push_children(&[child]);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
for key in input.get_pressed() {
|
||||
match key {
|
||||
KeyCode::KeyA | KeyCode::ArrowLeft => {
|
||||
**heading -= Vec2::X;
|
||||
}
|
||||
KeyCode::KeyD | KeyCode::ArrowRight => {
|
||||
**heading += Vec2::X;
|
||||
}
|
||||
KeyCode::KeyW | KeyCode::ArrowUp => {
|
||||
**heading += Vec2::Y;
|
||||
}
|
||||
KeyCode::KeyS | KeyCode::ArrowDown => {
|
||||
**heading -= Vec2::Y;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
if heading.y < 0. {
|
||||
texture.index = 0;
|
||||
} else if heading.y > 0. {
|
||||
texture.index = 1;
|
||||
} else if heading.x != 0. {
|
||||
texture.index = 2;
|
||||
sprite.flip_x = heading.x > 0.;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sprite_select(
|
||||
mut q: Query<(&Handle<TextureAtlasLayout>, &mut TextureAtlas), With<Player>>,
|
||||
keyboard_input: Res<ButtonInput<KeyCode>>,
|
||||
texture_atlases: Res<Assets<TextureAtlasLayout>>,
|
||||
) {
|
||||
if keyboard_input.just_pressed(KeyCode::KeyN) {
|
||||
info!("pressed N");
|
||||
if let Ok((texture, mut sprite)) = q.get_single_mut() {
|
||||
info!("next tex: {}", sprite.index);
|
||||
let t = texture_atlases
|
||||
.get(texture)
|
||||
.expect("could not load player texture");
|
||||
if sprite.index < t.textures.len() - 1 {
|
||||
sprite.index += 1;
|
||||
} else {
|
||||
sprite.index = 0;
|
||||
}
|
||||
}
|
||||
pub fn control(input: Res<Input>, mut player: Query<&mut Heading, With<Player>>) {
|
||||
if let Ok(mut heading) = player.get_single_mut() {
|
||||
heading.0 = input.movement;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
3
src/prelude.rs
Normal file
3
src/prelude.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
pub use crate::game::Gameobject;
|
||||
pub use crate::input::Input;
|
||||
pub use bevy::prelude::*;
|
|
@ -1,36 +1,58 @@
|
|||
use crate::{assets::AssetLoader, movement::YSortable};
|
||||
use bevy::prelude::*;
|
||||
use crate::movement::YSortable;
|
||||
use crate::prelude::*;
|
||||
|
||||
#[derive(Component, Debug)]
|
||||
#[derive(Component, Debug, Default)]
|
||||
pub struct Statue;
|
||||
|
||||
pub fn statue_at_position(
|
||||
assets: &Res<AssetLoader>,
|
||||
translation: Vec3,
|
||||
) -> (
|
||||
Statue,
|
||||
YSortable,
|
||||
bevy::prelude::SpriteBundle,
|
||||
bevy::prelude::TextureAtlas,
|
||||
) {
|
||||
(
|
||||
Statue,
|
||||
YSortable,
|
||||
SpriteBundle {
|
||||
transform: Transform::from_translation(translation),
|
||||
texture: assets.images.statue.clone(),
|
||||
..default()
|
||||
},
|
||||
TextureAtlas {
|
||||
layout: assets.layouts.statue.clone(),
|
||||
..default()
|
||||
},
|
||||
)
|
||||
#[derive(Bundle, Default)]
|
||||
pub struct StatueBundle {
|
||||
gameobject: Gameobject,
|
||||
statue: Statue,
|
||||
ysort: YSortable,
|
||||
sprite: SpriteBundle,
|
||||
texture: TextureAtlas,
|
||||
}
|
||||
|
||||
pub fn startup(mut commands: Commands, assets: Res<AssetLoader>) {
|
||||
commands.spawn(statue_at_position(&assets, Vec3::new(50., 50., 0.)));
|
||||
commands.spawn(statue_at_position(&assets, Vec3::new(50., 100., 0.)));
|
||||
pub fn startup(mut events: EventWriter<SpawnStatueEvent>) {
|
||||
events.send_batch([
|
||||
SpawnStatueEvent(Vec3::new(50., 50., 0.)),
|
||||
SpawnStatueEvent(Vec3::new(50., 100., 0.)),
|
||||
]);
|
||||
}
|
||||
|
||||
#[derive(Event)]
|
||||
pub struct SpawnStatueEvent(Vec3);
|
||||
|
||||
pub fn spawn_statue(
|
||||
mut events: EventReader<SpawnStatueEvent>,
|
||||
mut commands: Commands,
|
||||
assets: Res<AssetServer>,
|
||||
mut layouts: ResMut<Assets<TextureAtlasLayout>>,
|
||||
) {
|
||||
// TODO: rebuilding this layout each spawn is surely not correct?
|
||||
let layout = layouts.add(TextureAtlasLayout::from_grid(
|
||||
UVec2::new(40, 74),
|
||||
1,
|
||||
1,
|
||||
None,
|
||||
Some(UVec2::new(443, 20)),
|
||||
));
|
||||
|
||||
for ev in events.read() {
|
||||
let bundle = StatueBundle {
|
||||
sprite: SpriteBundle {
|
||||
transform: Transform::from_translation(ev.0),
|
||||
texture: assets.load("img/Props.png"),
|
||||
..default()
|
||||
},
|
||||
texture: TextureAtlas {
|
||||
layout: layout.clone(),
|
||||
..default()
|
||||
},
|
||||
..default()
|
||||
};
|
||||
commands.spawn(bundle);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exit(mut commands: Commands, q: Query<Entity, With<Statue>>) {
|
||||
|
|
Loading…
Reference in a new issue