Created
November 30, 2012 13:30
A CodePen by Christian Östman. The Rope
This file contains hidden or 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
<html> | |
<head> | |
</head> | |
<body> | |
</body> | |
</html> |
This file contains hidden or 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
var GRAVITY = {x:0,y:10}; | |
var FRICTION = {x:0.94,y:0.91}; | |
var NUM_JOINTS = 12; | |
var DISTANCE = 1.2; | |
var WEIGHT = 6; | |
var target = {x:0,y:0} | |
//Arrays | |
var px = new Array(); | |
var py = new Array(); | |
var oldx = new Array(); | |
var oldy = new Array(); | |
var ax = new Array(); | |
var ay = new Array(); | |
// rendering | |
var paper; | |
var path; | |
var rect; | |
window.onmousemove = function(event) | |
{ | |
target.x = event.clientX; | |
target.y = event.clientY; | |
} | |
window.onload = function() | |
{ | |
createRope(); | |
// Creates canvas 320 × 200 at 10, 50 | |
paper = Raphael(0, 0, 800, 400); | |
var pathStr = "M10 10"; | |
path = paper.path(pathStr); | |
path.attr({stroke: "#000000", "stroke-width": 3, "stroke-linecap": "round"}), | |
setInterval(render,1000/60) | |
rect = paper.rect(5, 5, 40, 40, 3); | |
rect.attr({fill:"#7dcbdd"}); | |
} | |
function collideRope() | |
{ | |
for (var i = 0; i < NUM_JOINTS; i++) | |
{ | |
if(py[i] > 250) //set border limit | |
py[i] = 250; | |
} | |
} | |
function render() | |
{ | |
updateRope(); //handels with both the gravity and weight force | |
// collideRope(); //handels collisions with the ground | |
//attach first point to the mouse x and y position | |
px[0] = target.x; | |
py[0] = target.y; | |
var pathStr = "M" + target.x + " " + target.y; | |
for(var j = 0; j <=NUM_JOINTS; j++) | |
{ | |
pathStr += "L" + px[j]; | |
pathStr += " " + py[j]; | |
} | |
path.attr("path",pathStr); | |
} | |
function updateRope() | |
{ | |
// FORCE | |
for (var i = 1; i <= NUM_JOINTS; i++) { | |
py[i] += (GRAVITY.y * 1/36); | |
px[i] += (GRAVITY.x * 1/36); | |
} | |
// FRICTION | |
for (var i = 0; i <= NUM_JOINTS; i++) { | |
var previousx = px[i]; | |
var previousy = py[i]; | |
px[i] += (px[i] - oldx[i]) * FRICTION.x; | |
py[i] += (py[i] - oldy[i]) * FRICTION.y; | |
oldx[i] = previousx; //equal old to previous | |
oldy[i] = previousy; | |
} | |
py[NUM_JOINTS] += (WEIGHT * 1/36); | |
// TENSION | |
var jointDistance = DISTANCE / NUM_JOINTS; //calculate average distance between join | |
for (var i = 1; i <= NUM_JOINTS; i++) { | |
var dx = (px[i] - px[i - 1]) / 100; //calculate distance between each join and the previous | |
var dy = (py[i] - py[i - 1]) / 100; | |
var d = Math.sqrt((dx * dx) + (dy * dy));//pythagoras to determine the real distance | |
var force = d - jointDistance; //force equals current distance minus the distance it should be in a 'relaxed' state | |
ax[i] = (dx / d) * 0.5 * 100 * force; //calculate acceleration | |
ay[i] = (dy / d) * 0.5 * 100 * force; | |
px[i] -= ax[i]; //add acceleration to position | |
py[i] -= ay[i]; | |
px[i - 1] += ax[i]; //add opposite acceleration to the previous join | |
py[i - 1] += ay[i]; | |
} | |
var dx = px[NUM_JOINTS] - px[NUM_JOINTS-1]; //calculate angle | |
var dy = py[NUM_JOINTS] - py[NUM_JOINTS-1]; | |
rect.attr({x:px[NUM_JOINTS] - 25,y:py[NUM_JOINTS],transform:"r" +-(Math.atan2(dx,dy)*(180/Math.PI)) }) //position equals last join | |
} | |
function createRope() | |
{ | |
for (var i = 0; i <= NUM_JOINTS; i++) | |
{ | |
px[i] = 0; | |
py[i] = 0; | |
oldx[i] = 0; | |
oldy[i] = 0; | |
ax[i] = 0; | |
ay[i] = 0; | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment