WQS2WD437EWG2CKPOY5TDWPEBE3US7LGHVAH2HVYQ7RW2L6FHJ5AC
T7TFTN36VJXR3CQDC66LXB2LKYSYUBVCI5KN3YAKNT2VESP7TPGQC
EG65GETJ6WWNENAGPJYVO3O2TGAHFIMFY52GGLKE5GTLPD47IRCQC
MKB2A5XCWBZO2E6QFE6PD36LF3IGMJCGJB5TGMRAPSKCKHS75ISAC
7FTW5AQKOO4W5AIHYZSAKLQR6LGVTXH7SKMSTA4ER4C4HP54VE4QC
C5GZASC2IIWFVVD2UTI2IKF7YDQYT3NHSUUUW66GSN4NCXTSPVIQC
7SXAXY6J4QHPDUUHCKZDEZOZ2IUMSBWODICOMIZH2KA2BGV3F54QC
EV477LPQ57FEHMFO6E3LL5MFWZC6NTGER42SKP5CJN73SWXGB5AQC
DBHCCY3W2DG4WYMXBZ2UCNYVGZ5PS5UUUNWCXVYJ4TMXQDIZT6GAC
CAN3DHITMPDA2DJC63QMMPMIC63FMWCUAI4ZLKPLEHIYG2EWIAHAC
5Y32O2B2GTH2UHFA3NO4ZY673XNHT3W4DQADFMK4LMKLSXMZKHGQC
ZH7HF4FYTYVE5NQFULKSDXIE3LHMFVQGI3FKF366QRY7NJLPADRQC
DHAY4KB3FVA3WZVBDVVGGBGLEACA7C4PFKSKGHNFOSXVNGYOXJ7AC
66PNECCRWS2BPZS555P2355EY2PAHZWHJJEXTDU2WUBOHANRNXFQC
ZUZLL6PWZE57MLTQJ56MT3HGIQU6NEHQRB63VQYJRY5HNVC7NVMAC
OQCI44VL3IROGBJ52MUI3AICPKEPAJVFL45PGQNNQRK4TKIK7HAAC
YT2GB32PAGZCSNZGKTQH7MCJ675TK2G5OHS7SY4R2FDCNBKQHXYAC
HYJ4HJQVLLDTE6JYKEYQK2LBWREOQUATESGB3QP7WDJB3IMVS6OAC
5EIYEUF3S5ETMMVECT7GGEEW6O45AJHAA7HS2EWK5II2IYYD7JGAC
NT6M5NVCET62C54HC6RHQRH2RJUGD4LYCYNSIKJFKCHBN7F33UQQC
D4QISWMTFAC4M2VFEQJBQ4FTJRRKTJCJCECDQPICUELOD75XSMUAC
RX53J3WT6RGLQVUDTYKRCMO2BMD765ZF4JC6ADPUVWSVLDZ7RI5AC
7BH3JTSGT655ESF4H7UY2BPSXV35JGKAKYUWZVLCKPCEAQDSL57QC
3PEU6H5YDCRN2O7IIORFPJRKDE6FOJVMBOXSAGU7CJWOHULYNEAQC
use super::{movement_pointer, PlayerAssets};
use bevy::prelude::*;
use bevy_ecs_ldtk::LdtkEntity;
use bevy_prototype_lyon::{entity::ShapeBundle, geometry::GeometryBuilder, shapes};
use leafwing_input_manager::prelude::*;
use moonshine_spawn::{spawn_children, SpawnChildren};
#[derive(Component)]
pub(crate) struct DashState(pub bool);
pub(crate) fn handle_dashing(mut query: Query<(&mut DashState, &ActionState<PlayerAction>)>) {
for (mut dash_state, action_state) in query.iter_mut() {
// handle hold dash
if action_state.just_pressed(&PlayerAction::HoldDash) {
dash_state.0 = true;
} else if action_state.just_released(&PlayerAction::HoldDash) {
dash_state.0 = false;
}
// Handle toggle dash
if action_state.just_pressed(&PlayerAction::ToggleDash) {
dash_state.0 = !dash_state.0;
}
}
}
pub(crate) fn move_player(
mut query: Query<
(
&ActionState<PlayerAction>,
&mut Transform,
Option<&mut Sprite>,
&DashState,
&mut movement_pointer::MovementDirection,
),
With<Player>,
>,
time: Res<Time>,
) {
for (action_state, mut transform, maybe_sprite, dash, mut md) in query.iter_mut() {
// Right now, treat our joystick as a velocity.
if let Some(dad) = action_state.clamped_axis_pair(&PlayerAction::Move) {
const SPEED: f32 = 350.0;
const DASH_SPEED: f32 = 700.0;
let movement = dad.xy();
if let Some(movement_norm) = movement.try_normalize() {
let speed = if dash.0 { DASH_SPEED } else { SPEED };
transform.translation += movement_norm.extend(0.0) * speed * time.delta_seconds();
md.0 = movement_norm;
md.1 = speed;
if let Some(mut sprite) = maybe_sprite {
// If we have a sprite, flip x if we moved in a negative x dir
// Might not be necessary
let x_movement = movement_norm.x;
match x_movement.signum() {
x if x == 1.0 && x_movement > f32::EPSILON => {
sprite.flip_x = false;
}
// cuz neg
x if x == -1.0 && x_movement < f32::EPSILON => {
sprite.flip_x = true;
}
_ => {}
}
}
} else {
md.0 = Vec2::ZERO;
md.1 = 0.0;
}
}
}
}
#[derive(Actionlike, PartialEq, Eq, Hash, Clone, Copy, Debug, Reflect)]
pub(crate) enum PlayerAction {
Move,
LightAttack,
HeavyAttack,
// Dash variants, both should just enable dash, but one
// needs to be held, while the other toggles dash on and off
HoldDash,
ToggleDash,
// X axis - switching between cards
// +Y axis - above deadzone, use card
// -Y axis - above deadzone, held, exhaust hand
Hand,
}
#[derive(Component, Default)]
pub(crate) struct Player;
#[derive(Bundle, Default, LdtkEntity)]
pub(crate) struct PlayerBlueprint {
pub(crate) player: Player,
}
#[derive(Bundle)]
pub(crate) struct PlayerBundle {
pub(crate) input_manager_bundle: InputManagerBundle<PlayerAction>,
// For now, use a mesh
// mesh: MaterialMesh2dBundle<ColorMaterial>,
pub(crate) sprite_sheet: SpriteSheetBundle,
// used to render a pointed arrow
pub(crate) movement_dir: movement_pointer::MovementDirection,
pub(crate) dash: DashState,
// moonshine children
pub(crate) children: SpawnChildren,
}
pub(crate) fn process_player_start(
mut commands: Commands,
new_entity_instances: Query<(Entity, &Transform), Added<Player>>,
// mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>,
player_assets: Res<PlayerAssets>,
) {
for (entity, transform) in new_entity_instances.iter() {
commands.entity(entity).insert(PlayerBundle {
input_manager_bundle: InputManagerBundle::with_map(default_input_map()),
movement_dir: movement_pointer::MovementDirection(Vec2::X, 0.0),
dash: DashState(false),
sprite_sheet: SpriteSheetBundle {
texture: player_assets.texture.clone(),
atlas: TextureAtlas {
layout: player_assets.layout.clone(),
index: 0,
},
transform: (*transform) * Transform::default().with_translation(Vec3::Y * 8.0),
..default()
},
// mesh: MaterialMesh2dBundle {
// mesh: meshes
// .add(Rectangle {
// half_size: (16.0, 24.0).into(),
// })
// .into(),
// // Be careful not to overwrite the LDtk transform
// // Change our origin
// transform: (*transform) * Transform::default().with_translation(Vec3::Y * 8.0),
// material: materials.add(Color::PURPLE),
// ..default()
// },
children: spawn_children(|cb| {
cb.spawn(movement_pointer::MovementPointerBundle {
pointer: movement_pointer::MovementPointer,
shape: ShapeBundle {
spatial: SpatialBundle {
transform: Transform::default().with_scale(Vec3::new(0.5, 1.0, 1.0)),
..default()
},
path: GeometryBuilder::build_as(&shapes::RegularPolygon {
sides: 3,
feature: shapes::RegularPolygonFeature::Apothem(5.0),
..default()
}),
material: materials.add(Color::ORANGE_RED),
..default()
},
});
}),
});
}
}
pub(crate) fn default_input_map() -> InputMap<PlayerAction> {
let mut map = InputMap::default();
map.insert(PlayerAction::Move, DualAxis::left_stick());
map.insert(PlayerAction::Move, VirtualDPad::wasd());
map.insert(PlayerAction::LightAttack, KeyCode::KeyZ);
map.insert(PlayerAction::HeavyAttack, KeyCode::KeyX);
map.insert(PlayerAction::HoldDash, GamepadButtonType::RightTrigger);
map.insert(PlayerAction::HoldDash, KeyCode::ShiftLeft);
map.insert(PlayerAction::ToggleDash, KeyCode::KeyC);
map.insert(PlayerAction::Hand, VirtualDPad::gamepad_face_buttons());
map.insert(PlayerAction::Hand, VirtualDPad::arrow_keys());
map
}
}
}
#[derive(Component)]
struct DashState(bool);
fn handle_dashing(mut query: Query<(&mut DashState, &ActionState<PlayerAction>)>) {
for (mut dash_state, action_state) in query.iter_mut() {
// handle hold dash
if action_state.just_pressed(&PlayerAction::HoldDash) {
dash_state.0 = true;
} else if action_state.just_released(&PlayerAction::HoldDash) {
dash_state.0 = false;
}
// Handle toggle dash
if action_state.just_pressed(&PlayerAction::ToggleDash) {
dash_state.0 = !dash_state.0;
}
}
}
fn move_player(
mut query: Query<
(
&ActionState<PlayerAction>,
&mut Transform,
Option<&mut Sprite>,
&DashState,
&mut movement_pointer::MovementDirection,
),
With<Player>,
>,
time: Res<Time>,
) {
for (action_state, mut transform, maybe_sprite, dash, mut md) in query.iter_mut() {
// Right now, treat our joystick as a velocity.
if let Some(dad) = action_state.clamped_axis_pair(&PlayerAction::Move) {
const SPEED: f32 = 350.0;
const DASH_SPEED: f32 = 700.0;
let movement = dad.xy();
if let Some(movement_norm) = movement.try_normalize() {
let speed = if dash.0 { DASH_SPEED } else { SPEED };
transform.translation += movement_norm.extend(0.0) * speed * time.delta_seconds();
md.0 = movement_norm;
md.1 = speed;
if let Some(mut sprite) = maybe_sprite {
// If we have a sprite, flip x if we moved in a negative x dir
// Might not be necessary
let x_movement = movement_norm.x;
match x_movement.signum() {
x if x == 1.0 && x_movement > f32::EPSILON => {
sprite.flip_x = false;
}
// cuz neg
x if x == -1.0 && x_movement < f32::EPSILON => {
sprite.flip_x = true;
}
_ => {}
}
}
} else {
md.0 = Vec2::ZERO;
md.1 = 0.0;
}
}
}
}
#[derive(Actionlike, PartialEq, Eq, Hash, Clone, Copy, Debug, Reflect)]
enum PlayerAction {
Move,
LightAttack,
HeavyAttack,
// Dash variants, both should just enable dash, but one
// needs to be held, while the other toggles dash on and off
HoldDash,
ToggleDash,
// X axis - switching between cards
// +Y axis - above deadzone, use card
// -Y axis - above deadzone, held, exhaust hand
Hand,
}
#[derive(Component, Default)]
struct Player;
#[derive(Bundle, Default, LdtkEntity)]
struct PlayerBlueprint {
player: Player,
}
#[derive(Bundle)]
struct PlayerBundle {
input_manager_bundle: InputManagerBundle<PlayerAction>,
// For now, use a mesh
// mesh: MaterialMesh2dBundle<ColorMaterial>,
sprite_sheet: SpriteSheetBundle,
// used to render a pointed arrow
movement_dir: movement_pointer::MovementDirection,
dash: DashState,
// moonshine children
children: SpawnChildren,
}
fn process_player_start(
mut commands: Commands,
new_entity_instances: Query<(Entity, &Transform), Added<Player>>,
// mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>,
player_assets: Res<PlayerAssets>,
) {
for (entity, transform) in new_entity_instances.iter() {
commands.entity(entity).insert(PlayerBundle {
input_manager_bundle: InputManagerBundle::with_map(default_input_map()),
movement_dir: movement_pointer::MovementDirection(Vec2::X, 0.0),
dash: DashState(false),
sprite_sheet: SpriteSheetBundle {
texture: player_assets.texture.clone(),
atlas: TextureAtlas {
layout: player_assets.layout.clone(),
index: 0,
},
transform: (*transform) * Transform::default().with_translation(Vec3::Y * 8.0),
..default()
},
// mesh: MaterialMesh2dBundle {
// mesh: meshes
// .add(Rectangle {
// half_size: (16.0, 24.0).into(),
// })
// .into(),
// // Be careful not to overwrite the LDtk transform
// // Change our origin
// transform: (*transform) * Transform::default().with_translation(Vec3::Y * 8.0),
// material: materials.add(Color::PURPLE),
// ..default()
// },
children: spawn_children(|cb| {
cb.spawn(movement_pointer::MovementPointerBundle {
pointer: movement_pointer::MovementPointer,
shape: ShapeBundle {
spatial: SpatialBundle {
transform: Transform::default().with_scale(Vec3::new(0.5, 1.0, 1.0)),
..default()
},
path: GeometryBuilder::build_as(&shapes::RegularPolygon {
sides: 3,
feature: RegularPolygonFeature::Apothem(5.0),
..default()
}),
material: materials.add(Color::ORANGE_RED),
..default()
},
});
}),
});
}
fn default_input_map() -> InputMap<PlayerAction> {
let mut map = InputMap::default();
map.insert(PlayerAction::Move, DualAxis::left_stick());
map.insert(PlayerAction::Move, VirtualDPad::wasd());
map.insert(PlayerAction::LightAttack, KeyCode::KeyZ);
map.insert(PlayerAction::HeavyAttack, KeyCode::KeyX);
map.insert(PlayerAction::HoldDash, GamepadButtonType::RightTrigger);
map.insert(PlayerAction::HoldDash, KeyCode::ShiftLeft);
map.insert(PlayerAction::ToggleDash, KeyCode::KeyC);
map.insert(PlayerAction::Hand, VirtualDPad::gamepad_face_buttons());
map.insert(PlayerAction::Hand, VirtualDPad::arrow_keys());
map
}
#[derive(Component)]
struct Camera;
#[derive(Bundle)]
struct CameraBundle {
camera: Camera,
camera_2d: Camera2dBundle,
pixel_camera: PixelCamera,
chroma_aberration: post_process::ChromaticAberattionSettings,
}
fn setup_camera(mut commands: Commands) {
commands.spawn(CameraBundle {
camera: Camera,
camera_2d: Camera2dBundle::default(),
pixel_camera: PixelCamera::from_size(ViewportSize::AutoMax {
max_width: LOGICAL_WIDTH,
max_height: LOGICAL_HEIGHT,
}),
chroma_aberration: post_process::ChromaticAberattionSettings {
// intensity: 0.02,
..default()
},
});
fn update_camera(
mut camera: Query<(&mut PixelCamera, &GlobalTransform), With<Camera>>,
player: Query<&GlobalTransform, With<Player>>,
) {
match (player.get_single(), camera.get_single_mut()) {
(Ok(transform), Ok((mut camera, cam_transform))) => {
// Lerp the camera to player's global translation point
let source = cam_transform.translation();
let goal = transform.translation();
let diff = goal - source;
let lerped = source + diff * 0.1; //* time.delta_seconds();
camera.subpixel_pos = lerped.xy();
}
_ => {
// Either the camera or the player doesnt exist
}
}
}
use super::{player::Player, post_process, LOGICAL_HEIGHT, LOGICAL_WIDTH};
use bevy::prelude::*;
use bevy_smooth_pixel_camera::components::PixelCamera;
use bevy_smooth_pixel_camera::viewport::ViewportSize;
#[derive(Component)]
pub(crate) struct Camera;
#[derive(Bundle)]
pub(crate) struct CameraBundle {
pub(crate) camera: Camera,
pub(crate) camera_2d: Camera2dBundle,
pub(crate) pixel_camera: PixelCamera,
pub(crate) chroma_aberration: post_process::ChromaticAberattionSettings,
}
pub(crate) fn setup_camera(mut commands: Commands) {
commands.spawn(CameraBundle {
camera: Camera,
camera_2d: Camera2dBundle::default(),
pixel_camera: PixelCamera::from_size(ViewportSize::AutoMax {
max_width: LOGICAL_WIDTH,
max_height: LOGICAL_HEIGHT,
}),
chroma_aberration: post_process::ChromaticAberattionSettings {
// intensity: 0.02,
..default()
},
});
}
pub(crate) fn update_camera(
mut camera: Query<(&mut PixelCamera, &GlobalTransform), With<Camera>>,
player: Query<&GlobalTransform, With<Player>>,
) {
match (player.get_single(), camera.get_single_mut()) {
(Ok(transform), Ok((mut camera, cam_transform))) => {
// Lerp the camera to player's global translation point
let source = cam_transform.translation();
let goal = transform.translation();
let diff = goal - source;
let lerped = source + diff * 0.1; //* time.delta_seconds();
camera.subpixel_pos = lerped.xy();
}
_ => {
// Either the camera or the player doesnt exist
}
}
}