Advertisement
Guest User

ball road

a guest
Nov 5th, 2012
290
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 5 11.57 KB | None | 0 0
  1. <!DOCTYPE HTML>
  2. <html>
  3.   <head>
  4.     <style>
  5.       body {
  6.         margin: 0px;
  7.         padding: 0px;
  8.       }
  9.       canvas {
  10.         border: 1px solid #9C9898;
  11.       }
  12.     </style>
  13.     <script src="http://www.html5canvastutorials.com/libraries/kinetic-v4.0.0.js"></script>
  14.     <script>
  15.       /*
  16.        * Vector math functions
  17.        */
  18.       function dot(a, b) {
  19.         return ((a.x * b.x) + (a.y * b.y));
  20.       }
  21.       function magnitude(a) {
  22.         return Math.sqrt((a.x * a.x) + (a.y * a.y));
  23.       }
  24.       function normalize(a) {
  25.         var mag = magnitude(a);
  26.  
  27.         if(mag == 0) {
  28.           return {
  29.             x: 0,
  30.             y: 0
  31.           };
  32.         }
  33.         else {
  34.           return {
  35.             x: a.x / mag,
  36.             y: a.y / mag
  37.           };
  38.         }
  39.       }
  40.       function add(a, b) {
  41.         return {
  42.           x: a.x + b.x,
  43.           y: a.y + b.y
  44.         };
  45.       }
  46.       function angleBetween(a, b) {
  47.         return Math.acos(dot(a, b) / (magnitude(a) * magnitude(b)));
  48.       }
  49.       function rotate(a, angle) {
  50.         var ca = Math.cos(angle);
  51.         var sa = Math.sin(angle);
  52.         var rx = a.x * ca - a.y * sa;
  53.         var ry = a.x * sa + a.y * ca;
  54.         return {
  55.           x: rx * -1,
  56.           y: ry * -1
  57.         };
  58.       }
  59.       function invert(a) {
  60.         return {
  61.           x: a.x * -1,
  62.           y: a.y * -1
  63.         };
  64.       }
  65.       /*
  66.        * this cross product function has been simplified by
  67.        * setting x and y to zero because vectors a and b
  68.        * lie in the canvas plane
  69.        */
  70.       function cross(a, b) {
  71.         return {
  72.           x: 0,
  73.           y: 0,
  74.           z: (a.x * b.y) - (b.x * a.y)
  75.         };
  76.       }
  77.       function getNormal(curve, ball, frame) {
  78.         var curveLayer = curve.getLayer();
  79.         var context = curveLayer.getContext();
  80.         var testRadius = 20;
  81.         // pixels
  82.         var totalX = 0;
  83.         var totalY = 0;
  84.         var x = ball.getX();
  85.         var y = ball.getY();
  86.         /*
  87.          * check various points around the center point
  88.          * to determine the normal vector
  89.          */
  90.         for(var n = 0; n < 20; n++) {
  91.          var angle = n * 2 * Math.PI / 20;
  92.          var offsetX = testRadius * Math.cos(angle);
  93.          var offsetY = testRadius * Math.sin(angle);
  94.          var testX = x + offsetX;
  95.          var testY = y + offsetY;
  96.          if(!context.isPointInPath(testX, testY)) {
  97.            totalX += offsetX;
  98.            totalY += offsetY;
  99.          }
  100.        }
  101.  
  102.        var normal;
  103.  
  104.        if(totalX === 0 && totalY === 0) {
  105.          normal = {
  106.            x: 0,
  107.            y: -1
  108.          };
  109.        }
  110.        else {
  111.          normal = {
  112.            x: totalX,
  113.            y: totalY
  114.          };
  115.        }
  116.  
  117.        return normalize(normal);
  118.      }
  119.      function handleCurveCollision(ball, curve) {
  120.        var curveLayer = curve.getLayer();
  121.        var curveContext = curveLayer.getContext();
  122.        var x = ball.getX();
  123.        var y = ball.getY();
  124.        var radius = ball.getRadius();
  125.  
  126.        var curveDamper = 0.01;
  127.        // 5% energy loss
  128.        //if(curveContext.isPointInPath(x, y)) {
  129.        if(curveContext.isPointInPath(x, y)) {
  130.  
  131.          console.log('is');
  132.          console.log(curve);
  133.          var normal = getNormal(curve, ball);
  134.          if(normal !== null) {
  135.  
  136.            console.log('normal');
  137.            console.log(normal.x + ' ' + normal.y);
  138.            var angleToNormal = angleBetween(normal, invert(ball.velocity));
  139.            var crossProduct = cross(normal, ball.velocity);
  140.            var polarity = crossProduct.z > 0 ? 1 : -1;
  141.             var collisonAngle = polarity * angleToNormal * 2;
  142.             var collisionVector = rotate(ball.velocity, collisonAngle);
  143.  
  144.             ball.velocity.x = collisionVector.x;
  145.             ball.velocity.y = collisionVector.y;
  146.             //ball.velocity.y = -0.5;
  147.             ball.velocity.x *= (1 - curveDamper);
  148.             ball.velocity.y *= (1 - curveDamper);
  149.  
  150.             //bubble ball up to the surface of the curve
  151.            
  152.             /*
  153.             while(curveContext.isPointInPath(x, y)) {
  154.               x += normal.x;
  155.  
  156.               if(ball.velocity.y > 0.1) {
  157.                 y += normal.y;
  158.               }
  159.               else {
  160.                 // nudge ball even less to prevent
  161.                 // bouncing at rest
  162.                 y += normal.y / 10;
  163.               }
  164.             }
  165.             */
  166.             while(curveContext.isPointInPath(x, y)) {
  167.               x += normal.x / 100;
  168.  
  169.               if(ball.velocity.y > 0.1) {
  170.                 y += normal.y / 100;
  171.               }
  172.               else {
  173.                 // nudge ball even less to prevent
  174.                 // bouncing at rest
  175.                 y += normal.y / 100;
  176.               }
  177.             }
  178.  
  179.            
  180.             //console.log(curveContext);
  181.             /*
  182.             while(!curveContext.isPointInPath(x, y)) {
  183.  
  184.               console.log('te');
  185.  
  186.                x += normal.x;
  187.  
  188.               if(ball.velocity.y > 0.1) {
  189.                 y += normal.y;
  190.               }
  191.               else {
  192.                 // nudge ball even less to prevent
  193.                 // bouncing at rest
  194.                 y += normal.y / 10;
  195.               }
  196.             }*/
  197.  
  198.             ball.setPosition(x, y);
  199.           }
  200.         }
  201.       }
  202.       function updateBall(ball, curve, frame) {
  203.         var timeDiff = frame.timeDiff;
  204.         var ballLayer = ball.getLayer();
  205.         var stage = ball.getStage();
  206.         var height = stage.getHeight();
  207.         var width = stage.getWidth();
  208.         var x = ball.getX();
  209.         var y = ball.getY();
  210.         var radius = ball.getRadius().x;
  211.  
  212.         // physics variables
  213.         var gravity = 0.8;
  214.         // px / second^2
  215.         var speedIncrementFromGravityEachFrame = gravity * timeDiff / 1000;
  216.         var collisionDamper = 0.2;
  217.         // 20% energy loss
  218.         var floorFriction = 1;
  219.         // px / second^2
  220.         var floorFrictionSpeedReduction = floorFriction * timeDiff / 1000;
  221.  
  222.         // if ball is being dragged and dropped
  223.         if(ball.isDragging()) {
  224.           var mousePos = stage.getMousePosition();
  225.  
  226.           if(mousePos !== null) {
  227.             var mouseX = mousePos.x;
  228.             var mouseY = mousePos.y;
  229.  
  230.             var c = 0.06 * timeDiff;
  231.             ball.velocity = {
  232.               x: c * (mouseX - ball.lastMouseX),
  233.               y: c * (mouseY - ball.lastMouseY)
  234.             };
  235.  
  236.             ball.lastMouseX = mouseX;
  237.             ball.lastMouseY = mouseY;
  238.           }
  239.         }
  240.         else {
  241.           // gravity
  242.           ball.velocity.y += speedIncrementFromGravityEachFrame;
  243.           x += ball.velocity.x;
  244.           y += ball.velocity.y;
  245.  
  246.           // ceiling condition
  247.           if(y < radius) {
  248.            y = radius;
  249.            ball.velocity.y *= -1;
  250.            ball.velocity.y *= (1 - collisionDamper);
  251.          }
  252.  
  253.          // floor condition
  254.          if(y > (height - radius)) {
  255.             y = height - radius;
  256.             ball.velocity.y *= -1;
  257.             ball.velocity.y *= (1 - collisionDamper);
  258.           }
  259.  
  260.           // floor friction
  261.           if(y == height - radius) {
  262.             if(ball.velocity.x > 0.1) {
  263.               ball.velocity.y -= floorFrictionSpeedReduction;
  264.             }
  265.             else if(ball.velocity.x < -0.1) {
  266.              ball.velocity.x += floorFrictionSpeedReduction;
  267.            }
  268.            else {
  269.              ball.velocity.x = 0;
  270.            }
  271.          }
  272.  
  273.          // right wall condition
  274.          if(x > (width - radius)) {
  275.             x = width - radius;
  276.             ball.velocity.x *= -1;
  277.             ball.velocity.x *= (1 - collisionDamper);
  278.           }
  279.  
  280.           // left wall condition
  281.           if(x < radius) {
  282.            x = radius;
  283.            ball.velocity.x *= -1;
  284.            ball.velocity.x *= (1 - collisionDamper);
  285.          }
  286.  
  287.          ball.setPosition(x, y);
  288.  
  289.          /*
  290.           * if the ball comes into contact with the
  291.           * curve, then bounce it in the direction of the
  292.           * curve's surface normal
  293.           */
  294.          handleCurveCollision(ball, curve);
  295.        }
  296.      }
  297.      window.onload = function() {
  298.        var stage = new Kinetic.Stage({
  299.          container: "container",
  300.          width: 578,
  301.          height: 400
  302.        });
  303.        var curveLayer = new Kinetic.Layer();
  304.        var ballLayer = new Kinetic.Layer();
  305.        var radius = 10;
  306.        var anim;
  307.        
  308.        var curve = new Kinetic.Line({  //578*400 (x * y)
  309.          points: [153, 200, 340, 250, //down
  310.                  340, 270,   //short to bottom
  311.                  153, 290,  //back to left
  312.                  153, 320,  //short to bottom
  313.                  390, 290,     //to the right long
  314.                  390, 220,        //up short
  315.                  153, 140,  //long to the left
  316.                  153, 200   //short to bottom
  317.                  ],
  318.          stroke: "red",
  319.          strokeWidth: 5,
  320.          lineCap: "round",
  321.          lineJoin: "round"
  322.        });
  323.        
  324.        /*
  325.         var curve = new Kinetic.Shape({
  326.          drawFunc: function(context) {
  327.            var height = stage.getHeight();
  328.            var width = stage.getWidth();
  329.            context.beginPath();
  330.            ctx = context;
  331.             ctx.moveTo(153,200);
  332.            ctx.lineTo(340,250);
  333.            ctx.lineTo(340, 270);
  334.            /*ctx.lineTo(153, 290);
  335.            ctx.lineTo(153, 320);
  336.           // ctx.fill();
  337.            //context.lineTo(40, height);
  338.            
  339.            context.closePath();
  340.            this.fill(context);
  341.            
  342.          },
  343.          fill: "#8dbdff"
  344.        });
  345.  */
  346.        curveLayer.add(curve);
  347.        /*
  348.        var curve = new Kinetic.Circle({
  349.          x: stage.getWidth() / 2,
  350.          y: stage.getHeight() / 2,
  351.          radius: 70,
  352.          fill: 'grey',
  353.          stroke: 'black',
  354.          strokeWidth: 4,
  355.          opacity: 0.5
  356.        });
  357.        curveLayer.add(curve);
  358.  */
  359.        // create ball
  360.        var ball = new Kinetic.Circle({
  361.          x: 200,
  362.          y: 20,
  363.          radius: radius,
  364.          //fill: "blue",
  365.          fill: {
  366.            start: {
  367.              x: -50,
  368.              y: -50
  369.            },
  370.            end: {
  371.              x: 50,
  372.              y: 50
  373.            },
  374.            colorStops: [0, 'red', 1, 'yellow']
  375.          },
  376.          draggable: true,
  377.          opacity: 0.8,
  378.          stroke: "black",
  379.          strokeWidth: 3
  380.        });
  381.        // custom property
  382.        ball.velocity = {
  383.          x: 0,
  384.          y: 0
  385.        };
  386.        ball.on("dragstart", function() {
  387.          ball.velocity = {
  388.            x: 0,
  389.            y: 0
  390.          };
  391.          anim.start();
  392.        });
  393.        
  394.        ball.on("mousedown", function() {
  395.          anim.stop();
  396.        });
  397.        ball.on("mouseover", function() {
  398.          document.body.style.cursor = "pointer";
  399.        });
  400.        ball.on("mouseout", function() {
  401.          document.body.style.cursor = "default";
  402.        });
  403.        ballLayer.add(ball);
  404.        stage.add(curveLayer);
  405.        stage.add(ballLayer);
  406.        anim = new Kinetic.Animation({
  407.          func: function(frame) {
  408.            updateBall(ball, curve, frame)
  409.          },
  410.          node: ballLayer
  411.        });
  412.        anim.start();
  413.      };
  414.    </script>
  415.   </head>
  416.   <body onmousedown="return false;">
  417.     <div id="container"></div>
  418.   </body>
  419. </html>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement