/* built with Studio Sketchpad:
* https://sketchpad.cc
*
* observe the evolution of this sketch:
* https://p5js.sketchpad.cc/sp/pad/view/ro.GrwKUsycNrY/rev.13
*
* authors:
* GoToLoop
* license (unless otherwise specified):
* creative commons attribution-share alike 3.0 license.
* https://creativecommons.org/licenses/by-sa/3.0/
*/
/**
* Hoppy Beaver (v2.04)
* Author: Pamela (2014/Feb)
* Processing: GoToLoop (2016/Apr/08)
*
* forum.Processing.org/two/discussion/8997/hoppy-beaver
*
* www.KhanAcademy.org/computing/computer-programming/
* programming-games-visualizations/side-scroller/p/project-hoppy-beaver-extreme
*
* p5js.ProcessingTogether.com/sp/pad/export/ro.Cp2G$x5ApiPI5r
* studio.ProcessingTogether.com/sp/pad/export/ro.9bTfM49wCIJza
*/
"use strict"
const KHAN = 'http:/' + '/www.KaSandbox.org/third_party/'
+ 'javascript-khansrc/live-editor/build/images/'
const REMOTE = true
//const REMOTE = false
const PATH = REMOTE && KHAN || ''
const STICKS = 200, TURFS = 30, FPS = 60, WEIGHT = 2.5
const sticks = Array(STICKS), turfs = Array(TURFS)
let beaver, score, bg, soil, win, lose
function preload() {
Beaver.falling = loadImage(PATH + 'creatures/Hopper-Happy.png')
Beaver.jumping = loadImage(PATH + 'creatures/Hopper-Jumping.png')
Grass.lawn = loadImage(PATH + 'cute/GrassBlock.png')
}
function setup() {
createCanvas(500, 400)
frameRate(FPS).strokeWeight(WEIGHT).rectMode(CORNER).imageMode(CORNER)
textSize(Score.SIZE).textAlign(CENTER, CENTER)
Beaver.falling.resize(Beaver.SIZE, Beaver.SIZE)
Beaver.jumping.resize(Beaver.SIZE, Beaver.SIZE)
Grass.lawn.resize(Grass.SIZE, Grass.SIZE)
beaver = new Beaver(width>>1, height - Beaver.GROUND)
Stick.counter = score = new Score(80, 20)
for (let y = round(height*.85), i = 0; i !== TURFS; ++i)
turfs[i] = new Grass(i*Grass.GAP, y)
Object.freeze(turfs)
for (let y = round(height*.65), i = 0; i !== STICKS; ++i)
sticks[i] = new Stick(i*Stick.GAP + width, round(random(20, y)))
Object.freeze(sticks)
bg = Object.freeze(color(0xE0, 0xFF, 0xFF))
soil = Object.freeze(color(0x80, 0x50, 0x2A))
win = Object.freeze(color('green'))
lose = Object.freeze(color('red'))
Stick.ink = Object.freeze(color(0x5A, 0x4A, 0))
Score.ink = Object.freeze(color('blue'))
Object.freeze(Object.freeze(Beaver).prototype)
Object.freeze(Object.freeze(Grass).prototype)
Object.freeze(Object.freeze(Stick).prototype)
Object.freeze(Object.freeze(Score).prototype)
}
function draw() {
background(bg).stroke(0).fill(soil).rect(0, height*.9, width, height*.1)
for (let i = 0; i !== TURFS; turfs[i++].script());
fill(Stick.ink)
for (let s, i = 0; i !== STICKS; beaver.gotStick(s = sticks[i++])
? (s.x = -Stick.W, ++score.collected, ++score.dead) : s.script());
keyIsPressed|mouseIsPressed && beaver.jump() || beaver.fall()
beaver.display()
noStroke().fill(Score.ink), score.display(STICKS)
if (score.dead === STICKS) {
const won = score.collected/STICKS >= Score.PERCENT
fill(won && win || lose)
text(won && 'YOU WIN!!!' || 'Collect More Next Time...', width>>1, height>>1)
}
}
class Beaver {
constructor(x, y) { this.x = x, this.y = y, this.isJumping = false }
static get SIZE() { return 40 }
static get GROUND() { return 50 } // Beaver.SIZE + 10
static get SPD() { return 5 }
display() {
image(this.isJumping && Beaver.jumping || Beaver.falling, this.x, this.y)
}
fall() {
this.y = min(this.y + Beaver.SPD, height - Beaver.GROUND)
return this.isJumping = false
}
jump() {
this.y = max(this.y - Beaver.SPD, 0)
return this.isJumping = true
}
gotStick(s) {
return this.x+Beaver.SIZE > s.x & this.x < s.x+Stick.W &
this.y+Beaver.SIZE > s.y & this.y < s.y+Stick.H
}
}
class Grass {
constructor(x, y) { this.x = x, this.y = y }
static get SIZE() { return 20 }
static get GAP() { return 20 }
static get SCROLL() { return 2 }
script() { this.update(), this.display() }
update() { (this.x -= Grass.SCROLL) < -Grass.SIZE && (this.x = width) }
display() { image(Grass.lawn, this.x, this.y) }
}
class Stick {
constructor(x, y) { this.x = x, this.y = y }
static get W() { return 10 }
static get H() { return 50 }
static get GAP() { return 40 }
static get SCROLL() { return 2 }
script() {
if (this.x > -Stick.W) this.update() <= -Stick.W?
++Stick.counter.dead : this.x < width && this.display()
}
update() { return this.x -= Stick.SCROLL }
display() { rect(this.x, this.y, Stick.W, Stick.H) }
}
class Score {
constructor(x, y) { this.x = x, this.y = y, this.collected = this.dead = 0 }
static get SIZE() { return 18 }
static get PERCENT() { return .9 }
display(total) {
text('Score: ' + nf(this.collected, 3) + '/' + total, this.x, this.y)
}
}