drag but bad rotation
This commit is contained in:
parent
cb74487f1b
commit
7dde61a98d
|
@ -2,3 +2,6 @@
|
||||||
|
|
||||||
A Stellarium game made for The icam Game jam 2024, using the Bevy game engine
|
A Stellarium game made for The icam Game jam 2024, using the Bevy game engine
|
||||||
|
|
||||||
|
Star data from : [YaleBrightStarCatalog (Bretton Wade)](https://github.com/brettonw/YaleBrightStarCatalog/blob/master/bsc5-short.json) (MIT License, Copyright (c) 2016 Bretton Wade)
|
||||||
|
|
||||||
|
Constellation data from :[Lizard Tail (Isana Kashiwai)](https://www.lizard-tail.com/isana/lab/starlitnight/)
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
use bevy::render::render_resource::PrimitiveTopology;
|
||||||
|
use bevy::render::render_asset::RenderAssetUsages;
|
||||||
use std::f64::consts::PI;
|
use std::f64::consts::PI;
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
|
@ -17,6 +19,7 @@ use crate::spawn_cons_lines;
|
||||||
use crate::NORMAL_BUTTON;
|
use crate::NORMAL_BUTTON;
|
||||||
use crate::RIGHT_BUTTON;
|
use crate::RIGHT_BUTTON;
|
||||||
use crate::WRONG_BUTTON;
|
use crate::WRONG_BUTTON;
|
||||||
|
use crate::SKY_RADIUS;
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct AnswerButton;
|
pub struct AnswerButton;
|
||||||
|
@ -30,7 +33,14 @@ pub struct ScoreLabel;
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct HintLabel;
|
pub struct HintLabel;
|
||||||
|
|
||||||
pub fn setup(mut commands: Commands, _asset_server: Res<AssetServer>) {
|
#[derive(Component)]
|
||||||
|
pub struct DebugLine;
|
||||||
|
|
||||||
|
pub fn setup(
|
||||||
|
mut commands: Commands,
|
||||||
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
|
) {
|
||||||
let container_node = NodeBundle {
|
let container_node = NodeBundle {
|
||||||
style: Style {
|
style: Style {
|
||||||
width: Val::Percent(100.0),
|
width: Val::Percent(100.0),
|
||||||
|
@ -160,6 +170,30 @@ pub fn setup(mut commands: Commands, _asset_server: Res<AssetServer>) {
|
||||||
|
|
||||||
commands.entity(centered_container).push_children(&[hint_label]);
|
commands.entity(centered_container).push_children(&[hint_label]);
|
||||||
|
|
||||||
|
|
||||||
|
let line_material = materials.add(StandardMaterial {
|
||||||
|
emissive: LinearRgba::rgb(2.0, 0.5, 0.5),
|
||||||
|
..default()
|
||||||
|
});
|
||||||
|
|
||||||
|
let vertices = vec![
|
||||||
|
Vec3::new(0.0, 0.0, 0.0),
|
||||||
|
Vec3::new(1.0, 0.0, 0.0)
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut mesh = Mesh::new(PrimitiveTopology::LineList, RenderAssetUsages::RENDER_WORLD);
|
||||||
|
mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, vertices);
|
||||||
|
|
||||||
|
commands.spawn((
|
||||||
|
PbrBundle {
|
||||||
|
mesh: meshes.add(mesh),
|
||||||
|
material: line_material.clone(),
|
||||||
|
transform: Transform::default(),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
DebugLine,
|
||||||
|
MainGame
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -229,6 +263,94 @@ pub fn player_interact(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn player_mouse_move (
|
||||||
|
buttons: Res<ButtonInput<MouseButton>>,
|
||||||
|
mut player_query: Query<(&mut Player, &mut Transform)>,
|
||||||
|
camera_query: Query<(&Camera, &GlobalTransform), With<Player>>,
|
||||||
|
window_query: Query<&Window, With<bevy::window::PrimaryWindow>>,
|
||||||
|
mut debug_line_query: Query<&mut Transform, (With<DebugLine>, Without<Player>)>,
|
||||||
|
) {
|
||||||
|
let Ok((mut player, mut player_transform)) = player_query.get_single_mut() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if !buttons.pressed(MouseButton::Left) {
|
||||||
|
player.dragging_pos = None;
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let window = window_query.single();
|
||||||
|
|
||||||
|
let Some(cursor_position) = window.cursor_position() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let (camera, camera_transform) = camera_query.single();
|
||||||
|
|
||||||
|
let Some(ray) = camera.viewport_to_world(camera_transform, cursor_position) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_global_cursor = ray.get_point(SKY_RADIUS);
|
||||||
|
|
||||||
|
let Some(old_global_cursor) = player.dragging_pos else {
|
||||||
|
player.dragging_pos = Some(new_global_cursor);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Ok(mut debug_transform) = debug_line_query.get_single_mut() {
|
||||||
|
let direction = old_global_cursor - new_global_cursor ;
|
||||||
|
let distance = direction.length();
|
||||||
|
|
||||||
|
// Scale the line to match the distance between the points
|
||||||
|
debug_transform.scale = Vec3::new(distance*5.0, 1.0, 1.0);
|
||||||
|
|
||||||
|
// Position the line at old_pos
|
||||||
|
debug_transform.translation = new_global_cursor;
|
||||||
|
|
||||||
|
// Rotate the line to point from old_pos to new_pos
|
||||||
|
if distance > f32::EPSILON {
|
||||||
|
let rotation = Quat::from_rotation_arc(Vec3::X, direction.normalize());
|
||||||
|
debug_transform.rotation = rotation;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
info!("no debug line");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if old_global_cursor != new_global_cursor {
|
||||||
|
let target_rotation = player_transform.rotation * rotate_to_align(old_global_cursor, new_global_cursor);
|
||||||
|
player_transform.rotation = player_transform.rotation.slerp(target_rotation, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
player.dragging_pos = Some(new_global_cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rotate_to_align(old_pos: Vec3, new_pos: Vec3) -> Quat {
|
||||||
|
// Step 1: Normalize the input vectors (assuming they're not already normalized)
|
||||||
|
let old_pos_normalized = old_pos.normalize();
|
||||||
|
let new_pos_normalized = new_pos.normalize();
|
||||||
|
|
||||||
|
// Step 2: Compute the axis of rotation (cross product between old and new positions)
|
||||||
|
let axis_of_rotation = old_pos_normalized.cross(new_pos_normalized).normalize();
|
||||||
|
|
||||||
|
if axis_of_rotation.length_squared() < f32::EPSILON {
|
||||||
|
return Quat::IDENTITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Compute the angle of rotation (dot product and arccosine)
|
||||||
|
//let dot_product = old_pos_normalized.dot(new_pos_normalized);
|
||||||
|
let dot_product = new_pos_normalized.dot(old_pos_normalized);
|
||||||
|
let angle_of_rotation = dot_product.acos(); // This gives us the angle in radians
|
||||||
|
|
||||||
|
if angle_of_rotation.is_nan() || angle_of_rotation.is_infinite() {
|
||||||
|
return Quat::IDENTITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4: Create a quaternion representing the rotation
|
||||||
|
Quat::from_axis_angle(axis_of_rotation, angle_of_rotation)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn ui_labels(
|
pub fn ui_labels(
|
||||||
|
|
15
src/main.rs
15
src/main.rs
|
@ -90,6 +90,20 @@ struct Player {
|
||||||
score: usize,
|
score: usize,
|
||||||
health: usize,
|
health: usize,
|
||||||
state: PlayerState,
|
state: PlayerState,
|
||||||
|
dragging_pos: Option<Vec3>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Player {
|
||||||
|
fn default() -> Self {
|
||||||
|
Player {
|
||||||
|
target_rotation: None,
|
||||||
|
target_cons_name: None,
|
||||||
|
score: 0,
|
||||||
|
health: 3,
|
||||||
|
state: PlayerState::Playing,
|
||||||
|
dragging_pos: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
|
@ -120,6 +134,7 @@ fn main() {
|
||||||
.add_systems(OnExit(GameState::Start), despawn_screen::<StartMenu>)
|
.add_systems(OnExit(GameState::Start), despawn_screen::<StartMenu>)
|
||||||
.add_systems(OnEnter(GameState::Game), game_state::setup)
|
.add_systems(OnEnter(GameState::Game), game_state::setup)
|
||||||
.add_systems(Update, game_state::player_interact.run_if(in_state(GameState::Game)))
|
.add_systems(Update, game_state::player_interact.run_if(in_state(GameState::Game)))
|
||||||
|
.add_systems(Update, game_state::player_mouse_move.run_if(in_state(GameState::Game)))
|
||||||
.add_systems(Update, game_state::ui_buttons.run_if(in_state(GameState::Game)))
|
.add_systems(Update, game_state::ui_buttons.run_if(in_state(GameState::Game)))
|
||||||
.add_systems(Update, game_state::ui_labels.run_if(in_state(GameState::Game)))
|
.add_systems(Update, game_state::ui_labels.run_if(in_state(GameState::Game)))
|
||||||
.add_systems(OnExit(GameState::Game), despawn_screen::<MainGame>)
|
.add_systems(OnExit(GameState::Game), despawn_screen::<MainGame>)
|
||||||
|
|
|
@ -5,7 +5,6 @@ use crate::Player;
|
||||||
use crate::GameState;
|
use crate::GameState;
|
||||||
use crate::GameOver;
|
use crate::GameOver;
|
||||||
use crate::StartMenu;
|
use crate::StartMenu;
|
||||||
use crate::PlayerState;
|
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
struct AudioPlayer;
|
struct AudioPlayer;
|
||||||
|
@ -67,13 +66,7 @@ pub fn setup(mut commands: Commands, _asset_server: Res<AssetServer>) {
|
||||||
transform: Transform::from_xyz(0.0, 0.0, 0.0),
|
transform: Transform::from_xyz(0.0, 0.0, 0.0),
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
Player {
|
Player::default(),
|
||||||
target_rotation: None,
|
|
||||||
target_cons_name: None,
|
|
||||||
score: 0,
|
|
||||||
health: 3,
|
|
||||||
state: PlayerState::Playing,
|
|
||||||
},
|
|
||||||
GameOver,
|
GameOver,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue