use babalcore::*;
use gdnative::api::GlobalConstants;
use gdnative::api::Input as GodotInput;
use gdnative::api::InputEventKey;
use gdnative::api::InputEventMouseButton;
use gdnative::api::InputEventMouseMotion;
use gdnative::api::InputEventScreenDrag;
use gdnative::api::InputEventScreenTouch;
use gdnative::api::OS;
use gdnative::prelude::*;
const NORMALIZED_TOUCHSCREEN_WIDTH: f32 = 1920.0;
#[derive(NativeClass)]
#[inherit(Node)]
pub struct Input {
disabled: bool,
mouse_captured: bool,
has_touchscreen: bool,
has_keyboard: bool,
escape_mode: bool,
input_jump: InputJump,
input_steer: InputSteer,
jump_button: Option<JumpButton>,
viewport_rect: Option<Vector2>,
}
#[derive(Debug, Clone, Copy)]
struct JumpButton {
top_left: Vector2,
bottom_right: Vector2,
}
#[methods]
impl Input {
fn new(_owner: &Node) -> Self {
let os = OS::godot_singleton();
let has_touchscreen = os.has_touchscreen_ui_hint();
godot_print!("Touch mode hint: {}", has_touchscreen);
Input {
disabled: false,
mouse_captured: false,
has_touchscreen,
has_keyboard: false,
escape_mode: false,
input_jump: InputJump::new(),
input_steer: InputSteer::new(),
jump_button: None,
viewport_rect: None,
}
}
#[export]
fn flush(&mut self, _owner: &Node) {
self.input_jump = InputJump::new();
self.input_steer = InputSteer::new();
}
fn normalize_mouse_x(&self, x: f32) -> f64 {
x as f64
}
fn normalize_touchscreen_x(&self, x: f32) -> f64 {
match self.viewport_rect {
Some(viewport_rect) => (x * NORMALIZED_TOUCHSCREEN_WIDTH / viewport_rect.x) as f64,
None => x as f64,
}
}
#[export]
fn _process(&mut self, _owner: &Node, _delta: f64) {
if !self.has_keyboard {
return;
}
let input = GodotInput::godot_singleton();
for scancode in vec![
GlobalConstants::KEY_LEFT,
GlobalConstants::KEY_KP_4,
GlobalConstants::KEY_A,
GlobalConstants::KEY_H,
] {
self.input_steer
.left_key(scancode, 1.0, input.is_key_pressed(scancode), None);
}
for scancode in vec![
GlobalConstants::KEY_RIGHT,
GlobalConstants::KEY_KP_6,
GlobalConstants::KEY_D,
GlobalConstants::KEY_L,
] {
self.input_steer
.right_key(scancode, 1.0, input.is_key_pressed(scancode), None);
}
}
#[export]
fn _input(&mut self, _owner: &Node, event: Variant) {
if self.disabled {
return;
}
if let Some(screen_drag) = event.try_to_object::<InputEventScreenDrag>() {
if self.mouse_captured {
let screen_drag = unsafe { screen_drag.assume_safe() };
godot_print!("{:?}", screen_drag.relative());
self.input_steer
.mouse_move(self.normalize_touchscreen_x(screen_drag.relative().x));
}
} else if let Some(mouse_motion) = event.try_to_object::<InputEventMouseMotion>() {
if self.has_touchscreen {
return;
}
if self.mouse_captured {
let mouse_motion = unsafe { mouse_motion.assume_safe() };
self.input_steer
.mouse_move(self.normalize_mouse_x(mouse_motion.relative().x));
}
} else if let Some(screen_touch) = event.try_to_object::<InputEventScreenTouch>() {
let screen_touch = unsafe { screen_touch.assume_safe() };
if let Some(jump_button) = self.jump_button {
let global_position = screen_touch.position();
if global_position.x >= jump_button.top_left.x
&& global_position.y >= jump_button.top_left.y
&& global_position.x <= jump_button.bottom_right.x
&& global_position.y <= jump_button.bottom_right.y
{
self.request_jump();
}
}
} else if let Some(mouse_button) = event.try_to_object::<InputEventMouseButton>() {
if self.has_touchscreen {
return;
}
let mouse_button = unsafe { mouse_button.assume_safe() };
if mouse_button.is_pressed() {
match mouse_button.button_index() {
GlobalConstants::BUTTON_LEFT => {
if self.mouse_captured {
self.request_jump()
}
}
GlobalConstants::BUTTON_RIGHT => self.escape(),
_ => {}
}
}
} else if let Some(key) = event.try_to_object::<InputEventKey>() {
self.has_keyboard = true;
let key = unsafe { key.assume_safe() };
match key.scancode() {
GlobalConstants::KEY_ESCAPE => self.escape(),
GlobalConstants::KEY_BACKSPACE => self.escape(),
GlobalConstants::KEY_DELETE => self.escape(),
GlobalConstants::KEY_F10 => self.escape(),
GlobalConstants::KEY_SPACE => {
if key.is_pressed() {
self.request_jump();
}
}
GlobalConstants::KEY_ENTER => {
if key.is_pressed() {
self.request_jump();
}
}
_ => {}
}
}
}
#[export]
fn _ready(&mut self, _owner: &Node) {
godot_print!("input start");
self.capture(true);
}
#[export]
fn _tree_exiting(&mut self, _owner: &Node) {
godot_print!("input stop");
self.capture(false);
}
#[export]
pub fn pop_jump(&mut self, _owner: &Node) -> bool {
self.input_jump.pop_jump(None)
}
#[export]
pub fn pop_steer(&mut self, _owner: &Node) -> f64 {
self.input_steer.pop_steer(None)
}
#[export]
fn set_jump_stickiness_factor(&mut self, _owner: &Node, jump_stickiness_factor: f64) {
self.input_jump
.set_stickiness_secs_f64(Some(jump_stickiness_factor * DEFAULT_STICKINESS_SECS_F64));
}
#[export]
fn set_mouse_sensibility_factor(&mut self, _owner: &Node, mouse_sensibility_factor: f64) {
self.input_steer.mouse_sensibility = mouse_sensibility_factor * DEFAULT_MOUSE_SENSIBILITY;
}
#[export]
fn set_keyboard_sensibility_factor(&mut self, _owner: &Node, keyboard_sensibility_factor: f64) {
self.input_steer.keyboard_sensibility =
keyboard_sensibility_factor * DEFAULT_KEYBOARD_SENSIBILITY;
}
#[export]
fn set_jump_button(&mut self, _owner: &Node, position: Vector2, size: Vector2, scale: Vector2) {
if size.x <= 0.0 || size.y <= 0.0 || scale.x <= 0.0 || scale.y <= 0.0 {
return;
}
let top_left = position;
let bottom_right = position + Vector2::new(size.x * scale.x, size.y * scale.y);
self.jump_button = Some(JumpButton {
top_left,
bottom_right,
});
}
#[export]
fn set_viewport_rect(&mut self, _owner: &Node, rect: Vector2) {
if rect.x <= 0.0 || rect.y <= 0.0 {
return;
}
self.viewport_rect = Some(rect);
}
#[export]
fn get_escape_mode(&self, _owner: &Node) -> bool {
return self.escape_mode;
}
#[export]
fn set_escape_mode(&mut self, _owner: &Node, mode: bool) {
self.escape_mode = mode;
self.capture(!mode);
}
#[export]
fn disable(&mut self, owner: &Node) {
self.set_escape_mode(owner, true);
self.disabled = true;
}
fn request_jump(&mut self) {
self.input_jump.push_jump(None);
}
fn escape(&mut self) {
self.escape_mode = true;
self.capture(false);
}
fn capture(&mut self, state: bool) {
if state != self.mouse_captured {
let mode = if state {
gdnative::api::Input::MOUSE_MODE_CAPTURED
} else {
gdnative::api::Input::MOUSE_MODE_VISIBLE
};
self.mouse_captured = state;
if !self.has_touchscreen {
let input = gdnative::api::Input::godot_singleton();
input.set_mouse_mode(mode);
}
}
}
}