License text

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER 
 * Copyright  2008, 2010 Oracle and/or its affiliates.  All rights reserved. 
 * Use is subject to license terms.
 * 
 * This file is available and licensed under the following license:
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met: 
 * 
 *   * Redistributions of source code must retain the above copyright notice, 
 *     this list of conditions and the following disclaimer. 
 *
 *   * Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the documentation
 *     and/or other materials provided with the distribution.
 *
 *   * Neither the name of Oracle Corporation nor the names of its contributors 
 *     may be used to endorse or promote products derived from this software 
 *     without specific prior written permission. 
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */

    

import javafx.scene.Cursor;
import javafx.scene.CustomNode;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Circle;

public class Ball extends CustomNode {
  public-init var sign: Boolean;
  public-init var radius: Number;
  var vx: Number;
  var vy: Number;
  var event: MouseEvent on replace old {
    if (event != null) {
      vx = event.dragX - old.dragX;
      vy = event.dragY - old.dragY;
      translateX += vx;
      translateY += vy;
    }
  }
  override function create() {
    def color = if (sign)  then Color.RED  else Color.BLUE;
    Circle {
      radius: radius - 1
      stroke: color
      fill: RadialGradient {
        radius: radius
        focusX: radius * 0.8
        focusY: radius * -0.8
        proportional: false
        stops: [
          Stop {
	  	offset: 0   
		color: Color.WHITE
	  }
          Stop {
	  	offset: 1   
		color: color
	  }
        ]
      }
      cursor: Cursor.HAND
      onMouseDragged: function(event) {
        this.event = event;
      }
      onMouseReleased: function(event) {
        this.event = null;
      }
    }
  }
  public function update() {
    if (event == null) {
      translateX += (vx *= 0.9);
      translateY += (vy *= 0.9);
      if (translateX < radius) { 
      	  vx = -vx;
	  translateX = radius + radius - translateX 
      }
      if (translateY < radius) { 
          vy = -vy;
	  translateY = radius + radius - translateY 
      }
      var w = scene.width  - radius;
      var h = scene.height - radius;
      if (translateX > w) { 
      	  vx = -vx;
	  translateX = w + w - translateX 
      }
      if (translateY > h) { 
      	  vy = -vy;
	  translateY = h + h - translateY 
      }
    }
  }
  public function process(ball: Ball) {
    var d  = ball.radius + radius;
    var dx = ball.translateX - translateX;
    var dy = ball.translateY - translateY;
    var dd = (dx * dx) + (dy * dy);
    var collision = dd <= (d * d);
    // process collision
    if (collision) {
      var dvx = ball.vx - vx;
      var dvy = ball.vy - vy;

      var mag = dvx * dx + dvy * dy;
      if (mag <= 0) {
        mag /= dd;
      
        var delta_vx = dx * mag;
        var delta_vy = dy * mag;

        ball.vx -= delta_vx * radius / d;
        ball.vy -= delta_vy * radius / d;

        vx += delta_vx * ball.radius / d;
        vy += delta_vy * ball.radius / d;
      }
    }
    // process gravity
    if (dd > 0) {
      var f = 0.05 * ball.radius * radius / dd;

      var delta_vx = dx * f;
      var delta_vy = dy * f;
      if (collision or (ball.sign == sign)) {
        delta_vx = -delta_vx;
        delta_vy = -delta_vy;
      }

      ball.vx -= delta_vx * radius / d;
      ball.vy -= delta_vy * radius / d;

      vx += delta_vx * ball.radius / d;
      vy += delta_vy * ball.radius / d;
    }
  }
}