use std::borrow::Borrow; use gdnative::api::*; use gdnative::prelude::*; /// the input state for the player enum InputState { Default, Shooting, Moving } /// the basic die used by the player #[derive(NativeClass)] #[inherit(RigidBody)] #[register_with(Self::register_builder)] pub struct BasicDie { #[property(path="base/camera_offset")] camera_offset: f32, #[property(path="base/camera_clamp")] camera_clamp: Vector2, #[property(path="shooting/max_force")] max_force: f32, #[property(path="shooting/up_angle")] up_angle: f32, #[property(path="input/mouse_sensitivity")] mouse_sensitivity: Vector2, input_state: InputState, current_force: f32, action_shooting: String, node_camera_arm_horizontal: Option>, node_camera_arm_vertical: Option>, } #[methods] impl BasicDie { // Register the builder for methods, properties and/or signals. fn register_builder(_builder: &ClassBuilder) { godot_print!("BasicDie builder is registered!"); } fn new(_owner: &RigidBody) -> Self { BasicDie { camera_offset: 0.0, camera_clamp: Vector2 { x: 0.0, y: 0.0 }, max_force: 0.0, up_angle: 5.0, mouse_sensitivity: Vector2 { x: 1.0, y: 1.0 }, input_state: InputState::Default, current_force: 0.0, action_shooting: String::from("mouse_btn_left"), node_camera_arm_horizontal: None, node_camera_arm_vertical: None, } } #[export] unsafe fn _ready(&mut self, owner: &RigidBody) { owner.set_physics_process(true); // look for the horizontal camera arm match owner.get_node(NodePath::from_str("CameraArmHorizontal")) { Some(node) => { let save_node = node.assume_safe(); match save_node.cast::() { Some(casted) => { let save_casted = casted.claim(); self.node_camera_arm_horizontal = Some(save_casted)}, _ => godot_warn!("Camera Arm was not of type 'Spatial'"), } }, _ => godot_warn!("No child node called 'Camera found'") } // look for the vertical camera arm match self.node_camera_arm_horizontal { Some(arm) => { let save_arm = arm.assume_safe(); match save_arm.get_node(NodePath::from_str("CameraArmVertical")) { Some(node) => { let save_node = node.assume_safe(); match save_node.cast::() { Some(casted) => { let save_casted = casted.claim(); self.node_camera_arm_vertical = Some(save_casted)}, _ => godot_warn!("Camera Arm was not of type 'Spatial'"), } }, _ => godot_warn!("No vertical arm found.") } }, _ => godot_warn!("No horizontal arm to look for the vertical arm") } } #[export] unsafe fn _physics_process(&mut self, owner: &RigidBody, delta: f64) { if matches!(self.input_state, InputState::Moving) { // TODO check if velocity reached a certain threshold and set the mode to default again }; } #[export] unsafe fn _input(&mut self, owner: &RigidBody, event: Ref) { self.general_input(event.borrow()); match self.input_state { InputState::Default => self.default_input(event), InputState::Shooting => self.shooting_input(event), InputState::Moving => self.moving_input(event), } } /// this input method will always be called, regardless of the input state unsafe fn general_input(&mut self, event: &Ref) { let save_event = event.assume_safe(); // get the input as mouse input let mouse_event = save_event.cast::(); match mouse_event { Some(motion_event) => { let x_mov = motion_event.relative().x * self.mouse_sensitivity.x; self.rotate_cam_horizontal(x_mov); }, _ => {} } } /// this input method will be called when looking around, before taking a shot unsafe fn default_input(&mut self, event: Ref) { let save_event = event.assume_safe(); godot_print!("default input"); // left mouse button was pressed => switch to shooting mode if save_event.is_action_pressed(GodotString::from_str(&self.action_shooting), false, false) { godot_print!("mouse_button, switching to shooting mode"); self.input_state = InputState::Shooting; return; } // get the input as mouse input let mouse_event = save_event.cast::(); match mouse_event { Some(motion_event) => { let y_mov = -motion_event.relative().y * self.mouse_sensitivity.y; self.rotate_cam_vertical(y_mov); }, _ => {} }; } /// this input method will be called when player is currently taking a shot unsafe fn shooting_input(&mut self, event: Ref) { let save_event = event.assume_safe(); godot_print!("shooting input"); if save_event.is_action_released(GodotString::from_str(&self.action_shooting), false) { self.input_state = InputState::Moving; // TODO add force based on input and strength return; } // get the input as mouse input let mouse_event = save_event.cast::(); match mouse_event { Some(motion_event) => { let y_mov = motion_event.relative().y * self.mouse_sensitivity.y; self.current_force = match self.current_force + y_mov { x if x < 0.0 => 0.0, x if x > self.max_force => self.max_force, _ => self.current_force + y_mov }; godot_print!("current force: {}", self.current_force); }, _ => {} }; } /// this input method will be called when player is moving unsafe fn moving_input(&mut self, event: Ref) { let save_event = event.assume_safe(); godot_print!("moving input"); // get the input as mouse input let mouse_event = save_event.cast::(); match mouse_event { Some(motion_event) => { let y_mov = motion_event.relative().y * self.mouse_sensitivity.y; self.rotate_cam_vertical(y_mov); }, _ => {} }; } unsafe fn rotate_cam_horizontal(&mut self, input: f32) { // make sure the arm exists match self.node_camera_arm_horizontal { Some(arm) => { // rotate the horizontal camera arm let save_arm = arm.assume_safe(); save_arm.rotate_object_local(Vector3 {x: 0.0, y: 1.0, z: 0.0}, input as f64) }, _ => godot_warn!("No horizontal camera arm assigned.") } } unsafe fn rotate_cam_vertical(&mut self, input: f32) { // make sure the camera arm actually exists match self.node_camera_arm_vertical { Some(arm) => { // check for the current rotation let save_arm = arm.assume_safe(); let current_rot = save_arm.rotation(); godot_print!("current rotation: {} | {} | {} ", current_rot.x, current_rot.y, current_rot.z); // clamp the rotation if current_rot.x + input > self.camera_clamp.x || current_rot.x + input <= self.camera_clamp.y { return; } // actually rotate if possible let save_arm = arm.assume_safe(); save_arm.rotate_object_local(Vector3 {x: 1.0, y: 0.0, z: 0.0}, input as f64) }, _ => godot_warn!("No vertical camera arm assigned") } } }