Created
February 17, 2021 09:02
-
-
Save lemilonkh/279f82005033073ebaa0f3777248ced7 to your computer and use it in GitHub Desktop.
Hookstronaut's Player Controller
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extends GravityBody | |
class_name Player | |
export(float, 0, 50) var jetpack_force = 2 | |
export(float, 0, 10) var grappling_hook_length = 50 | |
export(float, 0, 10) var grappling_hook_force = 20 | |
export(float, 0, 50) var mouse_sensitivity = 0.002 # rad/px | |
export(float, 0, 10) var controller_look_speed = 0.08 | |
var current_planet: RigidBody | |
onready var camera: Camera = $Pivot/Camera | |
onready var rope: MeshInstance = $Rope | |
onready var hook_emitter: Position3D = $Pivot/Camera/LightningGun/HookEmitter | |
var grappled_body: RigidBody | |
var grappled_offset: Vector3 = Vector3() | |
func _init(): | |
initial_velocity = 0 | |
func _ready(): | |
current_planet = find_closest_planet() | |
set_process_unhandled_input(true) | |
set_physics_process(true) | |
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) | |
func find_closest_planet(): | |
var planets = get_tree().get_nodes_in_group("gravity") | |
var min_distance = INF | |
var closest_planet | |
for planet in planets: | |
var distance = planet.global_transform.origin.distance_to(global_transform.origin) | |
if distance < min_distance: | |
closest_planet = planet | |
min_distance = distance | |
return closest_planet | |
func get_input(): | |
var input_direction = Vector3() | |
var cam_basis = camera.global_transform.basis | |
input_direction -= Input.get_action_strength("move_left") * cam_basis.x | |
input_direction += Input.get_action_strength("move_right") * cam_basis.x | |
input_direction += Input.get_action_strength("move_up") * cam_basis.y | |
input_direction -= Input.get_action_strength("move_down") * cam_basis.y | |
input_direction -= Input.get_action_strength("move_forward") * cam_basis.z | |
input_direction += Input.get_action_strength("move_back") * cam_basis.z | |
# rotate camera with controller | |
var camera_rotation = Vector2( | |
Input.get_action_strength("look_left") - Input.get_action_strength("look_right"), | |
Input.get_action_strength("look_down") - Input.get_action_strength("look_up") | |
) * controller_look_speed | |
if camera_rotation.length() > 0: | |
rotate_camera(camera_rotation) | |
return input_direction.normalized() | |
func _physics_process(delta): | |
var jetpack_velocity = get_input() * jetpack_force * delta | |
linear_velocity += jetpack_velocity | |
if Input.is_action_pressed("shoot"): | |
if grappled_body == null: | |
var raycast_result = perform_raycast() | |
# hook onto hit body | |
if !raycast_result.empty() and raycast_result["collider"] is RigidBody: | |
grappled_body = raycast_result["collider"] | |
grappled_offset = raycast_result["position"] - grappled_body.global_transform.origin | |
# apply force to self and hit object | |
if grappled_body != null: | |
var grappling_direction = (grappled_body.global_transform.origin - global_transform.origin).normalized() | |
var grappling_force = grappling_direction * grappling_hook_force | |
add_central_force(grappling_force) | |
grappled_body.add_central_force(-grappling_force) | |
# update grappling hook rope | |
var own_pos = hook_emitter.global_transform.origin | |
var target_pos = grappled_body.global_transform.origin + grappled_offset | |
var direction = target_pos - own_pos | |
rope.global_transform.origin = (own_pos + target_pos) / 2 | |
rope.mesh.height = direction.length() | |
rope.look_at(target_pos, Vector3(0, 1, 0)) | |
rope.rotate_object_local(Vector3(1, 0, 0), -PI/2) | |
rope.visible = true | |
else: | |
grappled_body = null | |
grappled_offset = Vector3() | |
rope.visible = false | |
if Input.is_action_pressed("pull"): | |
pass | |
#if current_planet != null: | |
#look_at(current_planet.global_transform.origin, Vector3(0, 0, 1)) | |
func perform_raycast(): | |
var center_position = get_viewport().size / 2 | |
var from = camera.project_ray_origin(center_position) | |
var to = camera.project_ray_normal(center_position) * grappling_hook_length | |
var raycast_result = get_world().direct_space_state.intersect_ray(from, to, [self]) | |
return raycast_result | |
func _input(event): | |
if event.is_action_pressed("toggle_capture"): | |
if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED: | |
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) | |
elif Input.get_mouse_mode() == Input.MOUSE_MODE_VISIBLE: | |
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) | |
if event.is_action_pressed("ui_exit"): | |
get_tree().quit(0) | |
func rotate_camera(movement: Vector2): | |
camera.rotate_y(movement.x) | |
$Pivot.rotate_x(movement.y) | |
$Pivot.rotation.x = clamp($Pivot.rotation.x, -PI, PI) | |
func _unhandled_input(event): | |
if event is InputEventMouseMotion and Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED: | |
var movement = -event.relative * mouse_sensitivity | |
rotate_camera(movement) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment