3D Physics Based Rope

From Unify Community Wiki
(Difference between revisions)
Jump to: navigation, search
m (Reverted edits by Jj55ee (talk) to last revision by NCarter)
m
 
(2 intermediate revisions by one user not shown)
Line 1: Line 1:
==Description and Assembly==
+
Author: Jacob Fletcher
This script makes 3D physics based ropes for things like powerlines blowing in the wind, hoses flopping around, ropes you can swing on, and more. Basically all you have to do is drop this script into one object, then add the second into the "target" variable and your ready to go!
+
 
 +
== Description ==
 +
 
 +
This script makes 3D physics based ropes for things like power-lines blowing in the wind, hoses flopping around, ropes you can swing on, and more.
 +
 
 +
== Usage == 
 +
 
 +
Drop this script into one object, then add the second into the "target" variable and your ready to go.
 +
 
  
 
== Rope_Line.js ==
 
== Rope_Line.js ==
 
<syntaxhighlight lang="javascript">
 
<syntaxhighlight lang="javascript">
 
//============================
 
//============================
//== Physics Based 3D Rope ==
+
//== Physics Based 3D Rope ==
//== File: Rope_Tube.js   ==
+
//== File: Rope_Tube.js ==
//== By: Jacob Fletcher   ==
+
//== By: Jacob Fletcher ==
//== Use and alter Freely ==
+
//== Use and alter Freely ==
 
//============================
 
//============================
 
 
//To see other things I have created, visit me at www.reverieinterative.com
 
//To see other things I have created, visit me at www.reverieinterative.com
 
 
//How To Use:
 
//How To Use:
 
// ( BASIC )
 
// ( BASIC )
Line 18: Line 24:
 
// 3. Assign the other end of the rope as the "Target" object in this script
 
// 3. Assign the other end of the rope as the "Target" object in this script
 
// 4. Play and enjoy!
 
// 4. Play and enjoy!
 
 
// (About Character Joints)
 
// (About Character Joints)
 
// Sometimes your rope needs to be very limp and by that I mean NO SPRINGY EFFECT.
 
// Sometimes your rope needs to be very limp and by that I mean NO SPRINGY EFFECT.
Line 24: Line 29:
 
// For example, On my joints in my drawing app, I set the swingAxis to (0,0,1) sense
 
// For example, On my joints in my drawing app, I set the swingAxis to (0,0,1) sense
 
// the only axis I want to swing is the Z axis (facing the camera) and the other settings to around -100 or 100.
 
// the only axis I want to swing is the Z axis (facing the camera) and the other settings to around -100 or 100.
 
 
var target : Transform;
 
var target : Transform;
 
var material : Material;
 
var material : Material;
Line 35: Line 39:
 
var endRestrained = false;
 
var endRestrained = false;
 
var useMeshCollision = false;
 
var useMeshCollision = false;
 
 
// Private Variables (Only change if you know what your doing)
 
// Private Variables (Only change if you know what your doing)
 
private var segmentPos : Vector3[];
 
private var segmentPos : Vector3[];
 
private var joints : GameObject[];
 
private var joints : GameObject[];
 
private var tubeRenderer : GameObject;
 
private var tubeRenderer : GameObject;
private var line;
+
private var line : TubeRenderer;
 
private var segments = 4;
 
private var segments = 4;
 
private var rope = false;
 
private var rope = false;
 
 
//Joint Settings
 
//Joint Settings
 
var swingAxis = Vector3(0,1,0);
 
var swingAxis = Vector3(0,1,0);
 
var lowTwistLimit = 0.0;
 
var lowTwistLimit = 0.0;
 
var highTwistLimit = 0.0;
 
var highTwistLimit = 0.0;
var swing1Limit = 20.0;
+
var swing1Limit = 20.0;
 
+
 
// Require a Rigidbody
 
// Require a Rigidbody
 
@script RequireComponent(Rigidbody)
 
@script RequireComponent(Rigidbody)
 
+
 
function OnDrawGizmos() {
 
function OnDrawGizmos() {
  if(target) {
+
if(target) {
      Gizmos.color = Color.yellow;
+
Gizmos.color = Color.yellow;
      Gizmos.DrawLine (transform.position, target.position);
+
Gizmos.DrawLine (transform.position, target.position);
      Gizmos.DrawWireSphere ((transform.position+target.position)/2,ropeWidth);
+
Gizmos.DrawWireSphere ((transform.position+target.position)/2,ropeWidth);
      Gizmos.color = Color.green;
+
Gizmos.color = Color.green;
      Gizmos.DrawWireSphere (transform.position, ropeWidth);
+
Gizmos.DrawWireSphere (transform.position, ropeWidth);
      Gizmos.color = Color.red;
+
Gizmos.color = Color.red;
      Gizmos.DrawWireSphere (target.position, ropeWidth);
+
Gizmos.DrawWireSphere (target.position, ropeWidth);
  } else {
+
} else {
      Gizmos.color = Color.green;
+
Gizmos.color = Color.green;
      Gizmos.DrawWireSphere (transform.position, ropeWidth);  
+
Gizmos.DrawWireSphere (transform.position, ropeWidth);
  }
+
}
 
}
 
}
  
 
function Awake()
 
