RigidbodyFPSWalker

From Unify Community Wiki
(Difference between revisions)
Jump to: navigation, search
(JavaScript - RigidbodyFPSController.js)
(I just added the C# translation)
 
(5 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
==Description==
 
==Description==
This is a minor update to Joaquim's rigidbody script based first person controller; includes the latest 'air control' & the moving object / parenting  additions from the forums.  
+
This is a rigidbody based first person controller. Traditionally first person controllers are done using the character controller and this is the recommended way, but sometimes you want it to use real physics. So forces automatically affect the rigidbody, and joints can be used to eg. make a rope swinging game.
 
+
Plus have added separate walk & backward speeds, run option (need to map "Run" key to in Project Settings / Input to enable), and rotate view option (instead of strafe). It's my first extensive change to a script, so feel free to change as needed! 
+
 
+
*original notes:
+
Traditionally first person controllers are done using the character controller and this is the recommended way, but sometimes you want it to use real physics. So forces automatically affect the rigidbody, and joints can be used to eg. make a rope swinging game.
+
  
 
The script works by adding a force in the direction of desired movement, it subtracts the current velocity from it, thus when letting go of all keys the character will stop. A maximum velocity change can be specified which will make the character come to reset slower faster and in effect apply more or less force to object the character runs into.
 
The script works by adding a force in the direction of desired movement, it subtracts the current velocity from it, thus when letting go of all keys the character will stop. A maximum velocity change can be specified which will make the character come to reset slower faster and in effect apply more or less force to object the character runs into.
Line 15: Line 10:
  
 
==JavaScript - RigidbodyFPSController.js==
 
==JavaScript - RigidbodyFPSController.js==
<javascript>
+
<syntaxhighlight lang="javascript">
var walkSpeed = 8.0;
+
var speed = 10.0;
var walkBackwardSpeed = 4.0;
+
 
var gravity = 10.0;
 
var gravity = 10.0;
 
var maxVelocityChange = 10.0;
 
var maxVelocityChange = 10.0;
var inAirControl = 0.1;
 
 
var canJump = true;
 
var canJump = true;
 
var jumpHeight = 2.0;
 
var jumpHeight = 2.0;
 +
private var grounded = false;
  
 +
@script RequireComponent(Rigidbody, CapsuleCollider)
  
// added for run (must set "Run" input to something in Project Settings / Input e.g. left shift)
 
 
var canRun = false;
 
var runSpeedChange = 4.0; // negative values here makes game unhappy
 
 
// added for keyboard rotation ('Horizontal' rotates instead of translates / strafe)
 
var canRotate = false;
 
var rotateSpeed = 1.0;
 
var rotateInAir = false;
 
 
private var grounded = false;
 
private var groundVelocity : Vector3;
 
private var capsule : CapsuleCollider;
 
 
@script RequireComponent(Rigidbody, CapsuleCollider)
 
 
 
function Awake ()
 
function Awake ()
 
{
 
{
  rigidbody.freezeRotation = true;
+
rigidbody.freezeRotation = true;
  rigidbody.useGravity = false;
+
rigidbody.useGravity = false;
  capsule = GetComponent(CapsuleCollider);
+
 
}
 
}
+
 
 
function FixedUpdate ()
 
function FixedUpdate ()
 
{
 
{
    if (grounded)
+
if (grounded)
  {  
+
{
       
+
// Calculate how fast we should be moving
        // Calculate how fast we should rotate
+
var targetVelocity = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
 +
targetVelocity = transform.TransformDirection(targetVelocity);
 +
targetVelocity *= speed;
 +
 +
// Apply a force that attempts to reach our target velocity
 +
var velocity = rigidbody.velocity;
 +
var velocityChange = (targetVelocity - velocity);
 +
velocityChange.x = Mathf.Clamp(velocityChange.x, -maxVelocityChange, maxVelocityChange);
 +
velocityChange.z = Mathf.Clamp(velocityChange.z, -maxVelocityChange, maxVelocityChange);
 +
velocityChange.y = 0;
 +
rigidbody.AddForce(velocityChange, ForceMode.VelocityChange);
 +
 +
// Jump
 +
if (canJump && Input.GetButton("Jump"))
 +
{
 +
rigidbody.velocity = Vector3(velocity.x, CalculateJumpVerticalSpeed(), velocity.z);
 +
}
 +
}
 +
 +
// We apply gravity manually for more tuning control
 +
rigidbody.AddForce(Vector3 (0, -gravity * rigidbody.mass, 0));
 +
 +
grounded = false;
 +
}
  
        var rotation = Input.GetAxis("Horizontal") * rotateSpeed;
+
function OnCollisionStay ()
       
+
{
        // Set 'Horizontal' input based on rotate variable
+
grounded = true;
 +
}
  
        var targetVelocity = (canRotate) ? new Vector3(0, rotation, Input.GetAxis("Vertical"))  
+
function CalculateJumpVerticalSpeed ()
        : new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
+
{
        // targetVelocity = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
+
// From the jump height and gravity we deduce the upwards speed
 +
// for the character to reach at the apex.
 +
return Mathf.Sqrt(2 * jumpHeight * gravity);
 +
}
 +
</syntaxhighlight>
  
        // Calculate how fast we should be moving
 
  
        targetVelocity = transform.TransformDirection(targetVelocity);
 
      if (Input.GetAxis("Vertical") > 0)
 
            {
 
                targetVelocity *= (canRun && Input.GetButton("Run")) ? walkSpeed + runSpeedChange : walkSpeed;
 
          }
 
        else
 
            {
 
                targetVelocity *= (canRun && Input.GetButton("Run")) ? walkBackwardSpeed + runSpeedChange : walkBackwardSpeed;
 
          }
 
       
 
        // Rotate if rotate is enabled
 
  
        if (canRotate)
 
            {
 
                transform.Rotate(0, rotation, 0);
 
            }
 
       
 
        // Apply a force that attempts to reach our target velocity
 
    var velocity = rigidbody.velocity;
 
      var velocityChange = (targetVelocity - velocity) + groundVelocity;
 
      velocityChange.x = Mathf.Clamp(velocityChange.x, -maxVelocityChange, maxVelocityChange);
 
        velocityChange.z = Mathf.Clamp(velocityChange.z, -maxVelocityChange, maxVelocityChange);
 
        velocityChange.y = 0;
 
      rigidbody.AddForce(velocityChange, ForceMode.VelocityChange);
 
     
 
        // Jump
 
    if (canJump && Input.GetButton("Jump"))
 
        {
 
              rigidbody.velocity = Vector3(velocity.x, CalculateJumpVerticalSpeed(), velocity.z);
 
        }
 
     
 
        grounded = false;
 
  }
 
  else
 
    {
 
      // Add in air
 
  
       
 
        // Calculate how fast we should rotate
 
  
        rotation = Input.GetAxis("Horizontal") * rotateSpeed;
+
==C# - RigidbodyFPSController.cs==
        /*
+
<syntaxhighlight lang="csharp">
        // Set 'Horizontal' input behavior based on whether we can rotate in air
+
using UnityEngine;
 +
using System.Collections;
  
        targetVelocity = (rotateInAir) ? new Vector3(0, rotation, Input.GetAxis("Vertical"))  
+
[RequireComponent (typeof (Rigidbody))]
        : new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
+
[RequireComponent (typeof (CapsuleCollider))]
        */   
+
        targetVelocity = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
+
  
        targetVelocity = transform.TransformDirection(targetVelocity) * inAirControl;
+
public class CharacterControls : MonoBehaviour {
 
+
       
+
public float speed = 10.0f;
        // Rotate if rotate in air is enabled.  
+
public float gravity = 10.0f;
 
+
public float maxVelocityChange = 10.0f;
        if (rotateInAir)
+
public bool canJump = true;
            {
+
public float jumpHeight = 2.0f;
                transform.Rotate(0, rotation, 0);
+
private bool grounded = false;
            }
+
       
+
        rigidbody.AddForce(targetVelocity, ForceMode.VelocityChange);
+
  }
+
void Awake () {
     
+
    rigidbody.freezeRotation = true;
    // We apply gravity manually for more tuning control
+
    rigidbody.useGravity = false;
    rigidbody.AddForce(Vector3 (0, -gravity * rigidbody.mass, 0));
+
}
 +
 +
void FixedUpdate () {
 +
    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 *= speed;
 +
       
 +
        // 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;
 +
        rigidbody.AddForce(velocityChange, ForceMode.VelocityChange);
 +
   
 +
        // Jump
 +
        if (canJump && Input.GetButton("Jump")) {
 +
            rigidbody.velocity = new Vector3(velocity.x, CalculateJumpVerticalSpeed(), velocity.z);
 +
        }
 +
    }
 +
   
 +
    // We apply gravity manually for more tuning control
 +
    rigidbody.AddForce(new Vector3 (0, -gravity * rigidbody.mass, 0));
 +
   
 +
    grounded = false;
 +
}
 +
 +
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 * gravity);
 +
}
 
}
 
}
 
