-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
549 additions
and
113 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
use bevy::prelude::{ButtonInput, KeyCode, Res}; | ||
|
||
pub enum GameControl { | ||
Up, | ||
Down, | ||
Left, | ||
Right, | ||
} | ||
|
||
impl GameControl { | ||
pub fn pressed(&self, keyboard_input: &Res<ButtonInput<KeyCode>>) -> bool { | ||
match self { | ||
GameControl::Up => { | ||
keyboard_input.pressed(KeyCode::KeyW) || keyboard_input.pressed(KeyCode::ArrowUp) | ||
} | ||
GameControl::Down => { | ||
keyboard_input.pressed(KeyCode::KeyS) || keyboard_input.pressed(KeyCode::ArrowDown) | ||
} | ||
GameControl::Left => { | ||
keyboard_input.pressed(KeyCode::KeyA) || keyboard_input.pressed(KeyCode::ArrowLeft) | ||
} | ||
GameControl::Right => { | ||
keyboard_input.pressed(KeyCode::KeyD) || keyboard_input.pressed(KeyCode::ArrowRight) | ||
} | ||
} | ||
} | ||
} | ||
|
||
pub fn get_movement(control: GameControl, input: &Res<ButtonInput<KeyCode>>) -> f32 { | ||
if control.pressed(input) { | ||
1.0 | ||
} else { | ||
0.0 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
use bevy::math::Vec3Swizzles; | ||
use bevy::prelude::*; | ||
|
||
use crate::actions::game_control::{get_movement, GameControl}; | ||
use crate::player::Player; | ||
use crate::GameState; | ||
|
||
mod game_control; | ||
|
||
pub const FOLLOW_EPSILON: f32 = 5.; | ||
|
||
pub struct ActionsPlugin; | ||
|
||
// This plugin listens for keyboard input and converts the input into Actions | ||
// Actions can then be used as a resource in other systems to act on the player input. | ||
impl Plugin for ActionsPlugin { | ||
fn build(&self, app: &mut App) { | ||
app.init_resource::<Actions>().add_systems( | ||
Update, | ||
set_movement_actions.run_if(in_state(GameState::Playing)), | ||
); | ||
} | ||
} | ||
|
||
#[derive(Default, Resource)] | ||
pub struct Actions { | ||
pub player_movement: Option<Vec2>, | ||
} | ||
|
||
pub fn set_movement_actions( | ||
mut actions: ResMut<Actions>, | ||
keyboard_input: Res<ButtonInput<KeyCode>>, | ||
touch_input: Res<Touches>, | ||
player: Query<&Transform, With<Player>>, | ||
camera: Query<(&Camera, &GlobalTransform), With<Camera2d>>, | ||
) { | ||
let mut player_movement = Vec2::new( | ||
get_movement(GameControl::Right, &keyboard_input) | ||
- get_movement(GameControl::Left, &keyboard_input), | ||
get_movement(GameControl::Up, &keyboard_input) | ||
- get_movement(GameControl::Down, &keyboard_input), | ||
); | ||
|
||
if let Some(touch_position) = touch_input.first_pressed_position() { | ||
let (camera, camera_transform) = camera.single(); | ||
if let Some(touch_position) = camera.viewport_to_world_2d(camera_transform, touch_position) | ||
{ | ||
let diff = touch_position - player.single().translation.xy(); | ||
if diff.length() > FOLLOW_EPSILON { | ||
player_movement = diff.normalize(); | ||
} | ||
} | ||
} | ||
|
||
if player_movement != Vec2::ZERO { | ||
actions.player_movement = Some(player_movement.normalize()); | ||
} else { | ||
actions.player_movement = None; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
use crate::actions::{set_movement_actions, Actions}; | ||
use crate::loading::AudioAssets; | ||
use crate::GameState; | ||
use bevy::prelude::*; | ||
use bevy_kira_audio::prelude::*; | ||
|
||
pub struct InternalAudioPlugin; | ||
|
||
// This plugin is responsible to control the game audio | ||
impl Plugin for InternalAudioPlugin { | ||
fn build(&self, app: &mut App) { | ||
app.add_plugins(AudioPlugin) | ||
.add_systems(OnEnter(GameState::Playing), start_audio) | ||
.add_systems( | ||
Update, | ||
control_flying_sound | ||
.after(set_movement_actions) | ||
.run_if(in_state(GameState::Playing)), | ||
); | ||
} | ||
} | ||
|
||
#[derive(Resource)] | ||
struct FlyingAudio(Handle<AudioInstance>); | ||
|
||
fn start_audio(mut commands: Commands, audio_assets: Res<AudioAssets>, audio: Res<Audio>) { | ||
audio.pause(); | ||
let handle = audio | ||
.play(audio_assets.flying.clone()) | ||
.looped() | ||
.with_volume(0.3) | ||
.handle(); | ||
commands.insert_resource(FlyingAudio(handle)); | ||
} | ||
|
||
fn control_flying_sound( | ||
actions: Res<Actions>, | ||
audio: Res<FlyingAudio>, | ||
mut audio_instances: ResMut<Assets<AudioInstance>>, | ||
) { | ||
if let Some(instance) = audio_instances.get_mut(&audio.0) { | ||
match instance.state() { | ||
PlaybackState::Paused { .. } => { | ||
if actions.player_movement.is_some() { | ||
instance.resume(AudioTween::default()); | ||
} | ||
} | ||
PlaybackState::Playing { .. } => { | ||
if actions.player_movement.is_none() { | ||
instance.pause(AudioTween::default()); | ||
} | ||
} | ||
_ => {} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,51 @@ | ||
#![allow(clippy::type_complexity)] | ||
|
||
mod actions; | ||
mod audio; | ||
mod loading; | ||
mod menu; | ||
mod player; | ||
|
||
use crate::actions::ActionsPlugin; | ||
use crate::audio::InternalAudioPlugin; | ||
use crate::loading::LoadingPlugin; | ||
use crate::menu::MenuPlugin; | ||
use crate::player::PlayerPlugin; | ||
|
||
use bevy::app::App; | ||
#[cfg(debug_assertions)] | ||
use bevy::diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}; | ||
use bevy::prelude::*; | ||
|
||
mod performance_matrix; | ||
mod systems; | ||
// This example game uses States to separate logic | ||
// See https://bevy-cheatbook.github.io/programming/states.html | ||
// Or https://github.com/bevyengine/bevy/blob/main/examples/ecs/state.rs | ||
#[derive(States, Default, Clone, Eq, PartialEq, Debug, Hash)] | ||
enum GameState { | ||
// During the loading State the LoadingPlugin will load our assets | ||
#[default] | ||
Loading, | ||
// During this State the actual game logic is executed | ||
Playing, | ||
// Here the menu is drawn and waiting for player interaction | ||
Menu, | ||
} | ||
|
||
pub struct SokobanPlugin; | ||
pub struct GamePlugin; | ||
|
||
impl Plugin for SokobanPlugin { | ||
impl Plugin for GamePlugin { | ||
fn build(&self, app: &mut App) { | ||
// app.add_plugins(DefaultPlugins); | ||
|
||
// #[cfg(debug_assertions)] | ||
// app.add_plugins(performance_matrix::PerformanceMatrixPlugin); | ||
app.init_state::<GameState>().add_plugins(( | ||
LoadingPlugin, | ||
MenuPlugin, | ||
ActionsPlugin, | ||
InternalAudioPlugin, | ||
PlayerPlugin, | ||
)); | ||
|
||
// app.add_systems(Startup, (systems::window::setup, systems::camera::setup)); | ||
#[cfg(debug_assertions)] | ||
{ | ||
app.add_plugins((FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin::default())); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
use crate::GameState; | ||
use bevy::prelude::*; | ||
use bevy_asset_loader::prelude::*; | ||
use bevy_kira_audio::AudioSource; | ||
|
||
pub struct LoadingPlugin; | ||
|
||
/// This plugin loads all assets using [`AssetLoader`] from a third party bevy plugin | ||
/// Alternatively you can write the logic to load assets yourself | ||
/// If interested, take a look at <https://bevy-cheatbook.github.io/features/assets.html> | ||
impl Plugin for LoadingPlugin { | ||
fn build(&self, app: &mut App) { | ||
app.add_loading_state( | ||
LoadingState::new(GameState::Loading) | ||
.continue_to_state(GameState::Menu) | ||
.load_collection::<AudioAssets>() | ||
.load_collection::<TextureAssets>(), | ||
); | ||
} | ||
} | ||
|
||
// the following asset collections will be loaded during the State `GameState::Loading` | ||
// when done loading, they will be inserted as resources (see <https://github.com/NiklasEi/bevy_asset_loader>) | ||
|
||
#[derive(AssetCollection, Resource)] | ||
pub struct AudioAssets { | ||
#[asset(path = "audio/flying.ogg")] | ||
pub flying: Handle<AudioSource>, | ||
} | ||
|
||
#[derive(AssetCollection, Resource)] | ||
pub struct TextureAssets { | ||
#[asset(path = "textures/bevy.png")] | ||
pub bevy: Handle<Image>, | ||
#[asset(path = "textures/github.png")] | ||
pub github: Handle<Image>, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,53 @@ | ||
// disable console on windows for release builds | ||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] | ||
|
||
use bevy::asset::AssetMetaCheck; | ||
use bevy::prelude::*; | ||
use soukoban_rs::SokobanPlugin; | ||
use bevy::window::PrimaryWindow; | ||
use bevy::winit::WinitWindows; | ||
use bevy::DefaultPlugins; | ||
use bevy_game::GamePlugin; // ToDo: Replace bevy_game with your new crate name. | ||
use std::io::Cursor; | ||
use winit::window::Icon; | ||
|
||
fn main() { | ||
App::new() | ||
.add_plugins(( | ||
DefaultPlugins.set(WindowPlugin { | ||
primary_window: Some(Window { | ||
title: "Sokoban".to_string(), | ||
canvas: Some("#bevy".to_owned()), | ||
prevent_default_event_handling: false, | ||
..default() | ||
}), | ||
.insert_resource(Msaa::Off) | ||
.insert_resource(AssetMetaCheck::Never) | ||
.insert_resource(ClearColor(Color::rgb(0.4, 0.4, 0.4))) | ||
.add_plugins(DefaultPlugins.set(WindowPlugin { | ||
primary_window: Some(Window { | ||
title: "Bevy game".to_string(), // ToDo | ||
// Bind to canvas included in `index.html` | ||
canvas: Some("#bevy".to_owned()), | ||
// Tells wasm not to override default event handling, like F5 and Ctrl+R | ||
prevent_default_event_handling: false, | ||
..default() | ||
}), | ||
// SokobanPlugin, | ||
)) | ||
..default() | ||
})) | ||
.add_plugins(GamePlugin) | ||
.add_systems(Startup, set_window_icon) | ||
.run(); | ||
} | ||
|
||
// Sets the icon on windows and X11 | ||
fn set_window_icon( | ||
windows: NonSend<WinitWindows>, | ||
primary_window: Query<Entity, With<PrimaryWindow>>, | ||
) { | ||
let primary_entity = primary_window.single(); | ||
let Some(primary) = windows.get_window(primary_entity) else { | ||
return; | ||
}; | ||
let icon_buf = Cursor::new(include_bytes!( | ||
"../build/macos/AppIcon.iconset/icon_256x256.png" | ||
)); | ||
if let Ok(image) = image::load(icon_buf, image::ImageFormat::Png) { | ||
let image = image.into_rgba8(); | ||
let (width, height) = image.dimensions(); | ||
let rgba = image.into_raw(); | ||
let icon = Icon::from_rgba(rgba, width, height).unwrap(); | ||
primary.set_window_icon(Some(icon)); | ||
}; | ||
} |
Oops, something went wrong.