function Awake()
 
{
 
{
  if(target) {
+
if(target) {
        BuildRope();
+
BuildRope();
  } else {
+
} else {
      Debug.LogError("You must have a gameobject attached to target: " + this.name,this);  
+
Debug.LogError("You must have a gameobject attached to target: " + this.name,this);
  }
+
}
 
}
 
}
  
 
function LateUpdate()
 
function LateUpdate()
 
{
 
{
  if(target) {
+
if(target) {
      // Does rope exist? If so, update its position
+
// Does rope exist? If so, update its position
      if(rope) {
+
if(rope) {
        line.SetPoints(segmentPos, ropeWidth, Color.white);
+
line.SetPoints(segmentPos, ropeWidth, Color.white);
   
+
line.enabled = true;
        line.enabled = true;
+
segmentPos[0] = transform.position;
          segmentPos[0] = transform.position;
+
for(var s:int=1;s<segments;s++)
 
+
{
          for(s=1;s<segments;s++)
+
segmentPos[s] = joints[s].transform.position;
          {
+
}
            segmentPos[s] = joints[s].transform.position;
+
}
          }
+
}
      }
+
  }
+
 
}
 
}
 
 
  
 
function BuildRope()
 
function BuildRope()
 
{
 
{
  tubeRenderer = new GameObject("TubeRenderer_" + gameObject.name);
+
tubeRenderer = new GameObject("TubeRenderer_" + gameObject.name);
  line = tubeRenderer.AddComponent(TubeRenderer);
+
line = tubeRenderer.AddComponent(TubeRenderer);
  line.useMeshCollision = useMeshCollision;
+
line.useMeshCollision = useMeshCollision;
 
+
// Find the amount of segments based on the distance and resolution
  // Find the amount of segments based on the distance and resolution
+
// Example: [resolution of 1.0 = 1 joint per unit of distance]
  // Example: [resolution of 1.0 = 1 joint per unit of distance]
+
segments = Vector3.Distance(transform.position,target.position)*resolution;
  segments = Vector3.Distance(transform.position,target.position)*resolution;
+
if(material) {
  if(material) {
+
material.SetTextureScale("_MainTex",Vector2(1,segments+2));
        material.SetTextureScale("_MainTex",Vector2(1,segments+2));
+
if(material.GetTexture("_BumpMap"))
        if(material.GetTexture("_BumpMap"))
+
material.SetTextureScale("_BumpMap",Vector2(1,segments+2));
            material.SetTextureScale("_BumpMap",Vector2(1,segments+2));
+
}
  }
+
line.vertices = new TubeVertex[segments];
  line.vertices = new TubeVertex[segments];
+
line.crossSegments = radialSegments;
  line.crossSegments = radialSegments;
+
line.material = material;
  line.material = material;
+
segmentPos = new Vector3[segments];
  segmentPos = new Vector3[segments];
+
joints = new GameObject[segments];
  joints = new GameObject[segments];
+
segmentPos[0] = transform.position;
  segmentPos[0] = transform.position;
+
segmentPos[segments-1] = target.position;
  segmentPos[segments-1] = target.position;
+
// Find the distance between each segment
   
+
var segs = segments-1;
  // Find the distance between each segment
+
var seperation = ((target.position - transform.position)/segs);
  var segs = segments-1;
+
for(var s:int=0;s < segments;s++)
  var seperation = ((target.position - transform.position)/segs);
+
{
       
+
// Find the each segments position using the slope from above
  for(s=0;s < segments;s++)
+
var vector : Vector3 = (seperation*s) + transform.position;
  {
+
segmentPos[s] = vector;
      // Find the each segments position using the slope from above
+
//Add Physics to the segments
      vector = (seperation*s) + transform.position;  
+
AddJointPhysics(s);
      segmentPos[s] = vector;
+
}
   
+
// Attach the joints to the target object and parent it to this object
      //Add Physics to the segments
+
var end : CharacterJoint = target.gameObject.AddComponent("CharacterJoint");
      AddJointPhysics(s);
+
end.connectedBody = joints[joints.length-1].transform.rigidbody;
  }
+
end.swingAxis = swingAxis;
 
+
end.lowTwistLimit.limit = lowTwistLimit;
  // Attach the joints to the target object and parent it to this object
+
end.highTwistLimit.limit = highTwistLimit;
  var end = target.gameObject.AddComponent("CharacterJoint");
+
end.swing1Limit.limit = swing1Limit;
  end.connectedBody = joints[joints.length-1].transform.rigidbody;
+
target.parent = transform;
  end.swingAxis = swingAxis;
+
if(endRestrained)
  end.lowTwistLimit.limit = lowTwistLimit;
+
{
  end.highTwistLimit.limit = highTwistLimit;
+
end.rigidbody.isKinematic = true;
  end.swing1Limit.limit = swing1Limit;
+
}
  target.parent = transform;
+
if(startRestrained)
 
+
{
  if(endRestrained)
+
transform.rigidbody.isKinematic = true;
  {
+
}
      end.rigidbody.isKinematic = true;
+
// Rope = true, The rope now exists in the scene!
  }
+
rope = true;
 
+
  if(startRestrained)
+
  {
+
        transform.rigidbody.isKinematic = true;
+
  }
+
 
+
  // Rope = true, The rope now exists in the scene!
+
  rope = true;
+
 
}
 
}
  