+
</syntaxhighlight>
function TrackGrounded (col : Collision)
+
{
+
  var minimumHeight = capsule.bounds.min.y + capsule.radius;
+
  for (var c : ContactPoint in col.contacts)
+
  {
+
      if (c.point.y < minimumHeight)
+
      {
+
        //we track velocity for rigidbodies we're standing on
+
        if (col.rigidbody) groundVelocity = col.rigidbody.velocity;
+
        //and become children of non-rigidbody colliders
+
        else transform.parent = col.transform;
+
        grounded = true;
+
      }
+
  } 
+
}
+
 
+
//unparent if we are no longer standing on our parent
+
function OnCollisionExit (col : Collision)
+
{
+
  if (col.transform == transform.parent) transform.parent = null;
+
}
+
 
+
function OnCollisionStay (col : Collision)
+
{
+
  TrackGrounded (col);
+
}
+
 
+
function OnCollisionEnter (col : Collision)
+
{
+
  TrackGrounded (col);
+
}
+
 
+
+
function 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 * gravity);
+
}
+
</javascript>
+

Latest revision as of 10:25, 7 May 2012

Contents

[edit] Description

This is a rigidbody based first person controller. Traditionally first person controllers are done using the character controller and this is the recommended way, but sometimes you want it to use real physics. So forces automatically affect the rigidbody, and joints can be used to eg. make a rope swinging game.

