// 'TheQuaker.java', 5/01 Joe Rosen // 6/15/01, "The Quaker", 'packaged food series' import java.applet.Applet; import java.awt.*; import java.net.URL; // classes // food object (e.g. pasta pocket, wheat kernal, etc.) class FoodObject { // constants // food object images public static final int TOTAL_FOODOBJ_IMGS = 2; // total # of food object images // width and height public static final int FOODOBJ_W = 45; public static final int FOODOBJ_H = 45; // direction ints public static final int DIRECTION_LEFT = 0; public static final int DIRECTION_RIGHT = 1; public static final int DIRECTION_UP = 2; public static final int DIRECTION_DOWN = 3; // anim public static final int OATSPIN_FPS = 75; // oat spin anim delay // vars // flag active= true/inactive= false public boolean active_flg; // "hair" point (oat "stalk" origin) public Point oatstalk_origin; // randomly determine length of oat stalk public int oatstalk_end, oatstalk_grow; // slow down oat stalk growth (by growing every x# of squiggle anims) public int slow_oatstalk_growth; // flag when oatstalk fully grown public boolean oatstalk_mature; // flag when food action is underway (true) complete (false) public boolean oat_growing_flg; // i.e. flag (true) while oat stalk's growing and oat's expanding // offshoot stalks // randomly determine length and direction of offshoot stalk public int[] offshootstalk_direction_x; // 0= left/1= right public Point[] offshootstalk_origin, offshootstalk_end, offshootstalk_grow; // using points to track x,y // oat enlarge public boolean enlarge_flg; // true= oat enlarging public int enlarge_w, enlarge_h; // oat rectangle and position public Rectangle oat_rct; // fully expanded rect // float public boolean float_flg; // after growing/expanding begin floating public int pos_x, pos_y; // position x,y public float offset_x, offset_y; // offset x,y // direction of float public int direction_flg; // randomly selected int, 0 to 3 // oat spin frame public int oat_frame; // 8 frames, 0-7 (each 45 pixels vertically apart) // oat spin anim timer public long oatspin_anmdelay; // independent timing control over oat's spin anim rate // static vars // hairline polygon public static Polygon hairline_poly; public static Rectangle hairline_rect; // bounding rect // keep count of the number of oat stalks grown public static int num_oatstalk; // hair (oat stalk) colors array public static Color[] oatstalk_harvestyellows_rgb; // shades of harvest yellows public static Color[] oatstalk_maturegrays_rbg; // shades of mature grays // drawing environment info (passed in from main class) public static Applet the_applet; public static int canvas_w, canvas_h; public static int head_w, head_h; public static Component main_component; public static Graphics composite_graphics; // drawing canvas public static Rectangle canvas_rect; // head loc, offset into canvas public static int head_left, head_top; // images and media tracker public static Image[] foodobj_imgs = new Image[TOTAL_FOODOBJ_IMGS]; public static MediaTracker foodobj_img_tracker; // float direction of last released food object public static int last_released_foodobj_direction; // methods: // constructor // public static: // init_foodobj_environvars // load_foodobj_imgs // public: // activate_foodobj // draw_foodobject_oatstalk // draw_foodobject_oatkernal // reset_foodobj // private: // target_foodobj_direction // constructor void FoodObject() { // flag active= true/inactive= false active_flg = false; // flag when oatstalk fully grown oatstalk_mature = false; // false= still growing // flag when food action is complete (oat stalk fully grown, oat fully expanded) oat_growing_flg = false; // slow down oat stalk growth (by growing every x# of squiggle anims) slow_oatstalk_growth = 1; // grow every 3rd squiggle } // end 'constructor' // init static food obj applet environment vars public static void init_foodobj_environvars( Applet the_aplt, int can_width, int can_height, int hd_l, int hd_t, Graphics comp_graphics ) { // applet environment info the_applet = the_aplt; canvas_w = can_width; canvas_h = can_height; head_left = hd_l; head_top = hd_t; composite_graphics = comp_graphics; // drawing canvas canvas_rect = new Rectangle(0, 0, canvas_w, canvas_h); // oats // create hairline polygon hairline_poly = new Polygon(); hairline_poly.addPoint(head_left + 83, head_top + 40); hairline_poly.addPoint(head_left + 97, head_top + 18); hairline_poly.addPoint(head_left + 116, head_top + 8); hairline_poly.addPoint(head_left + 132, head_top + 5); hairline_poly.addPoint(head_left + 153, head_top + 8); hairline_poly.addPoint(head_left + 168, head_top + 18); hairline_poly.addPoint(head_left + 185, head_top + 40); hairline_poly.addPoint(head_left + 170, head_top + 40); hairline_poly.addPoint(head_left + 161, head_top + 34); hairline_poly.addPoint(head_left + 109, head_top + 34); hairline_poly.addPoint(head_left + 96, head_top + 40); hairline_poly.addPoint(head_left + 83, head_top + 40); hairline_rect = hairline_poly.getBoundingBox(); // bounding rect // keep count of the number of oat stalks grown num_oatstalk = 0; // hair (oat stalk) colors array // shades of harvest yellows oatstalk_harvestyellows_rgb = new Color[5]; oatstalk_harvestyellows_rgb[0] = new Color(231,206,0); oatstalk_harvestyellows_rgb[1] = new Color(239,222,66); oatstalk_harvestyellows_rgb[2] = new Color(239,189,0); oatstalk_harvestyellows_rgb[3] = new Color(231,165,0); oatstalk_harvestyellows_rgb[4] = new Color(255,255,0); // shades of mature grays oatstalk_maturegrays_rbg = new Color[5]; oatstalk_maturegrays_rbg[0] = new Color(240,236,226); oatstalk_maturegrays_rbg[1] = new Color(213,205,196); oatstalk_maturegrays_rbg[2] = new Color(198,185,182); oatstalk_maturegrays_rbg[3] = new Color(175,170,170); oatstalk_maturegrays_rbg[4] = new Color(163,156,151); // float direction of last released food object last_released_foodobj_direction = 0; } // end method 'init_foodobj_environvars' // load food object images public static void load_foodobj_imgs() { // retrieve images from classpath URL tmp_url; // food object images and media tracker foodobj_img_tracker = new MediaTracker(the_applet); foodobj_imgs[0] = the_applet.getImage(the_applet.getCodeBase(), "images/oat_1.gif"); foodobj_img_tracker.addImage(foodobj_imgs[0], 1); foodobj_imgs[1] = the_applet.getImage(the_applet.getCodeBase(), "images/oat_strip.gif"); foodobj_img_tracker.addImage(foodobj_imgs[1], 2); } // end 'load_foodobj_imgs' // activate (re-init) food object public void activate_foodobj( boolean grow_stalk_flg ) { int tmp_rnd, idx, tmp_y_offset; // growing a new oat stalk? if (grow_stalk_flg == true) { // pick a coord to grow a stalk // keep picking until we have a coord within the Quaker's hairline while (! hairline_poly.inside(oatstalk_origin.x, oatstalk_origin.y) ) { // x, y oatstalk_origin.x = ((int) Math.round(Math.random() * hairline_rect.width)) + hairline_rect.x; oatstalk_origin.y = ((int) Math.round(Math.random() * hairline_rect.height)) + hairline_rect.y; } num_oatstalk++; // we've initialized a new oat stalk, inc counter // give the oat stalk a spurt of initial growth oatstalk_origin.y = oatstalk_origin.y - 1; // randomly determine length of oat stalk oatstalk_end = oatstalk_origin.y; oatstalk_grow = ((int) Math.round(Math.random() * 16)) + 8; // 16 - 24 pixels tall // slow down oat stalk growth (by growing every x# of squiggle anims) slow_oatstalk_growth = 3; // offshoot stalks // randomly determine length and direction of offshoot stalk // init arrays offshootstalk_direction_x = new int[3]; offshootstalk_end = new Point[3]; offshootstalk_origin = new Point[3]; offshootstalk_grow = new Point[3]; // init vals tmp_y_offset = 8; // offset from oat stalk y origin (where we draw offshoots) for (idx = 0; idx < 3; idx++) { offshootstalk_direction_x[idx] = (int) Math.round(Math.random() * 1); // 0= left/1= right offshootstalk_end[idx] = new Point(0,0); tmp_rnd = ((int) Math.round(Math.random() * 6)) + 4; // 4 - 10 // left or right? if (offshootstalk_direction_x[idx] == 0) offshootstalk_end[idx].x = oatstalk_origin.x - tmp_rnd; // left else offshootstalk_end[idx].x = oatstalk_origin.x + tmp_rnd; // right offshootstalk_end[idx].y = oatstalk_origin.y - (tmp_rnd * 2); offshootstalk_origin[idx] = new Point(oatstalk_origin.x, (oatstalk_origin.y - tmp_y_offset)); // give the offshoot stalk a spurt of initial growth offshootstalk_grow[idx] = new Point(0,0); if (offshootstalk_direction_x[idx] == 0) offshootstalk_grow[idx].x = offshootstalk_origin[idx].x - 2; else offshootstalk_grow[idx].x = offshootstalk_origin[idx].x + 2; offshootstalk_grow[idx].y = offshootstalk_origin[idx].y - tmp_y_offset; tmp_y_offset = tmp_y_offset + 4; // offshoots are 4 pixels apart } } // end 'if (grow_stalk_flg == true)' // init oat enlarge enlarge_w = 4; enlarge_h = 4; enlarge_flg = true; // when oat stalk is fully grown, begin expanding oat kernal // food object rect (max size rect, positioned before float) int tmp_x = oatstalk_origin.x - ((int) (FOODOBJ_W / 2)); int tmp_y = (oatstalk_origin.y - oatstalk_grow) - ((int) (FOODOBJ_H / 2)); oat_rct = new Rectangle(tmp_x, tmp_y, FOODOBJ_W, FOODOBJ_H); // float // choose food object direction and float offset target_foodobj_direction(); float_flg = false; // after growing/expanding, begin floating // flag when food action is underway (true) complete (false) oat_growing_flg = true; // i.e. flag (true) while oat stalk's growing and oat's expanding // oat spin frame oat_frame = 0; // 8 frames, 0-7 (each 45 pixels vertically apart) // oat spin anim timer oatspin_anmdelay = System.currentTimeMillis() + OATSPIN_FPS; // anim, x# fps; // flag active= true/inactive= false active_flg = true; } // end method 'activate_foodobj' // draw food object, oat stalk public void draw_foodobject_oatstalk() { int rgb_idx, idx, tmp_y_offset; boolean tmp_flg_grow = false; // slow down oat stalk growth (by growing every x# of squiggle anims) if (slow_oatstalk_growth < 3) { slow_oatstalk_growth++; } else { // grow every 3rd squiggle // grow stalk ? if ( oatstalk_end > (oatstalk_origin.y - oatstalk_grow) ) oatstalk_end--; else oatstalk_mature = true; // mark oatstalk fully grown slow_oatstalk_growth = 1; // reset tmp_flg_grow = true; } // pick a hair color rgb_idx = (int) Math.round(Math.random() * 4); // 0 - 4 //System.out.println("stalk color: " + rgb_idx); // set oatstalk color if (oatstalk_mature && !oat_growing_flg) composite_graphics.setColor(oatstalk_maturegrays_rbg[rgb_idx]); else composite_graphics.setColor(oatstalk_harvestyellows_rgb[rgb_idx]); // draw oatstalk composite_graphics.drawLine(oatstalk_origin.x, oatstalk_origin.y, oatstalk_origin.x, oatstalk_end); // draw offshoot stalks tmp_y_offset = 8; // offset from oat stalk y origin (where we draw offshoots) for (idx = 0; idx < 3; idx++) { if ( oatstalk_end <= (oatstalk_origin.y - tmp_y_offset) ) { if (tmp_flg_grow == true) { // grow? if (offshootstalk_direction_x[idx] == 0) { if (offshootstalk_grow[idx].x > offshootstalk_end[idx].x) offshootstalk_grow[idx].x = offshootstalk_grow[idx].x - 2; } else { if (offshootstalk_grow[idx].x < offshootstalk_end[idx].x) offshootstalk_grow[idx].x = offshootstalk_grow[idx].x + 2; } if (offshootstalk_grow[idx].y > offshootstalk_end[idx].y) offshootstalk_grow[idx].y = offshootstalk_grow[idx].y - 4; } composite_graphics.drawLine(offshootstalk_origin[idx].x, offshootstalk_origin[idx].y, offshootstalk_grow[idx].x, offshootstalk_grow[idx].y); } tmp_y_offset = tmp_y_offset + 4; // offshoots are 4 pixels apart } composite_graphics.setColor(Color.black); // restore color } // end method 'draw_foodobject_oatstalk()' // draw food object, oat kernal public void draw_foodobject_oatkernal() { int oat_pt_x, oat_pt_y; Graphics clip_g; // clip/crop // when oat stalk is fully grown (mature), expand oat kernal if ( (oatstalk_mature == true) && (oat_growing_flg == true) ) { oat_pt_x = oatstalk_origin.x - (enlarge_w / 2); oat_pt_y = (oatstalk_origin.y - oatstalk_grow) - (enlarge_h / 2); // expand (?) if ( (oat_pt_x <= oat_rct.x) || (oat_pt_y <= oat_rct.y) ) { enlarge_w = FOODOBJ_W; enlarge_h = FOODOBJ_H; oat_pt_x = oat_rct.x; oat_pt_y = oat_rct.y; composite_graphics.drawImage(foodobj_imgs[0], oat_pt_x, oat_pt_y, enlarge_w, enlarge_h, null); oat_growing_flg = false; // flag, oat is done expanding float_flg = true; // after growing/expanding begin floating } else { composite_graphics.drawImage(foodobj_imgs[0], oat_pt_x, oat_pt_y, enlarge_w, enlarge_h, null); enlarge_w++; enlarge_h++; } } // when oat is fully expanded, float/spin if (float_flg == true) { // is food object still within canvas? if ( canvas_rect.intersects(oat_rct) ) { // if still within canvas float food object.... oat_rct.x = (int) Math.round(((float) oat_rct.x) + offset_x); oat_rct.y = (int) Math.round(((float) oat_rct.y) + offset_y); clip_g = composite_graphics.create(); // create clip rect // set clip rect clip_g.clipRect(oat_rct.x, oat_rct.y, FOODOBJ_W, FOODOBJ_H); clip_g.drawImage(foodobj_imgs[1], oat_rct.x, (oat_rct.y - (oat_frame * 45)), the_applet); clip_g.dispose(); // dispose clip rect if (System.currentTimeMillis() >= oatspin_anmdelay) { // advance/reset oat spin frame, 8 frames, 0-7 (each 45 pixels vertically apart) if (oat_frame < 7) oat_frame++; else oat_frame = 0; // reset oat spin anim timer oatspin_anmdelay = System.currentTimeMillis() + OATSPIN_FPS; // anim, x# fps; } } else { // .... otherwise, deactivate float. float_flg = false; // deactivate food object active_flg = false; // flag active= true/inactive= false } } } // end method 'draw_foodobject_oatkernal()' // choose food object direction and float offset private void target_foodobj_direction() { float direction_target, number_of_moves; int tmp_rand; int origin_y = oatstalk_origin.y - oatstalk_grow; int origin_x = oatstalk_origin.x; // direction direction_flg = (int) (Math.round(Math.random() * 3)); // randomly selected int, 0 to 3 // never pick the same direction twice in a row while (direction_flg == last_released_foodobj_direction) direction_flg = (int) (Math.round(Math.random() * 3)); // float direction of last released food object last_released_foodobj_direction = direction_flg; // target, calculated offset switch (direction_flg) { case DIRECTION_UP: offset_y = (float) -1.0; number_of_moves = origin_y; direction_target = (float) (Math.round(Math.random() * canvas_w)); offset_x = (direction_target - origin_x) / number_of_moves; // System.out.println("up: " + offset_x + "," + offset_y); break; case DIRECTION_DOWN: offset_y = (float) 1.0; number_of_moves = canvas_h - origin_y; direction_target = (float) (Math.round(Math.random() * canvas_w)); offset_x = (direction_target - origin_x) / number_of_moves; // System.out.println("down: " + offset_x + "," + offset_y); break; case DIRECTION_LEFT: offset_x = (float) -1.0; number_of_moves = origin_x; direction_target = (float) (Math.round(Math.random() * canvas_h)); offset_y = (direction_target - origin_y) / number_of_moves; // System.out.println("left: " + offset_x + "," + offset_y); break; default: case DIRECTION_RIGHT: offset_x = (float) 1.0; number_of_moves = canvas_w - origin_x; direction_target = (float) (Math.round(Math.random() * canvas_h)); offset_y = (direction_target - origin_y) / number_of_moves; // System.out.println("right: " + offset_x + "," + offset_y); break; } } // end 'target_foodobj_direction' // reset food object public void reset_foodobj() { // shut down all flags oat_growing_flg = false; enlarge_flg = false; oatstalk_mature = false; float_flg = false; active_flg = false; } // end 'reset_foodobj' } // end class 'FoodObject' // main program class public class TheQuaker extends Applet implements Runnable { // constants // x/y, drawings canvas static final int CANVAS_W = 375; static final int CANVAS_H = 450; static final int TOTAL_IMGS = 6; // total # of images // base buff idx references for image parts static final int BASE_IDX_HEAD = 0; //head static final int BASE_IDX_HAT = 2; // hat static final int BASE_IDX_EYES = 4; // hat // image dimensions // head static final int HEAD_W = 262; static final int HEAD_H = 259; // hat static final int HAT_W = 303; static final int HAT_H = 153; // hat, offset from head static final int HAT_HEAD_OFFSET_X = 13; static final int HAT_HEAD_OFFSET_Y = 28; // eyes static final int EYES_W = 98; static final int EYES_H = 38; // eyes, offset from head static final int EYES_HEAD_OFFSET_X = 84; static final int EYES_HEAD_OFFSET_Y = 67; // eyes, positions in eyes strip static final int EYESSTRIP_CENTER = 0; static final int EYESSTRIP_LEFT = 1; static final int EYESSTRIP_RIGHT = 2; static final int EYESSTRIP_UP = 3; static final int EYESSTRIP_DOWN = 4; static final int EYESSTRIP_CLOSED = 5; // y distance between eyes in eye strip static final int EYESSTRIP_SEPARATION_Y = 39; // total number of food objects public static final int TOTAL_FOODOBJS = 250; // vars // composite buffer, images and media tracker static Image composite_image; static Graphics composite_graphics; static Image[] imgs = new Image[TOTAL_IMGS]; static MediaTracker img_tracker; // animation thread static Thread anim_thread; // squiggle anim timer static long squiggle_delay; // squiggle flag static int squiggle_flg; // 0-1, 2 frame squiggle anim // head loc, offset into canvas static int head_left, head_top; // hat static int hat_x, hat_y; // hat cur coords static int hat_y_up, hat_y_down; // hat y coords, fully up and fully down // hat action flag static int hat_action_flg; // 1= on; 0= off; 2= on/i.e. hat going down // eyes // eyes status flg (0= closed/1= open) static int eyesstatus_flg; // eyes blink delay static long eyesblink_delay; // eyes gaze-- left, right, up, down, or center static int gaze_flg; // gaze: 0= left; 1= right; 2= up; 3= down; 4= center static long gaze_time; // eyes gaze left or right every 4000 - 10000 miliseconds static long gaze_delay; // hold eyes gazing left or right (before // food objects array static FoodObject[] food_obj; // init flag static boolean init_flg = false; // false until initialization in 'main()' is complete // methods: // init // start // stop // destroy // update // run // mouseDown // keyDown // paint // private methods: // my_paint // draw_head // draw hat // 'init()' public void init() { int idx; // array index // composite buffer composite_image = createImage(CANVAS_W, CANVAS_H); composite_graphics = composite_image.getGraphics(); // load images and media tracker img_tracker = new MediaTracker(this); // head imgs[0] = getImage(getCodeBase(), "images/head_1.gif"); img_tracker.addImage(imgs[0], 1); imgs[1] = getImage(getCodeBase(), "images/head_2.gif"); img_tracker.addImage(imgs[1], 2); // hat imgs[2] = getImage(getCodeBase(), "images/hat_1.gif"); img_tracker.addImage(imgs[2], 3); imgs[3] = getImage(getCodeBase(), "images/hat_2.gif"); img_tracker.addImage(imgs[3], 4); // eyes imgs[4] = getImage(getCodeBase(), "images/eyes_1.gif"); img_tracker.addImage(imgs[4], 5); imgs[5] = getImage(getCodeBase(), "images/eyes_2.gif"); img_tracker.addImage(imgs[5], 6); // misc init // anim flags squiggle_flg = 0; // squiggle flag: 0/1, 2 frame squiggle anim= // anim timers squiggle_delay = System.currentTimeMillis() + 100; // squiggle anim, 10 fps // head loc, offset into canvas head_left = (CANVAS_W - HEAD_W) / 2; head_top = ((CANVAS_H - HEAD_H) / 2) + 50; // init static food obj environment vars FoodObject.init_foodobj_environvars(this, CANVAS_W, CANVAS_H, head_left, head_top, composite_graphics); // instantiate food objects food_obj = new FoodObject[TOTAL_FOODOBJS]; for (idx = 0; idx < TOTAL_FOODOBJS; idx++) { food_obj[idx] = new FoodObject(); food_obj[idx].oatstalk_origin = new Point(0,0); } // load food object images FoodObject.load_foodobj_imgs(); // hat hat_action_flg = 0; // hat action flag: 1= on; 0= off; 2= on/i.e. hat going down hat_y_down = head_top - HAT_HEAD_OFFSET_Y; // hat y coords, fully up and fully down hat_y_up = hat_y_down - 75; hat_y = hat_y_down; hat_x = head_left - HAT_HEAD_OFFSET_X; // init eyes status flg (0= closed/1= open) eyesstatus_flg = 1; // initially open // init eyes blink delay (blink every .50 to 1.5 seconds) eyesblink_delay = System.currentTimeMillis() + ( (long) (Math.round(Math.random() * 1000) + 500) ); // eyes gaze-- left, right, up, down, or center gaze_flg = 0; // gaze: 0= left; 1= right; 2= up; 3= down; 4= center gaze_time = System.currentTimeMillis() + ((long) (Math.round(Math.random() * 6000) + 4000) ); // eyes gaze left or right every 4000 - 10000 miliseconds // init flag init_flg = true; // false until initialization is complete } // end method 'init()' // 'start()' // called when the applet becomes visible on screen public void start() { // create animation thread anim_thread = new Thread(this); // start animation thread anim_thread.start(); } // end method 'start()' // 'stop()' // called when the applet is no longer visible on screen public void stop() { // stop and destroy animation thread if (anim_thread != null) anim_thread = null; } // end method 'stop()' // 'destroy()' // called just before the browser exits public void destroy() { // stop and destroy animation thread if (anim_thread != null) anim_thread = null; // dispose offscreen graphics context, TheChef composite buffer composite_graphics.dispose(); composite_graphics = null; } // end method 'destroy()' // 'update()' // update the screen public void update(Graphics g) { // intercepting 'update()' avoids background erase if (composite_graphics != null) paint(g); // call 'paint()' } // end method 'update()' // 'run()', thread runner public void run() { int idx; int paint_flg = 0; while ( anim_thread == Thread.currentThread() ) { // anim timers // squiggle if (System.currentTimeMillis() >= squiggle_delay) { // squiggle flag if (squiggle_flg == 1) squiggle_flg = 0; // 0/1, 2 frame squiggle anim else squiggle_flg = 1; squiggle_delay = System.currentTimeMillis() + 100; // squiggle anim, 10 fps // flag paint paint_flg = 1; } // hat // note: hat action= oat kernels growing, but not yet released boolean hat_action_complete_flg = true; // assume hat action complete // shut down hat action only after all food objects (oat kernels) are fully grown for (idx = 0; idx < TOTAL_FOODOBJS; idx++) { if (food_obj[idx].oat_growing_flg == true) { hat_action_complete_flg = false; break; // hat action isn't yet complete, we're done here } } // shut down hat action? if (hat_action_complete_flg == true) { // is hat down? if (hat_y == hat_y_down) hat_action_flg = 0; // 1= on; 0= off; 2= on/e.g. hat going down else hat_action_flg = 2; } // begin: eyes blink // close (note: don't blink during hat action, i.e. while hat's up) if ( (hat_action_complete_flg == true) && ((eyesstatus_flg == 1) && (System.currentTimeMillis() >= eyesblink_delay)) ) { // mark eyes status flag eyesstatus_flg = 0; // flag eyes closed // keep blinking eyes closed 125 milisecs eyesblink_delay = System.currentTimeMillis() + 125; // flag paint paint_flg = 1; } // open else if ( (eyesstatus_flg == 0) && (System.currentTimeMillis() >= eyesblink_delay) ) { // mark eyes status flag eyesstatus_flg = 1; // flag eyes open // re-init eyes blink delay (blink every .50 to 1.5 seconds) eyesblink_delay = System.currentTimeMillis() + ( (long) (Math.round(Math.random() * 1000) + 500) ); // flag paint paint_flg = 1; } // close: eyes blink // begin: eye gaze // gaze: 0= left; 1= right; 2= up; 3= down; 4= center // if the hat's going up force eyes up, else eyes center if (hat_action_complete_flg == false) gaze_flg = 2; // randomly select a gaze else if ( System.currentTimeMillis() >= gaze_time ) { // checking for floating food objects boolean tmp_float_flg = false; for (idx = 0; idx < TOTAL_FOODOBJS; idx++) if (food_obj[idx].float_flg == true) { tmp_float_flg = true; break; } // if there's a floating food object, let gaze follow direction of last released oat kernel if (tmp_float_flg == true) gaze_flg = FoodObject.last_released_foodobj_direction; else gaze_flg = (int) Math.round(Math.random() * 1); // else, restrict gaze rnd left or right // hold eyes gazing left, right, up, or down (before returning center) 1000 - 3000 mls gaze_delay = System.currentTimeMillis() + ( (long) (Math.round(Math.random() * 2000) + 1000) ); gaze_time = ( (long) (Math.round(Math.random() * 6000) + 4000) ) + gaze_delay; // reset gaze time (4-10 secs) //System.out.println("set *timed* gaze: " + gaze_flg); } // default: eyes return center else if ( (gaze_flg != 4) && (System.currentTimeMillis() >= gaze_delay) ) gaze_flg = 4; // end: eye gaze // paint (??) if (paint_flg == 1) repaint(); // force repaint // sleep try { Thread.sleep(25); } catch (InterruptedException e) {} } // end "while (Thread.currentThread() == anim_thread)" } // end method 'run()' // 'mouseDown()' // called when the mouse button is pressed down public boolean mouseDown(Event evt, int x, int y) { int rnd_idx; // activate an oat stalk if (FoodObject.num_oatstalk < TOTAL_FOODOBJS) food_obj[FoodObject.num_oatstalk].activate_foodobj(true); else { // all oat stalks are grown, simply expand a randomly selected oat kernel rnd_idx = (int) ( Math.round(Math.random() * (TOTAL_FOODOBJS - 1)) ); food_obj[rnd_idx].activate_foodobj(false); } // activate head action (?) if (hat_action_flg == 0) { hat_y = hat_y_down; // re-init hat y pos (hat down) hat_action_flg = 1; // head action flag, 1= on; 0= off; 2= on/e.g. hat going down } // hat going down? if so send it back up again else if (hat_action_flg == 2) hat_action_flg = 1; return true; } // end method 'mouseDown()' // 'keyDown()' public boolean keyDown(Event evt, int key) { int idx; //System.out.println("key: " + key); // on "space bar" down shave head, i.e. clear all oats (re-init) if (key == 32) { for (idx = 0; idx < FoodObject.num_oatstalk; idx++) food_obj[idx].reset_foodobj(); // reset food object // reset/re-init all of the following: FoodObject.num_oatstalk = 0; // reset count of the number of oat stalks grown } return true; } // end method 'keyDown()' // 'paint()' public void paint(Graphics g) { // if init's complete, draw images in composite buffer and blast to screen if (init_flg) my_paint(g); } // end method 'paint()' // private methods // draw images in composite buffer and blast to screen // synchronized metod, don't initiate another "paint" session until one's complete synchronized void my_paint(Graphics g) { int idx; // if composite buffer's non-existent, return immediately if (composite_graphics == null) return; // fill composite buffer with white paint composite_graphics.setColor(Color.white); composite_graphics.fillRect(0, 0, CANVAS_W, CANVAS_H); // have images loaded? if ( (! img_tracker.checkAll(true)) || (! FoodObject.foodobj_img_tracker.checkAll(true)) ) { // text font Font txt_Font = new Font("Helvetica", Font.PLAIN, 9); // set text string font composite_graphics.setFont(txt_Font); // set text string color composite_graphics.setColor(Color.black); // write to screen composite_graphics.drawString("Loading Images...", 25, 25); } else { // draw head draw_head(); } // black border composite_graphics.setColor(Color.black); composite_graphics.drawRect(0, 0, (CANVAS_W - 1), (CANVAS_H - 1)); // blast composite buffer to screen g.drawImage(composite_image, 0, 0, null); } // end method 'my_paint()' // draw head void draw_head() { int idx, idx_head, idx_eyes, eyes_x, eyes_y, eyesclip_y; Graphics clip_g; // clip/crop // squiggle anim base idx_head = BASE_IDX_HEAD; idx_eyes = BASE_IDX_EYES; if (squiggle_flg == 1) { idx_head = idx_head + 1; idx_eyes = idx_eyes + 1; } // head // draw head into buffer composite_graphics.drawImage(imgs[idx_head], head_left, head_top, null); // begin: eyes clip_g = composite_graphics.create(); // create clip rect // set clip rect eyes_x = head_left + EYES_HEAD_OFFSET_X; eyesclip_y = head_top + EYES_HEAD_OFFSET_Y; // begin: eye strip y pos // closed (blinK) if (eyesstatus_flg == 0) eyes_y = (head_top + EYES_HEAD_OFFSET_Y) - (EYESSTRIP_SEPARATION_Y * EYESSTRIP_CLOSED); // open (gaze) else { eyes_y = head_top + EYES_HEAD_OFFSET_Y; // default gaze (eyes center gaze, i.e. top of strip) // gaze-- left, right, up, down, or center switch (gaze_flg) { // left case 0: eyes_y = eyes_y - (EYESSTRIP_SEPARATION_Y * EYESSTRIP_LEFT); break; // right case 1: eyes_y = eyes_y - (EYESSTRIP_SEPARATION_Y * EYESSTRIP_RIGHT); break; // up case 2: eyes_y = eyes_y - (EYESSTRIP_SEPARATION_Y * EYESSTRIP_UP); break; // down case 3: eyes_y = eyes_y - (EYESSTRIP_SEPARATION_Y * EYESSTRIP_DOWN); break; // center case 4: eyes_y = eyes_y - (EYESSTRIP_SEPARATION_Y * EYESSTRIP_CENTER); break; } } // end: eye strip y pos clip_g.clipRect(eyes_x, eyesclip_y, EYES_W, EYES_H); // draw eyes into buffer clip_g.drawImage(imgs[idx_eyes], eyes_x, eyes_y, this); // dispose clip rect clip_g.dispose(); // end: eyes // note: if hat's fully down, there's no need to draw oat stalks // draw food object, oat stalks if (hat_action_flg != 0) // don't bother drawing if hat's down for (idx = 0; idx < FoodObject.num_oatstalk; idx++) food_obj[idx].draw_foodobject_oatstalk(); // draw hat draw_hat(); // draw food object, oat kernals for (idx = 0; idx < FoodObject.num_oatstalk; idx++) food_obj[idx].draw_foodobject_oatkernal(); } // end method 'draw_head()' // draw hat void draw_hat() { int img_idx, tmp_x, tmp_rnd; // 'hat_action_flg' : 1= on; 0= off; 2= on/i.e. hat going down // base idx, head img_idx = BASE_IDX_HAT; // squiggle anim base if (squiggle_flg == 1) img_idx = img_idx + 1; // raise hat up ? if ( (hat_action_flg == 1) && (hat_y > hat_y_up) ) { hat_y = hat_y - 2; // make sure we haven't raised hat beyond max height if (hat_y < hat_y_up) hat_y = hat_y_up; } // send hat down ? else if ( (hat_action_flg == 2) && (hat_y < hat_y_down) ) { hat_y = hat_y + 2; // make sure we haven't lowered hat beneath min height if (hat_y > hat_y_down) hat_y = hat_y_down; } // hat down else if (hat_action_flg == 0) { hat_y = hat_y_down; } // stagger hat_x on hat rise and fall (unsmooth rise/fall anim) if ( (hat_y == hat_y_up) || (hat_y == hat_y_down) ) tmp_x = hat_x; else { tmp_x = hat_x; tmp_rnd = (int) Math.round(Math.random() * 3); switch (tmp_rnd) { case 0: tmp_x = hat_x - 2; break; case 1: tmp_x = hat_x; break; case 2: tmp_x = hat_x + 2; break; } } // draw hat into buffer composite_graphics.drawImage(imgs[img_idx], tmp_x, hat_y, null); } // end method 'draw_hat()' } // end class "TheQuaker"