@@ 12,7 12,7 @@ pub struct Parts(#[entities] Vec<Entity>);
#[derive(Component, Serialize, Deserialize, MapEntities)]
#[relationship(relationship_target = Parts)]
-pub struct PartInShip(#[entities] Entity);
+pub struct PartInShip(#[entities] pub Entity);
#[derive(Component, Serialize, Deserialize)]
#[require(Transform)]
@@ 1,3 1,4 @@
+use std::ops::Deref;
use crate::attachment::{Joint, JointOf, SnapOf, SnapOfJoint};
use crate::ecs::{Part, ThrustEvent};
use bevy::color::palettes::css::{FUCHSIA, GREEN};
@@ 20,7 21,14 @@ pub fn key_input_plugin(app: &mut App) {
}
#[derive(Resource, Default)]
-struct AttachmentDebugRes(bool);
+pub struct AttachmentDebugRes(pub bool);
+impl Deref for AttachmentDebugRes {
+ type Target = bool;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
fn debug_render_keybind(
keys: Res<ButtonInput<KeyCode>>,
@@ 1,12 1,16 @@
+use bevy::color::palettes::css::{ORANGE, RED};
use crate::client::Me;
use crate::ecs::{CursorWorldCoordinates, DragRequestEvent, Part};
use bevy::prelude::*;
use bevy_rapier2d::dynamics::MassProperties;
use bevy_rapier2d::prelude::AdditionalMassProperties;
+use crate::attachment::{JointOf, PartInShip, SnapOf, SnapOfJoint};
+use crate::client::colors::GREEN;
+use crate::client::key_input::AttachmentDebugRes;
pub fn parts_plugin(app: &mut App) {
app.insert_resource(DragResource(None));
- app.add_systems(Update, (handle_incoming_parts, handle_updated_parts));
+ app.add_systems(Update, (handle_incoming_parts, handle_updated_parts, update_drag_ghosts));
app.add_observer(on_part_release);
}
@@ 55,18 59,29 @@ fn handle_updated_parts(
#[derive(Resource)]
struct DragResource(Option<Entity>);
+#[derive(Component)]
+struct DragGhost;
fn on_part_click(
ev: Trigger<Pointer<Pressed>>,
- sprites: Query<&Sprite, Without<Me>>,
+ sprites: Query<(&Sprite, &Transform), Without<Me>>,
mut drag: ResMut<DragResource>,
+ mut commands: Commands
) {
if ev.button != PointerButton::Primary {
return;
}
- let Ok(_) = sprites.get(ev.target()) else {
+ let Ok(sprite) = sprites.get(ev.target()) else {
return;
};
+ let mut s = sprite.0.clone();
+ s.color = Color::srgba(0.7, 0.7, 0.7, 1.0);
+ commands.spawn((
+ DragGhost,
+ sprite.1.clone(),
+ s
+ ));
+
drag.0 = Some(ev.target());
}
@@ 75,17 90,74 @@ fn on_part_release(
mut drag: ResMut<DragResource>,
mut events: EventWriter<DragRequestEvent>,
cursor: Res<CursorWorldCoordinates>,
+ mut commands: Commands,
+ ghosts: Query<Entity, With<DragGhost>>,
) {
if ev.button != PointerButton::Primary {
return;
}
- if let Some(e) = drag.0
- && let Some(c) = cursor.0
- {
- debug!(?e, ?c, "sending drag request");
- events.write(DragRequestEvent(e, c));
+ if let Some(e) = drag.0 {
+ for ghost in &ghosts {
+ commands.entity(ghost).despawn();
+ }
+
+ if let Some(c) = cursor.0 {
+ debug!(?e, ?c, "sending drag request");
+ events.write(DragRequestEvent(e, c));
+ }
}
drag.0 = None;
}
+fn update_drag_ghosts(
+ mut ghost: Single<&mut Transform, (With<DragGhost>, Without<SnapOf>, Without<JointOf>, Without<Part>)>,
+ cursor: Res<CursorWorldCoordinates>,
+ snaps: Query<(&Transform, &SnapOfJoint, &SnapOf)>,
+ joints: Query<(&Transform, &JointOf)>,
+ parts: Query<&GlobalTransform, With<Part>>,
+ debug: Res<AttachmentDebugRes>,
+ mut gizmos: Gizmos,
+) {
+ let Some(cursor) = cursor.0 else { return };
+
+ const CUTOFF: f32 = 25.0; // px
+
+ let mut best_distance = f32::INFINITY;
+ let mut best_target = Transform::from_xyz(cursor.x, cursor.y, 0.0);
+
+ for (snap_local_transform, snap_joint, snap_part) in &snaps {
+ let Ok(parent_position) = parts.get(snap_part.0) else { continue; };
+ let snap_global_translation = parent_position.transform_point(snap_local_transform.translation).xy();
+
+ let distance_to_cursor = cursor.distance(snap_global_translation);
+
+ if distance_to_cursor > best_distance {
+ if debug.0 {gizmos.circle_2d(snap_global_translation, 3.0, RED); }
+ continue;
+ }
+ if distance_to_cursor > CUTOFF {
+ if debug.0 {gizmos.circle_2d(snap_global_translation, 3.0, ORANGE); }
+ continue;
+ }
+
+ if debug.0 { gizmos.circle_2d(snap_global_translation, 3.0, GREEN); }
+
+ let Ok((offset, parent)) = joints.get(snap_joint.0) else { continue; };
+ let Ok(parent_pos) = parts.get(parent.0) else { continue; };
+
+ let joint_target = parent_pos.transform_point(offset.translation);
+
+ if debug.0 { gizmos.circle_2d(joint_target.xy(), 3.0, GREEN); }
+
+ let target_transform = Transform {
+ translation: joint_target,
+ rotation: parent_position.rotation().mul_quat(offset.rotation),
+ scale: offset.scale,
+ };
+ best_distance = distance_to_cursor;
+ best_target = target_transform;
+ }
+
+ **ghost = best_target;
+}<
\ No newline at end of file