function AddJointPhysics(n)
+
function AddJointPhysics(n : int)
 
{
 
{
  joints[n] = new GameObject("Joint_" + n);
+
joints[n] = new GameObject("Joint_" + n);
  joints[n].transform.parent = transform;
+
joints[n].transform.parent = transform;
  var rigid = joints[n].AddComponent("Rigidbody");
+
var rigid : Rigidbody = joints[n].AddComponent("Rigidbody");
  if(!useMeshCollision) {
+
if(!useMeshCollision) {
        var col = joints[n].AddComponent("SphereCollider");
+
var col : SphereCollider = joints[n].AddComponent("SphereCollider");
        col.radius = ropeWidth;
+
col.radius = ropeWidth;
  }
+
}
  var ph = joints[n].AddComponent("CharacterJoint");
+
var ph : CharacterJoint = joints[n].AddComponent("CharacterJoint");
  ph.swingAxis = swingAxis;
+
ph.swingAxis = swingAxis;
  ph.lowTwistLimit.limit = lowTwistLimit;
+
ph.lowTwistLimit.limit = lowTwistLimit;
  ph.highTwistLimit.limit = highTwistLimit;
+
ph.highTwistLimit.limit = highTwistLimit;
  ph.swing1Limit.limit = swing1Limit;
+
ph.swing1Limit.limit = swing1Limit;
  //ph.breakForce = ropeBreakForce; <--------------- TODO
+
//ph.breakForce = ropeBreakForce; <--------------- TODO
 
+
joints[n].transform.position = segmentPos[n];
  joints[n].transform.position = segmentPos[n];
+
rigid.drag = ropeDrag;
   
+
rigid.mass = ropeMass;
  rigid.drag = ropeDrag;
+
if(n==0){ ph.connectedBody = transform.rigidbody;
  rigid.mass = ropeMass;
+
} else
 
+
{
  if(n==0){    
+
ph.connectedBody = joints[n-1].rigidbody;
      ph.connectedBody = transform.rigidbody;
+
}
  } else
+
} </syntaxhighlight>
  {
+
      ph.connectedBody = joints[n-1].rigidbody;  
+
  }
+
         
+
}  
+
*/</syntaxhighlight>
+
  
 
== MODIFIED TubeRenderer.js ==
 
== MODIFIED TubeRenderer.js ==
 
<syntaxhighlight lang="javascript">
 
<syntaxhighlight lang="javascript">
 
//TubeRenderer.js
 
//TubeRenderer.js
 
+
 
//This script is created by Ray Nothnagel of Last Bastion Games. It is
 
//This script is created by Ray Nothnagel of Last Bastion Games. It is
 
//free for use and available on the Unify Wiki.
 
//free for use and available on the Unify Wiki.
 
+
 
//For other components I've created, see:
 
//For other components I've created, see:
 
//http://lastbastiongames.com/middleware/
 
//http://lastbastiongames.com/middleware/
 
+
 
//(C) 2008 Last Bastion Games
 
//(C) 2008 Last Bastion Games
 
+
 
//--------------------------------------------------------------
 
//--------------------------------------------------------------
 
+
 
//EDIT: MODIFIED BY JACOB FLETCHER FOR USE WITH THE ROPE SCRIPT
 
//EDIT: MODIFIED BY JACOB FLETCHER FOR USE WITH THE ROPE SCRIPT
 
//http://www.reverieinteractive.com
 
//http://www.reverieinteractive.com
 
+
 
+
 
