From e5f7e1ba844285df620a5aecbca1ec984c3b21a4 Mon Sep 17 00:00:00 2001 From: Phew Date: Sat, 20 Dec 2025 10:48:05 +0100 Subject: [PATCH] Code cleanup, fixed compilation error and added button based joystick as default --- TWANG32/TWANG32.ino | 1290 ++++++++++++++++++++++--------------------- 1 file changed, 661 insertions(+), 629 deletions(-) diff --git a/TWANG32/TWANG32.ino b/TWANG32/TWANG32.ino index 627eb55..74a3c7c 100644 --- a/TWANG32/TWANG32.ino +++ b/TWANG32/TWANG32.ino @@ -1,57 +1,59 @@ /* - TWANG32 - An ESP32 port of TWANG - (c) B. Dring 3/2018 - License: Creative Commons 4.0 Attribution - Share Alike - - TWANG was originally created by Critters - https://github.com/Critters/TWANG - - It was inspired by Robin Baumgarten's Line Wobbler Game - - Recent Changes - - Updated to move FastLEDshow to core 0 - Fixed Neopixel - - Used latest FastLED library..added compile check - - Updated to move FastLEDshow to core 0 - - Reduced MAX_LEDS on Neopixel - - Move some defines to a separate config.h file to make them accessible to other files - - Changed volume typo on serial port settings menu + TWANG32 - An ESP32 port of TWANG + (c) B. Dring 3/2018 + License: Creative Commons 4.0 Attribution - Share Alike - Project TODO - - Make the strip type configurable via serial and wifi - - - Usage Notes: - - Changes to LED strip and other hardware are in config.h - - Change the strip type to what you are using and compile/load firmware - - Use Serial port or Wifi to set your strip length. + TWANG was originally created by Critters + https://github.com/Critters/TWANG + + It was inspired by Robin Baumgarten's Line Wobbler Game + + Recent Changes + - Updated to move FastLEDshow to core 0 + Fixed Neopixel + - Used latest FastLED library..added compile check + - Updated to move FastLEDshow to core 0 + - Reduced MAX_LEDS on Neopixel + - Move some defines to a separate config.h file to make them accessible to other files + - Changed volume typo on serial port settings menu + + Project TODO + - Make the strip type configurable via serial and wifi + + + Usage Notes: + - Changes to LED strip and other hardware are in config.h + - Change the strip type to what you are using and compile/load firmware + - Use Serial port or Wifi to set your strip length. */ -// +// #define VERSION "2018-06-28" #include -#include +#include #include "Arduino.h" #include "RunningMedian.h" // twang files #include "config.h" +#ifdef USE_GYRO_JOYSTICK #include "twang_mpu.h" -#include "enemy.h" -#include "particle.h" -#include "spawner.h" -#include "lava.h" -#include "boss.h" -#include "conveyor.h" +#endif +#include "Enemy.h" +#include "Particle.h" +#include "Spawner.h" +#include "Lava.h" +#include "Boss.h" +#include "Conveyor.h" #include "iSin.h" #include "sound.h" #include "settings.h" #include "wifi_ap.h" #if defined(FASTLED_VERSION) && (FASTLED_VERSION < 3001000) - #error "Requires FastLED 3.1 or later; check github for latest code." + #error "Requires FastLED 3.1 or later; check github for latest code." #endif @@ -71,13 +73,13 @@ int joystickWobble = 0; // Stores the max amount of acceleration (wob // WOBBLE ATTACK #define DEFAULT_ATTACK_WIDTH 70 // Width of the wobble attack, world is 1000 wide -int attack_width = DEFAULT_ATTACK_WIDTH; +int attack_width = DEFAULT_ATTACK_WIDTH; #define ATTACK_DURATION 500 // Duration of a wobble attack (ms) long attackMillis = 0; // Time the attack started -bool attacking = 0; // Is the attack in progress? +bool attacking = 0; // Is the attack in progress? #define BOSS_WIDTH 40 -// TODO all animation durations should be defined rather than literals +// TODO all animation durations should be defined rather than literals // because they are used in main loop and some sounds too. #define STARTUP_WIPEUP_DUR 200 #define STARTUP_SPARKLE_DUR 1300 @@ -90,7 +92,9 @@ bool attacking = 0; // Is the attack in progress? #define WIN_CLEAR_DURATION 1000 #define WIN_OFF_DURATION 1200 +#ifdef USE_GYRO_JOYSTICK Twang_MPU accelgyro = Twang_MPU(); +#endif CRGB leds[VIRTUAL_LED_COUNT]; RunningMedian MPUAngleSamples = RunningMedian(5); RunningMedian MPUWobbleSamples = RunningMedian(5); @@ -131,13 +135,13 @@ Conveyor conveyorPool[CONVEYOR_COUNT] = { Boss boss = Boss(); enum stages { - STARTUP, - PLAY, - WIN, - DEAD, - SCREENSAVER, - BOSS_KILLED, - GAMEOVER + STARTUP, + PLAY, + WIN, + DEAD, + SCREENSAVER, + BOSS_KILLED, + GAMEOVER } stage; long stageStartTime; // Stores the time the stage changed for stages that are time based @@ -145,7 +149,7 @@ int playerPosition; // Stores the player position int playerPositionModifier; // +/- adjustment to player position bool playerAlive; long killTime; -int lives = LIVES_PER_LEVEL; +int lives = LIVES_PER_LEVEL; bool lastLevel = false; int score = 0; @@ -157,7 +161,7 @@ static TaskHandle_t FastLEDshowTaskHandle = 0; static TaskHandle_t userTaskHandle = 0; /** show() for ESP32 - * Call this function instead of FastLED.show(). It signals core 0 to issue a show, + * Call this function instead of FastLED.show(). It signals core 0 to issue a show, * then waits for a notification that it is done. */ void FastLEDshowESP32() @@ -197,44 +201,52 @@ void FastLEDshowTask(void *pvParameters) void setup() { - Serial.begin(115200); - Serial.print("\r\nTWANG32 VERSION: "); Serial.println(VERSION); - - settings_init(); // load the user settings from EEPROM - - Wire.begin(); - accelgyro.initialize(); - + Serial.begin(115200); + Serial.print("\r\nTWANG32 VERSION: "); Serial.println(VERSION); + + settings_init(); // load the user settings from EEPROM + + Wire.begin(); +#ifdef USE_GYRO_JOYSTICK + accelgyro.initialize(); +#endif + #ifdef USE_NEOPIXEL - Serial.print("\r\nCompiled for WS2812B (Neopixel) LEDs"); - FastLED.addLeds(leds, MAX_LEDS); + Serial.print("\r\nCompiled for WS2812B (Neopixel) LEDs"); + FastLED.addLeds(leds, MAX_LEDS); #endif #ifdef USE_APA102 - Serial.print("\r\nCompiled for APA102 (Dotstar) LEDs"); - FastLED.addLeds(leds, MAX_LEDS); + Serial.print("\r\nCompiled for APA102 (Dotstar) LEDs"); + FastLED.addLeds(leds, MAX_LEDS); #endif - - FastLED.setBrightness(user_settings.led_brightness); - FastLED.setDither(1); - - // -- Create the ESP32 FastLED show task - xTaskCreatePinnedToCore(FastLEDshowTask, "FastLEDshowTask", 2048, NULL, 2, &FastLEDshowTaskHandle, FASTLED_SHOW_CORE); - sound_init(DAC_AUDIO_PIN); - - ap_setup(); + FastLED.setBrightness(user_settings.led_brightness); + FastLED.setDither(1); - stage = STARTUP; - stageStartTime = millis(); - lives = user_settings.lives_per_level; - + // -- Create the ESP32 FastLED show task + xTaskCreatePinnedToCore(FastLEDshowTask, "FastLEDshowTask", 2048, NULL, 2, &FastLEDshowTaskHandle, FASTLED_SHOW_CORE); + + sound_init(DAC_AUDIO_PIN); + +#ifndef USE_GYRO_JOYSTICK + pinMode(upButtonPinNumber, INPUT_PULLUP); + pinMode(downButtonPinNumber, INPUT_PULLUP); + pinMode(leftButtonPinNumber, INPUT_PULLUP); + pinMode(rightButtonPinNumber, INPUT_PULLUP); +#endif + + ap_setup(); + + stage = STARTUP; + stageStartTime = millis(); + lives = user_settings.lives_per_level; } void loop() { long mm = millis(); - int brightness = 0; - + int brightness = 0; + ap_client_check(); // check for web client checkSerialInput(); @@ -243,18 +255,16 @@ void loop() { SFXattacking(); }else{ SFXtilt(joystickTilt); - - } }else if(stage == DEAD){ SFXdead(); } if (mm - previousMillis >= MIN_REDRAW_INTERVAL) { - getInput(); + getInput(); + + - - long frameTimer = mm; previousMillis = mm; @@ -266,26 +276,26 @@ void loop() { stage = WIN; } }else{ - if(lastInputTime+TIMEOUT < mm){ + if(lastInputTime+TIMEOUT < mm){ stage = SCREENSAVER; } } - + if(stage == SCREENSAVER){ - screenSaverTick(); + screenSaverTick(); }else if(stage == STARTUP){ - if (stageStartTime+STARTUP_FADE_DUR > mm) { - tickStartup(mm); - } - else - { - SFXcomplete(); - levelNumber = 0; - loadLevel(); - } - }else if(stage == PLAY){ + if (stageStartTime+STARTUP_FADE_DUR > mm) { + tickStartup(mm); + } + else + { + SFXcomplete(); + levelNumber = 0; + loadLevel(); + } + }else if(stage == PLAY){ // PLAYING if(attacking && attackMillis+ATTACK_DURATION < mm) attacking = 0; @@ -298,20 +308,20 @@ void loop() { // If still not attacking, move! playerPosition += playerPositionModifier; if(!attacking){ - SFXtilt(joystickTilt); + SFXtilt(joystickTilt); //int moveAmount = (joystickTilt/6.0); // 6.0 is ideal at 16ms interval (6.0 / (16.0 / MIN_REDRAW_INTERVAL)) - int moveAmount = (joystickTilt/(6.0)); // 6.0 is ideal at 16ms interval + int moveAmount = (joystickTilt/(6.0)); // 6.0 is ideal at 16ms interval if(DIRECTION) moveAmount = -moveAmount; moveAmount = constrain(moveAmount, -MAX_PLAYER_SPEED, MAX_PLAYER_SPEED); - + playerPosition -= moveAmount; - if(playerPosition < 0) - playerPosition = 0; - - // stop player from leaving if boss is alive - if (boss.Alive() && playerPosition >= VIRTUAL_LED_COUNT) // move player back - playerPosition = 999; //(user_settings.led_count - 1) * (1000.0/user_settings.led_count); - + if(playerPosition < 0) + playerPosition = 0; + + // stop player from leaving if boss is alive + if (boss.Alive() && playerPosition >= VIRTUAL_LED_COUNT) // move player back + playerPosition = 999; //(user_settings.led_count - 1) * (1000.0/user_settings.led_count); + if(playerPosition >= VIRTUAL_LED_COUNT && !boss.Alive()) { // Reached exit! levelComplete(); @@ -330,266 +340,259 @@ void loop() { tickBoss(); tickLava(); tickEnemies(); - drawPlayer(); + drawPlayer(); drawAttack(); drawExit(); }else if(stage == DEAD){ // DEAD FastLED.clear(); - tickDie(mm); + tickDie(mm); if(!tickParticles()){ loadLevel(); } }else if(stage == WIN){ - // LEVEL COMPLETE + // LEVEL COMPLETE tickWin(mm); }else if(stage == BOSS_KILLED){ - tickBossKilled(mm); - } else if (stage == GAMEOVER) { - if (stageStartTime+GAMEOVER_FADE_DURATION > mm) - { - tickGameover(mm); - } - else - { - FastLED.clear(); - save_game_stats(false); // boss not killed - - // restart from the beginning - stage = STARTUP; - stageStartTime = millis(); - lives = user_settings.lives_per_level; - - } - } + tickBossKilled(mm); + } else if (stage == GAMEOVER) { + if (stageStartTime+GAMEOVER_FADE_DURATION > mm) + { + tickGameover(mm); + } else { + FastLED.clear(); + save_game_stats(false); // boss not killed - //FastLED.show(); - FastLEDshowESP32(); - - } - - + // restart from the beginning + stage = STARTUP; + stageStartTime = millis(); + lives = user_settings.lives_per_level; + } + } + //FastLED.show(); + FastLEDshowESP32(); + } } // --------------------------------- // ------------ LEVELS ------------- // --------------------------------- -void loadLevel(){ - // leave these alone - FastLED.setBrightness(user_settings.led_brightness); - updateLives(); - cleanupLevel(); - playerAlive = 1; - lastLevel = false; // this gets changed on the boss level - - /// Defaults...OK to change the following items in the levels below - attack_width = DEFAULT_ATTACK_WIDTH; - playerPosition = 0; - - /* ==== Level Editing Guide =============== - Level creation is done by adding to or editing the switch statement below - - You can add as many levels as you want but you must have a "case" - for each level. The case numbers must start at 0 and go up without skipping any numbers. - - Don't edit case 0 or the last (boss) level. They are special cases and editing them could - break the code. - - TWANG uses a virtual 1000 LED grid. It will then scale that number to your strip, so if you - want something in the middle of your strip use the number 500. Consider the size of your strip - when adding features. All time values are specified in milliseconds (1/1000 of a second) - - You can add any of the following features. - - Enemies: You add up to 10 enemies with the spawnEnemy(...) functions. - spawnEnemy(position, direction, speed, wobble); - position: Where the enemy starts - direction: If it moves, what direction does it go 0=down, 1=away - speed: How fast does it move. Typically 1 to 4. - wobble: 0=regular movement, 1=bouncing back and forth use the speed value - to set the length of the wobble. - - Spawn Pools: This generates and endless source of new enemies. 2 pools max - spawnPool[index].Spawn(position, rate, speed, direction, activate); - index: You can have up to 2 pools, use an index of 0 for the first and 1 for the second. - position: The location the enemies with be generated from. - rate: The time in milliseconds between each new enemy - speed: How fast they move. Typically 1 to 4. - direction: Directions they go 0=down, 1=away - activate: The delay in milliseconds before the first enemy - - Lava: You can create 4 pools of lava. - spawnLava(left, right, ontime, offtime, offset, state, grow, flow); - left: the lower end of the lava pool - right: the upper end of the lava pool - ontime: How long the lave stays on. - offset: the delay before the first switch - state: does it start on or off - grow: This specifies the rate of growth. Use 0 for no growth. Reasonable growth is 0.1 to 0.5 - flow: This specifies the rate/direction of flow. Reasonable numbers are 0.2 to 0.8 - - Conveyor: You can create 2 conveyors. - spawnConveyor(startPoint, endPoint, direction) - startPoint: The close end of the conveyor - endPoint: The far end of the conveyor - direction(speed): positive = away, negative = towards you (must be less than +/- player speed) - - ===== Other things you can adjust per level ================ - - Player Start position: - playerPosition = xxx; - - - The size of the TWANG attack - attack_width = xxx; - - - */ - switch(levelNumber){ - case 0: // basic introduction - playerPosition = 200; - spawnEnemy(1, 0, 0, 0); - break; - case 1: - // Slow moving enemy - spawnEnemy(900, 0, 1, 0); - break; - case 2: - // Spawning enemies at exit every 2 seconds - spawnPool[0].Spawn(1000, 3000, 2, 0, 0); - break; - case 3: - // Lava intro - spawnLava(400, 490, 2000, 2000, 0, Lava::OFF, 0, 0); - spawnEnemy(350, 0, 1, 0); - spawnPool[0].Spawn(1000, 5500, 3, 0, 0); - break; - case 4: - // intro to moving lava (down) - spawnLava(400, 490, 2000, 2000, 0, Lava::OFF, 0, -0.5); - spawnEnemy(350, 0, 1, 0); - spawnPool[0].Spawn(1000, 5500, 3, 0, 0); - break; - case 5: - // lava spreading - spawnLava(400, 450, 2000, 2000, 0, Lava::OFF, 0.25, 0); - spawnEnemy(350, 0, 1, 0); - spawnPool[0].Spawn(1000, 5500, 3, 0, 0); - break; - case 6: - // Sin wave enemy - spawnEnemy(700, 1, 7, 275); - spawnEnemy(500, 1, 5, 250); - break; - case 7: - // Sin enemy swarm - spawnEnemy(700, 1, 7, 275); - spawnEnemy(500, 1, 5, 250); - - spawnEnemy(600, 1, 7, 200); - spawnEnemy(800, 1, 5, 350); - - spawnEnemy(400, 1, 7, 150); - spawnEnemy(450, 1, 5, 400); - break; +void loadLevel(){ + // leave these alone + FastLED.setBrightness(user_settings.led_brightness); + updateLives(); + cleanupLevel(); + playerAlive = 1; + lastLevel = false; // this gets changed on the boss level + + /// Defaults...OK to change the following items in the levels below + attack_width = DEFAULT_ATTACK_WIDTH; + playerPosition = 0; + + /* ==== Level Editing Guide =============== + Level creation is done by adding to or editing the switch statement below + + You can add as many levels as you want but you must have a "case" + for each level. The case numbers must start at 0 and go up without skipping any numbers. + + Don't edit case 0 or the last (boss) level. They are special cases and editing them could + break the code. + + TWANG uses a virtual 1000 LED grid. It will then scale that number to your strip, so if you + want something in the middle of your strip use the number 500. Consider the size of your strip + when adding features. All time values are specified in milliseconds (1/1000 of a second) + + You can add any of the following features. + + Enemies: You add up to 10 enemies with the spawnEnemy(...) functions. + spawnEnemy(position, direction, speed, wobble); + position: Where the enemy starts + direction: If it moves, what direction does it go 0=down, 1=away + speed: How fast does it move. Typically 1 to 4. + wobble: 0=regular movement, 1=bouncing back and forth use the speed value + to set the length of the wobble. + + Spawn Pools: This generates and endless source of new enemies. 2 pools max + spawnPool[index].Spawn(position, rate, speed, direction, activate); + index: You can have up to 2 pools, use an index of 0 for the first and 1 for the second. + position: The location the enemies with be generated from. + rate: The time in milliseconds between each new enemy + speed: How fast they move. Typically 1 to 4. + direction: Directions they go 0=down, 1=away + activate: The delay in milliseconds before the first enemy + + Lava: You can create 4 pools of lava. + spawnLava(left, right, ontime, offtime, offset, state, grow, flow); + left: the lower end of the lava pool + right: the upper end of the lava pool + ontime: How long the lave stays on. + offset: the delay before the first switch + state: does it start on or off + grow: This specifies the rate of growth. Use 0 for no growth. Reasonable growth is 0.1 to 0.5 + flow: This specifies the rate/direction of flow. Reasonable numbers are 0.2 to 0.8 + + Conveyor: You can create 2 conveyors. + spawnConveyor(startPoint, endPoint, direction) + startPoint: The close end of the conveyor + endPoint: The far end of the conveyor + direction(speed): positive = away, negative = towards you (must be less than +/- player speed) + + ===== Other things you can adjust per level ================ + + Player Start position: + playerPosition = xxx; + + + The size of the TWANG attack + attack_width = xxx; + + + */ + switch(levelNumber){ + case 0: // basic introduction + playerPosition = 200; + spawnEnemy(1, 0, 0, 0); + break; + case 1: + // Slow moving enemy + spawnEnemy(900, 0, 1, 0); + break; + case 2: + // Spawning enemies at exit every 2 seconds + spawnPool[0].Spawn(1000, 3000, 2, 0, 0); + break; + case 3: + // Lava intro + spawnLava(400, 490, 2000, 2000, 0, Lava::OFF, 0, 0); + spawnEnemy(350, 0, 1, 0); + spawnPool[0].Spawn(1000, 5500, 3, 0, 0); + break; + case 4: + // intro to moving lava (down) + spawnLava(400, 490, 2000, 2000, 0, Lava::OFF, 0, -0.5); + spawnEnemy(350, 0, 1, 0); + spawnPool[0].Spawn(1000, 5500, 3, 0, 0); + break; + case 5: + // lava spreading + spawnLava(400, 450, 2000, 2000, 0, Lava::OFF, 0.25, 0); + spawnEnemy(350, 0, 1, 0); + spawnPool[0].Spawn(1000, 5500, 3, 0, 0); + break; + case 6: + // Sin wave enemy + spawnEnemy(700, 1, 7, 275); + spawnEnemy(500, 1, 5, 250); + break; + case 7: + // Sin enemy swarm + spawnEnemy(700, 1, 7, 275); + spawnEnemy(500, 1, 5, 250); + + spawnEnemy(600, 1, 7, 200); + spawnEnemy(800, 1, 5, 350); + + spawnEnemy(400, 1, 7, 150); + spawnEnemy(450, 1, 5, 400); + break; case 8: - // lava moving up - playerPosition = 200; - spawnLava(10, 180, 2000, 2000, 0, Lava::OFF, 0, 0.5); - spawnEnemy(350, 0, 1, 0); - spawnPool[0].Spawn(1000, 5500, 3, 0, 0); - break; - case 9: - // Conveyor - spawnConveyor(100, 600, -6); - spawnEnemy(800, 0, 0, 0); - break; - case 10: - // Conveyor of enemies - spawnConveyor(50, 1000, 6); - spawnEnemy(300, 0, 0, 0); - spawnEnemy(400, 0, 0, 0); - spawnEnemy(500, 0, 0, 0); - spawnEnemy(600, 0, 0, 0); - spawnEnemy(700, 0, 0, 0); - spawnEnemy(800, 0, 0, 0); - spawnEnemy(900, 0, 0, 0); - break; - case 11: - // lava spread and fall - spawnLava(400, 450, 2000, 2000, 0, Lava::OFF, 0.2, -0.5); - spawnEnemy(350, 0, 1, 0); - spawnPool[0].Spawn(1000, 5500, 3, 0, 0); - break; - case 12: // spawn train; - spawnPool[0].Spawn(900, 1300, 2, 0, 0); - break; - case 13: // spawn train skinny attack width; - attack_width = 32; - spawnPool[0].Spawn(900, 1800, 2, 0, 0); - break; - case 14: // evil fast split spawner - spawnPool[0].Spawn(550, 1500, 2, 0, 0); - spawnPool[1].Spawn(550, 1500, 2, 1, 0); - break; - case 15: // split spawner with exit blocking lava - spawnPool[0].Spawn(500, 1200, 2, 0, 0); - spawnPool[1].Spawn(500, 1200, 2, 1, 0); - spawnLava(900, 950, 2200, 800, 2000, Lava::OFF, 0, 0); - break; - case 16: - // Lava run - spawnLava(195, 300, 2000, 2000, 0, Lava::OFF, 0, 0); - spawnLava(400, 500, 2000, 2000, 0, Lava::OFF, 0, 0); - spawnLava(600, 700, 2000, 2000, 0, Lava::OFF, 0, 0); - spawnPool[0].Spawn(1000, 3800, 4, 0, 0); - break; - case 17: - // Sin enemy #2 practice (slow conveyor) - spawnEnemy(700, 1, 7, 275); - spawnEnemy(500, 1, 5, 250); - spawnPool[0].Spawn(1000, 5500, 4, 0, 3000); - spawnPool[1].Spawn(0, 5500, 5, 1, 10000); - spawnConveyor(100, 900, -4); - break; - case 18: - // Sin enemy #2 (fast conveyor) - spawnEnemy(800, 1, 7, 275); - spawnEnemy(700, 1, 7, 275); - spawnEnemy(500, 1, 5, 250); - spawnPool[0].Spawn(1000, 3000, 4, 0, 3000); - spawnPool[1].Spawn(0, 5500, 5, 1, 10000); - spawnConveyor(100, 900, -6); - break; - case 19: // (don't edit last level) - // Boss this should always be the last level - spawnBoss(); - break; - } - stageStartTime = millis(); - stage = PLAY; + // lava moving up + playerPosition = 200; + spawnLava(10, 180, 2000, 2000, 0, Lava::OFF, 0, 0.5); + spawnEnemy(350, 0, 1, 0); + spawnPool[0].Spawn(1000, 5500, 3, 0, 0); + break; + case 9: + // Conveyor + spawnConveyor(100, 600, -6); + spawnEnemy(800, 0, 0, 0); + break; + case 10: + // Conveyor of enemies + spawnConveyor(50, 1000, 6); + spawnEnemy(300, 0, 0, 0); + spawnEnemy(400, 0, 0, 0); + spawnEnemy(500, 0, 0, 0); + spawnEnemy(600, 0, 0, 0); + spawnEnemy(700, 0, 0, 0); + spawnEnemy(800, 0, 0, 0); + spawnEnemy(900, 0, 0, 0); + break; + case 11: + // lava spread and fall + spawnLava(400, 450, 2000, 2000, 0, Lava::OFF, 0.2, -0.5); + spawnEnemy(350, 0, 1, 0); + spawnPool[0].Spawn(1000, 5500, 3, 0, 0); + break; + case 12: // spawn train; + spawnPool[0].Spawn(900, 1300, 2, 0, 0); + break; + case 13: // spawn train skinny attack width; + attack_width = 32; + spawnPool[0].Spawn(900, 1800, 2, 0, 0); + break; + case 14: // evil fast split spawner + spawnPool[0].Spawn(550, 1500, 2, 0, 0); + spawnPool[1].Spawn(550, 1500, 2, 1, 0); + break; + case 15: // split spawner with exit blocking lava + spawnPool[0].Spawn(500, 1200, 2, 0, 0); + spawnPool[1].Spawn(500, 1200, 2, 1, 0); + spawnLava(900, 950, 2200, 800, 2000, Lava::OFF, 0, 0); + break; + case 16: + // Lava run + spawnLava(195, 300, 2000, 2000, 0, Lava::OFF, 0, 0); + spawnLava(400, 500, 2000, 2000, 0, Lava::OFF, 0, 0); + spawnLava(600, 700, 2000, 2000, 0, Lava::OFF, 0, 0); + spawnPool[0].Spawn(1000, 3800, 4, 0, 0); + break; + case 17: + // Sin enemy #2 practice (slow conveyor) + spawnEnemy(700, 1, 7, 275); + spawnEnemy(500, 1, 5, 250); + spawnPool[0].Spawn(1000, 5500, 4, 0, 3000); + spawnPool[1].Spawn(0, 5500, 5, 1, 10000); + spawnConveyor(100, 900, -4); + break; + case 18: + // Sin enemy #2 (fast conveyor) + spawnEnemy(800, 1, 7, 275); + spawnEnemy(700, 1, 7, 275); + spawnEnemy(500, 1, 5, 250); + spawnPool[0].Spawn(1000, 3000, 4, 0, 3000); + spawnPool[1].Spawn(0, 5500, 5, 1, 10000); + spawnConveyor(100, 900, -6); + break; + case 19: // (don't edit last level) + // Boss this should always be the last level + spawnBoss(); + break; + } + stageStartTime = millis(); + stage = PLAY; } void spawnBoss(){ - lastLevel = true; - boss.Spawn(); - moveBoss(); + lastLevel = true; + boss.Spawn(); + moveBoss(); } void moveBoss(){ - int spawnSpeed = 1800; - if(boss._lives == 2) spawnSpeed = 1600; - if(boss._lives == 1) spawnSpeed = 1000; - spawnPool[0].Spawn(boss._pos, spawnSpeed, 3, 0, 0); - spawnPool[1].Spawn(boss._pos, spawnSpeed, 3, 1, 0); + int spawnSpeed = 1800; + if(boss._lives == 2) spawnSpeed = 1600; + if(boss._lives == 1) spawnSpeed = 1000; + spawnPool[0].Spawn(boss._pos, spawnSpeed, 3, 0, 0); + spawnPool[1].Spawn(boss._pos, spawnSpeed, 3, 1, 0); } /* ======================== spawn Functions ===================================== The following spawn functions add items to pools by looking for an unactive - item in the pool. You can only add as many as the ..._COUNT. Additonal attemps - to add will be ignored. - + item in the pool. You can only add as many as the ..._COUNT. Additonal attemps + to add will be ignored. + ============================================================================== */ void spawnEnemy(int pos, int dir, int speed, int wobble){ @@ -642,29 +645,29 @@ void cleanupLevel(){ void levelComplete(){ stageStartTime = millis(); stage = WIN; - - if (lastLevel) { - stage = BOSS_KILLED; - } - if (levelNumber != 0) // no points for the first level - { - score = score + (lives * 10); // - } + + if (lastLevel) { + stage = BOSS_KILLED; + } + if (levelNumber != 0) // no points for the first level + { + score = score + (lives * 10); // + } } -void nextLevel(){ - levelNumber ++; - - if(lastLevel) { - stage = STARTUP; - stageStartTime = millis(); - lives = user_settings.lives_per_level; - - } - else { - lives = user_settings.lives_per_level; - loadLevel(); - } +void nextLevel(){ + levelNumber ++; + + if(lastLevel) { + stage = STARTUP; + stageStartTime = millis(); + lives = user_settings.lives_per_level; + + } + else { + lives = user_settings.lives_per_level; + loadLevel(); + } } void gameOver(){ @@ -675,9 +678,9 @@ void gameOver(){ void die(){ playerAlive = 0; - if(levelNumber > 0) - lives --; - + if(levelNumber > 0) + lives --; + if(lives == 0){ stage = GAMEOVER; stageStartTime = millis(); @@ -702,13 +705,13 @@ void tickStartup(long mm) if(stageStartTime+STARTUP_WIPEUP_DUR > mm) // fill to the top with green { int n = _min(map(((mm-stageStartTime)), 0, STARTUP_WIPEUP_DUR, 0, user_settings.led_count), user_settings.led_count); // fill from top to bottom - for(int i = 0; i<= n; i++){ + for(int i = 0; i<= n; i++){ leds[i] = CRGB(0, 255, 0); - } + } } - else if(stageStartTime+STARTUP_SPARKLE_DUR > mm) // sparkle the full green bar + else if(stageStartTime+STARTUP_SPARKLE_DUR > mm) // sparkle the full green bar { - for(int i = 0; i< user_settings.led_count; i++){ + for(int i = 0; i< user_settings.led_count; i++){ if(random8(30) < 28) leds[i] = CRGB(0, 255, 0); // most are green else { @@ -716,23 +719,23 @@ void tickStartup(long mm) leds[i] = CRGB(flicker, 150, flicker); // some flicker brighter } } - + } else if (stageStartTime+STARTUP_FADE_DUR > mm) // fade it out to bottom { int n = _max(map(((mm-stageStartTime)), STARTUP_SPARKLE_DUR, STARTUP_FADE_DUR, 0, user_settings.led_count), 0); // fill from top to bottom int brightness = _max(map(((mm-stageStartTime)), STARTUP_SPARKLE_DUR, STARTUP_FADE_DUR, 255, 0), 0); - // for(int i = 0; i<= n; i++){ - + // for(int i = 0; i<= n; i++){ + // leds[i] = CRGB(0, brightness, 0); // } - for(int i = n; i< user_settings.led_count; i++){ - + for(int i = n; i< user_settings.led_count; i++){ + leds[i] = CRGB(0, brightness, 0); - } - } + } + } SFXFreqSweepWarble(STARTUP_FADE_DUR, millis()-stageStartTime, 40, 400, 20); - + } void tickEnemies(){ @@ -767,34 +770,34 @@ void tickEnemies(){ } void tickBoss(){ - // DRAW - if(boss.Alive()){ - boss._ticks ++; - for(int i = getLED(boss._pos-BOSS_WIDTH/2); i<=getLED(boss._pos+BOSS_WIDTH/2); i++){ - leds[i] = CRGB::DarkRed; - leds[i] %= 100; - } - // CHECK COLLISION - if(getLED(playerPosition) > getLED(boss._pos - BOSS_WIDTH/2) && getLED(playerPosition) < getLED(boss._pos + BOSS_WIDTH)){ - die(); - return; - } - // CHECK FOR ATTACK - if(attacking){ - if( - (getLED(playerPosition+(attack_width/2)) >= getLED(boss._pos - BOSS_WIDTH/2) && getLED(playerPosition+(attack_width/2)) <= getLED(boss._pos + BOSS_WIDTH/2)) || - (getLED(playerPosition-(attack_width/2)) <= getLED(boss._pos + BOSS_WIDTH/2) && getLED(playerPosition-(attack_width/2)) >= getLED(boss._pos - BOSS_WIDTH/2)) - ){ - boss.Hit(); - if(boss.Alive()){ - moveBoss(); - }else{ - spawnPool[0].Kill(); - spawnPool[1].Kill(); - } - } - } - } + // DRAW + if(boss.Alive()){ + boss._ticks ++; + for(int i = getLED(boss._pos-BOSS_WIDTH/2); i<=getLED(boss._pos+BOSS_WIDTH/2); i++){ + leds[i] = CRGB::DarkRed; + leds[i] %= 100; + } + // CHECK COLLISION + if(getLED(playerPosition) > getLED(boss._pos - BOSS_WIDTH/2) && getLED(playerPosition) < getLED(boss._pos + BOSS_WIDTH)){ + die(); + return; + } + // CHECK FOR ATTACK + if(attacking){ + if( + (getLED(playerPosition+(attack_width/2)) >= getLED(boss._pos - BOSS_WIDTH/2) && getLED(playerPosition+(attack_width/2)) <= getLED(boss._pos + BOSS_WIDTH/2)) || + (getLED(playerPosition-(attack_width/2)) <= getLED(boss._pos + BOSS_WIDTH/2) && getLED(playerPosition-(attack_width/2)) >= getLED(boss._pos - BOSS_WIDTH/2)) + ){ + boss.Hit(); + if(boss.Alive()){ + moveBoss(); + }else{ + spawnPool[0].Kill(); + spawnPool[1].Kill(); + } + } + } + } } void drawPlayer(){ @@ -820,73 +823,73 @@ void tickSpawners(){ } void tickLava(){ - int A, B, p, i, brightness, flicker; - long mm = millis(); - - Lava LP; - for(i = 0; i 0) - leds[led] = CRGB(0, 0, b); + if(speed < 0) + n = (led + (m/100)) % levels; + + b = map(n, 5, 0, 0, CONVEYOR_BRIGHTNESS); + if(b > 0) + leds[led] = CRGB(0, 0, b); } if(playerPosition > conveyorPool[i]._startPoint && playerPosition < conveyorPool[i]._endPoint){ @@ -940,56 +943,56 @@ void tickComplete(long mm) // the boss is dead void tickBossKilled(long mm) // boss funeral { - static uint8_t gHue = 0; - - FastLED.setBrightness(255); // super bright! - - int brightness = 0; - FastLED.clear(); - - if(stageStartTime+6500 > mm){ - gHue++; - fill_rainbow( leds, user_settings.led_count, gHue, 7); // FastLED's built in rainbow - if( random8() < 200) { // add glitter - leds[ random16(user_settings.led_count) ] += CRGB::White; - } - SFXbosskilled(); - }else if(stageStartTime+7000 > mm){ - int n = _max(map(((mm-stageStartTime)), 5000, 5500, user_settings.led_count, 0), 0); - for(int i = 0; i< n; i++){ - brightness = (sin(((i*10)+mm)/500.0)+1)*255; - leds[i].setHSV(brightness, 255, 50); - } - SFXcomplete(); - }else{ - nextLevel(); - } + static uint8_t gHue = 0; + + FastLED.setBrightness(255); // super bright! + + int brightness = 0; + FastLED.clear(); + + if(stageStartTime+6500 > mm){ + gHue++; + fill_rainbow( leds, user_settings.led_count, gHue, 7); // FastLED's built in rainbow + if( random8() < 200) { // add glitter + leds[ random16(user_settings.led_count) ] += CRGB::White; + } + SFXbosskilled(); + }else if(stageStartTime+7000 > mm){ + int n = _max(map(((mm-stageStartTime)), 5000, 5500, user_settings.led_count, 0), 0); + for(int i = 0; i< n; i++){ + brightness = (sin(((i*10)+mm)/500.0)+1)*255; + leds[i].setHSV(brightness, 255, 50); + } + SFXcomplete(); + }else{ + nextLevel(); + } } void tickDie(long mm) { // a short bright explosion...particles persist after it. - const int duration = 200; // milliseconds - const int width = 20; // half width of the explosion + const int duration = 200; // milliseconds + const int width = 20; // half width of the explosion - if(stageStartTime+duration > mm) {// Spread red from player position up and down the width - - int brightness = map((mm-stageStartTime), 0, duration, 255, 150); // this allows a fade from white to red - - // fill up - int n = _max(map(((mm-stageStartTime)), 0, duration, getLED(playerPosition), getLED(playerPosition)+width), 0); - for(int i = getLED(playerPosition); i<= n; i++){ - leds[i] = CRGB(255, brightness, brightness); - } - - // fill to down - n = _max(map(((mm-stageStartTime)), 0, duration, getLED(playerPosition), getLED(playerPosition)-width), 0); - for(int i = getLED(playerPosition); i>= n; i--){ - leds[i] = CRGB(255, brightness, brightness); - } - } + if(stageStartTime+duration > mm) {// Spread red from player position up and down the width + + int brightness = map((mm-stageStartTime), 0, duration, 255, 150); // this allows a fade from white to red + + // fill up + int n = _max(map(((mm-stageStartTime)), 0, duration, getLED(playerPosition), getLED(playerPosition)+width), 0); + for(int i = getLED(playerPosition); i<= n; i++){ + leds[i] = CRGB(255, brightness, brightness); + } + + // fill to down + n = _max(map(((mm-stageStartTime)), 0, duration, getLED(playerPosition), getLED(playerPosition)-width), 0); + for(int i = getLED(playerPosition); i>= n; i--){ + leds[i] = CRGB(255, brightness, brightness); + } + } } void tickGameover(long mm) { - + int brightness = 0; if(stageStartTime+GAMEOVER_SPREAD_DURATION > mm) // Spread red from player position to top and bottom @@ -1034,13 +1037,13 @@ void tickWin(long mm) { }else if(stageStartTime+WIN_CLEAR_DURATION > mm){ int n = _max(map(((mm-stageStartTime)), WIN_FILL_DURATION, WIN_CLEAR_DURATION, user_settings.led_count, 0), 0); // clear from top to bottom for(int i = 0; i< n; i++){ - brightness = user_settings.led_brightness; + brightness = user_settings.led_brightness; leds[i] = CRGB(0, brightness, 0); } SFXwin(); }else if(stageStartTime+WIN_OFF_DURATION > mm){ // wait a while with leds off leds[0] = CRGB(0, user_settings.led_brightness, 0); - }else{ + }else{ nextLevel(); } } @@ -1050,17 +1053,17 @@ void drawLives() { // show how many lives are left by drawing a short line of green leds for each life SFXcomplete(); // stop any sounds - FastLED.clear(); - - int pos = 0; + FastLED.clear(); + + int pos = 0; for (int i = 0; i < lives; i++) - { + { for (int j=0; j<4; j++) { leds[pos++] = CRGB(0, 255, 0); - FastLED.show(); + FastLED.show(); } - leds[pos++] = CRGB(0, 0, 0); + leds[pos++] = CRGB(0, 0, 0); delay(20); } FastLED.show(); @@ -1105,21 +1108,21 @@ bool inLava(int pos){ return false; } -void updateLives(){ - drawLives(); +void updateLives(){ + drawLives(); } void save_game_stats(bool bossKill) -{ - user_settings.games_played += 1; - user_settings.total_points += score; - if (score > user_settings.high_score) - user_settings.high_score += score; - if (bossKill) - user_settings.boss_kills += 1; - - show_game_stats(); - settings_eeprom_write(); +{ + user_settings.games_played += 1; + user_settings.total_points += score; + if (score > user_settings.high_score) + user_settings.high_score += score; + if (bossKill) + user_settings.boss_kills += 1; + + show_game_stats(); + settings_eeprom_write(); } // --------------------------------- @@ -1128,22 +1131,23 @@ void save_game_stats(bool bossKill) void screenSaverTick(){ long mm = millis(); int mode = (mm/30000)%4; - - SFXcomplete(); // turn off sound...play testing showed this to be a problem - if (mode == 0) { - Fire2012(); - } - else if (mode == 1) - sinelon(); - else if (mode == 2) - juggle(); - else { - random_LED_flashes(); - } - + SFXcomplete(); // turn off sound...play testing showed this to be a problem + + if (mode == 0) { + Fire2012(); + } + else if (mode == 1) + sinelon(); + else if (mode == 2) + juggle(); + else { + random_LED_flashes(); + } + } +#ifdef USE_GYRO_JOYSTICK // --------------------------------- // ----------- JOYSTICK ------------ // --------------------------------- @@ -1155,21 +1159,21 @@ void getInput(){ // if(digitalRead(leftButtonPinNumber) == HIGH) joystickTilt = -90; // if(digitalRead(rightButtonPinNumber) == HIGH) joystickTilt = 90; // if(digitalRead(attackButtonPinNumber) == HIGH) joystickWobble = ATTACK_THRESHOLD; - int16_t ax, ay, az; - int16_t gx, gy, gz; + int16_t ax, ay, az; + int16_t gx, gy, gz; accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz); - - - + + + int a = (JOYSTICK_ORIENTATION == 0?ax:(JOYSTICK_ORIENTATION == 1?ay:az))/166; int g = (JOYSTICK_ORIENTATION == 0?gx:(JOYSTICK_ORIENTATION == 1?gy:gz)); - - #ifdef JOYSTICK_DEBUG - Serial.print("a:"); Serial.println(a); - Serial.print("g:"); Serial.println(g); - #endif - + + #ifdef JOYSTICK_DEBUG + Serial.print("a:"); Serial.println(a); + Serial.print("g:"); Serial.println(g); + #endif + if(abs(a) < user_settings.joystick_deadzone) a = 0; if(a > 0) a -= user_settings.joystick_deadzone; if(a < 0) a += user_settings.joystick_deadzone; @@ -1181,13 +1185,41 @@ void getInput(){ joystickTilt = 0-joystickTilt; } joystickWobble = abs(MPUWobbleSamples.getHighest()); - - #ifdef JOYSTICK_DEBUG - //Serial.print("tilt:"); Serial.println(joystickTilt); - //Serial.print("wobble:"); Serial.println(joystickWobble); - #endif - + + #ifdef JOYSTICK_DEBUG + //Serial.print("tilt:"); Serial.println(joystickTilt); + //Serial.print("wobble:"); Serial.println(joystickWobble); + #endif + } +#else + +void getInput() { + // This is responsible for the player movement speed and attacking. + // You can replace it with anything you want that passes a -90>+90 value to joystickTilt + // and any value to joystickWobble that is greater than ATTACK_THRESHOLD (defined at start) + // For example you could use 3 momentary buttons: + + bool up = digitalRead(upButtonPinNumber) == LOW; + bool down = digitalRead(downButtonPinNumber) == LOW; + bool left = digitalRead(leftButtonPinNumber) == LOW; + bool right = digitalRead(rightButtonPinNumber) == LOW; + + joystickTilt = 0; + if (up) { + joystickTilt = 90 ; + } else if (down) { + joystickTilt = -90; + } + + if (left || right) { + joystickWobble = user_settings.attack_threshold; + } else { + joystickWobble = 0; + } +} + +#endif // --------------------------------- // -------------- SFX -------------- @@ -1197,64 +1229,64 @@ void getInput(){ This is used sweep across (up or down) a frequency range for a specified duration. A sin based warble is added to the frequency. This function is meant to be called on each frame to adjust the frequency in sync with an animation - - duration = over what time period is this mapped - elapsedTime = how far into the duration are we in - freqStart = the beginning frequency - freqEnd = the ending frequency - warble = the amount of warble added (0 disables) - + + duration = over what time period is this mapped + elapsedTime = how far into the duration are we in + freqStart = the beginning frequency + freqEnd = the ending frequency + warble = the amount of warble added (0 disables) + */ void SFXFreqSweepWarble(int duration, int elapsedTime, int freqStart, int freqEnd, int warble) { - int freq = map_constrain(elapsedTime, 0, duration, freqStart, freqEnd); - if (warble) - warble = map(sin(millis()/20.0)*1000.0, -1000, 1000, 0, warble); - - sound(freq + warble, user_settings.audio_volume); + int freq = map_constrain(elapsedTime, 0, duration, freqStart, freqEnd); + if (warble) + warble = map(sin(millis()/20.0)*1000.0, -1000, 1000, 0, warble); + + sound(freq + warble, user_settings.audio_volume); } /* - + This is used sweep across (up or down) a frequency range for a specified duration. Random noise is optionally added to the frequency. This function is meant to be called on each frame to adjust the frequency in sync with an animation - - duration = over what time period is this mapped - elapsedTime = how far into the duration are we in - freqStart = the beginning frequency - freqEnd = the ending frequency - noiseFactor = the amount of noise to added/subtracted (0 disables) - + + duration = over what time period is this mapped + elapsedTime = how far into the duration are we in + freqStart = the beginning frequency + freqEnd = the ending frequency + noiseFactor = the amount of noise to added/subtracted (0 disables) + */ void SFXFreqSweepNoise(int duration, int elapsedTime, int freqStart, int freqEnd, uint8_t noiseFactor) { - int freq; - - if (elapsedTime > duration) - freq = freqEnd; - else - freq = map(elapsedTime, 0, duration, freqStart, freqEnd); - - if (noiseFactor) - noiseFactor = noiseFactor - random8(noiseFactor / 2); - - sound(freq + noiseFactor, user_settings.audio_volume); + int freq; + + if (elapsedTime > duration) + freq = freqEnd; + else + freq = map(elapsedTime, 0, duration, freqStart, freqEnd); + + if (noiseFactor) + noiseFactor = noiseFactor - random8(noiseFactor / 2); + + sound(freq + noiseFactor, user_settings.audio_volume); } void SFXtilt(int amount){ - if (amount == 0){ - SFXcomplete(); - return; - } - + if (amount == 0){ + SFXcomplete(); + return; + } + int f = map(abs(amount), 0, 90, 80, 900)+random8(100); if(playerPositionModifier < 0) f -= 500; - if(playerPositionModifier > 0) f += 200; - int vol = map(abs(amount), 0, 90, user_settings.audio_volume / 2, user_settings.audio_volume * 3/4); + if(playerPositionModifier > 0) f += 200; + int vol = map(abs(amount), 0, 90, user_settings.audio_volume / 2, user_settings.audio_volume * 3/4); sound(f,vol); } void SFXattacking(){ @@ -1264,24 +1296,24 @@ void SFXattacking(){ } sound(freq, user_settings.audio_volume); } -void SFXdead(){ - SFXFreqSweepNoise(1000, millis()-killTime, 1000, 10, 200); +void SFXdead(){ + SFXFreqSweepNoise(1000, millis()-killTime, 1000, 10, 200); } void SFXgameover(){ - SFXFreqSweepWarble(GAMEOVER_SPREAD_DURATION, millis()-killTime, 440, 20, 60); + SFXFreqSweepWarble(GAMEOVER_SPREAD_DURATION, millis()-killTime, 440, 20, 60); } void SFXkill(){ sound(2000, user_settings.audio_volume); } void SFXwin(){ - SFXFreqSweepWarble(WIN_OFF_DURATION, millis()-stageStartTime, 40, 400, 20); + SFXFreqSweepWarble(WIN_OFF_DURATION, millis()-stageStartTime, 40, 400, 20); } void SFXbosskilled() { - SFXFreqSweepWarble(7000, millis()-stageStartTime, 75, 1100, 60); + SFXFreqSweepWarble(7000, millis()-stageStartTime, 75, 1100, 60); } void SFXcomplete(){ @@ -1300,16 +1332,16 @@ long map_constrain(long x, long in_min, long in_max, long out_min, long out_max) } else { x = constrain(x, in_max, in_min); - } + } return map(x, in_min, in_max, out_min, out_max); } // Fire2012 by Mark Kriegsman, July 2012 // as part of "Five Elements" shown here: http://youtu.be/knWiGsmgycY -//// +//// // This basic one-dimensional 'fire' simulation works roughly as follows: // There's a underlying array of 'heat' cells, that model the temperature -// at each point along the line. Every cycle through the simulation, +// at each point along the line. Every cycle through the simulation, // four steps are performed: // 1) All cells cool down a little bit, losing heat to the air // 2) The heat from each cell drifts 'up' and diffuses a little @@ -1320,7 +1352,7 @@ long map_constrain(long x, long in_min, long in_max, long out_min, long out_max) // Temperature is in arbitrary units from 0 (cold black) to 255 (white hot). // // This simulation scales it self a bit depending on NUM_LEDS; it should look -// "OK" on anywhere from 20 to 100 LEDs without too much tweaking. +// "OK" on anywhere from 20 to 100 LEDs without too much tweaking. // // I recommend running this simulation at anywhere from 30-100 frames per second, // meaning an interframe delay of about 10-35 milliseconds. @@ -1334,7 +1366,7 @@ long map_constrain(long x, long in_min, long in_max, long out_min, long out_max) // // COOLING: How much does the air cool as it rises? // Less cooling = taller flames. More cooling = shorter flames. -// Default 50, suggested range 20-100 +// Default 50, suggested range 20-100 #define COOLING 75 // SPARKING: What chance (out of 255) is there that a new spark will be lit? @@ -1355,12 +1387,12 @@ void Fire2012() for( int i = 0; i < user_settings.led_count; i++) { heat[i] = qsub8( heat[i], random8(0, ((COOLING * 10) / user_settings.led_count) + 2)); } - + // Step 2. Heat from each cell drifts 'up' and diffuses a little for( int k= user_settings.led_count - 1; k >= 2; k--) { heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3; } - + // Step 3. Randomly ignite new 'sparks' of heat near the bottom if( random8() < SPARKING ) { int y = random8(7); @@ -1381,15 +1413,15 @@ void Fire2012() } void LED_march() { - int n, b, c, i; - - long mm = millis(); - - - for(i = 0; i orange n = (mm/250)%10; b = 10+((sin(mm/500.00)+1)*20.00); @@ -1398,25 +1430,25 @@ void LED_march() { if(i%10 == n){ leds[i] = CHSV( c, 255, 150); } - } - + } + } void random_LED_flashes() { - long mm = millis(); - int i; - - for(i = 0; i