> show canvas only <


/* built with Studio Sketchpad: 
 *   https://sketchpad.cc
 * 
 * observe the evolution of this sketch: 
 *   https://studio.sketchpad.cc/sp/pad/view/ro.atO1lQhCj7U/rev.21
 * 
 * authors: 
 *   GoToLoop

 * license (unless otherwise specified): 
 *   creative commons attribution-share alike 3.0 license.
 *   https://creativecommons.org/licenses/by-sa/3.0/ 
 */ 



/**
 * Hoppy Beaver (v1.0)
 * Author: Pamela (2014/Feb)
 * Processing: GoToLoop (2015/Jan)
 *
 * www.KhanAcademy.org/computing/computer-programming/
 * programming-games-visualizations/side-scroller/a/scoring-and-winning
 *
 * studio.processingtogether.com/sp/pad/export/ro.9bTfM49wCIJza/latest
 */

/* @pjs pauseOnBlur = true;
        preload = "/static/uploaded_resources/p.6273/Hopper-Happy.png,
                   /static/uploaded_resources/p.6273/Hopper-Jumping.png,
                   /static/uploaded_resources/p.6273/GrassBlock.png";
 */

/* @pjs pauseOnBlur = true;
        preload = "creatures/Hopper-Happy.png,
                   creatures/Hopper-Jumping.png,
                   cute/GrassBlock.png";
 */

static final String KHAN = "https://" + "www.kasandbox.org/third_party/"
  + "javascript-khansrc/live-editor/build/images/";

static final String SKETCHPAD = "/static/uploaded_resources/p.6273/";

static final boolean REMOTE = true;
//static final boolean REMOTE = false;

static final color BG = #E0FFFF, SOIL = #80502A;
static final short SMOOTH = 4, FPS = 60, SCROLL = 2;
static final short STICKS = 200, TURFS = 30;

Stick[] sticks = new Stick[STICKS];
Grass[] turfs  = new Grass[TURFS];

Beaver beaver;
Score score;

void setup() {
  size(500, 400, JAVA2D);
  smooth(SMOOTH);
  frameRate(FPS);
  noStroke();

  textSize(Score.SIZE);
  textAlign(CENTER, CENTER);

  rectMode(CORNER);
  imageMode(CORNER);

  String path = REMOTE? SKETCHPAD : "";
  //String path = REMOTE? KHAN : "";

  (Beaver.falling = loadImage(path + "Hopper-Happy.png"))
  //(Beaver.falling = loadImage(path + "creatures/Hopper-Happy.png"))
    .resize(Beaver.SIZE, Beaver.SIZE);
  (Beaver.jumping = loadImage(path + "Hopper-Jumping.png"))
  //(Beaver.jumping = loadImage(path + "creatures/Hopper-Jumping.png"))
    .resize(Beaver.SIZE, Beaver.SIZE);
  (Grass.lawn = loadImage(path + "GrassBlock.png"))
  //(Grass.lawn = loadImage(path + "cute/GrassBlock.png"))
    .resize(Grass.SIZE, Grass.SIZE);

  beaver = new Beaver(width>>1, height - Beaver.GROUND);
  Stick.counter = score = new Score(80, 20);

  for (int y = round(height*.85), i = 0; i != TURFS; ++i)
    turfs[i] = new Grass(i*Grass.GAP, y);

  for (int y = round(height*.65), i = 0; i != STICKS; ++i)
    sticks[i] = new Stick(i*Stick.GAP + width, (int) random(20, y));
}

void draw() {
  background(BG);

  fill(SOIL);
  rect(0, height*.9, width, height*.1);

  for (Grass t : turfs)  t.script();

  fill(Stick.INK);
  for (Stick s : sticks)
    if (beaver.gotStick(s))  s.x ^= ~++score.collected | ++score.dead;
    else s.script();

  keyCode = keyPressed | mousePressed? beaver.jump() : beaver.fall();
  beaver.display();

  fill(Score.INK);
  score.display();

  if (score.dead == STICKS) {
    boolean win = score.collected/(float)STICKS >= Score.PERCENT;
    fill(win? #008000 : #FF0000);
    text(win? "YOU WIN!!!" : "Collect More Next Time..."
      , width>>1, height>>1);
  }
}

static abstract class BeaverStatic {
  static final int SIZE = 40, GROUND = SIZE+10, SPD = 5;
  static PImage falling, jumping;
}

final class Beaver extends BeaverStatic {
  boolean isJumping;
  int x, y;

  Beaver(int xx, int yy) {
    x = xx;
    y = yy;
  }

  void display() {
    image(isJumping? jumping : falling, x, y);
  }

  int fall() {
    isJumping = false;
    return y = min(y + SPD, height - GROUND);
  }

  int jump() {
    isJumping = true;
    return y = max(y - SPD, 0);
  }

  boolean gotStick(Stick s) {
    return x+SIZE > s.x & x < s.x+Stick.W & y+SIZE > s.y & y < s.y+Stick.H;
  }
}

static abstract class GrassStatic {
  static final int SIZE = 20, GAP = 20;
  static PImage lawn;
}

final class Grass extends GrassStatic {
  short x, y;

  Grass(int xx, int yy) {
    x = (short) xx;
    y = (short) yy;
  }

  void script() {
    update();
    display();
  }

  void update() {
    if ((x -= SCROLL) < -SIZE)  x = (short) width;
  }

  void display() {
    image(lawn, x, y);
  }
}

static abstract class StickStatic {
  static final color INK = #5A4A00;
  static final short W = 10, H = 50, GAP = 40;
  static Score counter;
}

final class Stick extends StickStatic {
  short x, y;

  Stick(int xx, int yy) {
    x = (short) xx;
    y = (short) yy;
  }

  void script() {
    if (x < -W)  return;
    update();
    if (x < -W)  ++counter.dead;
    else if (x < width)  display();
  }

  void update() {
    x -= SCROLL;
  }

  void display() {
    rect(x, y, W, H);
  }
}

final class Score {
  static final color INK  = #0000FF;
  static final short SIZE = 18;
  static final float PERCENT = .9;

  short x, y;
  short collected = 0, dead = 0;

  Score(int xx, int yy) {
    x = (short) xx;
    y = (short) yy;
  }

  void display() {
    text("Score: " + nf(collected, 3) + "/" + STICKS, x, y);
  }
}