class TubeVertex {
 
class TubeVertex {
  var point : Vector3 = Vector3.zero;
+
var point : Vector3 = Vector3.zero;
  var radius : float = 1.0;
+
var radius : float = 1.0;
  var color : Color = Color.white;
+
var color : Color = Color.white;
 
+
  function TubeVertex(pt : Vector3, r : float, c : Color) {
+
function TubeVertex(pt : Vector3, r : float, c : Color) {
      point=pt;
+
point=pt;
      radius=r;
+
radius=r;
      color=c;
+
color=c;
  }
+
}
 
}
 
}
 
+
 
var vertices : TubeVertex[];
 
var vertices : TubeVertex[];
 
var material : Material;
 
var material : Material;
Line 224: Line 207:
 
var maxRebuildTime = 0.1;
 
var maxRebuildTime = 0.1;
 
var useMeshCollision = false;
 
var useMeshCollision = false;
 
+
 
private var lastCameraPosition1 : Vector3;
 
private var lastCameraPosition1 : Vector3;
 
private var lastCameraPosition2 : Vector3;
 
private var lastCameraPosition2 : Vector3;
Line 230: Line 213:
 
private var lastCrossSegments : int;
 
private var lastCrossSegments : int;
 
private var lastRebuildTime = 0.00;
 
private var lastRebuildTime = 0.00;
private var mesh;
+
private var mesh : Mesh;
 
private var colliderExists = false;
 
private var colliderExists = false;
 
private var usingBumpmap = false;
 
private var usingBumpmap = false;
 
+
 
function Reset() {
 
function Reset() {
  vertices = [TubeVertex(Vector3.zero, 1.0, Color.white), TubeVertex(Vector3(1,0,0), 1.0, Color.white)];
+
vertices = [TubeVertex(Vector3.zero, 1.0, Color.white), TubeVertex(Vector3(1,0,0), 1.0, Color.white)];
 
}
 
}
 
+
 
function Start() {
 
function Start() {
  Reset();
+
Reset();
  mesh = new Mesh();
+
mesh = new Mesh();
  gameObject.AddComponent(MeshFilter);
+
gameObject.AddComponent(MeshFilter);
  var mr : MeshRenderer = gameObject.AddComponent(MeshRenderer);
+
var mr : MeshRenderer = gameObject.AddComponent(MeshRenderer);
  mr.material = material;
+
mr.material = material;
  if(material) {
+
if(material) {
        if(material.GetTexture("_BumpMap")) usingBumpmap = true;
+
if(material.GetTexture("_BumpMap")) usingBumpmap = true;
  }
+
}
 
}
 
}
 
+
 
