// psycho_hitchcock.java // 12/20/01, 'Psycho Hitchcock' Electromic import java.applet.Applet; import java.awt.*; import java.net.URL; // not java 1.02 compliant //import java.lang.reflect.Array; // classes // 'FilmStrip' class, film strip class FilmStrip { // constants // vars // playback vars (set upon instantiation) public int frame_x, frame_y; // filmstrip location on screen public int frame_w, frame_h; // filmstrip frame width and height public int frame_total; // total # of frames public long frame_fps; // frames per second public boolean frame_loop; // play once (false) or loop (true) public int[] frame_array; // array of frames to play // ^^ note: frames are sequenced by position in strip, i.e. {1,3,1,1} // filmstrip image and media tracker public Image filmstrip_img; public MediaTracker filmstrip_img_tracker; // internal tracking vars (updated internally during frame play) public boolean play_flg; // movie playing (true) public int cur_frame; // current filmstrip frame number public long fps_update_time; // fps update time // static vars // drawing environment info (passed in from main class) public static Applet the_applet; public static int canvas_w, canvas_h; public static Component main_component; public static Graphics composite_graphics; // drawing canvas public static Rectangle canvas_rct; // methods: // constructor // public static: // init_filmstrip_drawenvironvars // public: // load_filmstrip_img // start_stop_filmstrip // set_filmstrip_frame_num // crank_filmstrip_projector // constructor public FilmStrip( int f_x, int f_y, int f_w, int f_h, int f_total, int f_fps, boolean f_loop ) { // playback vars frame_x = f_x; frame_y = f_y; // filmstrip location on screen frame_w = f_w; frame_h = f_h; // filmstrip frame width and height frame_total = f_total; // total # of frames frame_fps = (long) (1000 / f_fps); // frames per second frame_loop = f_loop; // play once (false) or loop (true) // internal tracking vars (updated internally during frame play) play_flg = false; // movie playing (true) cur_frame = 1; // current filmstrip frame number fps_update_time = 0; // fps update time } // end 'constructor' // init static filmstrip applet/drawing environment vars public static void filmstrip_drawenvironvars( Applet the_aplt, int can_width, int can_height, Graphics comp_graphics ) { // applet environment info the_applet = the_aplt; canvas_w = can_width; canvas_h = can_height; composite_graphics = comp_graphics; // drawing canvas canvas_rct = new Rectangle(0, 0, canvas_w, canvas_h); } // end method 'filmstrip_drawenvironvars' // load filmstrip image public void load_filmstrip_img( String img_name ) { // filmstrip image and media tracker filmstrip_img_tracker = new MediaTracker(the_applet); filmstrip_img = the_applet.getImage(the_applet.getCodeBase(), ("images/" + img_name)); filmstrip_img_tracker.addImage(filmstrip_img,1); } // end 'load_filmstrip_img' // play/pause (start/stop) filmstrip public void start_stop_filmstrip(boolean start_stop_flg) { play_flg = start_stop_flg; // movie playing (true) cur_frame = 1; // always play from frame 1 fps_update_time = System.currentTimeMillis() + frame_fps; // cue fps update } // end method 'start_stop_filmstrip' // draw/advance (project) filmstrip frames // returns 'true' if frame's been painted/updated public void crank_filmstrip_projector(int expand_w, int expand_h) { Image resize_img; Graphics clip_g, resize_g; // clip/crop, resize int frame_y_offset; int tmp_frame_x, tmp_frame_y; if (! play_flg) return; // return immediately unless play flag is true // fps update ? if ( play_flg && (System.currentTimeMillis() >= fps_update_time) ) { // crank frame if (cur_frame < frame_total) cur_frame++; else { // if we're looping, cycle back to frame one if (frame_loop) cur_frame = 1; } // update fps timer fps_update_time = System.currentTimeMillis() + frame_fps; } // filmstrip y offset frame_y_offset = (frame_array[(cur_frame - 1)] - 1) * frame_h; // are we expanding or contracting? if ( (expand_w < frame_w) || (expand_h < frame_h) ) { // expand/contract resize_img = the_applet.createImage(frame_w, frame_h); resize_g = resize_img.getGraphics(); // draw frame into buffer resize_g.drawImage(filmstrip_img, 0, -frame_y_offset, the_applet); // now copy this img to the buffer/screen resized tmp_frame_x = (frame_x + frame_w) - expand_w; tmp_frame_y = (frame_y + frame_h) - expand_h; composite_graphics.drawImage(resize_img, tmp_frame_x, tmp_frame_y, expand_w, expand_h, the_applet); // black border composite_graphics.setColor(Color.black); composite_graphics.drawRect(tmp_frame_x, tmp_frame_y, expand_w, expand_h); // cleanup resize_g.dispose(); resize_img = null; } else { // normal clip_g = composite_graphics.create(); // create clip rect clip_g.clipRect(frame_x, frame_y, frame_w, frame_h); // draw frame into buffer clip_g.drawImage(filmstrip_img, frame_x, (frame_y - frame_y_offset), the_applet); clip_g.dispose(); // dispose clip rect } // debug //System.out.println("frame w h: " + expand_w + "," + expand_h); } // end method 'crank_filmstrip_projector()' } // end class 'FilmStrip' // 'BloodSpurt' class, spurting bloody knife wounds class BloodSpurt { // constants // blood spurt images public static final int TOTAL_BLOODSPURT_IMGS = 1; // total # of blood spurt images // width and height public static final int BLOODSPURT_W = 69; public static final int BLOODSPURT_H = 69; // anim public static final int BLOODSPURT_FPS = 125; // blood spurt anim delay public static final int BLOODSPURT_FRAMES = 8; // total # of blood spurt frames // vars // flag active= true/inactive= false public boolean active_flg; // blood spurt center point/origin public Point bloodspurt_origin; // blood spurt frame public int bloodspurt_frame; // x # of frames, each frame BLOODSPURT_H pixels vertically apart // blood spurt anim timer public long bloodspurt_anmdelay; // independent timing control over blood spurt anim rate // static vars // drawing environment info (passed in from main class) public static Applet the_applet; public static int canvas_w, canvas_h; public static Component main_component; public static Graphics composite_graphics; // drawing canvas public static Rectangle canvas_rect; // blood spurt image(s) and media tracker public static Image[] bloodspurt_imgs = new Image[TOTAL_BLOODSPURT_IMGS]; public static MediaTracker bloodspurt_img_tracker; // methods: // constructor // public static: // init_bloodspurt_environvars // load_bloodspurt_imgs // public: // activate_bloodspurt // draw_bloodspurt // reset_bloodspurt // constructor void BloodObject() { // flag active= true/inactive= false active_flg = false; // init empty point //bloodspurt_origin = new Point(0,0); } // end 'constructor' // init static blood splurt applet environment vars public static void init_bloodspurt_environvars( Applet the_aplt, int can_width, int can_height, Graphics comp_graphics ) { // applet environment info the_applet = the_aplt; canvas_w = can_width; canvas_h = can_height; composite_graphics = comp_graphics; // drawing canvas canvas_rect = new Rectangle(0, 0, canvas_w, canvas_h); } // end method 'init_bloodspurt_environvars' // load static blood spurt images public static void load_bloodspurt_imgs() { // blood spurt images and media tracker bloodspurt_img_tracker = new MediaTracker(the_applet); bloodspurt_imgs[0] = the_applet.getImage(the_applet.getCodeBase(), "images/bloodspurt.gif"); bloodspurt_img_tracker.addImage(bloodspurt_imgs[0], 1); } // end 'load_bloodspurt_imgs' // activate (re-init) blood spurt public void activate_bloodspurt( int x_origin, int y_origin ) { // flag active= true/inactive= false active_flg = true; // set blood spurt center point/origin //bloodspurt_origin.setLocation(x_origin - (BLOODSPURT_W / 2), y_origin - (BLOODSPURT_H / 2)); bloodspurt_origin.x = x_origin - (BLOODSPURT_W / 2); bloodspurt_origin.y = y_origin - (BLOODSPURT_H / 2); // blood spurt frame bloodspurt_frame = 0; // init to first frame (zero) // blood spurt anim timer, independent timing control over blood spurt anim rate bloodspurt_anmdelay = System.currentTimeMillis() + BLOODSPURT_FPS; } // end method 'activate_bloodspurt' // draw blood spurts public void draw_bloodspurt() { int y_offset = 0; Graphics clip_g; // clip/crop // blood spurt frame if (System.currentTimeMillis() >= bloodspurt_anmdelay) { if (bloodspurt_frame < (BLOODSPURT_FRAMES - 1)) bloodspurt_frame++; else bloodspurt_frame = 0; bloodspurt_anmdelay = System.currentTimeMillis() + BLOODSPURT_FPS; } y_offset = BLOODSPURT_H * bloodspurt_frame; clip_g = composite_graphics.create(); // create clip rect // set clip rect clip_g.clipRect(bloodspurt_origin.x, bloodspurt_origin.y, BLOODSPURT_W, BLOODSPURT_H); clip_g.drawImage(bloodspurt_imgs[0], bloodspurt_origin.x, (bloodspurt_origin.y - y_offset), the_applet); clip_g.dispose(); // dispose clip rect } // end method 'draw_bloodspurt()' // reset blood spurt public void reset_bloodspurt() { // shut down all flags active_flg = false; } // end 'reset_bloodspurt' } // end class 'BloodSpurt' // applet // main program class, 'psycho_hitchcock' public class psycho_hitchcock extends Applet implements Runnable { // constants // x/y, drawings canvas static final int CANVAS_W = 336; static final int CANVAS_H = 404; static final int TOTAL_IMGS = 4; // total # of images // base buff idx references for image parts static final int IMG_IDX_HEAD = 0; //head static final int IMG_IDX_EYES = 1; // eyes static final int IMG_IDX_BRAIN = 2; // brain static final int IMG_IDX_LOGO = 3; // logo // image dimensions // hitchcock head static final int HEAD_W = 325; static final int HEAD_H = 300; // hitchcock head, offset from canvas top/left static final int HEAD_OFFSET_X = 6; static final int HEAD_OFFSET_Y = 103; // hitchcock eyes static final int EYES_W = 89; static final int EYES_H = 38; // hitchcock eyes, offset from head static final int EYES_HEAD_OFFSET_X = 148; static final int EYES_HEAD_OFFSET_Y = 43; // brain static final int BRAIN_W = 72; static final int BRAIN_H = 76; // brain, offset from head static final int BRAIN_HEAD_OFFSET_X = 124; static final int BRAIN_HEAD_OFFSET_Y = 4; // hitchcock logo static final int LOGO_W = 74; static final int LOGO_H = 126; // hitchcock logo, offset from canvas top/left static final int LOGO_OFFSET_X = 10; static final int LOGO_OFFSET_Y = 10; // hitchcock logo, horiz/vert direction static final int LOGO_MOVE_UP = 0; static final int LOGO_MOVE_DOWN = 1; static final int LOGO_MOVE_LEFT = 0; static final int LOGO_MOVE_RIGHT = 1; // total # of filmstrip objects // 0= psycho; 1= rear window; 2= north by northwest; 3= vertigo; 4= the birds static final int TOTAL_FILMSTRIP_OBJS = 5; // total # of blood spurt objects static final int TOTAL_BLOODSPURT_OBJS = 100; // brain expand/contract anim static final long BRAINANM_DELAY = 125; // 8 fps (brain expand contract frames) // anim frames-per-second static final long HITCH_FPS = 100; // hitchcock, 10 fps static final long LOGO_FPS = 66; // logo, ~15 fps // image load leader dots fps update time static final long DOTS_FPS = 125; // update 8x per second // vars // composite buffer and media tracker static Image composite_image; static Graphics composite_graphics; static MediaTracker img_tracker; // images static Image[] imgs = new Image[TOTAL_IMGS]; // graphics component of this applet, used to force immediate repaints static Graphics applet_graphics; // animation thread static Thread anim_thread; // squiggle anim timer(s) static long hitch_squiggle_delay, logo_squiggle_delay; // squiggle flag(s) static int hitch_squiggle_flg, logo_squiggle_flg; // e.g. 0-1, 2 frame squiggle anim // 'blood spurt' object array BloodSpurt[] bloodspurt_obj; static int bloodspurt_obj_cnt; // keep count of activated blood spurts // 'film strip' object array static FilmStrip[] filmstrip_obj; // image locations // hitchcock's head static int head_left, head_top; // hitchcock's eyes static int eyes_left, eyes_top; // hitchcock's brain static int brain_left, brain_top; // polygons static Polygon filmstrip_brain_poly; // filmstrip/brain static Polygon bloodspurt_bust_poly; // hitchcock's body (bust portrait poly)/bloodspurts // eye flags // 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= center; 1= left; 2= right; 3= up; 4= down static int force_gaze_flg; // force gaze= 1, e.g. during Hitch logo anim static long gaze_time; // eyes gaze left or right every 4000 - 10000 miliseconds static long gaze_delay; // hold eyes gazing left or right (before returning to center gaze) // brain expand/contract anim // brain status flg (1= expand/0= contract) static int brainstatus_flg; static int brainanm_frame; // brain frame (total 6 frame anim) // expand/contract anim delay static long brainanm_delay; // hitchock logo flag static boolean logo_flg; // true = visible // hitchock logo, horiz/vert coords static int hrz_logo_coord, vrt_logo_coord; // hitchock logo, horiz/vert direction flags static int hrz_logo_direction, vrt_logo_direction; // image load leader dots (animate 1 to 5 dots) static int img_load_anm_dots; static long dots_update_time; // leader dots fps update time // filmstrip static int filmstrip_idx; // ^^ 0= psycho; 1= rear window; 2= north by northwest; 3= vertigo; 4= the birds static boolean filmstrip_play_flg; // true= a filmstrip is playing // expand/contract filmstrip frame static int[][] filmstrip_w_h; // init flag static boolean init_flg = false; // false until initialization in 'main()' is complete // methods: // init // start // stop // destroy // update // run // mouseDown // mouseUp // keyDown // keyUp // paint // private methods: // my_paint // draw_hitchcock_head // draw_hitchcock_brain // draw_hitchcock_logo // 'init()' public void init() { int idx; // filmstrip playback ary int[] tmp_frame_total = new int[TOTAL_FILMSTRIP_OBJS]; int[] tmp_filmstrip_fps = new int[TOTAL_FILMSTRIP_OBJS]; // psycho int[] tmp_filmstrip_ary_1 = {1,2,1,2,1,2,1,2,1,2,3,4,5,6,5,4,3,4,5,6,5,4,3,4,5,6,1,2,1,2,1,2,1,2,1,2,3,4,5,6,5,4,3,4,5,6,5,4,3,4,5,6,1,2,1,2,1,2,1,2,1,2,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,9,10,11,12,13,14,15,16,9,10,11,12,13,14,15,16,9,18,19,20,21,22,23,24,17,18,19,20,21,22,23,24,17,18,19,20,21,22,23,24,17}; //tmp_frame_total[0] = Array.getLength(tmp_filmstrip_ary_1); // debug: report array length //System.out.println("psycho # frames: " + tmp_frame_total[0]); tmp_frame_total[0] = 119; tmp_filmstrip_fps[0] = 7; // rear window int[] tmp_filmstrip_ary_2 = {1,2,1,3,4,5,6,5,4,5,6,5}; tmp_frame_total[1] = 12; tmp_filmstrip_fps[1] = 7; // north by northwest int[] tmp_filmstrip_ary_3 = {6,7,6,7,6,7,6,7,6,7,8,9,8,9,8,9,8,9,8,9,1,2,3,4,5}; tmp_frame_total[2] = 25; tmp_filmstrip_fps[2] = 8; // vertigo int[] tmp_filmstrip_ary_4 = {1,2,3,4,5,6,7,8}; tmp_frame_total[3] = 8; tmp_filmstrip_fps[3] = 8; // the birds int[] tmp_filmstrip_ary_5 = {1,2,1,2,1,2,3,4,3,4,3,4,5,6,5,6,5,6,7,8,7,8,7,8,9,10,9,10,9,10,11,12,11,12,11,12,13,14,13,14,13,14,15,16,15,16,15,16,17,18,17,18,17,18,19,20,19,20,19,20,21,22,21,22,21,22}; tmp_frame_total[4] = 66; tmp_filmstrip_fps[4] = 8; // composite buffer composite_image = createImage(CANVAS_W, CANVAS_H); composite_graphics = composite_image.getGraphics(); // graphics component of this applet, used to force immediate repaints applet_graphics = this.getGraphics(); // misc init // anim flags hitch_squiggle_flg = 0; logo_squiggle_flg = 0; // e.g. 0-1, 2 frame squiggle anim // anim timers hitch_squiggle_delay = System.currentTimeMillis() + HITCH_FPS; // hitch squiggle anm, 10 fps logo_squiggle_delay = System.currentTimeMillis() + LOGO_FPS; // logo squiggle anm, ~15 fps // init static blood spurt obj environment vars BloodSpurt.init_bloodspurt_environvars(this, CANVAS_W, CANVAS_H, composite_graphics); // create bloospurt object array bloodspurt_obj = new BloodSpurt[TOTAL_BLOODSPURT_OBJS]; // instantiate blood spurt objects for (idx = 0; idx < TOTAL_BLOODSPURT_OBJS; idx++) { bloodspurt_obj[idx] = new BloodSpurt(); bloodspurt_obj[idx].bloodspurt_origin = new Point(0,0); } // load blood spurt object images BloodSpurt.load_bloodspurt_imgs(); bloodspurt_obj_cnt = 0; // keep count of activated bloodspurts // init static filmstrip applet/drawing environment vars FilmStrip.filmstrip_drawenvironvars(this, CANVAS_W, CANVAS_H, composite_graphics); // create filmstrip object array filmstrip_obj = new FilmStrip[TOTAL_FILMSTRIP_OBJS]; // instantiate filmstrip object // 1-2) frame_x/y, filmstrip location on screen // 3-4) frame_w/h, filmstrip frame width and height // 5) frame_total, total # of frames // 6) frame_fps, frames per second // 7) frame_loop, play once (false) or loop (true) for (idx = 0; idx < TOTAL_FILMSTRIP_OBJS; idx++) filmstrip_obj[idx] = new FilmStrip( 17, 16, 144, 112, tmp_frame_total[idx], tmp_filmstrip_fps[idx], true ); // psycho // init, array of frames to play filmstrip_obj[0].frame_array = new int[tmp_frame_total[0]]; // ^^ note: frames are sequenced by position in strip, i.e. {1,3,1,1} System.arraycopy(tmp_filmstrip_ary_1,0,filmstrip_obj[0].frame_array,0,tmp_frame_total[0]); //filmstrip_obj[0].frame_array = tmp_filmstrip_ary; // load filmstrip object image filmstrip_obj[0].load_filmstrip_img("psycho.gif"); // rear window filmstrip_obj[1].frame_array = new int[tmp_frame_total[1]]; System.arraycopy(tmp_filmstrip_ary_2,0,filmstrip_obj[1].frame_array,0,tmp_frame_total[1]); filmstrip_obj[1].load_filmstrip_img("rear_window.gif"); // north by northwest filmstrip_obj[2].frame_array = new int[tmp_frame_total[2]]; System.arraycopy(tmp_filmstrip_ary_3,0,filmstrip_obj[2].frame_array,0,tmp_frame_total[2]); filmstrip_obj[2].load_filmstrip_img("north_by_northwest.gif"); // vertigo filmstrip_obj[3].frame_array = new int[tmp_frame_total[3]]; System.arraycopy(tmp_filmstrip_ary_4,0,filmstrip_obj[3].frame_array,0,tmp_frame_total[3]); filmstrip_obj[3].load_filmstrip_img("vertigo.gif"); // the birds filmstrip_obj[4].frame_array = new int[tmp_frame_total[4]]; System.arraycopy(tmp_filmstrip_ary_5,0,filmstrip_obj[4].frame_array,0,tmp_frame_total[4]); filmstrip_obj[4].load_filmstrip_img("the_birds.gif"); // load images and media tracker img_tracker = new MediaTracker(this); // hitchcock's head imgs[IMG_IDX_HEAD] = getImage(getCodeBase(), "images/hitchcock_head.gif"); img_tracker.addImage(imgs[IMG_IDX_HEAD], 1); // hitchcock's eyes imgs[IMG_IDX_EYES] = getImage(getCodeBase(), "images/hitchcock_eyes.gif"); img_tracker.addImage(imgs[IMG_IDX_EYES], 2); // hitchcock's brain imgs[IMG_IDX_BRAIN] = getImage(getCodeBase(), "images/hitchcock_brain.gif"); img_tracker.addImage(imgs[IMG_IDX_BRAIN], 3); // hitchcock log imgs[IMG_IDX_LOGO] = getImage(getCodeBase(), "images/hitchcock_logo.gif"); img_tracker.addImage(imgs[IMG_IDX_LOGO], 4); // image locations // hitchcock's head head_left = HEAD_OFFSET_X; head_top = HEAD_OFFSET_Y; // hitchcock's eyes eyes_left = head_left + EYES_HEAD_OFFSET_X; eyes_top = head_top + EYES_HEAD_OFFSET_Y; // hitchcock's brain brain_left = head_left + BRAIN_HEAD_OFFSET_X; brain_top = head_top + BRAIN_HEAD_OFFSET_Y; // create polygons // filmstrip/brain polygon filmstrip_brain_poly = new Polygon(); filmstrip_brain_poly.addPoint(head_left + 103, head_top + 151); filmstrip_brain_poly.addPoint(head_left + 83, head_top + 98); filmstrip_brain_poly.addPoint(head_left + 86, head_top + 55); filmstrip_brain_poly.addPoint(head_left + 97, head_top + 30); filmstrip_brain_poly.addPoint(head_left + 169, head_top + 0); filmstrip_brain_poly.addPoint(head_left + 200, head_top + 5); filmstrip_brain_poly.addPoint(head_left + 240, head_top + 50); filmstrip_brain_poly.addPoint(head_left + 247, head_top + 112); filmstrip_brain_poly.addPoint(head_left + 235, head_top + 163); filmstrip_brain_poly.addPoint(head_left + 216, head_top + 193); filmstrip_brain_poly.addPoint(head_left + 192, head_top + 216); filmstrip_brain_poly.addPoint(head_left + 148, head_top + 192); filmstrip_brain_poly.addPoint(head_left + 116, head_top + 153); filmstrip_brain_poly.addPoint(head_left + 103, head_top + 151); // hitchcock's body (bust portrait poly)/bloodspurts bloodspurt_bust_poly = new Polygon(); bloodspurt_bust_poly.addPoint(head_left + 0, head_top + 298); bloodspurt_bust_poly.addPoint(head_left + 0, head_top + 285); bloodspurt_bust_poly.addPoint(head_left + 7, head_top + 263); bloodspurt_bust_poly.addPoint(head_left + 19, head_top + 237); bloodspurt_bust_poly.addPoint(head_left + 78, head_top + 191); bloodspurt_bust_poly.addPoint(head_left + 78, head_top + 185); bloodspurt_bust_poly.addPoint(head_left + 102, head_top + 163); bloodspurt_bust_poly.addPoint(head_left + 103, head_top + 151); bloodspurt_bust_poly.addPoint(head_left + 116, head_top + 153); bloodspurt_bust_poly.addPoint(head_left + 148, head_top + 192); bloodspurt_bust_poly.addPoint(head_left + 192, head_top + 216); bloodspurt_bust_poly.addPoint(head_left + 216, head_top + 193); bloodspurt_bust_poly.addPoint(head_left + 216, head_top + 209); bloodspurt_bust_poly.addPoint(head_left + 232, head_top + 225); bloodspurt_bust_poly.addPoint(head_left + 256, head_top + 229); bloodspurt_bust_poly.addPoint(head_left + 256, head_top + 235); bloodspurt_bust_poly.addPoint(head_left + 273, head_top + 240); bloodspurt_bust_poly.addPoint(head_left + 307, head_top + 260); bloodspurt_bust_poly.addPoint(head_left + 324, head_top + 299); bloodspurt_bust_poly.addPoint(head_left + 0, head_top + 298); // brain status flg (1= expand/0= contract) brainstatus_flg = -1; // -1 = not expanding or contracting brainanm_frame = 1; // brain frame (total 6 frame anim) // 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= center; 1= left; 2= right; 3= up; 4= down force_gaze_flg = 0; // force gaze= 1, e.g. during Hitch logo anim gaze_time = System.currentTimeMillis() + ((long) (Math.round(Math.random() * 6000) + 4000) ); // set eye gaze every 4000 - 10000 miliseconds // init logo flag logo_flg = false; // initially hidden // init (random position within window) logo, horiz/vert coords hrz_logo_coord = (int) ( Math.round(Math.random() * (CANVAS_W - LOGO_W)) ); vrt_logo_coord = (int) ( Math.round(Math.random() * (CANVAS_H - LOGO_H)) ); // init logo, horiz/vert (random up-down/right-left) direction flags hrz_logo_direction = (int) ( Math.round(Math.random() * 2) ); vrt_logo_direction = (int) ( Math.round(Math.random() * 2) ); // image load leader dots (animate 1 to 5 dots) img_load_anm_dots = 1; dots_update_time = System.currentTimeMillis() + DOTS_FPS; // leader dots fps update time // filmstrip filmstrip_idx = 0; // ^^ 0= psycho; 1= rear window; 2= north by northwest; 3= vertigo; 4= the birds filmstrip_play_flg = false; // true= filmstrip is playing // expand/contract filmstrip frame filmstrip_w_h = new int[6][2]; filmstrip_w_h[0][0] = 28; filmstrip_w_h[0][1] = 22; filmstrip_w_h[1][0] = 56; filmstrip_w_h[1][1] = 44; filmstrip_w_h[2][0] = 84; filmstrip_w_h[2][1] = 66; filmstrip_w_h[3][0] = 112; filmstrip_w_h[3][1] = 88; filmstrip_w_h[4][0] = 144; filmstrip_w_h[4][1] = 112; filmstrip_w_h[5][0] = 144; filmstrip_w_h[5][1] = 112; // 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 applet graphics and offscreen graphics context/ composite buffer applet_graphics.dispose(); applet_graphics = null; 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 paint_flg = 0; int logo_center_x, logo_center_y; while ( anim_thread == Thread.currentThread() ) { // anim timers // squiggle: // hitchcock if (System.currentTimeMillis() >= hitch_squiggle_delay) { // squiggle flag if (hitch_squiggle_flg == 1) hitch_squiggle_flg = 0; // 0/1, 2 frame squiggle anim else hitch_squiggle_flg = 1; hitch_squiggle_delay = System.currentTimeMillis() + HITCH_FPS; // squiggle anim, 10 fps // flag paint paint_flg = 1; } // logo if (System.currentTimeMillis() >= logo_squiggle_delay) { if (logo_squiggle_flg == 1) logo_squiggle_flg = 0; // 0/1, 2 frame squiggle anim else logo_squiggle_flg = 1; logo_squiggle_delay = System.currentTimeMillis() + LOGO_FPS; // flag paint paint_flg = 1; } // eyes blink update // blink if ( (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; // debug: report blink //System.out.println("BLINK"); } // 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; } // gaze-- eyes open, left (1), center (0) or right (2) // note: adjust gaze regardless of whether eyes are open or closed if (force_gaze_flg == 0) { // left or right ? if ( (gaze_flg == 0) && (System.currentTimeMillis() >= gaze_time) ) { // random gaze_flg = ((int) (Math.random() * 2)) + 1; // hold eyes gazing left or right (before returning center) 1000 - 3000 miliseconds gaze_delay = System.currentTimeMillis() + ((long) ((Math.random() * 3001) + 1000)); } // return eyes center ? else if ( (gaze_flg > 0) && (System.currentTimeMillis() >= gaze_delay) ) { gaze_flg = 0; gaze_time = System.currentTimeMillis() + ((long) ((Math.random() * 6001) + 4000)); // eyes gaze left or right every 4000 - 10000 miliseconds } } // force gaze based on logo direction // up | right // ---------- // left | down else if ( (force_gaze_flg == 1) && (filmstrip_play_flg == false) ) { // calculate logo center point logo_center_x = hrz_logo_coord + (LOGO_W / 2); logo_center_y = vrt_logo_coord + (LOGO_H / 2); // gaze_flg: 0= center; 1= left; 2= right; 3= up; 4= down gaze_flg = 0; // default (in case we missed a combo below) if ( (logo_center_x <= (CANVAS_W/ 2)) && (logo_center_y <= (CANVAS_H/ 2)) ) gaze_flg = 3; else if ( (logo_center_x > (CANVAS_W/ 2)) && (logo_center_y <= (CANVAS_H/ 2)) ) gaze_flg = 2; else if ( (logo_center_x <= (CANVAS_H/ 2)) && (logo_center_y > (CANVAS_W/ 2)) ) gaze_flg = 1; else if ( (logo_center_x > (CANVAS_H/ 2)) && (logo_center_y > (CANVAS_W/ 2)) ) gaze_flg = 4; } // 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 tmp_filmstrip_idx; if ( !init_flg ) return true; // return immediately if we're not done initializing // filmstrip if ( filmstrip_brain_poly.inside(x, y) ) { // brain expand/contract anim // brain status flg (1= expand/0= contract) brainstatus_flg = 1; // **note: account for a mouse down while brain anim is still contracting if ( (brainanm_frame > 1) && (brainanm_frame < 5) ) brainanm_frame = brainanm_frame + 1; // **see above note else brainanm_frame = 1; // first brain frame // expand/contract anim delay brainanm_delay = System.currentTimeMillis() + BRAINANM_DELAY; // pick a film (don't pick the same film 2x's in a row) tmp_filmstrip_idx = (int) Math.round(Math.random() * (TOTAL_FILMSTRIP_OBJS - 1)); while (tmp_filmstrip_idx == filmstrip_idx) tmp_filmstrip_idx = (int) Math.round(Math.random() * (TOTAL_FILMSTRIP_OBJS - 1)); filmstrip_idx = tmp_filmstrip_idx; //System.out.println("filmstrip_idx: " + filmstrip_idx); // debug: report filmstrip_idx // play start filmstrip_obj[filmstrip_idx].start_stop_filmstrip(true); // filmstrip play flag filmstrip_play_flg = true; // true= filmstrip is playing gaze_flg = 3; // gaze: 0= center; 1= left; 2= right; 3= up; 4= down force_gaze_flg = 1; // force gaze= 1, e.g. during Hitch logo anim, filmstrip playing, etc. } // activate blood spurt else if ( (bloodspurt_obj_cnt < TOTAL_BLOODSPURT_OBJS) && bloodspurt_bust_poly.inside(x, y) ) { bloodspurt_obj[bloodspurt_obj_cnt].activate_bloodspurt(x, y); bloodspurt_obj_cnt++; // inc (keep count of activated blood spurts) } return true; } // end method 'mouseDown()' // 'mouseUp()' // called when the mouse button comes back up public boolean mouseUp(Event evt, int x, int y) { if ( !init_flg ) return true; // return immediately if we're not done initializing // filmstrip stop if ( filmstrip_obj[filmstrip_idx].play_flg == true ) { // brain expand/contract anim // brain status flg (1= expand/0= contract) brainstatus_flg = 0; // start contracting immediately if ( (brainanm_frame > 1) && (brainanm_frame < 5) ) brainanm_frame = brainanm_frame - 1; // brain frame else if (brainanm_frame >= 5) brainanm_frame = 4; // expand/contract anim delay brainanm_delay = System.currentTimeMillis() + BRAINANM_DELAY; } return true; } // end method 'mouseUp()' // 'keyDown()' public boolean keyDown(Event evt, int key) { int idx; // debug: report key code //System.out.println("key: " + key); // on "space bar" down clear all blood spurts (re-init) if (key == 32) { for (idx = 0; idx < TOTAL_BLOODSPURT_OBJS; idx++) bloodspurt_obj[idx].reset_bloodspurt(); // reset blood spurts object // reset/re-init all of the following: bloodspurt_obj_cnt = 0; // reset count, total number of blood spurts } // show/hide logo // '/' '?': down else if ( (key == 47) || (key == 63) ) { logo_flg = true; force_gaze_flg = 1; // force gaze= 1, e.g. during Hitch logo anim, filmstrip playing, etc. } // test: forced gaze // 'd' 'D': down //else if ( (key == 100) || (key == 68) ) { // gaze_flg = 4; // gaze: 0= center; 1= left; 2= right; 3= up; 4= down // force_gaze_flg = 1; //} return true; } // end method 'keyDown()' // 'keyUp()' public boolean keyUp(Event evt, int key) { // debug: report key code //System.out.println("keyUp: " + key); // 'm'/'M' hide filmstrip mask (clip region) //if ( (key == 109) || (key == 77) ) // filmstrip_obj[0].show_hide_filmstrip_mask(true); // hide logo logo_flg = false; // release forced gaze // note: if 'filmstrip_play_flg' true= filmstrip is playing if ( filmstrip_play_flg == true ) gaze_flg = 3; // gaze: retain gaze eyes up else { gaze_flg = 0; // gaze: reset gaze eyes center and resume random gaze force_gaze_flg = 0; // unlock forced gaze gaze_time = System.currentTimeMillis() + ((long) (Math.round(Math.random() * 6000) + 4000) ); // set eye gaze every 4000 - 10000 miliseconds } return true; } // end method 'keyUp()' // '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 method, don't initiate another "paint" session until one's complete synchronized void my_paint(Graphics g) { int idx; String dots_str; boolean tmp_filmstrips_loaded_flg; // 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); // filmstrip mediatracker(s) tmp_filmstrips_loaded_flg = true; // assume all loaded for (idx = 0; idx < TOTAL_FILMSTRIP_OBJS; idx++) { if (! filmstrip_obj[idx].filmstrip_img_tracker.checkAll(true)) { tmp_filmstrips_loaded_flg = false; } } // have images loaded? if ( (! img_tracker.checkAll(true)) || (! BloodSpurt.bloodspurt_img_tracker.checkAll(true)) || (! tmp_filmstrips_loaded_flg) ) { //System.out.println("loading...."); // debug // 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); // build str and write to screen dots_str = "Loading Images"; for (idx = 1; idx <= img_load_anm_dots; idx++) dots_str = dots_str + "."; composite_graphics.drawString(dots_str, 25, 25); // image load leader dots (animate 1 to 5 dots) if ( System.currentTimeMillis() >= dots_update_time ) { if (img_load_anm_dots < 5) img_load_anm_dots++; else img_load_anm_dots = 1; dots_update_time = System.currentTimeMillis() + DOTS_FPS; } } else { int tmp_idx = brainanm_frame - 1; // filmstrip expand/contract w/h array idx // draw hitchcock's head draw_hitchcock_head(); // crank film strip projector filmstrip_obj[filmstrip_idx].crank_filmstrip_projector(filmstrip_w_h[tmp_idx][0], filmstrip_w_h[tmp_idx][1]); // draw hitchcock's brain if ( filmstrip_obj[filmstrip_idx].play_flg == true ) draw_hitchcock_brain(); // draw hitchcock logo if (logo_flg) draw_hitchcock_logo(); // draw blood blood spurt(s) for (idx = 0; idx < TOTAL_BLOODSPURT_OBJS; idx++) if (bloodspurt_obj[idx].active_flg) bloodspurt_obj[idx].draw_bloodspurt(); } // black border composite_graphics.setColor(Color.black); composite_graphics.drawRect(0, 0, (CANVAS_W - 1), (CANVAS_H - 1)); // debug: poly test/draw outline /* composite_graphics.setColor(Color.green); composite_graphics.drawPolygon(filmstrip_brain_poly); composite_graphics.setColor(Color.yellow); composite_graphics.drawPolygon(bloodspurt_bust_poly); composite_graphics.setColor(Color.black); */ // blast composite buffer to screen g.drawImage(composite_image, 0, 0, null); } // end method 'my_paint()' // draw hitchcock's head void draw_hitchcock_head() { int y_offset; Graphics clip_g = null; // clip/crop // head clip_g = composite_graphics.create(); // create clip clip_g.clipRect(head_left, head_top, HEAD_W, HEAD_H); // clip // squiggle if (hitch_squiggle_flg == 0) y_offset = 0; else y_offset = HEAD_H; clip_g.drawImage(imgs[IMG_IDX_HEAD], head_left, head_top - y_offset, this); // draw clip_g.dispose(); // dispose clip // eyes clip_g = composite_graphics.create(); // create clip clip_g.clipRect( eyes_left, eyes_top, EYES_W, EYES_H ); // clip // squiggle if (hitch_squiggle_flg == 0) y_offset = 0; else y_offset = (EYES_H * 6); // blink/eyes closed? if (eyesstatus_flg == 0) y_offset = y_offset + (EYES_H * 5); // adjust gaze else y_offset = y_offset + (EYES_H * gaze_flg); clip_g.drawImage(imgs[IMG_IDX_EYES], eyes_left, eyes_top - y_offset, this); // draw clip_g.dispose(); // dispose clip // test: //composite_graphics.drawImage(imgs[IMG_IDX_BRAIN], brain_left, brain_top - y_offset, this); } // end method 'draw_hitchcock_head()' // draw hitchcock's brain void draw_hitchcock_brain() { int y_offset; Graphics clip_g = null; // clip/crop // brain // shut down anm? if ( (brainstatus_flg == 0) && (brainanm_frame == 1) && (System.currentTimeMillis() >= brainanm_delay) ) { filmstrip_obj[filmstrip_idx].start_stop_filmstrip(false); // play stop // filmstrip play flag filmstrip_play_flg = false; // true= filmstrip is playing // flag, neither expanding or contracting brainstatus_flg = -1; force_gaze_flg = 0; // release force gaze= 0 } else { // select frame if (System.currentTimeMillis() >= brainanm_delay) { if ( (brainstatus_flg == 1) && (brainanm_frame < 5) ) { brainanm_frame++; //System.out.println("expanding...."); // debug // reset expand/contract anim delay brainanm_delay = System.currentTimeMillis() + BRAINANM_DELAY; } else if ( (brainstatus_flg == 0) && (brainanm_frame > 1) ) { brainanm_frame--; //System.out.println("contracting...."); // debug brainanm_delay = System.currentTimeMillis() + BRAINANM_DELAY; } } // squiggle if ( (System.currentTimeMillis() >= brainanm_delay) && (brainanm_frame >= 5) ) { if (brainanm_frame == 5) brainanm_frame = 6; else brainanm_frame = 5; brainanm_delay = System.currentTimeMillis() + BRAINANM_DELAY; } y_offset = BRAIN_H * (brainanm_frame - 1); // create clip clip_g = composite_graphics.create(); clip_g.clipRect( brain_left, brain_top, BRAIN_W, BRAIN_H ); // clip // draw clip_g.drawImage(imgs[IMG_IDX_BRAIN], brain_left, brain_top - y_offset, this); clip_g.dispose(); // dispose clip } } // end method 'draw_hitchcock_brain()' // draw hitchcock logo void draw_hitchcock_logo() { int y_offset; Graphics clip_g = null; // clip/crop // create clip clip_g = composite_graphics.create(); clip_g.clipRect(hrz_logo_coord, vrt_logo_coord, LOGO_W, LOGO_H); // clip // squiggle y_offset = 0; if (logo_squiggle_flg == 1) y_offset = LOGO_H; clip_g.drawImage(imgs[IMG_IDX_LOGO], hrz_logo_coord, vrt_logo_coord - y_offset, this); // draw clip_g.dispose(); // dispose clip // change horiz direction (?) if ( (hrz_logo_coord + LOGO_W) >= (CANVAS_W - 1) ) hrz_logo_direction = LOGO_MOVE_LEFT; else if (hrz_logo_coord <= 1) hrz_logo_direction = LOGO_MOVE_RIGHT; // change vert direction (?) if ( (vrt_logo_coord + LOGO_H) >= (CANVAS_H - 1) ) vrt_logo_direction = LOGO_MOVE_UP; else if (vrt_logo_coord <= 1) vrt_logo_direction = LOGO_MOVE_DOWN; // adjust logo horiz/vert coords if (hrz_logo_direction == LOGO_MOVE_RIGHT) hrz_logo_coord = hrz_logo_coord + 2; else hrz_logo_coord = hrz_logo_coord - 2; if (vrt_logo_direction == LOGO_MOVE_DOWN) vrt_logo_coord = vrt_logo_coord + 2; else vrt_logo_coord = vrt_logo_coord - 2; } // end method 'draw_hitchcock_logo()' } // end class "psycho_hitchcock"