use super::state::*;
use bevy::prelude::*;
pub fn update_throw_from_mouse(
windows: Query<&Window>,
camera_query: Query<(&Camera, &GlobalTransform), With<crate::dice3d::types::MainCamera>>,
mut throw_state: ResMut<ThrowControlState>,
command_input: Res<crate::dice3d::types::CommandInput>,
ui_state: Res<crate::dice3d::types::UiState>,
) {
if command_input.active || ui_state.active_tab != crate::dice3d::types::AppTab::DiceRoller {
return;
}
let Ok(window) = windows.get_single() else {
return;
};
let Some(cursor_position) = window.cursor_position() else {
throw_state.mouse_over_box = false;
return;
};
let Ok((camera, camera_transform)) = camera_query.get_single() else {
return;
};
let Some(ray) = camera.viewport_to_world(camera_transform, cursor_position) else {
return;
};
if ray.direction.y.abs() < 0.0001 {
throw_state.mouse_over_box = false;
return;
}
let t = (BOX_FLOOR_Y - ray.origin.y) / ray.direction.y;
if t < 0.0 {
throw_state.mouse_over_box = false;
return;
}
let intersection = ray.origin + ray.direction * t;
let is_in_box = ThrowControlState::is_point_in_box(intersection);
let target = ThrowControlState::clamp_to_box_floor(intersection);
throw_state.target_point = target;
throw_state.mouse_over_box = is_in_box;
throw_state.throw_strength = ThrowControlState::calculate_strength_from_distance(target);
}
pub fn update_throw_arrow(
throw_state: Res<ThrowControlState>,
mut arrow_query: Query<(&mut Transform, &mut Visibility), With<ThrowDirectionArrow>>,
ui_state: Res<crate::dice3d::types::UiState>,
) {
for (mut transform, mut visibility) in arrow_query.iter_mut() {
if ui_state.active_tab != crate::dice3d::types::AppTab::DiceRoller {
*visibility = Visibility::Hidden;
continue;
}
*visibility = Visibility::Visible;
transform.translation = Vec3::new(
throw_state.target_point.x,
BOX_FLOOR_Y + 0.1,
throw_state.target_point.z,
);
let direction = throw_state.target_point - BOX_CENTER;
if direction.length() > 0.01 {
let angle = direction.z.atan2(direction.x);
transform.rotation = Quat::from_rotation_y(-angle + std::f32::consts::FRAC_PI_2);
}
let scale = 0.3 + throw_state.throw_strength * 0.5;
transform.scale = Vec3::new(scale, scale, scale);
}
}
pub fn spawn_throw_arrow(
commands: &mut Commands,
meshes: &mut ResMut<Assets<Mesh>>,
materials: &mut ResMut<Assets<StandardMaterial>>,
) {
let arrow_material = materials.add(StandardMaterial {
base_color: Color::srgba(1.0, 0.3, 0.1, 0.8),
unlit: true,
alpha_mode: AlphaMode::Blend,
..default()
});
let body_mesh = meshes.add(Cylinder::new(0.05, 0.4));
let head_mesh = meshes.add(Cone {
radius: 0.12,
height: 0.25,
});
commands
.spawn((
PbrBundle {
transform: Transform::from_translation(Vec3::new(0.0, BOX_FLOOR_Y + 0.1, 0.0)),
visibility: Visibility::Visible,
..default()
},
ThrowDirectionArrow,
))
.with_children(|parent| {
parent.spawn(PbrBundle {
mesh: body_mesh,
material: arrow_material.clone(),
transform: Transform::from_translation(Vec3::new(0.0, 0.0, 0.2))
.with_rotation(Quat::from_rotation_x(std::f32::consts::FRAC_PI_2)),
..default()
});
parent.spawn(PbrBundle {
mesh: head_mesh,
material: arrow_material,
transform: Transform::from_translation(Vec3::new(0.0, 0.0, 0.5))
.with_rotation(Quat::from_rotation_x(std::f32::consts::FRAC_PI_2)),
..default()
});
});
}
pub fn handle_strength_slider(
mouse_button: Res<ButtonInput<MouseButton>>,
mut throw_state: ResMut<ThrowControlState>,
track_query: Query<(&Node, &GlobalTransform), With<StrengthSliderTrack>>,
mut handle_query: Query<&mut Style, With<StrengthSliderHandle>>,
windows: Query<&Window>,
) {
if !mouse_button.pressed(MouseButton::Left) {
return;
}
let Ok(window) = windows.get_single() else {
return;
};
let Some(cursor_position) = window.cursor_position() else {
return;
};
for (node, global_transform) in track_query.iter() {
let track_rect = node.logical_rect(global_transform);
let expanded_rect = bevy::math::Rect {
min: Vec2::new(track_rect.min.x - 15.0, track_rect.min.y),
max: Vec2::new(track_rect.max.x + 15.0, track_rect.max.y),
};
if expanded_rect.contains(cursor_position) {
let relative_y = cursor_position.y - track_rect.min.y;
let track_height = track_rect.height();
let normalized = (relative_y / track_height).clamp(0.0, 1.0);
let inverted = 1.0 - normalized;
throw_state.max_strength = 1.0 + inverted * 14.0;
for mut style in handle_query.iter_mut() {
style.top = Val::Percent(normalized * 100.0);
}
}
}
}