/** Interesting procedure creative(): bouncing ball which follows some rules of simple projectile 
 * motion. Includes gravity (which is set at 2 pixels per 100 square microseconds)
 and loss of kinetic energy upon collision (velocity decreases by a quarter).
 Air resistance is however not included. 
 Also, collisions are revised to make it look more realistic. 
 
 This assignment took around 6 hours*/

import java.awt.*;
/** Assignment A4: Bouncing balls */
class Ball extends YourTurtle {
    private int radius; //radius of ball
    private int vx; //velocity of ball in x direction
    private int vy; //velocity of ball in y direction
    
    /** Constructor: new turtle starting at (x, y) with speed (vx, vy)
     * and forms a ball of radius r of color c. */
    public Ball(int x, int y, int vx, int vy, int r, Color c) {
        moveTo(x, y, (int) getAngle());
        this.vx= vx;
        this.vy= vy;
        radius= r;
        setColor(c);
        fillCircle(2*r);
    }
    
    /** Constructor: new turtle starting at the midpoint of the panel, 
     * with speed (vx, vy) and forms a ball of radius r, of color c. */
    public Ball(int vx, int vy, int r) {
        moveTo(getWidth()/2, getHeight()/2, (int) getAngle());
        this.vx= vx;
        this.vy= vy;
        radius= r;
        setColor(Color.black);
        fillCircle(2*r);
    }
    
    /** = radius of balls */
    public int getRadius() {
        return radius;
    }
    
    /** = speed of ball in x direction */
    public int getVx() {
        return vx;
    }
    
    /** = speed of ball in y direction */
    public int getVy() {
        return vy;
    }
    
    /** moves the ball in (vx, vy) once
     * if ball hits a wall, it will bounce off and move in the opposite direction */
    public void moveBallOnce() {
        Color save= getColor();
        setColor(12);
        fillCircle(2*radius);
        moveTo(getX()+vx, getY()-vy, (int) getAngle());
        setColor(save);
        fillCircle(2*radius);
        if ((getY() < radius) || ((getHeight()-getY()) < radius)) {
            vy= -vy;
        }
        if ((getX() < radius) || ((getWidth()-getX()) < radius)) {
            vx= -vx;
        }
    }
    
    /** moves the ball in (vx, vy) in an infinite loop
     * if ball hits a wall, it will bounce off and move in the opposite direction
     * to stop the loop, click on Reset */
    public void inMotion() {
        int k= 0;
        // invariant: k is the number of times the ball has moved
        while (k == 0) {
            pause(100);
            moveBallOnce();
        }
    }
    
    /** Constructor: a window without anything in it */
    public Ball() {
        clear();
    }
    
    private int g= 2; // gravity = 2 pixels per 100 square microseconds;
    
    /** follows some of the laws of simple projectile motion.
     * Includes gravity (which is set at 2 pixels per 100 square microseconds)
     and loss of kinetic energy upon collision (velocity decreases by a quarter).
     Air resistance is however not included. 
     Also, collisions are revised to make it look more realistic. */
    public void creative() {
        int k= 0;
        while (10*vy != 1 && 10*vx != 1) {
            pause(100);
            Color save;
            if ((getY() < radius) || ((getHeight() - getY()) < radius) || (getX() < radius)
                    || ((getWidth() - getX()) < radius)) {
                save= getColor();
                setColor(12);
                fillCircle(2*radius);
                if (getY() < radius) {
                    moveTo(getX(), radius, (int) getAngle());
                    vy= -vy*3/4;
                    vx= vx*3/4;
                }
                if ((getHeight() - getY()) < radius) {
                    moveTo(getX(), getHeight() - radius, (int) getAngle());
                    vy= -vy*3/4;
                    vx= vx*3/4;
                }
                if (getX() < radius) {
                    moveTo(radius, getY(), (int) getAngle());
                    vx= -vx*3/4;
                    vy= vy*3/4;
                }
                if (((getWidth() - getX()) < radius)) {
                    moveTo(getWidth() - radius, getY(), (int) getAngle());
                    vx= -vx*3/4;
                    vy= vy*3/4;
                }
                setColor(save);
                fillCircle(2*radius);
            }
            save= getColor();
            setColor(12);
            fillCircle(2*radius);
            vy= vy-g;
            moveTo(getX()+vx, getY()-vy, (int) getAngle());
            setColor(save);
            fillCircle(2*radius);;
        }
    }
    
}