from Processing import *

# Base class for all creatures
class Creature:
    # Construct the class
    def __init__(self, size):
        self.size = size
        self.x = random( width() )
        self.y = random( height() )

    # Move the creature
    def move(self):
        pass

    # Draw the creature
    def draw(self):
        ellipse(self.x, self.y, self.size, self.size)

    # Return the location of the creature as a dictionary
    def location(self):
        return {'x':self.x, 'y':self.y}

# Custom subclass of Creature
# Change class name to your username
class Mfrusso(Creature):

    def __init__(self, size):
        Creature.__init__(self, size)

        # Creature velocity and acceleration
        self.vx, self.vy = 1.0, 1.0
        self.ax, self.ay = 0.0, 0.0

        # Randomly generated target position
        self.resetTarget()

        # List to hold bubble locations
        self.bubbles = []

        # Lists for hair strand points
        self.hair1 = []
        self.hair2 = []
        self.hair3 = []
        for i in range(100):
            self.hair1.append( {'x':self.x - 0.1*self.size , 'y':self.y - 0.5*self.size } )
            self.hair2.append( {'x':self.x,                  'y':self.y - 0.5*self.size } )
            self.hair3.append( {'x':self.x + 0.1*self.size , 'y':self.y - 0.5*self.size } )

    def resetTarget(self):
        # Randomly change the fish target point
        self.targetx = random(self.size, width()-self.size)
        self.targety = random(self.size, height()-self.size)

    def move(self):
        # Accelerate creature toward random target position
        self.ax = 0.0001*(self.targetx-self.x);
        self.ay = 0.0001*(self.targety-self.y);

        # Change velocity to reflect acceleration
        self.vx += self.ax;
        self.vy += self.ay;

        # The creature can only swim so fast in any direction
        self.vx = constrain(self.vx, -0.5, 0.5);
        self.vy = constrain(self.vy, -0.5, 0.5);

        # Change position to reflect velocity
        self.x += self.vx;
        self.y += self.vy;

        # Update hair strands
        del self.hair1[0]
        del self.hair2[0]
        del self.hair3[0]
        self.hair1.append( {'x':self.x - 0.1*self.size , 'y':self.y - 0.5*self.size } )
        self.hair2.append( {'x':self.x,                  'y':self.y - 0.5*self.size } )
        self.hair3.append( {'x':self.x + 0.1*self.size , 'y':self.y - 0.5*self.size } )

        # Move bubbles
        i = len(self.bubbles) - 1
        while i >= 0:
            b = self.bubbles[i]
            if b['y'] < 0:              # Delete bubbles that are off sketch
                del self.bubbles[i]
            else:
                b['y'] -= 1.5
            i = i - 1

        # periodically add a new bubble
        if random(100) < 5:
            self.bubbles.append( {'x':self.x, 'y':self.y} )

        # If gets too close to the target, reset
        if dist(self.x, self.y, self.targetx, self.targety) < 100:
            self.resetTarget()

    def draw(self):
        x, y, s = self.x, self.y, self.size

        # Face
        stroke(127)
        fill(255,200,200)
        ellipse(x, y, s, s)

        # Eyes
        fill(255)
        stroke(0)
        ellipse(x-0.18*s, y-0.2*s, 0.3*s, 0.3*s)
        ellipse(x+0.18*s, y-0.2*s, 0.3*s, 0.3*s)
        fill(0)
        noStroke()
        ellipse(x-0.18*s, y-0.2*s, 0.1*s, 0.1*s)
        ellipse(x+0.18*s, y-0.2*s, 0.1*s, 0.1*s)

        # Cheeks
        fill(255,150,150)
        ellipse(x-0.2*s, y+0.15*s, 0.4*s, 0.4*s)
        ellipse(x+0.2*s, y+0.15*s, 0.4*s, 0.4*s)

        # Lips
        fill(255,0,0)
        ellipse(x, y+0.15*s, 0.2*s, 0.2*s)
        fill(32)
        ellipse(x, y+0.15*s, 0.05*s, 0.05*s)

        # Draw Hair
        stroke(0)
        for h in [ self.hair1, self.hair2, self.hair3 ]:
            for i in range(1, len(h)):
                line( h[i-1]['x'], h[i-1]['y'], h[i]['x'], h[i]['y'] )

        # Draw bubbles
        for p in self.bubbles:
            fill(255)
            stroke(127)
            ellipse(p['x'], p['y'], 10, 10)

creatures = []
creatures.append( Mfrusso(50) )
creatures.append( Mfrusso(75) )
creatures.append( Mfrusso(30) )

window(800, 600)

# Draw all creatures
backImage = loadImage("underwater.jpg")
def draw(o, e):
    # Draw the tank background
    image(backImage, 0, 0)

    # Draw and animate each of the objects
    for c in creatures:
        c.move()
        c.draw()

# Draw all
frameRate(30)
onLoop += draw
loop()
