# Walking on the roof with rigidbody movement

I believe this is something that not many people have asked for, its kinda weird I know, but the result should be awesome.

Here’s the code I have.

``````using UnityEngine;
using System.Collections;

[RequireComponent (typeof (Rigidbody))]

public class Player_movement : MonoBehaviour {

public float PlayerSpeedWalk = 30.0f;
public float gravitypull = 10.0f;
public float maxVelocityChange = 15.0f;
//	public float jumpHeight = 2.0f;

private bool grounded = false;
private Vector3 localgravity;
private Vector3 globalgravity;
private Vector3 curgravitywell;
private Vector3 direction;

void Awake ()
{
rigidbody.freezeRotation = true;
rigidbody.useGravity = false;
}

void FixedUpdate ()
{

RaycastHit hit2;
if (Physics.Raycast(transform.position, Vector3.down, out hit2))
{
globalgravity = hit2.point;
}

if (grounded)
{

// Calculate how fast we should be moving
Vector3 targetVelocity = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
targetVelocity = transform.TransformDirection(targetVelocity);
targetVelocity *= PlayerSpeedWalk;

// Apply a force that attempts to reach our target velocity
Vector3 velocity = rigidbody.velocity;
Vector3 velocityChange = (targetVelocity - velocity);
velocityChange.x = Mathf.Clamp(velocityChange.x, -maxVelocityChange, maxVelocityChange);
velocityChange.z = Mathf.Clamp(velocityChange.z, -maxVelocityChange, maxVelocityChange);
velocityChange.y = 0;

//			if (Input.GetButton("Jump"))
//			{
//				rigidbody.velocity = new Vector3(velocity.x, CalculateJumpVerticalSpeed(), velocity.z);
//			}

Vector3 localdown = transform.TransformDirection(Vector3.down);
RaycastHit hit;
Debug.DrawRay(transform.position, localdown, Color.red);
if (Physics.Raycast(transform.position, localdown, out hit))
{
transform.rotation = Quaternion.FromToRotation(Vector3.up, hit.normal);
Debug.DrawLine(transform.position, hit.point);
localgravity = hit.point;
}
curgravitywell = Vector3.Lerp(localgravity, globalgravity, 0.25f);
direction = curgravitywell - transform.position;
}
else
{
transform.rotation = Quaternion.LookRotation(Vector3.forward);
direction = Vector3.down;
}
grounded = false;
Debug.DrawRay (transform.position, direction);
}

void OnCollisionStay ()
{
grounded = true;
}
//	float CalculateJumpVerticalSpeed()
//	{
//		// From the jump height and gravity we deduce the upwards speed
//		// for the character to reach at the apex.
//		return Mathf.Sqrt(2 * jumpHeight * gravitypull);
//	}
}
``````

And it works, pretty ok, the problem is once I go past the halfway mark (where my wall starts curving over and becoming upside down) the character flips out and basically just dies. It flips out and slingshots him all over the place.

Even if I set the lerp to 0, so that global gravity should have no effect on you, it still does it. I can upload the webplayer if anyone wants to see the result of this code, or you can run it on a capsule with a capsule collider yourself.

maybe this script will work.It will walk on anything.
Note:this script was not done by me i simply googled it for you.

``````    var moveSpeed: float = 6; // move speed
var turnSpeed: float = 90; // turning speed (degrees/second)
var lerpSpeed: float = 10; // smoothing speed
var gravity: float = 10; // gravity acceleration
var isGrounded: boolean;
var deltaGround: float = 0.2; // character is grounded up to this distance
var jumpSpeed: float = 10; // vertical jump initial speed
var jumpRange: float = 10; // range to detect target wall

private var surfaceNormal: Vector3; // current surface normal
private var myNormal: Vector3; // character normal
private var distGround: float; // distance from character position to ground
private var jumping = false; // flag "I'm jumping to wall"
private var vertSpeed: float = 0; // vertical jump current speed

function Start(){
myNormal = transform.up; // normal starts as character up direction
rigidbody.freezeRotation = true; // disable physics rotation
// distance from transform.position to ground
distGround = collider.bounds.extents.y - collider.center.y;
}

function FixedUpdate(){
// apply constant weight force according to character normal:
}

function Update(){
if (jumping) return; // abort Update while jumping to a wall
var ray: Ray;
var hit: RaycastHit;
if (Input.GetButtonDown("Jump")){ // jump pressed:
ray = Ray(transform.position, transform.forward);
if (Physics.Raycast(ray, hit, jumpRange)){ // wall ahead?
}
else if (isGrounded){ // no: if grounded, jump up
rigidbody.velocity += jumpSpeed * myNormal;
}
}

// movement code - turn left/right with Horizontal axis:
transform.Rotate(0, Input.GetAxis("Horizontal")*turnSpeed*Time.deltaTime, 0);
// update surface normal and isGrounded:
ray = Ray(transform.position, -myNormal); // cast ray downwards
if (Physics.Raycast(ray, hit)){ // use it to update myNormal and isGrounded
isGrounded = hit.distance <= distGround + deltaGround;
surfaceNormal = hit.normal;
}
else {
isGrounded = false;
// assume usual ground normal to avoid "falling forever"
surfaceNormal = Vector3.up;
}
myNormal = Vector3.Lerp(myNormal, surfaceNormal, lerpSpeed*Time.deltaTime);
// find forward direction with new myNormal:
var myForward = Vector3.Cross(transform.right, myNormal);
// align character to the new myNormal while keeping the forward direction:
var targetRot = Quaternion.LookRotation(myForward, myNormal);
transform.rotation = Quaternion.Lerp(transform.rotation, targetRot, lerpSpeed*Time.deltaTime);
// move the character forth/back with Vertical axis:
transform.Translate(0, 0, Input.GetAxis("Vertical")*moveSpeed*Time.deltaTime);
}

function JumpToWall(point: Vector3, normal: Vector3){
jumping = true; // signal it's jumping to wall
rigidbody.isKinematic = true; // disable physics while jumping
var orgPos = transform.position;
var orgRot = transform.rotation;
var dstPos = point + normal * (distGround + 0.5); // will jump to 0.5 above wall
var myForward = Vector3.Cross(transform.right, normal);
var dstRot = Quaternion.LookRotation(myForward, normal);
for (var t: float = 0.0; t < 1.0; ){
t += Time.deltaTime;
transform.position = Vector3.Lerp(orgPos, dstPos, t);
transform.rotation = Quaternion.Slerp(orgRot, dstRot, t);
yield; // return here next frame
}
myNormal = normal; // update myNormal
rigidbody.isKinematic = false; // enable physics
jumping = false; // jumping to wall finished
}
``````