I did it as following:
1. Create a KinematicBody, add MeshInstance and CollisionShape,
2. Rotate the character mesh and make it lie down,it's head is on +Z axis(blue), in Godot -Z is forward.(don't skip this step, it will save some rotations while applying gravity, else you may need to calculate some quaternions and then apply it),
3. Lock all angular axis, since we take full control over the body's rotation,
4. Optional, create an Area with CollisionShape, names foot at the bottom to check if we are are on ground,so that we need not keep pulling the body when it's on ground,
5. Calculate the direction from the character to the planet's center, look at planet's center and apply gravity in direction, if we are not on ground.
6. Note, I made planet as a StaticBody, it is in group "Planet".
The code is as follows:
extends KinematicBody
onready var planet = get_parent().get_node("Planet")
const GRAVITY = -1.0
const ORIGIN = Vector3()
const ZERO_GRAVITY = Vector3()
const Y_AXIS = Vector3(0, 1, 0)
var my_gravity_scale = 1
var gravity_force = Vector3()
var is_on_ground = false
func _ready():
self.axis_lock_angular_x = true
self.axis_lock_angular_y = true
self.axis_lock_angular_z = true
return
func _physics_process(delta):
attract(delta)
return
func attract(delta):
if not is_on_ground:
var target_dir = (planet.global_transform.origin - self.global_transform.origin).normalized()
gravity_force = target_dir * my_gravity_scale *delta
self.look_at(planet.global_transform.origin, Y_AXIS)
self.move_and_collide(gravity_force)
else:
gravity_force = ZERO_GRAVITY
return
func _on_Foot_body_entered(body):
if body.is_in_group("Planet"):
print("Landed")
is_on_ground = true
return
func _on_Foot_body_exited(body):
if body.is_in_group("Planet"):
is_on_ground = false
return