175 lines
5.2 KiB
Rust
175 lines
5.2 KiB
Rust
use std::{hash::Hash, time::Duration};
|
|
|
|
use animation::{run_animations, AnimBundle, Animation};
|
|
use bevy::{ecs::system::SystemId, prelude::*, sprite::MaterialMesh2dBundle, utils::HashMap};
|
|
|
|
use bevy_rapier2d::prelude::*;
|
|
|
|
use crate::{AppState, METER};
|
|
|
|
use super::{scene::PlayerCoords, set::IngameSet};
|
|
|
|
mod animation;
|
|
|
|
#[derive(Component)]
|
|
struct Player {
|
|
move_cooldown: Timer,
|
|
}
|
|
|
|
impl Default for Player {
|
|
fn default() -> Self {
|
|
Self {
|
|
move_cooldown: Timer::from_seconds(0.01, TimerMode::Repeating),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Resource)]
|
|
pub struct PlayerSpawnOneshot(pub SystemId);
|
|
|
|
impl FromWorld for PlayerSpawnOneshot {
|
|
fn from_world(world: &mut World) -> Self {
|
|
Self(world.register_system(add_player))
|
|
}
|
|
}
|
|
|
|
pub(super) fn player_plugin(app: &mut App) {
|
|
app.add_systems(
|
|
Update,
|
|
(
|
|
move_player,
|
|
debug_player_pos,
|
|
run_animations::<PlayerAnimations>,
|
|
),
|
|
)
|
|
.init_resource::<PlayerSpawnOneshot>();
|
|
}
|
|
|
|
#[derive(Component, Hash, PartialEq, Eq, Default)]
|
|
enum PlayerAnimations {
|
|
#[default]
|
|
Idle,
|
|
Walk,
|
|
}
|
|
|
|
fn debug_player_pos(query: Query<&Transform, With<Player>>) {
|
|
let trans = query.single();
|
|
}
|
|
fn move_player(
|
|
kb_input: Res<ButtonInput<KeyCode>>,
|
|
mut query: Query<(
|
|
&mut Velocity,
|
|
&Transform,
|
|
&mut Player,
|
|
&mut KinematicCharacterController,
|
|
)>,
|
|
mut camera_query: Query<&mut Transform, (With<Camera2d>, Without<Player>)>,
|
|
phys: Query<&KinematicCharacterControllerOutput>,
|
|
player_coords: Res<PlayerCoords>,
|
|
time: Res<Time>,
|
|
) {
|
|
let (mut vel, p_transform, mut player, mut controller) = query.single_mut();
|
|
let (mut cam_transform) = camera_query.single_mut();
|
|
let (output) = phys.get_single();
|
|
if player.move_cooldown.tick(time.delta()).finished() {
|
|
let mut moved = false;
|
|
let mut move_x = 0;
|
|
let mut move_y = 0;
|
|
let mut jump = false;
|
|
|
|
if kb_input.pressed(KeyCode::KeyA) {
|
|
moved = true;
|
|
move_x -= 1;
|
|
}
|
|
if kb_input.pressed(KeyCode::KeyD) {
|
|
moved = true;
|
|
move_x += 1;
|
|
}
|
|
if kb_input.pressed(KeyCode::Space) && output.is_ok_and(|x| x.grounded) {
|
|
moved = true;
|
|
move_y += 1;
|
|
}
|
|
|
|
let orig = cam_transform.translation;
|
|
cam_transform.translation -= ((orig - p_transform.translation.xy().extend(0.0)) / 30.0);
|
|
|
|
controller.translation = Some(Vec2::new(move_x as f32 * 6., 0. - 0.01));
|
|
vel.linvel += Vec2::new(0., move_y as f32 * 3. * METER);
|
|
}
|
|
}
|
|
|
|
fn add_player(
|
|
mut commands: Commands,
|
|
mut meshes: ResMut<Assets<Mesh>>,
|
|
mut materials: ResMut<Assets<ColorMaterial>>,
|
|
mut texture_atlas_layouts: ResMut<Assets<TextureAtlasLayout>>,
|
|
asset_server: Res<AssetServer>,
|
|
player_coords: Res<PlayerCoords>,
|
|
) {
|
|
let tex_idle = asset_server.load("idle.png");
|
|
let layout_idle = TextureAtlasLayout::from_grid(UVec2::splat(512), 2, 1, None, None);
|
|
let layout_idle_handle = texture_atlas_layouts.add(layout_idle);
|
|
|
|
let tex_walk = asset_server.load("walk.png");
|
|
let layout_walk = TextureAtlasLayout::from_grid(UVec2::splat(512), 4, 1, None, None);
|
|
let layout_walk_handle = texture_atlas_layouts.add(layout_walk);
|
|
|
|
let anims = animation::AnimationManager::default()
|
|
.insert(
|
|
PlayerAnimations::Idle,
|
|
Animation::new(layout_idle_handle.clone(), 2, 4, tex_idle.clone()),
|
|
)
|
|
.insert(
|
|
PlayerAnimations::Walk,
|
|
Animation::new(layout_walk_handle.clone(), 4, 10, tex_walk.clone()),
|
|
);
|
|
|
|
commands
|
|
.spawn((
|
|
Player::default(),
|
|
AnimBundle {
|
|
tag: PlayerAnimations::Idle,
|
|
mgr: anims,
|
|
},
|
|
SpriteBundle {
|
|
sprite: Sprite {
|
|
custom_size: Some(Vec2::splat(1.)),
|
|
..Default::default()
|
|
},
|
|
transform: (*player_coords).into(),
|
|
texture: tex_idle,
|
|
..Default::default()
|
|
},
|
|
TextureAtlas {
|
|
layout: layout_idle_handle,
|
|
index: 0,
|
|
},
|
|
))
|
|
.insert((
|
|
RigidBody::Dynamic,
|
|
player_coords.get_collider(),
|
|
LockedAxes::ROTATION_LOCKED,
|
|
Velocity::default(),
|
|
))
|
|
.insert(KinematicCharacterController {
|
|
//translation: todo!(),
|
|
//custom_shape: todo!(),
|
|
//custom_mass: todo!(),
|
|
//up: todo!(),
|
|
offset: CharacterLength::Absolute(0.01),
|
|
slide: true,
|
|
//autostep: Some(CharacterAutostep {
|
|
// max_height: CharacterLength::Relative(0.1),
|
|
// min_width: CharacterLength::Absolute(1.0),
|
|
// include_dynamic_bodies: false,
|
|
//}),
|
|
//max_slope_climb_angle: todo!(),
|
|
//min_slope_slide_angle: todo!(),
|
|
//apply_impulse_to_dynamic_bodies: todo!(),
|
|
snap_to_ground: Some(CharacterLength::Absolute(0.5)),
|
|
//filter_flags: todo!(),
|
|
//filter_groups: todo!(),
|
|
// normal_nudge_factor: 1.,
|
|
..Default::default()
|
|
});
|
|
}
|