A card game engine for TCGs, primarily Magic: The Gathering but with support for others
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Revert "Attempting to finish the draggable object class, but it isn't working, will see if there's a better alternative elsewhere"

This reverts commit 517f4907a44046e469550d6c036fbdc63b0255aa.

+20 -323
-13
client/scenes/main.tscn
··· 9 9 grow_vertical = 2 10 10 11 11 [node name="ManaGroveNode" type="ManaGroveNode" parent="." unique_id=2018257899] 12 - 13 - [node name="DraggableObject" type="DraggableObject" parent="." unique_id=838482379] 14 - layout_mode = 0 15 - offset_right = 286.0 16 - offset_bottom = 409.0 17 - 18 - [node name="ColorRect" type="ColorRect" parent="DraggableObject" unique_id=2073394659] 19 - layout_mode = 1 20 - anchors_preset = 15 21 - anchor_right = 1.0 22 - anchor_bottom = 1.0 23 - grow_horizontal = 2 24 - grow_vertical = 2
+20 -310
gdext/src/draggable.rs
··· 1 1 use std::collections::HashMap; 2 2 3 - use godot::{classes::{Control, IControl, InputEvent, InputEventMouseButton, Tween, control::MouseFilter}, global::{MouseButton, deg_to_rad}, prelude::*}; 3 + use godot::{classes::{Control, IControl, InputEvent, InputEventMouseButton, Tween, control::MouseFilter}, prelude::*}; 4 4 5 5 /// A draggable object that supports mouse interaction with state-based animation system. 6 6 /// ··· 36 36 /// Base object (Control) 37 37 base: Base<Control>, 38 38 /// The speed at which the object moves. 39 - #[export] 40 39 moving_speed: i32, 41 40 /// Whether the object can be interacted with. 42 - #[export] 43 41 can_be_interacted_with: bool, 44 42 /// The distance the object hovers when interacted with. 45 - #[export] 46 43 hover_distance: i32, 47 44 /// The scale multiplier when hovering. 48 - #[export] 49 45 hover_scale: f32, 50 46 /// The rotation in degrees when hovering. 51 - #[export] 52 47 hover_rotation: f32, 53 48 /// The duration for hover animations. 54 - #[export] 55 49 hover_duration: f32, 56 50 /// State Machine 57 51 current_state: DraggableState, ··· 69 63 original_hover_rotation: f32, 70 64 /// Position and animation tracking. Track position during hover animation 71 65 current_hover_position: Vector2, 72 - target_destination: Vector2, 73 - target_rotation: f32, 74 66 /// Move operation tracking 75 67 original_destination: Vector2, 76 68 /// Move operation tracking ··· 78 70 /// Move operation tracking 79 71 destination_degree: f32, 80 72 /// Tween objects 81 - move_tween: Option<Gd<Tween>>, 73 + move_tween: Option<Tween>, 82 74 /// Tween objects 83 - hover_tween: Option<Gd<Tween>>, 84 - /// Stored Z-Index 85 - stored_z_index: i32, 86 - is_returning_to_original: bool, 87 - is_pressed: bool, 75 + hover_tween: Option<Tween>, 88 76 } 89 77 90 78 fn allowed_transitions(state: DraggableState) -> Vec<DraggableState> { ··· 95 83 DraggableState::Moving => vec![DraggableState::Idle] 96 84 } 97 85 } 98 - 99 - const VISUAL_DRAG_Z_OFFSET: i32 = 0; 100 86 101 87 #[godot_api] 102 88 impl IControl for DraggableObject { ··· 122 108 destination_degree: 0., 123 109 move_tween: None, 124 110 hover_tween: None, 125 - stored_z_index: 0, 126 - is_returning_to_original: false, 127 - target_destination: Vector2::ZERO, 128 - target_rotation: 0., 129 - is_pressed: false 130 111 } 131 112 } 132 113 133 114 fn ready(&mut self) { 134 - self.base_mut() 115 + let base = self.base.to_init_gd().clone(); 116 + 117 + self.base 118 + .to_init_gd() 135 119 .set_mouse_filter(MouseFilter::STOP); 136 120 // connect("mouse_entered", on_mouse_enter) 137 121 self.signals() ··· 146 130 .gui_input() 147 131 .connect_self(Self::on_gui_input); 148 132 149 - self.original_destination = self.base() 133 + self.original_destination = self.base 134 + .to_init_gd() 150 135 .get_global_position(); 151 - self.original_rotation = self.base() 136 + self.original_rotation = self.base 137 + .to_init_gd() 152 138 .get_rotation(); 153 - self.original_position = self.base() 139 + self.original_position = self.base 140 + .to_init_gd() 154 141 .get_position(); 155 - self.original_scale = self.base() 142 + self.original_scale = self.base 143 + .to_init_gd() 156 144 .get_scale(); 157 - self.original_hover_rotation = self.base() 145 + self.original_hover_rotation = self.base 146 + .to_init_gd() 158 147 .get_rotation(); 159 - self.stored_z_index = self.base() 160 - .get_z_index(); 161 - } 162 - 163 - fn process(&mut self, _delta: f64) { 164 - match &self.current_state { 165 - DraggableState::Holding => { 166 - let new_mouse_position = self.base().get_global_mouse_position() - self.current_holding_mouse_position; 167 - 168 - self.base_mut() 169 - .set_global_position(new_mouse_position); 170 - }, 171 - _ => () 172 - } 173 148 } 174 149 } 175 150 ··· 207 182 } 208 183 } 209 184 210 - /// Virtual method to determine if hovering animation can start. 211 - /// Override in subclasses to implement custom hovering conditions. 212 185 fn can_start_hovering(&mut self) -> bool { 213 - true 186 + false 214 187 } 215 188 216 189 fn change_state(&mut self, new_state: DraggableState) -> bool { ··· 231 204 true 232 205 } 233 206 234 - fn handle_mouse_button(&mut self, mouse_event: Gd<InputEventMouseButton>) { 235 - if mouse_event.get_button_index() != MouseButton::LEFT { 236 - return; 237 - } 238 - 239 - // Ignore all input during Moving state 240 - if self.current_state == DraggableState::Moving { 241 - return; 242 - } 243 - 244 - if mouse_event.is_pressed() { 245 - self.handle_mouse_pressed(); 246 - } 207 + fn handle_mouse_button(&mut self, event: Gd<InputEventMouseButton>) { 247 208 248 - if mouse_event.is_released() { 249 - self.handle_mouse_released(); 250 - } 251 209 } 252 210 253 211 fn exit_state(&mut self, state: DraggableState) { 254 - match state { 255 - DraggableState::Hovering => { 256 - let stored_z_index = self.stored_z_index; 257 212 258 - self.base_mut() 259 - .set_z_index(stored_z_index); 260 - self.stop_hover_animation(); 261 - }, 262 - DraggableState::Holding => { 263 - let stored_z_index = self.stored_z_index; 264 - let original_scale = self.original_scale; 265 - let original_hover_rotation = self.original_hover_rotation; 266 - 267 - self.base_mut() 268 - .set_z_index(stored_z_index); 269 - // Reset visual effects but preserve position for return_card() animation 270 - self.base_mut() 271 - .set_scale(original_scale); 272 - self.base_mut() 273 - .set_rotation(original_hover_rotation); 274 - }, 275 - DraggableState::Moving => { 276 - self.base_mut() 277 - .set_mouse_filter(MouseFilter::STOP); 278 - }, 279 - _ => () 280 - } 281 213 } 282 214 283 - fn enter_state(&mut self, state: DraggableState, from_state: DraggableState) { 284 - match state { 285 - DraggableState::Idle => { 286 - let stored_z_index = self.stored_z_index; 287 - 288 - self.base_mut() 289 - .set_z_index(stored_z_index); 290 - self.base_mut() 291 - .set_mouse_filter(MouseFilter::STOP); 292 - }, 293 - DraggableState::Hovering => { 294 - let stored_z_index = self.stored_z_index; 295 - 296 - self.base_mut() 297 - .set_z_index(stored_z_index + VISUAL_DRAG_Z_OFFSET); 298 - self.start_hover_animation(); 299 - }, 300 - DraggableState::Holding => { 301 - let stored_z_index = self.stored_z_index; 302 - 303 - // Preserve hover position if transitioning from Hovering state 304 - if from_state == DraggableState::Hovering { 305 - self.preserve_hover_position(); 306 - } 307 - 308 - self.current_holding_mouse_position = self.base() 309 - .get_local_mouse_position(); 310 - self.base_mut() 311 - .set_z_index(stored_z_index + VISUAL_DRAG_Z_OFFSET); 312 - self.base_mut() 313 - .set_rotation(0.); 314 - }, 315 - DraggableState::Moving => { 316 - let stored_z_index = self.stored_z_index; 317 - 318 - // Stop hover animations and ignore input during programmatic movement 319 - if let Some(hover_tween) = &mut self.hover_tween { 320 - if hover_tween.is_valid() { 321 - hover_tween.kill(); 322 - self.hover_tween = None; 323 - } 324 - } 325 - 326 - self.base_mut() 327 - .set_z_index(stored_z_index + VISUAL_DRAG_Z_OFFSET); 328 - self.base_mut() 329 - .set_mouse_filter(MouseFilter::IGNORE); 330 - } 331 - } 332 - } 333 - 334 - fn start_hover_animation(&mut self) { 335 - if let Some(hover_tween) = &mut self.hover_tween { 336 - if hover_tween.is_valid() { 337 - hover_tween.kill(); 338 - self.hover_tween = None; 339 - let original_position = self.original_position; // Reset position to original before starting new hover 340 - self.base_mut() 341 - .set_position(original_position); 342 - let original_scale = self.original_scale; 343 - self.base_mut() 344 - .set_scale(original_scale); 345 - let original_hover_rotation = self.original_hover_rotation; 346 - self.base_mut() 347 - .set_rotation(original_hover_rotation); 348 - } 349 - } 350 - 351 - // Update original position to current position (important for correct return) 352 - self.original_position = self.base().get_position(); 353 - self.original_scale = self.base().get_scale(); 354 - self.original_hover_rotation = self.base().get_rotation(); 355 - 356 - // Store current position before animation 357 - self.current_hover_position = self.base().get_position(); 358 - 359 - // Create new hover tween 360 - let mut hover_tween = self.create_tween(); 361 - hover_tween.set_parallel(); // Allow multiple properties to animate simultaneously 362 - 363 - // Animate position (hover up) 364 - let position = self.base().get_position(); 365 - let target_position = Vector2::new(position.x, position.y - (self.hover_distance as f32)); 366 - let obj = Gd::<Object>::from_instance_id(self.to_gd().instance_id()); 367 - hover_tween.tween_property(&obj, "position", &Variant::from(target_position), self.hover_duration.into()); 368 - 369 - // Animate scale 370 - hover_tween.tween_property(&obj, "scale", &Variant::from(self.original_scale * self.hover_scale), self.hover_duration.into()); 371 - 372 - // Animate rotation 373 - hover_tween.tween_property(&obj, "rotation", &Variant::from(deg_to_rad(self.hover_rotation.into())), self.hover_duration.into()); 374 - 375 - // Update current hover position tracking 376 - let func = Callable::from_object_method(&self.to_gd(), "update_hover_position"); 377 - hover_tween.tween_method(&func, &Variant::from(self.base().get_position()), &Variant::from(target_position), self.hover_duration.into()); 378 - } 379 - 380 - /// Preserve current hover position when transitioning to Holding 381 - fn preserve_hover_position(&mut self) { 382 - // Stop hover animation and preserve current position 383 - if let Some(hover_tween) = &mut self.hover_tween { 384 - if hover_tween.is_valid() { 385 - hover_tween.kill(); 386 - self.hover_tween = None; 387 - } 388 - } 389 - 390 - // Explicitly set position to current hover position 391 - // This ensures smooth transition from hover animation to holding 392 - let current_hover_position = self.current_hover_position; 393 - self.base_mut() 394 - .set_position(current_hover_position); 395 - } 396 - 397 - fn stop_hover_animation(&mut self) { 398 - 399 - } 400 - 401 - pub fn finish_move(&mut self) { 402 - // Complete movement processing 403 - self.is_moving_to_destination = false; 404 - let destination_degree = self.destination_degree; 405 - self.base_mut() 406 - .set_rotation(destination_degree); 407 - 408 - // Update original position and rotation only when not returning to original 409 - // Important: Use original target values from move() instead of global_position 410 - if !self.is_returning_to_original { 411 - self.original_destination = self.target_destination; 412 - self.original_rotation = self.target_rotation; 413 - } 414 - 415 - // Reset return flag 416 - self.is_returning_to_original = false; 417 - 418 - // End Moving state, return to Idle 419 - self.change_state(DraggableState::Idle); 420 - 421 - // Call inherited class callback 422 - self.on_move_done() 423 - } 215 + fn enter_state(&mut self, new_state: DraggableState, old_state: DraggableState) { 424 216 425 - fn on_move_done(&mut self) { 426 - // This function can be overridden by subclasses to handle when the move is done. 427 - } 428 - 429 - fn create_tween(&mut self) -> Gd<Tween> { 430 - self.base().get_tree().create_tween() 431 - } 432 - 433 - pub fn update_hover_position(&mut self, pos: Vector2) { 434 - self.current_hover_position = pos; 435 - } 436 - 437 - /// Moves the object to target position with optional rotation using smooth animation. 438 - /// Automatically transitions to Moving state and handles animation timing based on distance. 439 - fn move_obj(&mut self, target_destination: Vector2, degree: f32) { 440 - // Skip if current position and rotation match target 441 - if self.base().get_global_position() == target_destination && self.base().get_rotation() == degree { 442 - return; 443 - } 444 - 445 - // Force transition to Moving state (highest priority) 446 - self.change_state(DraggableState::Moving); 447 - 448 - // Stop existing movement 449 - if let Some(move_tween) = &mut self.move_tween { 450 - if move_tween.is_valid() { 451 - move_tween.kill(); 452 - self.move_tween = None; 453 - } 454 - } 455 - 456 - // Store target position and rotation for original value preservation 457 - self.target_destination = target_destination; 458 - self.target_rotation = degree; 459 - 460 - // Initial setup 461 - self.base_mut().set_rotation(0.); 462 - self.destination_degree = degree; 463 - self.is_moving_to_destination = true; 464 - 465 - // Smooth Tween-based movement with dynamic duration based on moving_speed 466 - let distance = self.base().get_global_position().distance_to(target_destination); 467 - let duration = distance / (self.moving_speed as f32); 468 - 469 - let mut move_tween = self.create_tween(); 470 - let obj = Gd::<Object>::from_instance_id(self.to_gd().instance_id()); 471 - move_tween.tween_property(&obj, "global_position", &Variant::from(target_destination), duration.into()); 472 - let func = Callable::from_object_method(&self.to_gd(), "finish_move"); 473 - move_tween.tween_callback(&func); 474 - } 475 - 476 - fn handle_mouse_pressed(&mut self) { 477 - self.is_pressed = true; 478 - 479 - match self.current_state { 480 - DraggableState::Hovering => { 481 - self.change_state(DraggableState::Holding); 482 - }, 483 - DraggableState::Idle => { 484 - if self.is_mouse_inside && self.can_be_interacted_with && self.can_start_hovering() { 485 - self.change_state(DraggableState::Holding); 486 - } 487 - }, 488 - _ => () 489 - } 490 - } 491 - 492 - fn handle_mouse_released(&mut self) { 493 - self.is_pressed = false; 494 - 495 - match self.current_state { 496 - DraggableState::Holding => { 497 - self.change_state(DraggableState::Idle); 498 - }, 499 - _ => () 500 - } 501 - } 502 - 503 - /// Returns the object to its original position with smooth animation. 504 - fn return_to_original(&mut self) { 505 - self.is_returning_to_original = true; 506 - self.move_obj(self.original_destination, self.original_rotation); 507 217 } 508 218 } 509 219