function LateUpdate () {
 
function LateUpdate () {
  if (!vertices || vertices.length <= 1) {
+
if (!vertices || vertices.length <= 1) {
      renderer.enabled=false;
+
renderer.enabled=false;
      return;
+
return;
  }
+
}
 
+
  renderer.enabled=true;
+
renderer.enabled=true;
  if (crossSegments != lastCrossSegments) {
+
if (crossSegments != lastCrossSegments) {
      crossPoints = new Vector3[crossSegments];
+
crossPoints = new Vector3[crossSegments];
      var theta : float = 2.0*Mathf.PI/crossSegments;
+
var theta : float = 2.0*Mathf.PI/crossSegments;
      for (c=0;c<crossSegments;c++) {
+
for (var c:int=0;c<crossSegments;c++) {
        crossPoints[c] = Vector3(Mathf.Cos(theta*c), Mathf.Sin(theta*c), 0);
+
crossPoints[c] = Vector3(Mathf.Cos(theta*c), Mathf.Sin(theta*c), 0);
      }
+
}
      lastCrossSegments = crossSegments;
+
lastCrossSegments = crossSegments;
  }
+
}
     
+
  var meshVertices : Vector3[] = new Vector3[vertices.length*crossSegments];
+
var meshVertices : Vector3[] = new Vector3[vertices.length*crossSegments];
  var uvs : Vector2[] = new Vector2[vertices.length*crossSegments];
+
var uvs : Vector2[] = new Vector2[vertices.length*crossSegments];
  var colors : Color[] = new Color[vertices.length*crossSegments];
+
var colors : Color[] = new Color[vertices.length*crossSegments];
  var tris : int[] = new int[vertices.length*crossSegments*6];
+
var tris : int[] = new int[vertices.length*crossSegments*6];
  var lastVertices : int[] = new int[crossSegments];
+
var lastVertices : int[] = new int[crossSegments];
  var theseVertices : int[] = new int[crossSegments];
+
var theseVertices : int[] = new int[crossSegments];
  var rotation : Quaternion;
+
var rotation : Quaternion;
     
+
  for (p=0;p<vertices.length;p++) {
+
for (var p:int=0;p<vertices.length;p++) {
      if(p<vertices.length-1)
+
if(p<vertices.length-1)
        rotation = Quaternion.FromToRotation(Vector3.forward,vertices[p+1].point-vertices[p].point);
+
rotation = Quaternion.FromToRotation(Vector3.forward,vertices[p+1].point-vertices[p].point);
         
+
      for (c=0;c<crossSegments;c++) {
+
for (c=0;c<crossSegments;c++) {
        var vertexIndex : int = p*crossSegments+c;
+
var vertexIndex : int = p*crossSegments+c;
        meshVertices[vertexIndex] = vertices[p].point + rotation * crossPoints[c] * vertices[p].radius;
+
meshVertices[vertexIndex] = vertices[p].point + rotation * crossPoints[c] * vertices[p].radius;
        uvs[vertexIndex] = Vector2((0.0+c)/crossSegments,(0.0+p)/vertices.length);
+
uvs[vertexIndex] = Vector2((0.0+c)/crossSegments,(0.0+p)/vertices.length);
        colors[vertexIndex] = vertices[p].color;
+
colors[vertexIndex] = vertices[p].color;
 
+
        lastVertices[c]=theseVertices[c];
+
lastVertices[c]=theseVertices[c];
        theseVertices[c] = p*crossSegments+c;
+
theseVertices[c] = p*crossSegments+c;
      }
+
}
 
+
      //make triangles
+
//make triangles
      if (p>0) {
+
if (p>0) {
        for (c=0;c<crossSegments;c++) {
+
for (c=0;c<crossSegments;c++) {
            var start : int= (p*crossSegments+c)*6;
+
var start : int= (p*crossSegments+c)*6;
            tris[start] = lastVertices[c];
+
tris[start] = lastVertices[c];
            tris[start+1] = lastVertices[(c+1)%crossSegments];
+
tris[start+1] = lastVertices[(c+1)%crossSegments];
            tris[start+2] = theseVertices[c];
+
tris[start+2] = theseVertices[c];
            tris[start+3] = tris[start+2];
+
tris[start+3] = tris[start+2];
            tris[start+4] = tris[start+1];
+
tris[start+4] = tris[start+1];
            tris[start+5] = theseVertices[(c+1)%crossSegments];
+
tris[start+5] = theseVertices[(c+1)%crossSegments];
        }
+
}
      }
+
}
  }
+
}
 
+
    //Clear mesh for new build  (jf)  
+
//Clear mesh for new build  (jf)
  mesh.Clear();
+
mesh.Clear();
  mesh.vertices = meshVertices;
+
mesh.vertices = meshVertices;
  mesh.triangles = tris;
+
mesh.triangles = tris;
  mesh.RecalculateNormals();
+
mesh.RecalculateNormals();
  if(usingBumpmap)
+
if(usingBumpmap)
      mesh.tangents = CalculateTangents(meshVertices);
+
mesh.tangents = CalculateTangents(meshVertices);
  mesh.uv = uvs;
+
mesh.uv = uvs;
 
+
  if(useMeshCollision)
+
if(useMeshCollision)
      if(colliderExists) {
+
if(colliderExists) {
        gameObject.GetComponent(MeshCollider).sharedMesh = mesh;
+
gameObject.GetComponent(MeshCollider).sharedMesh = mesh;
      } else {
+
} else {
        gameObject.AddComponent(MeshCollider);
+
gameObject.AddComponent(MeshCollider);
        colliderExists = true;
+
colliderExists = true;
      }
+
}
  GetComponent(MeshFilter).mesh = mesh;
+
GetComponent(MeshFilter).mesh = mesh;
 
}
 
}
 
+
 
+
 
+
function CalculateTangents(verts)
+
function CalculateTangents(verts : Vector3[])
 
{
 
{
  var tangents = new Vector4[verts.length];
+
var tangents : Vector4[] = new Vector4[verts.length];
 
+
  for(i=0;i<tangents.length;i++)
+
for(var i:int=0;i<tangents.length;i++)
  {
+
{
      var vertex1 = i > 0 ? verts[i-1] : verts[i];
+
var vertex1 = i > 0 ? verts[i-1] : verts[i];
        var vertex2 = i < tangents.length - 1 ? verts[i+1] : verts[i];
+
  var vertex2 = i < tangents.length - 1 ? verts[i+1] : verts[i];
        var tan = (vertex1 - vertex2).normalized;
+
  var tan = (vertex1 - vertex2).normalized;
        tangents[i] = Vector4( tan.x, tan.y, tan.z, 1.0 );
+
  tangents[i] = Vector4( tan.x, tan.y, tan.z, 1.0 );
  }
+
}
  return tangents;  
+
return tangents;
 
}
 
}
 
