jumping around
This commit is contained in:
commit
a0f3e44245
|
@ -0,0 +1 @@
|
||||||
|
/target
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,10 @@
|
||||||
|
[package]
|
||||||
|
name = "rust-bevy-test"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Astro <astro@spaceboyz.net>"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rand = "0.8"
|
||||||
|
bevy = { version = "0.6", features = ["jpeg"] }
|
||||||
|
heron = { git = "https://github.com/jcornaz/heron.git", features = ["3d"] }
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,34 @@
|
||||||
|
let
|
||||||
|
mozilla = import (builtins.fetchTarball https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz);
|
||||||
|
nixpkgs = import <nixpkgs> { overlays = [ mozilla ]; };
|
||||||
|
in
|
||||||
|
|
||||||
|
with nixpkgs;
|
||||||
|
|
||||||
|
mkShell {
|
||||||
|
buildInputs = [
|
||||||
|
alsaLib
|
||||||
|
cmake
|
||||||
|
udev
|
||||||
|
freetype
|
||||||
|
latest.rustChannels.nightly.rust
|
||||||
|
#rustc cargo
|
||||||
|
expat
|
||||||
|
openssl
|
||||||
|
pkgconfig
|
||||||
|
python3
|
||||||
|
vulkan-validation-layers
|
||||||
|
xlibs.libX11
|
||||||
|
];
|
||||||
|
|
||||||
|
APPEND_LIBRARY_PATH = lib.makeLibraryPath [
|
||||||
|
vulkan-loader
|
||||||
|
xlibs.libXcursor
|
||||||
|
xlibs.libXi
|
||||||
|
xlibs.libXrandr
|
||||||
|
];
|
||||||
|
|
||||||
|
shellHook = ''
|
||||||
|
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$APPEND_LIBRARY_PATH"
|
||||||
|
'';
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
use crate::player::Player;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct PlayerCamera;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct Light;
|
||||||
|
|
||||||
|
|
||||||
|
pub fn setup(mut commands: Commands) {
|
||||||
|
let camera_transform = Transform::from_xyz(-10.0, 10.0, 20.0)
|
||||||
|
.looking_at(Vec3::ZERO, Vec3::Y);
|
||||||
|
commands.spawn()
|
||||||
|
.insert_bundle(PerspectiveCameraBundle {
|
||||||
|
transform: camera_transform,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.insert(PlayerCamera);
|
||||||
|
|
||||||
|
|
||||||
|
// light
|
||||||
|
let hilight_transform = Transform::from_xyz(0.0, 200.0, 0.0);
|
||||||
|
commands.spawn()
|
||||||
|
.insert_bundle(PointLightBundle {
|
||||||
|
transform: hilight_transform,
|
||||||
|
point_light: PointLight {
|
||||||
|
range: 2000.0,
|
||||||
|
radius: 2000.0,
|
||||||
|
intensity: 4000.0,
|
||||||
|
shadows_enabled: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.insert(Light);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn track_players(
|
||||||
|
time: Res<Time>,
|
||||||
|
mut queries: QuerySet<(
|
||||||
|
QueryState<&Transform, With<Player>>,
|
||||||
|
QueryState<&mut Transform, With<PlayerCamera>>,
|
||||||
|
QueryState<&mut Transform, With<Light>>,
|
||||||
|
)>,
|
||||||
|
) {
|
||||||
|
let mut min_x = None;
|
||||||
|
let mut max_x = None;
|
||||||
|
let mut max_y = None;
|
||||||
|
let mut min_z = None;
|
||||||
|
let mut max_z = None;
|
||||||
|
for transform in queries.q0().iter() {
|
||||||
|
let t = &transform.translation;
|
||||||
|
|
||||||
|
if min_x.map_or(true, |min_x| t.x < min_x) {
|
||||||
|
min_x = Some(t.x);
|
||||||
|
}
|
||||||
|
if max_x.map_or(true, |max_x| t.x > max_x) {
|
||||||
|
max_x = Some(t.x);
|
||||||
|
}
|
||||||
|
if max_y.map_or(true, |max_y| t.y > max_y) {
|
||||||
|
max_y = Some(t.y);
|
||||||
|
}
|
||||||
|
if min_z.map_or(true, |min_z| t.z < min_z) {
|
||||||
|
min_z = Some(t.z);
|
||||||
|
}
|
||||||
|
if max_z.map_or(true, |max_z| t.z > max_z) {
|
||||||
|
max_z = Some(t.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(target) = max_y.and_then(|max_y| {
|
||||||
|
let dist = 10.0f32.max(
|
||||||
|
max_x? - min_x?
|
||||||
|
).max(
|
||||||
|
(max_z? - min_z?) / 2.0
|
||||||
|
);
|
||||||
|
Some(Vec3::new(min_x? - dist, max_y + dist, max_z? + 2.0 * dist))
|
||||||
|
}) {
|
||||||
|
for mut camera_transform in queries.q1().iter_mut() {
|
||||||
|
let t = &mut camera_transform.translation;
|
||||||
|
*t = *t + time.delta_seconds() * (target - *t) / 2.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(light_pos) = max_y.and_then(|max_y| {
|
||||||
|
Some(Vec3::new(
|
||||||
|
(max_x? + min_x?) / 2.0,
|
||||||
|
max_y + 8.0,
|
||||||
|
(max_z? + min_z?) / 2.0 + 10.0,
|
||||||
|
))
|
||||||
|
}) {
|
||||||
|
for ref mut light_transform in queries.q2().iter_mut() {
|
||||||
|
light_transform.translation = light_pos;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("No player to target!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
use bevy::{
|
||||||
|
prelude::*,
|
||||||
|
app::AppExit,
|
||||||
|
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
|
||||||
|
};
|
||||||
|
use heron::prelude::*;
|
||||||
|
|
||||||
|
mod camera;
|
||||||
|
mod map;
|
||||||
|
mod player;
|
||||||
|
|
||||||
|
#[derive(PhysicsLayer)]
|
||||||
|
pub enum Layer {
|
||||||
|
Map,
|
||||||
|
Player,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
App::new()
|
||||||
|
.add_plugin(LogDiagnosticsPlugin::default())
|
||||||
|
.add_plugin(FrameTimeDiagnosticsPlugin::default())
|
||||||
|
.add_plugins(DefaultPlugins)
|
||||||
|
.add_plugin(PhysicsPlugin::default())
|
||||||
|
.insert_resource(Gravity::from(Vec3::new(0.0, -9.81, 0.0)))
|
||||||
|
.insert_resource(ClearColor(Color::rgb(0.7, 0.7, 1.0)))
|
||||||
|
.add_startup_system(camera::setup)
|
||||||
|
.add_system(camera::track_players)
|
||||||
|
.add_startup_system(map::setup)
|
||||||
|
.add_system(map::build)
|
||||||
|
.add_system(map::collide)
|
||||||
|
.add_startup_system(player::setup)
|
||||||
|
.add_system(player::input)
|
||||||
|
.add_system(exit_on_escape)
|
||||||
|
.add_system(log_collisions)
|
||||||
|
// .add_system(keyboard_input_camera)
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn exit_on_escape(keyboard_input: Res<Input<KeyCode>>, mut exit: EventWriter<AppExit>) {
|
||||||
|
if keyboard_input.pressed(KeyCode::Escape) {
|
||||||
|
exit.send(AppExit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn log_collisions(mut events: EventReader<CollisionEvent>) {
|
||||||
|
for event in events.iter() {
|
||||||
|
match event {
|
||||||
|
CollisionEvent::Started(d1, d2) => {
|
||||||
|
println!("Collision started between {:?} and {:?}", d1, d2)
|
||||||
|
}
|
||||||
|
CollisionEvent::Stopped(d1, d2) => {
|
||||||
|
println!("Collision stopped between {:?} and {:?}", d1, d2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,193 @@
|
||||||
|
use rand::prelude::*;
|
||||||
|
use bevy::{
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
use heron::prelude::*;
|
||||||
|
use crate::Layer;
|
||||||
|
|
||||||
|
pub struct LevelResources {
|
||||||
|
soil_material: Handle<StandardMaterial>,
|
||||||
|
grass_material: Handle<StandardMaterial>,
|
||||||
|
last_build: Option<Time>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct GroundContact(pub usize);
|
||||||
|
|
||||||
|
impl std::default::Default for GroundContact {
|
||||||
|
fn default() -> Self {
|
||||||
|
GroundContact(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Component)]
|
||||||
|
pub struct Ground {
|
||||||
|
/// (x0, width)
|
||||||
|
x: (f32, f32),
|
||||||
|
/// ground top
|
||||||
|
y: f32,
|
||||||
|
/// (z0, width)
|
||||||
|
z: (f32, f32),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ground {
|
||||||
|
const HEIGHT: f32 = 2.5;
|
||||||
|
|
||||||
|
pub fn overlaps(&self, other: &Self) -> bool {
|
||||||
|
self.x.0 + self.x.1 >= other.x.0 &&
|
||||||
|
self.x.0 <= other.x.0 + other.x.1 &&
|
||||||
|
self.z.0 + self.z.1 >= other.z.0 &&
|
||||||
|
self.z.0 <= other.z.0 + other.z.1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_transform(&self) -> Transform {
|
||||||
|
let half_width = self.x.1 / 2.0;
|
||||||
|
let half_height = Self::HEIGHT / 2.0;
|
||||||
|
let half_depth = self.z.1 / 2.0;
|
||||||
|
Transform::from_xyz(
|
||||||
|
self.x.0 + half_width,
|
||||||
|
self.y + half_height,
|
||||||
|
self.z.0 + half_depth,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_box(&self) -> shape::Box {
|
||||||
|
let half_width = self.x.1 / 2.0;
|
||||||
|
let half_height = Self::HEIGHT / 2.0;
|
||||||
|
let half_depth = self.z.1 / 2.0;
|
||||||
|
shape::Box {
|
||||||
|
min_x: - half_width,
|
||||||
|
min_y: - half_height,
|
||||||
|
min_z: - half_depth,
|
||||||
|
max_x: half_width,
|
||||||
|
max_y: half_height,
|
||||||
|
max_z: half_depth,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn half_extends(&self) -> Vec3 {
|
||||||
|
let half_width = self.x.1 / 2.0;
|
||||||
|
let half_height = Self::HEIGHT / 2.0;
|
||||||
|
let half_depth = self.z.1 / 2.0;
|
||||||
|
Vec3::new(half_width, half_height, half_depth)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setup(
|
||||||
|
mut commands: Commands,
|
||||||
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
|
) {
|
||||||
|
let res = LevelResources {
|
||||||
|
soil_material: materials.add(Color::rgb(0.8, 0.7, 0.1).into()),
|
||||||
|
grass_material: materials.add(Color::rgb(0.2, 1.0, 0.25).into()),
|
||||||
|
last_build: None,
|
||||||
|
};
|
||||||
|
commands.insert_resource(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(
|
||||||
|
time: Res<Time>,
|
||||||
|
mut commands: Commands,
|
||||||
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
|
mut res: ResMut<LevelResources>,
|
||||||
|
grounds: Query<&Ground>,
|
||||||
|
) {
|
||||||
|
// let now = time.seconds_since_startup();
|
||||||
|
if res.last_build.is_none() //res.last_build.as_ref().map_or(true, |last_build| now - last_build.seconds_since_startup() >= 0.1)
|
||||||
|
{
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
for z in -9..10 {
|
||||||
|
for x in -9..10 {
|
||||||
|
let ground = Ground {
|
||||||
|
x: (2.0 * x as f32, 2.0),
|
||||||
|
y: rng.gen_range::<f32, _>(0.0..2.0),
|
||||||
|
z: (2.0 * z as f32, 2.0),
|
||||||
|
};
|
||||||
|
let mut collision = false;
|
||||||
|
for other in grounds.iter() {
|
||||||
|
if ground.overlaps(other) {
|
||||||
|
// println!("collision: {:?}x{:?} && {:?}x{:?}", ground.x, ground.z, other.x, other.z);
|
||||||
|
collision = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !collision {
|
||||||
|
add_ground(&mut commands, &mut meshes, &res, ground);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.last_build = Some(time.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_ground(
|
||||||
|
commands: &mut Commands,
|
||||||
|
meshes: &mut ResMut<Assets<Mesh>>,
|
||||||
|
res: &ResMut<LevelResources>,
|
||||||
|
ground: Ground,
|
||||||
|
) {
|
||||||
|
let mut transform = ground.to_transform();
|
||||||
|
|
||||||
|
let bounds = ground.to_box();
|
||||||
|
let mut soil_box = bounds.clone();
|
||||||
|
soil_box.max_y = soil_box.min_y + 0.7 * (soil_box.max_y - soil_box.min_y);
|
||||||
|
let mut grass_box = bounds.clone();
|
||||||
|
grass_box.min_y = soil_box.max_y;
|
||||||
|
|
||||||
|
let soil_mesh = meshes.add(Mesh::from(soil_box));
|
||||||
|
commands.spawn()
|
||||||
|
.insert_bundle(PbrBundle {
|
||||||
|
mesh: soil_mesh,
|
||||||
|
material: res.soil_material.clone(),
|
||||||
|
transform: transform.clone(),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
|
||||||
|
let grass_mesh = meshes.add(Mesh::from(grass_box));
|
||||||
|
commands.spawn()
|
||||||
|
.insert_bundle(PbrBundle {
|
||||||
|
mesh: grass_mesh,
|
||||||
|
material: res.grass_material.clone(),
|
||||||
|
transform: transform.clone(),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.insert(RigidBody::Static)
|
||||||
|
.insert(CollisionShape::Cuboid {
|
||||||
|
border_radius: None,
|
||||||
|
half_extends: ground.half_extends(),
|
||||||
|
})
|
||||||
|
.insert(ground);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn collide(mut events: EventReader<CollisionEvent>, mut contacted: Query<&mut GroundContact>) {
|
||||||
|
fn is_map(layers: CollisionLayers) -> bool {
|
||||||
|
layers.contains_group(Layer::Map)
|
||||||
|
}
|
||||||
|
|
||||||
|
events
|
||||||
|
.iter()
|
||||||
|
// We care about when the entities "start" to collide
|
||||||
|
.filter_map(|event| {
|
||||||
|
let (entity_1, _entity_2) = event.rigid_body_entities();
|
||||||
|
let (layers_1, layers_2) = event.collision_layers();
|
||||||
|
if ! is_map(layers_1) && is_map(layers_2) {
|
||||||
|
Some((event, entity_1))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}).for_each(|(event, entity)| {
|
||||||
|
match event {
|
||||||
|
CollisionEvent::Started(_, _) => {
|
||||||
|
if let Ok(mut contact) = contacted.get_mut(entity) {
|
||||||
|
contact.0 = contact.0.saturating_add(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CollisionEvent::Stopped(_, _) => {
|
||||||
|
if let Ok(mut contact) = contacted.get_mut(entity) {
|
||||||
|
contact.0 = contact.0.saturating_sub(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,162 @@
|
||||||
|
use std::f32::consts::PI;
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use heron::prelude::*;
|
||||||
|
use crate::{
|
||||||
|
map::GroundContact,
|
||||||
|
Layer,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct Player {
|
||||||
|
rotation: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setup(
|
||||||
|
mut commands: Commands,
|
||||||
|
asset_server: Res<AssetServer>,
|
||||||
|
) {
|
||||||
|
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 transform = Transform::from_xyz(0.0, 12.0, 0.0);
|
||||||
|
commands.spawn()
|
||||||
|
.insert(RigidBody::Dynamic)
|
||||||
|
.insert(CollisionLayers::none()
|
||||||
|
.with_group(Layer::Player)
|
||||||
|
.with_masks(&[Layer::Player, Layer::Map])
|
||||||
|
)
|
||||||
|
.insert(CollisionShape::Cone {
|
||||||
|
half_height: 0.7,
|
||||||
|
radius: 0.4,
|
||||||
|
})
|
||||||
|
.insert(PhysicMaterial {
|
||||||
|
restitution: 0.0,
|
||||||
|
density: 8.0,
|
||||||
|
friction: 1.0,
|
||||||
|
})
|
||||||
|
.insert(RotationConstraints::lock())
|
||||||
|
.insert(Velocity::default())
|
||||||
|
.insert(Player {
|
||||||
|
rotation: 0.0,
|
||||||
|
})
|
||||||
|
.insert(GroundContact::default())
|
||||||
|
.insert(GlobalTransform::default())
|
||||||
|
.insert(transform)
|
||||||
|
.with_children(|children| {
|
||||||
|
let transform = Transform::default();
|
||||||
|
children.spawn_bundle(PbrBundle {
|
||||||
|
mesh: mesh1.clone(),
|
||||||
|
material: material1.clone(),
|
||||||
|
transform,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
children.spawn_bundle(PbrBundle {
|
||||||
|
mesh: mesh2.clone(),
|
||||||
|
material: material2.clone(),
|
||||||
|
transform,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
children.spawn_bundle(PbrBundle {
|
||||||
|
mesh: mesh3.clone(),
|
||||||
|
material: material3.clone(),
|
||||||
|
transform,
|
||||||
|
..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<Input<KeyCode>>, mut players: Query<(&mut Velocity, &mut Player, &mut Transform, &GroundContact)>) {
|
||||||
|
let x;
|
||||||
|
let z;
|
||||||
|
let target_rotation;
|
||||||
|
match [KeyCode::Right, KeyCode::Left, KeyCode::Up, KeyCode::Down].map(|k| input.pressed(k)) {
|
||||||
|
[false, false, false, true] => {
|
||||||
|
z = 1.0;
|
||||||
|
x = 0.0;
|
||||||
|
target_rotation = Some(0.0);
|
||||||
|
}
|
||||||
|
[false, true, false, true] => {
|
||||||
|
z = 0.7;
|
||||||
|
x = -0.7;
|
||||||
|
target_rotation = Some(1.75 * PI);
|
||||||
|
}
|
||||||
|
[false, true, false, false] => {
|
||||||
|
z = 0.0;
|
||||||
|
x = -1.0;
|
||||||
|
target_rotation = Some(1.5 * PI);
|
||||||
|
}
|
||||||
|
[false, true, true, false] => {
|
||||||
|
z = -0.7;
|
||||||
|
x = -0.7;
|
||||||
|
target_rotation = Some(1.25 * PI);
|
||||||
|
}
|
||||||
|
[false, false, true, false] => {
|
||||||
|
z = -1.0;
|
||||||
|
x = 0.0;
|
||||||
|
target_rotation = Some(1.0 * PI);
|
||||||
|
}
|
||||||
|
[true, false, true, false] => {
|
||||||
|
z = -0.7;
|
||||||
|
x = 0.7;
|
||||||
|
target_rotation = Some(0.75 * PI);
|
||||||
|
}
|
||||||
|
[true, false, false, false] => {
|
||||||
|
z = 0.0;
|
||||||
|
x = 1.0;
|
||||||
|
target_rotation = Some(0.5 * PI);
|
||||||
|
}
|
||||||
|
[true, false, false, true] => {
|
||||||
|
z = 0.7;
|
||||||
|
x = 0.7;
|
||||||
|
target_rotation = Some(0.25 * PI);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
z = 0.0;
|
||||||
|
x = 0.0;
|
||||||
|
target_rotation = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let y = if input.pressed(KeyCode::Space) {
|
||||||
|
1.6
|
||||||
|
} else if x != 0.0 || z != 0.0 {
|
||||||
|
// walk bobbing
|
||||||
|
0.3
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
};
|
||||||
|
|
||||||
|
const SPEED: f32 = 3.0;
|
||||||
|
let target_velocity = SPEED * Vec3::new(x, y, z);
|
||||||
|
for (mut velocity, mut player, mut transform, contact) in players.iter_mut() {
|
||||||
|
if contact.0 > 0 && velocity.linear.y.abs() < 0.2 {
|
||||||
|
velocity.linear = target_velocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(target_rotation) = target_rotation {
|
||||||
|
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_axis_angle(
|
||||||
|
Vec3::Y,
|
||||||
|
player.rotation
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue