Playing with the Bevy game engine
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
entevsbaer/src/player.rs

177 lines
6.6 KiB

use std::f32::consts::PI;
use bevy::prelude::*;
use heron::prelude::*;
use rand::prelude::*;
use crate::{
input::{InputState, Key, Source as InputSource},
map::GroundContact,
off_map::CanFallOffMap,
projectile::{EGG_RADIUS, Projectile},
Layer,
};
#[derive(Component)]
pub struct Player {
input_source: InputSource,
rotation: f32,
last_shot: Option<Time>,
}
pub fn spawn_player(
mut commands: Commands,
players: Query<&Player>,
input: Res<InputState>,
asset_server: Res<AssetServer>,
) {
let input_source = match input.keys.iter().find(|(input_source, key)|
if [Key::Jump, Key::Shoot].iter().any(|k| k == key) {
! players.iter().any(|player| player.input_source == *input_source)
} else {
false
}
) {
Some((input_source, _)) => input_source,
None => return,
};
println!("New input_source: {:?}", input_source);
let mesh1 = asset_server.load("Mini-Game Variety Pack/Models/Characters/gltf/character_duck.gltf#Mesh0/Primitive0");
let mesh2 = asset_server.load("Mini-Game Variety Pack/Models/Characters/gltf/character_duck.gltf#Mesh0/Primitive1");
let mesh3 = asset_server.load("Mini-Game Variety Pack/Models/Characters/gltf/character_duck.gltf#Mesh0/Primitive2");
let mesh4 = asset_server.load("Mini-Game Variety Pack/Models/Characters/gltf/character_duck.gltf#Mesh1/Primitive0");
let material1 = asset_server.load("Mini-Game Variety Pack/Models/Characters/gltf/character_duck.gltf#Material0");
let material2 = asset_server.load("Mini-Game Variety Pack/Models/Characters/gltf/character_duck.gltf#Material1");
let material3 = asset_server.load("Mini-Game Variety Pack/Models/Characters/gltf/character_duck.gltf#Material2");
let mut rng = rand::thread_rng();
let transform = Transform::from_xyz(rng.gen_range(-3.0..3.0), 5.0, rng.gen_range(-3.0..3.0));
commands.spawn()
.insert(RigidBody::Dynamic)
.insert(CollisionLayers::none()
.with_group(Layer::Player)
.with_masks(&[Layer::Player, Layer::Projectile, Layer::Map])
)
.insert(CollisionShape::Cone {
half_height: 0.85,
radius: 0.7,
})
.insert(PhysicMaterial {
restitution: 0.0,
density: 10.0,
friction: 1.0,
})
.insert(RotationConstraints::lock())
.insert(Velocity::default())
.insert(Player {
input_source: input_source.clone(),
rotation: 0.0,
last_shot: None,
})
.insert(CanFallOffMap)
.insert(GroundContact::default())
.insert(GlobalTransform::default())
.insert(transform)
.with_children(|children| {
children.spawn_bundle(PbrBundle {
mesh: mesh1.clone(),
material: material1.clone(),
..Default::default()
});
children.spawn_bundle(PbrBundle {
mesh: mesh2.clone(),
material: material2.clone(),
..Default::default()
});
children.spawn_bundle(PbrBundle {
mesh: mesh3.clone(),
material: material3.clone(),
..Default::default()
});
let transform = Transform::from_translation(-0.71 * Vec3::Y);
children.spawn_bundle(PbrBundle {
mesh: mesh4.clone(),
material: material1.clone(),
transform,
..Default::default()
});
});
}
pub fn input(
time: Res<Time>,
input: Res<InputState>,
mut players: Query<(&mut Velocity, &mut Player, &mut Transform, &GroundContact)>,
res: Res<crate::map::LevelResources>,
mut commands: Commands,
) {
const SPEED: f32 = 4.0;
for (mut velocity, mut player, mut transform, contact) in players.iter_mut() {
let direction = input.direction_of(&player.input_source);
let x = direction.x;
let z = direction.y;
let y = if input.keys.contains(&(player.input_source.clone(), Key::Jump)) {
1.2
} else if x != 0.0 || z != 0.0 {
// walk bobbing
0.3
} else {
0.0
};
let target_velocity = SPEED * Vec3::new(x, y, z);
if contact.0 > 0 && velocity.linear.y.abs() < 0.2 {
// only move if GroundContact and not falling
velocity.linear = target_velocity;
}
if direction.length_squared() > 0.0 {
// spin
let target_rotation = direction.angle_between(Vec2::Y);
if (player.rotation - 2.0 * PI - target_rotation).abs() < (player.rotation - target_rotation).abs() {
player.rotation -= 2.0 * PI;
}
if (player.rotation + 2.0 * PI - target_rotation).abs() < (player.rotation - target_rotation).abs() {
player.rotation += 2.0 * PI;
}
player.rotation += 10.0 * time.delta_seconds() * (target_rotation - player.rotation);
transform.rotation = Quat::from_rotation_y(player.rotation);
}
if player.last_shot.as_ref().map_or(true, |last_shot| time.seconds_since_startup() - last_shot.seconds_since_startup() >= 0.5)
&& input.keys.contains(&(player.input_source.clone(), Key::Shoot))
{
let direction = Quat::from_rotation_y(player.rotation) * Vec3::Z;
let mut transform = Transform::from_translation(transform.translation + 1.0 * direction);
transform.scale += 0.3 * direction;
commands.spawn()
.insert(RigidBody::Dynamic)
.insert(CollisionLayers::none()
.with_group(Layer::Projectile)
.with_masks(&[Layer::Player, Layer::Map, Layer::Projectile])
)
.insert(CollisionShape::Sphere {
radius: EGG_RADIUS,
})
.insert(PhysicMaterial {
restitution: 1.0,
density: 10_000.0,
friction: 1.0,
})
.insert(Velocity::from_linear(30.0 * direction))
.insert(Projectile)
.insert(CanFallOffMap)
.insert(GlobalTransform::default())
.insert_bundle(PbrBundle {
mesh: res.egg_mesh.clone(),
material: res.egg_material.clone(),
transform,
..Default::default()
});
player.last_shot = Some(time.clone());
}
}
}