+
 
+
 
+
 
//sets all the points to points of a Vector3 array, as well as capping the ends.
 
//sets all the points to points of a Vector3 array, as well as capping the ends.
 
function SetPoints(points : Vector3[], radius : float, col : Color) {
 
function SetPoints(points : Vector3[], radius : float, col : Color) {
  if (points.length < 2) return;
+
if (points.length < 2) return;
      vertices = new TubeVertex[points.length+2];
+
vertices = new TubeVertex[points.length+2];
 
+
      var v0offset : Vector3 = (points[0]-points[1])*0.01;
+
var v0offset : Vector3 = (points[0]-points[1])*0.01;
      vertices[0] = TubeVertex(v0offset+points[0], 0.0, col);
+
vertices[0] = TubeVertex(v0offset+points[0], 0.0, col);
      var v1offset : Vector3 = (points[points.length-1] - points[points.length-2])*0.01;
+
var v1offset : Vector3 = (points[points.length-1] - points[points.length-2])*0.01;
      vertices[vertices.length-1] = TubeVertex(v1offset+points[points.length-1], 0.0, col);
+
vertices[vertices.length-1] = TubeVertex(v1offset+points[points.length-1], 0.0, col);
 
+
  for (p=0;p<points.length;p++) {
+
for (var p:int=0;p<points.length;p++) {
      vertices[p+1] = TubeVertex(points[p], radius, col);
+
vertices[p+1] = TubeVertex(points[p], radius, col);
  }
+
}
}  
+
}</syntaxhighlight>
</syntaxhighlight>
+
  
 
[[Category: JavaScript]]
 
[[Category: JavaScript]]
 
[[Category: Physics]]
 
[[Category: Physics]]

Latest revision as of 16:06, 11 December 2012

Author: Jacob Fletcher

Contents

[edit] Description

This script makes 3D physics based ropes for things like power-lines blowing in the wind, hoses flopping around, ropes you can swing on, and more.

[edit] Usage

Drop this script into one object, then add the second into the "target" variable and your ready to go.


[edit] Rope_Line.js

//============================
//==	Physics Based 3D Rope ==
//==	File: Rope_Tube.js	==
//==	By: Jacob Fletcher	==
//==	Use and alter Freely	==
//============================
//To see other things I have created, visit me at www.reverieinterative.com
//How To Use:
// ( BASIC )
// 1. Simply add this script to the object you want a rope teathered to
// 3. Assign the other end of the rope as the "Target" object in this script
// 4. Play and enjoy!
// (About Character Joints)
// Sometimes your rope needs to be very limp and by that I mean NO SPRINGY EFFECT.
// In order to do this, you must loosen it up using the swingAxis and twist limits.
// For example, On my joints in my drawing app, I set the swingAxis to (0,0,1) sense
// the only axis I want to swing is the Z axis (facing the camera) and the other settings to around -100 or 100.
var target : Transform;
var material : Material;
var ropeWidth = 0.5;
var resolution = 0.5;
var ropeDrag = 0.1;
var ropeMass = 0.5;
var radialSegments = 6;
var startRestrained = true;
var endRestrained = false;
var useMeshCollision = false;
// Private Variables (Only change if you know what your doing)
private var segmentPos : Vector3[];
private var joints : GameObject[];
private var tubeRenderer : GameObject;
private var line : TubeRenderer;
private var segments = 4;
private var rope = false;
//Joint Settings
var swingAxis = Vector3(0,1,0);
var lowTwistLimit = 0.0;
var highTwistLimit = 0.0;
var swing1Limit	= 20.0;
// Require a Rigidbody
@script RequireComponent(Rigidbody)
 
function OnDrawGizmos() {
	if(target) {
		Gizmos.color = Color.yellow;
		Gizmos.DrawLine (transform.position, target.position);
		Gizmos.DrawWireSphere ((transform.position+target.position)/2,ropeWidth);
		Gizmos.color = Color.green;
		Gizmos.DrawWireSphere (transform.position, ropeWidth);
		Gizmos.color = Color.red;
		Gizmos.DrawWireSphere (target.position, ropeWidth);
	} else {
		Gizmos.color = Color.green;
		Gizmos.DrawWireSphere (transform.position, ropeWidth);	
	}
}
 
function Awake()
{
	if(target) {
		 BuildRope();
	} else {
		Debug.LogError("You must have a gameobject attached to target: " + this.name,this);	
	}
}
 
