Skip to content

Instantly share code, notes, and snippets.

@ByteAtATime
Created November 20, 2023 18:27
Show Gist options
  • Save ByteAtATime/4de202127e02687c2e8c65604d0f34b9 to your computer and use it in GitHub Desktop.
Save ByteAtATime/4de202127e02687c2e8c65604d0f34b9 to your computer and use it in GitHub Desktop.
godot-rust Simple Player Controller
#[derive(GodotClass)]
#[class(base = CharacterBody3D)]
struct Player {
#[export]
base_speed: f32,
#[export]
sprint_speed_multiplier: f32,
#[export]
air_speed_multiplier: f32,
#[export]
jump_velocity: f32,
#[export]
sensitivity: f32,
#[export]
accel: f32,
#[export]
default_fov: f32,
#[export]
sprint_fov: f32,
speed: f32,
sprinting: bool,
camera: Option<Gd<Camera3D>>,
#[base]
body: Base<CharacterBody3D>,
}
#[godot_api]
impl Player {}
#[godot_api]
impl ICharacterBody3D for Player {
fn init(body: Base<CharacterBody3D>) -> Self {
let base_speed = 15.0;
Self {
base_speed,
sprint_speed_multiplier: 1.5,
air_speed_multiplier: 0.5,
jump_velocity: 20.0,
sensitivity: 0.3,
accel: 15.0,
default_fov: 75.0,
sprint_fov: 90.0,
speed: base_speed,
sprinting: false,
camera: None,
body,
}
}
fn process(&mut self, delta: f64) {
let delta = delta as f32;
let fov = self.camera.as_ref().unwrap().get_fov();
if Input::singleton().is_action_pressed("move_sprint".into()) {
self.sprinting = true;
self.camera.as_mut().unwrap().set_fov(fov.lerp(self.sprint_fov, 10.0 * delta));
} else {
self.sprinting = false;
self.camera.as_mut().unwrap().set_fov(fov.lerp(self.default_fov, 10.0 * delta));
}
}
fn physics_process(&mut self, delta: f64) {
if self.body.is_on_floor() {
self.speed = self.base_speed * if self.sprinting { self.sprint_speed_multiplier } else { 1.0 };
} else {
self.speed = self.base_speed * self.air_speed_multiplier * if self.sprinting { self.sprint_speed_multiplier } else { 1.0 };
}
let delta = delta as f32;
let gravity = ProjectSettings::singleton().get_setting("physics/3d/default_gravity".into()).to::<f32>();
let mut velocity = self.body.get_velocity();
if !self.body.is_on_floor() {
velocity.y -= gravity * delta;
}
if Input::singleton().is_action_pressed("move_jump".into()) && self.body.is_on_floor() {
velocity.y += self.jump_velocity;
}
let input_dir = Input::singleton().get_vector("move_left".into(), "move_right".into(), "move_forward".into(), "move_backward".into());
let direction = input_dir.normalized().rotated(-self.body.get_rotation().y);
let direction = Vector3::new(direction.x, 0.0, direction.y);
velocity.x = velocity.x.lerp(direction.x * self.speed, self.accel * delta);
velocity.z = velocity.z.lerp(direction.z * self.speed, self.accel * delta);
self.body.set_velocity(velocity);
self.body.move_and_slide();
}
fn ready(&mut self) {
Input::singleton().set_mouse_mode(MouseMode::MOUSE_MODE_CAPTURED);
self.camera = Some(Camera3D::new_alloc());
self.body.add_child(self.camera.as_mut().unwrap().clone().upcast());
}
fn input(&mut self, event: Gd<InputEvent>) {
if !event.is_class("InputEventMouseMotion".into()) { return; }
let event = event.cast::<InputEventMouseMotion>();
let cur_rotation = self.body.get_rotation_degrees();
self.body.set_rotation_degrees(Vector3::new(
clamp((cur_rotation.x - event.get_relative().y * self.sensitivity).to_variant(), (-85.0).to_variant(), 85.0.to_variant()).to(),
cur_rotation.y - event.get_relative().x * self.sensitivity,
0.0,
));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment