class Player { Particle p; Particle peg; float radius, eyeRadius, speed, forceRadius; boolean up, right, down, left, suck, blow; // for keyboard control private boolean sucking, blowing, bounced; private int suckCnt, blowCnt; private int div = 800; // to weaken the blowing/sucking on enemies private Vector blowRings; private color c, g; Player () { p = phys.makeParticle(1, width/2, height/2, 0); peg = phys.makeParticle(1, width/2, height/2, 0); peg.makeFixed(); radius = playerSize; eyeRadius = radius*0.38f; forceRadius = radius*4; speed = playerSpeed; up = right = down = left = false; suckCnt = blowCnt = 0; blowRings = new Vector(5, 5); c = playerColor; g = playerGlow; } void keyMove() { if ( !(bounced && isMoving()) ) { bounced = false; float v = speed/mass(); if ( up ) { p.setVelocity(vx(), -v, 0); } if ( down ) { p.setVelocity(vx(), v, 0); } if ( left ) { p.setVelocity(-v, vy(), 0); } if ( right ) { p.setVelocity(v, vy(), 0); } } keepOnScreen(); peg.moveTo(x(), y(), 0); } void move(float x, float y) { if ( !(bounced && isMoving()) ) { bounced = false; p.setVelocity(x/mass(), y/mass(), 0); } keepOnScreen(); peg.moveTo(x(), y(), 0); } private void keepOnScreen() { if ( x() < radius ) { p.moveTo(radius, y(), 0); addVelocity(30/mass(), 0); } else if ( x() > width - radius ) { p.moveTo(width - radius, y(), 0); addVelocity(-30/mass(), 0); } if ( y() < radius ) { p.moveTo(x(), radius, 0); addVelocity(0, 30/mass()); } else if ( y() > height - radius ) { p.moveTo(x(), height - radius, 0); addVelocity(0, -30/mass()); } } void addVelocity(float x, float y) { p.addVelocity(x, y, 0); bounced = true; } void setMass(float m) { p.setMass(constrain(m, 1, 3)); } void reset() { p.moveTo(width/2, height/2, 0); peg.moveTo(width/2, height/2, 0); sucking = false; blowing = false; } void interact(Pulser puls) { float d = dist(x(), y(), puls.x(), puls.y()); if ( d > forceRadius + puls.radius() || puls.isCaught() ) return; if ( sucking ) { puls.attach(); if ( puls.attachedFor() > 3 ) puls.setMood(VORACIOUS); else puls.setMood(HAPPY); } else if ( puls.isAttached() ) { puls.detach(); if ( puls.mood() == VORACIOUS ) puls.addVelocity( (puls.x() - x())*2, (puls.y() - y())*2 ); else puls.addVelocity( (puls.x() - x())/4, (puls.y() - y())/4 ); } if ( blowRings.size() > 0 && d < ((Ring)blowRings.firstElement()).radius() + puls.radius() ) { float dx = (puls.x() - x())/d; float dy = (puls.y() - y())/d; if ( puls.mood() == VORACIOUS ) puls.setVelocity(2*blowStrength*dx, 2*blowStrength*dy); else puls.setVelocity(blowStrength*dx, blowStrength*dy); puls.setMood(HAPPY); } } void interact(Deathskull sk) { float d = dist(x(), y(), sk.x(), sk.y()); if ( d > forceRadius + 30 ) return; if ( sucking ) sk.setVelocity( (x() - sk.x())/div, (y() - sk.y())/div ); if ( isBlowing() && d < ((Ring)blowRings.firstElement()).radius() + 30 ) sk.setVelocity( (sk.x() - x())/div, (sk.y() - y())/div ); if ( d < radius + 35 ) { float cx = sk.x() - x(); float cy = sk.y() - y(); float mult = ((radius + 35 - d)/d); sk.moveTo(sk.x() + (cx*mult*0.05f), sk.y() + (cy*mult*0.05)); p.moveTo(x() - (cx*mult), y() - (cx*mult), 0); } } void interact(Sucker su) { float d = dist(x(), y(), su.x(), su.y()); if ( d > forceRadius + 30 ) return; if ( sucking ) su.setVelocity( (x() - su.x())/div, (y() - su.y())/div ); if ( isBlowing() && d < ((Ring)blowRings.firstElement()).radius() + 30 ) su.setVelocity( (su.x() - x())/div, (su.y() - y())/div ); if ( d < radius + su.radius() ) { float cx = su.x() - x(); float cy = su.y() - y(); float mult = ((radius + 30 - d)/d); su.moveTo(su.x() + (cx*mult*0.05f), su.y() + (cy*mult*0.05f)); p.moveTo(x() - (cx*mult), y() - (cx*mult), 0); } } void interact(Blower bl) { float d = dist(x(), y(), bl.x(), bl.y()); if ( d > forceRadius + 30 ) return; if ( sucking ) bl.setVelocity( (x() - bl.x())/div, (y() - bl.y())/div ); if ( isBlowing() && d < ((Ring)blowRings.firstElement()).radius() + 30 ) bl.setVelocity( (bl.x() - x())/div, (bl.y() - y())/div ); if ( d < radius + bl.radius() ) { float cx = bl.x() - x(); float cy = bl.y() - y(); float mult = ((radius + 30 - d)/d); bl.moveTo(bl.x() + (cx*mult*0.05f), bl.y() + (cy*mult*0.05f)); p.moveTo(x() - (cx*mult), y() - (cx*mult), 0); } } void suck(boolean b) { if ( !blowing && b ) sucking = true; else sucking = false; } void keySuck() { suck(suck); } boolean isSucking() { return sucking; } void blow(boolean b, boolean c) { if ( !blowing && b ) { if ( c ) blowRings.add(new Ring(1024)); else blowRings.add(new Ring()); } blowing = b; } void keyBlow(boolean c) { blow(blow, c); } void spawnRing() { blowRings.add(new Ring()); } boolean isBlowing() { return blowRings.size() > 0; } boolean isMoving() { return (abs(vx()) > 2f || abs(vy()) > 2f); } float radius() { return radius; } float mass() { return p.mass(); } float x() { return p.position().x(); } float y() { return p.position().y(); } float vx() { return p.velocity().x(); } float vy() { return p.velocity().y(); } void render() { noFill(); stroke(c); pushMatrix(); translate(x(), y()); // suck waves if ( sucking ) { float rad = constrain(forceRadius * cos((suckCnt%30)*PI/60), radius, forceRadius); octa(rad); suckCnt++; } else suckCnt = 0; // blow waves for (int i = 0; i < blowRings.size(); i++) { Ring tmp = (Ring)blowRings.get(i); if ( tmp.finished ) { blowRings.remove(i); i--; } else { tmp.update(); tmp.render(); } } // the player if ( drawGlow ) { float radI = radius; float radO = radius; float eRadI = eyeRadius; float eRadO = eyeRadius; for (int i = 1; i < 10; i++) { radI *= 0.97f; eRadI *= 0.97f; radO *= 1.03f; eRadO *= 1.03f; stroke(red(g), green(g), blue(g), 200f/i); octa(radI); octa(radO); diamond(eRadI, -radius*0.5f, radius*0.1f); diamond(eRadO, radius*0.5f, radius*0.1f); triangle(radI*-0.5625, radI*0.55, radI*0.5626, radI*0.55, 0, radI*0.8f); triangle(radO*-0.5625, radO*0.55, radO*0.5626, radO*0.55, 0, radO*0.8f); } fill(255, 255, 190, 50); ellipse(-radius*0.5f, radius*0.1f, eyeRadius*0.4f, eyeRadius*0.4f); ellipse(radius*0.5f, radius*0.1f, eyeRadius*0.4f, eyeRadius*0.4f); } noFill(); stroke(c); octa(radius); // left eye diamond(eyeRadius, -radius*0.5f, radius*0.1f); plus(eyeRadius, -radius*0.5f, radius*0.1f); cross(eyeRadius*0.5f, -radius*0.5f, radius*0.1f); // right eye diamond(eyeRadius, radius*0.5f, radius*0.1f); plus(eyeRadius, radius*0.5f, radius*0.1f); cross(eyeRadius*0.5f, radius*0.5f, radius*0.1f); // mouth triangle(radius*-0.5625, radius*0.55, radius*0.5626, radius*0.55, 0, radius*0.8f); popMatrix(); } class Ring { boolean finished; private float radius, endRadius, step; private color col; Ring() { radius = playerSize; endRadius = forceRadius; step = 10; col = c; } Ring(float r) { radius = playerSize; endRadius = r; step = 10; col = color(255, 0, 0, 160); } float radius() { return radius; } void update() { radius += step; } void render() { stroke(col); octa(radius); if ( radius >= endRadius ) finished = true; } } }