function LateUpdate()
{
	if(target) {
		// Does rope exist? If so, update its position
		if(rope) {
		 line.SetPoints(segmentPos, ropeWidth, Color.white);
		 line.enabled = true;
			segmentPos[0] = transform.position;
			for(var s:int=1;s<segments;s++)
			{
			 segmentPos[s] = joints[s].transform.position;
			}
		}
	}
}
 
function BuildRope()
{
	tubeRenderer = new GameObject("TubeRenderer_" + gameObject.name);
	line = tubeRenderer.AddComponent(TubeRenderer);
	line.useMeshCollision = useMeshCollision;
	// Find the amount of segments based on the distance and resolution
	// Example: [resolution of 1.0 = 1 joint per unit of distance]
	segments = Vector3.Distance(transform.position,target.position)*resolution;
	if(material) {
		 material.SetTextureScale("_MainTex",Vector2(1,segments+2));
		 if(material.GetTexture("_BumpMap"))
			material.SetTextureScale("_BumpMap",Vector2(1,segments+2));
	}
	line.vertices = new TubeVertex[segments];
	line.crossSegments = radialSegments;
	line.material = material;
	segmentPos = new Vector3[segments];
	joints = new GameObject[segments];
	segmentPos[0] = transform.position;
	segmentPos[segments-1] = target.position;
	// Find the distance between each segment
	var segs = segments-1;
	var seperation = ((target.position - transform.position)/segs);
	for(var s:int=0;s < segments;s++)
	{
		// Find the each segments position using the slope from above
		var vector : Vector3 = (seperation*s) + transform.position;	
		segmentPos[s] = vector;
		//Add Physics to the segments
		AddJointPhysics(s);
	}
	// Attach the joints to the target object and parent it to this object
	var end : CharacterJoint = target.gameObject.AddComponent("CharacterJoint");
	end.connectedBody = joints[joints.length-1].transform.rigidbody;
	end.swingAxis = swingAxis;
	end.lowTwistLimit.limit = lowTwistLimit;
	end.highTwistLimit.limit = highTwistLimit;
	end.swing1Limit.limit	= swing1Limit;
	target.parent = transform;
	if(endRestrained)
	{
		end.rigidbody.isKinematic = true;
	}
	if(startRestrained)
	{
		transform.rigidbody.isKinematic = true;
	}
	// Rope = true, The rope now exists in the scene!
	rope = true;
}
 
function AddJointPhysics(n : int)
{
	joints[n] = new GameObject("Joint_" + n);
	joints[n].transform.parent = transform;
	var rigid : Rigidbody = joints[n].AddComponent("Rigidbody");
	if(!useMeshCollision) {
		 var col : SphereCollider = joints[n].AddComponent("SphereCollider");
		 col.radius = ropeWidth;
	}
	var ph : CharacterJoint = joints[n].AddComponent("CharacterJoint");
	ph.swingAxis = swingAxis;
	ph.lowTwistLimit.limit = lowTwistLimit;
	ph.highTwistLimit.limit = highTwistLimit;
	ph.swing1Limit.limit	= swing1Limit;
	//ph.breakForce = ropeBreakForce; <--------------- TODO
	joints[n].transform.position = segmentPos[n];
	rigid.drag = ropeDrag;
	rigid.mass = ropeMass;
	if(n==0){			ph.connectedBody = transform.rigidbody;
	} else
	{
		ph.connectedBody = joints[n-1].rigidbody;	
	}
}

[edit] MODIFIED TubeRenderer.js

//TubeRenderer.js
 
//This script is created by Ray Nothnagel of Last Bastion Games. It is
//free for use and available on the Unify Wiki.
 
//For other components I've created, see:
//http://lastbastiongames.com/middleware/
 
//(C) 2008 Last Bastion Games
 
//--------------------------------------------------------------
 
//EDIT: MODIFIED BY JACOB FLETCHER FOR USE WITH THE ROPE SCRIPT
//http://www.reverieinteractive.com
 
 
class TubeVertex {
	var point : Vector3 = Vector3.zero;
	var radius : float = 1.0;
	var color : Color = Color.white;
 
	function TubeVertex(pt : Vector3, r : float, c : Color) {
		point=pt;
		radius=r;
		color=c;
	}
}
 
var vertices : TubeVertex[];
var material : Material;
var crossSegments : int = 3;
var flatAtDistance : float=-1;
var movePixelsForRebuild = 6;
var maxRebuildTime = 0.1;
var useMeshCollision = false;
 
private var lastCameraPosition1 : Vector3;
private var lastCameraPosition2 : Vector3;
private var crossPoints : Vector3[];
private var lastCrossSegments : int;
private var lastRebuildTime = 0.00;
private var mesh : Mesh;
private var colliderExists = false;
private var usingBumpmap = false;
 