The script works by adding a force in the direction of desired movement, it subtracts the current velocity from it, thus when letting go of all keys the character will stop. A maximum velocity change can be specified which will make the character come to reset slower faster and in effect apply more or less force to object the character runs into.

[edit] Usage

You can download a sample project with the complete setup here:

RigidbodyFPS.zip

[edit] JavaScript - RigidbodyFPSController.js

var speed = 10.0;
var gravity = 10.0;
var maxVelocityChange = 10.0;
var canJump = true;
var jumpHeight = 2.0;
private var grounded = false;
 
@script RequireComponent(Rigidbody, CapsuleCollider)
 
function Awake ()
{
	rigidbody.freezeRotation = true;
	rigidbody.useGravity = false;
}
 
function FixedUpdate ()
{
	if (grounded)
	{
		// Calculate how fast we should be moving
		var targetVelocity = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
		targetVelocity = transform.TransformDirection(targetVelocity);
		targetVelocity *= speed;
 
		// Apply a force that attempts to reach our target velocity
		var velocity = rigidbody.velocity;
		var velocityChange = (targetVelocity - velocity);
		velocityChange.x = Mathf.Clamp(velocityChange.x, -maxVelocityChange, maxVelocityChange);
		velocityChange.z = Mathf.Clamp(velocityChange.z, -maxVelocityChange, maxVelocityChange);
		velocityChange.y = 0;
		rigidbody.AddForce(velocityChange, ForceMode.VelocityChange);
 
		// Jump
		if (canJump && Input.GetButton("Jump"))
		{
			rigidbody.velocity = Vector3(velocity.x, CalculateJumpVerticalSpeed(), velocity.z);
		}
	}
 
	// We apply gravity manually for more tuning control
	rigidbody.AddForce(Vector3 (0, -gravity * rigidbody.mass, 0));
 
	grounded = false;
}
 
function OnCollisionStay ()
{
	grounded = true;	
}
 
function 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 * gravity);
}



[edit] C# - RigidbodyFPSController.cs

using UnityEngine;
using System.Collections;
 
[RequireComponent (typeof (Rigidbody))]
[RequireComponent (typeof (CapsuleCollider))]
 
public class CharacterControls : MonoBehaviour {
 
	public float speed = 10.0f;
	public float gravity = 10.0f;
	public float maxVelocityChange = 10.0f;
	public bool canJump = true;
	public float jumpHeight = 2.0f;
	private bool grounded = false;
 
 
 
	void Awake () {
	    rigidbody.freezeRotation = true;
	    rigidbody.useGravity = false;
	}
 
	void FixedUpdate () {
	    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 *= speed;
 
	        // 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;
	        rigidbody.AddForce(velocityChange, ForceMode.VelocityChange);
 
	        // Jump
	        if (canJump && Input.GetButton("Jump")) {
	            rigidbody.velocity = new Vector3(velocity.x, CalculateJumpVerticalSpeed(), velocity.z);
	        }
	    }
 
	    // We apply gravity manually for more tuning control
	    rigidbody.AddForce(new Vector3 (0, -gravity * rigidbody.mass, 0));
 
	    grounded = false;
	}
 
	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 * gravity);
	}
}
Personal tools
Namespaces

Variants
Actions
Navigation
Extras
Toolbox