// Bryan Blackford - bblackfo@ucsc.edu // ahh! real monsters! class Monster { float x,y; // position // head and jaw from separate svg files move independently PShape shHead,shJaw; // shape scaling factor float scaleF = 0.1; float jawOffset = 0; // jaw position Y //enum {JAW_UP,JAW_DOWN} JAWMOVES; // no enums in processing //JAWMOVES jawMoves = JAW_DOWN; float[] jawSpeed = {-2,1}; // speed jaw moves {up/closed,down/open} int jawMoves = 0; // current movement stage of jaw // current movement state of monster // 0=idle, 1=flying up out of hiding, 2=coming down from sky // 3=moving around field // 4=keypressed,moving off bottom screen // 5=moving into hiding int move = 0; // movement speeds for each of the move states float[] moveSpeed = {0,-11,8,3,8,-1}; boolean bHiding = true; // hiding state (drawn behind mountains) float targetX,targetY; // moving to position (moves:2,3) float hideX,hideY; // init/hiding position set by constructor (moves:5) boolean drawBox = false; //debug: draw box around head // constructor. X,Y set hiding position. files are SVG images. Monster(String headfile,String jawfile,float X,float Y) { // load and scale SVG files shHead = loadShape(headfile); shHead.scale(scaleF); shJaw = loadShape(jawfile); shJaw.scale(scaleF); hideX = x = X; hideY = y = Y; } // move monster void update() { // move jaw //switch (jawMoves) //case 0: jawOffset += jawSpeed[jawMoves]; // switch direction of jaw motion if (jawOffset < -10) // top of jaw motion jawMoves = 1; if (jawOffset > 8) // bottom of jaw motion jawMoves = 0; // move monster switch (move) { case 0: //idle //x+=random(-1,1); y+=random(-1,1); break; case 1: // fly out of hiding y+= moveSpeed[move]; if (getBottom() < 0) { // sky reached, start swooping move = 2; bHiding = false; setMouthX(targetX); } break; case 2: // swoop down from sky y+= moveSpeed[move]; if (getMouthY() > targetY) { // target reached, return to idle setMouthY(targetY); move = 0; } break; case 3: // normal clicky movement // some emergent jittering effect is occuring, it's a feature not a bug! if (abs(getMouthX()-targetX) < moveSpeed[move]) setMouthX(targetX); if (getMouthX() < targetX) x += moveSpeed[move]; if (getMouthX() > targetX) x -= moveSpeed[move]; if (abs(getMouthY()-targetY) < moveSpeed[move]) setMouthY(targetY); if (getMouthY() < targetY) y += moveSpeed[move]; if (getMouthY() > targetY) y -= moveSpeed[move]; // target reached, return to idle if (getMouthY()==targetY && getMouthX()==targetX) move = 0; break; case 4: // run away y+= moveSpeed[move]; if (y > Height) { // bottom of screen reached, move into hiding position move = 5; x = hideX; y = hideY+20; bHiding = true; } break; case 5: // move into hiding spot y+=moveSpeed[move]; if (y < hideY) { // hiding reached, idle y = hideY; move = 0; } break; } } void draw() // drawring time! { shape(shHead,x,y); // draw head if (drawBox) { // monster in a box pushMatrix(); stroke(255); noFill(); rect(x,y,getHeadWidth(),getHeadHeight()); popMatrix(); } shape(shJaw,x,getMouthY()); // draw jaw } // dimensions and positions of head/jaw float getHeadHeight(){return shHead.height*scaleF;} float getHeadWidth (){return shHead.width *scaleF;} float getMidX(){return x+(getHeadWidth()/2);} float getRightX() {return x+getHeadWidth();} float getMouthY() {return y+getHeadHeight()+jawOffset;} float getMouthX() {return getMidX();} float getLeftMouth() {return x+ (getHeadWidth()/3);} float getRightMouth() {return x+((getHeadWidth()/3)*2);} float getJawHeight() {return shJaw.height*scaleF;} float getBottom() {return y+getHeadHeight()+jawOffset+getJawHeight();} // movement void setMouthX(float X) {x = X-(getHeadWidth()/2);} void setMouthY(float Y) {y = Y-getHeadHeight();} void setMouthXY(float X,float Y) { setMouthX(X); setMouthY(Y); } // set move state, target position void setMove(int Move,float X,float Y) { move = Move; targetX = X; targetY = Y; switch(Move) { case 0: break; // do nothing } } }