function Reset() {
	vertices = [TubeVertex(Vector3.zero, 1.0, Color.white), TubeVertex(Vector3(1,0,0), 1.0, Color.white)];
}
 
function Start() {
	Reset();
	mesh = new Mesh();
	gameObject.AddComponent(MeshFilter);
	var mr : MeshRenderer = gameObject.AddComponent(MeshRenderer);
	mr.material = material;
	if(material) {
			if(material.GetTexture("_BumpMap")) usingBumpmap = true;
	}
}
 
function LateUpdate () {
	if (!vertices || vertices.length <= 1) {
		renderer.enabled=false;
		return;
	}
 
	renderer.enabled=true;
	if (crossSegments != lastCrossSegments) {
		crossPoints = new Vector3[crossSegments];
		var theta : float = 2.0*Mathf.PI/crossSegments;
		for (var c:int=0;c<crossSegments;c++) {
			crossPoints[c] = Vector3(Mathf.Cos(theta*c), Mathf.Sin(theta*c), 0);
		}
		lastCrossSegments = crossSegments;
	}
 
	var meshVertices : Vector3[] = new Vector3[vertices.length*crossSegments];
	var uvs : Vector2[] = new Vector2[vertices.length*crossSegments];
	var colors : Color[] = new Color[vertices.length*crossSegments];
	var tris : int[] = new int[vertices.length*crossSegments*6];
	var lastVertices : int[] = new int[crossSegments];
	var theseVertices : int[] = new int[crossSegments];
	var rotation : Quaternion;
 
	for (var p:int=0;p<vertices.length;p++) {
		if(p<vertices.length-1)
			rotation = Quaternion.FromToRotation(Vector3.forward,vertices[p+1].point-vertices[p].point);
 
		for (c=0;c<crossSegments;c++) {
			var vertexIndex : int = p*crossSegments+c;
			meshVertices[vertexIndex] = vertices[p].point + rotation * crossPoints[c] * vertices[p].radius;
			uvs[vertexIndex] = Vector2((0.0+c)/crossSegments,(0.0+p)/vertices.length);
			colors[vertexIndex] = vertices[p].color;
 
			lastVertices[c]=theseVertices[c];
			theseVertices[c] = p*crossSegments+c;
		}
 
		//make triangles
		if (p>0) {
			for (c=0;c<crossSegments;c++) {
				var start : int= (p*crossSegments+c)*6;
				tris[start] = lastVertices[c];
				tris[start+1] = lastVertices[(c+1)%crossSegments];
				tris[start+2] = theseVertices[c];
				tris[start+3] = tris[start+2];
				tris[start+4] = tris[start+1];
				tris[start+5] = theseVertices[(c+1)%crossSegments];
			}
		}
	}
 
	 //Clear mesh for new build  (jf)	
	mesh.Clear();
	mesh.vertices = meshVertices;
	mesh.triangles = tris;
	mesh.RecalculateNormals();
	if(usingBumpmap)
		mesh.tangents = CalculateTangents(meshVertices);
	mesh.uv = uvs;
 
	if(useMeshCollision)
		if(colliderExists) {
			gameObject.GetComponent(MeshCollider).sharedMesh = mesh;
		} else {
			gameObject.AddComponent(MeshCollider);
			colliderExists = true;
		}
	GetComponent(MeshFilter).mesh = mesh;
}
 
 
 
function CalculateTangents(verts : Vector3[])
{
	var tangents : Vector4[] = new Vector4[verts.length];
 
	for(var i:int=0;i<tangents.length;i++)
	{
		var vertex1 = i > 0 ? verts[i-1] : verts[i];
		  var vertex2 = i < tangents.length - 1 ? verts[i+1] : verts[i];
		  var tan = (vertex1 - vertex2).normalized;
		  tangents[i] = Vector4( tan.x, tan.y, tan.z, 1.0 );
	}
	return tangents;	
}
 
 
 
//sets all the points to points of a Vector3 array, as well as capping the ends.
function SetPoints(points : Vector3[], radius : float, col : Color) {
	if (points.length < 2) return;
		vertices = new TubeVertex[points.length+2];
 
		var v0offset : Vector3 = (points[0]-points[1])*0.01;
		vertices[0] = TubeVertex(v0offset+points[0], 0.0, col);
		var v1offset : Vector3 = (points[points.length-1] - points[points.length-2])*0.01;
		vertices[vertices.length-1] = TubeVertex(v1offset+points[points.length-1], 0.0, col);
 
	for (var p:int=0;p<points.length;p++) {
		vertices[p+1] = TubeVertex(points[p], radius, col);
	}
}
Personal tools
Namespaces

Variants
Actions
Navigation
Extras
Toolbox