// Eliminator music instrument game // copyright 2008 Les Hall // this software is protected by the GNU General Public License // parameters 1200 => int screen_width; // width of screen 800 => int screen_height; // height of screen 32 => int screen_res_x; // width of screen in LEDs 12 => int screen_res_y; // height of screen in LEDs 30 => int led_size_x; // width of LEDs 30 => int led_size_y; // height of LEDs 4096 => int num_fft_samples; // size of FFT 4 => float frame_rate; // frames per second 0.1 => float fft_scale; // scales the FFT to full value num_fft_samples / 256 => int fft_offset; // lower frequencies to ignore 1.010 => float speedup_multiplier; // time constant for enemy speedup 0.010 => float enemy_speed; // rate of descent of enemies in screens per second 200 => int button_width; // width of buttons 75 => int button_height; // height of buttons // variables int exit; // 1 when it's time to exit the game num_fft_samples / 2 => int num_fft_freqs; // number of frequencies in FFT float spectrum[num_fft_freqs]; // the FFT spectrum Event frame; // fires once every frame int display[screen_res_x][screen_res_y]; // colors of LEDs float eliminator_position[screen_res_x]; // how far up the eliminators are float enemy_position[screen_res_x]; // how far down the enemies are float column_status[screen_res_x]; // 1 if column is destroyed // class instantiations screen Screen; scoreboard ScoreBoard; fourier Fourier; gameplay GamePlay; endgame EndGame; // time loop while (true) { // wait for next frame frame => now; // perform the gameplay GamePlay.adjust_positions (); GamePlay.annihilate (); GamePlay.destructify (); GamePlay.speedup (); // draw the display Screen.clear_display (); Screen.put_eliminators (); Screen.put_enemies (); Screen.draw (); // check to see if game is over GamePlay.gameover (); // end program if exit is one if (exit > 0) { break; } } // cleanup ScoreBoard.stop_score_update (); if (exit == 1) { EndGame.message (); } ScoreBoard.close (); Screen.close (); // class to exit the game class endgame { // function to display exit message fun void message () { // the screen window MAUI_View endgame_view; endgame_view.size (button_width, button_height); endgame_view.name ("Game Over"); endgame_view.display (); // The exit button MAUI_Button button_exit; button_exit.pushType (); button_exit.size (button_width, button_height); button_exit.position (0, 0); button_exit.name ("Exit"); endgame_view.addElement (button_exit); // wait for exit button to be pressed button_exit.onChange () => now; // destroy the exit window endgame_view.destroy (); } } // class to implement gameplay class gameplay { // function to adjust positions fun void adjust_positions () { for (0 => int x; x < screen_res_x; x++) { spectrum[x + fft_offset] / fft_scale => eliminator_position[x]; enemy_speed / frame_rate +=> enemy_position[x]; } } // function to annihilate eliminators with enemies fun void annihilate () { for (0 => int x; x < screen_res_x; x++) { eliminator_position[x] => float temp; if (temp > 1) { 1 => temp; } temp - (1 - enemy_position[x]) => float overlap; if (overlap > 0) { if (overlap > temp) { temp => overlap; } overlap -=> enemy_position[x]; } } } // function to destroy columns where enemies have reached bottom of screen fun void destructify () { for (0 => int x; x < screen_res_x; x++) { if ( (enemy_position[x] > 1.0 - 1.0 / (screen_res_y $ float) ) & (column_status[x] == 0) ) { 1 => column_status[x]; Screen.destructify (x); } } } // function to advance enemy speed fun void speedup () { speedup_multiplier *=> enemy_speed; } // function to determine if game is over fun void gameover () { int sum; 0 => sum; for (0 => int x; x < screen_res_x; x++) { if (column_status[x] == 1) { 1 +=> sum; } } if (sum == screen_res_x) { 1 => exit; } } } // class to perform FFT class fourier { // the patch adc => FFT fft => blackhole; // the patch parameters num_fft_samples => fft.size; Windowing.hamming(num_fft_samples) => fft.window; // shred to perform FFT spork ~ do_fft (); fun void do_fft () { while (true) { fft.upchuck ().fvals () @=> spectrum; frame.broadcast (); second / frame_rate => now; } } } // class to draw scoreboard class scoreboard { // variables int player_score; // score of the player time start_time; // starting time of game int shred_id; // shred id for updatescore function now => start_time; // the screen window MAUI_View scoreboard_view; scoreboard_view.size (button_width, 2 * button_height); scoreboard_view.position (screen_width / 2 - screen_res_x * led_size_x / 2 - button_width - 25, screen_height - (2 * button_height + 25) ); scoreboard_view.name ("Eliminator ScoreBoard"); scoreboard_view.display (); // The score button MAUI_Button button_score; button_score.pushType (); button_score.size (button_width, button_height); button_score.position (0, 0); button_score.name ("Score: " + player_score); scoreboard_view.addElement (button_score); // The exit button MAUI_Button button_exit; button_exit.pushType (); button_exit.size (button_width, button_height); button_exit.position (0, button_height); button_exit.name ("Exit Game"); scoreboard_view.addElement (button_exit); // shred to update the scoreboard spork ~ updatescore (); fun void updatescore () { me.id () => shred_id; while (true) { ( (now - start_time) / second) $ int => player_score; button_score.name ("Score:" + player_score); second => now; } } // shred to watch exit button spork ~ exit_button_watcher (); fun void exit_button_watcher () { button_exit.onChange () => now; 2 => exit; } // function to stop the scorekeeping fun void stop_score_update () { Machine.remove (shred_id); } // function to destroy the scoreboard_view window fun void close () { scoreboard_view.destroy (); } } // class to draw screen class screen { // the screen window MAUI_View screen_view; screen_view.size (screen_res_x * led_size_x, screen_res_y * led_size_y); screen_view.position (screen_width / 2 - screen_res_x * led_size_x / 2, screen_height / 2 - screen_res_y * led_size_y / 2 ); screen_view.name ("Eliminator Music Game"); screen_view.display (); // the LED matrix MAUI_LED led[screen_res_x][screen_res_y]; for (0 => int x; x < screen_res_x; x++) { for (0 => int y; y < screen_res_y; y++) { led[x][y].size (led_size_x, led_size_y); led[x][y].position (x * led_size_x, (screen_res_y -1 - y) * led_size_y); led[x][y].unlight (); screen_view.addElement (led[x][y]); } } // function to clear display fun void clear_display () { for (0 => int x; x < screen_res_x; x++) { for (0 => int y; y < screen_res_y; y++) { 0 => display[x][y]; } } } // function to put eliminators on display fun void put_eliminators () { for (0 => int x; x < screen_res_x; x++) { (screen_res_y * eliminator_position[x]) $ int - 1 => int y_pos; if (y_pos >= screen_res_y) { screen_res_y - 1 => y_pos; } if (y_pos >= 0) { 2 => display[x][y_pos]; } } } // function to put enemies on display fun void put_enemies () { for (0 => int x; x < screen_res_x; x++) { (screen_res_y * (1 - enemy_position[x]) ) $ int => int y_pos; if (y_pos >= screen_res_y) { screen_res_y - 1 => y_pos; } if (y_pos >= 0) { 1 => display[x][y_pos]; } } } // function to draw input spectrum fun void draw () { for (0 => int x; x < screen_res_x; x++) { if (column_status[x] == 0) { for (0 => int y; y < screen_res_y; y++) { if (display[x][y] == 0) { led[x][y].unlight (); } if (display[x][y] == 1) { led[x][y].color (led[x][y].red); led[x][y].light (); } if (display[x][y] == 2) { led[x][y].color (led[x][y].green); led[x][y].light (); } } } } } // function to destructify a column fun void destructify (int x) { for (0 => int y; y < screen_res_y; y++) { 3 => display[x][y]; led[x][y].color (led[x][y].blue); led[x][y].light (); } } // function to destroy the screen window fun void close () { screen_view.destroy (); } }