diff --git a/TWANG32/Particle.h b/TWANG32/Particle.h index b9b4ff2..91f85a8 100644 --- a/TWANG32/Particle.h +++ b/TWANG32/Particle.h @@ -4,24 +4,29 @@ class Particle { public: - void Spawn(int pos); + void Spawn(int pos, int life, int aging_speed, const int color[3]); void Tick(int USE_GRAVITY); void Kill(); bool Alive(); int _pos; int _power; + int _color[3]; private: int _life; int _alive; int _sp; + int _aging; }; -void Particle::Spawn(int pos){ +void Particle::Spawn(int pos, int life, int aging_speed, const int color[3]){ _pos = pos; - _sp = random(-200, 200); + _sp = random(-life, life); _power = 255; _alive = 1; - _life = 220 - abs(_sp); + _life = life - abs(_sp); + _aging = aging_speed; + + for (int i = 0; i< 3; i++) _color[i] = color[i]; } void Particle::Tick(int USE_GRAVITY){ @@ -33,7 +38,7 @@ void Particle::Tick(int USE_GRAVITY){ _sp += _life/10; } if(USE_GRAVITY && _pos > 500) _sp -= 10; - _power = 100 - _life; + _power = 100 - _aging*_life; if(_power <= 0){ Kill(); }else{ diff --git a/TWANG32/TWANG32.ino b/TWANG32/TWANG32.ino index 84c1068..ff09234 100644 --- a/TWANG32/TWANG32.ino +++ b/TWANG32/TWANG32.ino @@ -53,6 +53,7 @@ #include "sound.h" #include "settings.h" #include "wifi_ap.h" +#include "colors.h" #if defined(FASTLED_VERSION) && (FASTLED_VERSION < 3001000) #error "Requires FastLED 3.1 or later; check github for latest code." @@ -89,6 +90,7 @@ int attack_width = DEFAULT_ATTACK_WIDTH; #define STARTUP_WIPEUP_DUR 200 #define STARTUP_SPARKLE_DUR 1300 #define STARTUP_FADE_DUR 1500 +#define COLOR_SELECT_DUR 1000 #define GAMEOVER_SPREAD_DURATION 1000 #define GAMEOVER_FADE_DURATION 1500 @@ -157,6 +159,7 @@ enum stages { long stageStartTime; // Stores the time the stage changed for stages that are time based long killTime; bool lastLevel = false; +int killPos = 0; int score = 0; @@ -256,8 +259,7 @@ void setup() { player[0].setColor(0,255,0); player[1].setColor(127,2,255); for (Player& p : player) - p.Lives ( 2 ); - //p.Lives ( user_settings.lives_per_level ); + p.Lives ( user_settings.lives_per_level ); } @@ -269,10 +271,15 @@ void loop() { checkSerialInput(); if(stage == PLAY){ - if(player[0].attacking){ + bool attacking = false; + for (const Player& p: player) attacking = attacking || p.attacking; + + if(attacking){ SFXattacking(); }else{ - SFXtilt(joystickTilt[0]); + int tilt = -1000; + for (int i=0; i user_settings.joystick_deadzone) || - (abs(joystickWobble[i]) >= user_settings.attack_threshold); + isMoving = isMoving || + ((abs(joystickTilt[i]) > user_settings.joystick_deadzone) || + (abs(joystickWobble[i]) >= user_settings.attack_threshold)); } if(isMoving) @@ -321,7 +328,22 @@ void loop() { }else if(stage == PLAY){ // PLAYING + // allow selecting player color during first sec of first level + if (levelNumber == 0) { + if ((stageStartTime + COLOR_SELECT_DUR) > mm) { + for (Player& p : player) { + if (joystickWobble[p.Id()] >= user_settings.attack_threshold) { + random_player_color(p); + stageStartTime = mm; + return; + } + } + } + } + + // real action here for (Player& p : player) { + if (p.captured) continue; if (joystickWobble[p.Id()] >= user_settings.attack_threshold) p.startAttack(mm); @@ -360,25 +382,26 @@ void loop() { // Ticks and draw calls FastLED.clear(); + + // exploding players during PLAY stage + tickParticles(); + for (Player& p : player) tickConveyors(p); tickSpawners(); tickBoss(); tickLava(); - for (Player& p : player) - if (!p.captured) tickEnemies(p); - for (const Player& p : player) { - if (p.Alive()) { - drawPlayer(p); - drawAttack(p); - } - } + + for (Player& p : player) if (!p.captured) tickEnemies(p); + for (const Player& p : player) if (!p.captured) drawAttack(p); + for (const Player& p : player) if (!p.captured) drawPlayer(p); + drawExit(); }else if(stage == DEAD){ // DEAD FastLED.clear(); - tickDie(player[0], mm); // TODO: fix me! Add whoDied function! + tickDie(mm); if(!tickParticles()){ loadLevel(); } @@ -702,8 +725,7 @@ void nextLevel(){ for (Player& p : player) p.Lives ( user_settings.lives_per_level ); - } - else { + } else { for (Player& p : player) { if (!p.Alive()) p.Lives ( user_settings.lives_per_level ); } @@ -732,6 +754,11 @@ void die(Player& p){ allDead &= !pp.Alive(); } + for(int ip = 0; ip < PARTICLE_COUNT; ip++){ + if(stillPlaying>0) particlePool[ip].Spawn(p.position, 25, 3, p.color); + else particlePool[ip].Spawn(p.position, 200, 1, p.color); // final explosion + } + // someone is still playing the level, continue (an animation for the dead player should be added) if(stillPlaying>0) return; @@ -743,13 +770,11 @@ void die(Player& p){ } else // some still have lifes to live, go to DEAD stage and repat the level { - for(int ip = 0; ip < PARTICLE_COUNT; ip++){ - particlePool[ip].Spawn(p.position); - } stageStartTime = millis(); stage = DEAD; } killTime = millis(); + killPos = p.position; } // ---------------------------------- @@ -924,19 +949,24 @@ void tickLava(){ } bool tickParticles(){ + // TODO: the new version of this function is a bit stupid. Should be rewritten. bool stillActive = false; - uint8_t brightness; + float brightness; + uint8_t r, g, b; + + // loop over particles for(int p = 0; p < PARTICLE_COUNT; p++){ if(particlePool[p].Alive()){ particlePool[p].Tick(USE_GRAVITY); - if (particlePool[p]._power < 5) - { - brightness = (5 - particlePool[p]._power) * 10; - leds[getLED(particlePool[p]._pos)] += CRGB(brightness, brightness/2, brightness/2);\ - } - else - leds[getLED(particlePool[p]._pos)] += CRGB(particlePool[p]._power, 0, 0); + if (particlePool[p]._power < 5) brightness = (float) (5 - particlePool[p]._power) * 10 / 255; + else brightness = (float) particlePool[p]._power / 255; + + r = (uint8_t) ( particlePool[p]._color[0] * brightness); + g = (uint8_t) ( particlePool[p]._color[1] * brightness); + b = (uint8_t) ( particlePool[p]._color[2] * brightness); + + leds[getLED(particlePool[p]._pos)] += CRGB(r, g, b); stillActive = true; } @@ -1033,7 +1063,7 @@ void tickBossKilled(long mm) // boss funeral } } -void tickDie(const Player& p, long mm) { // a short bright explosion...particles persist after it. +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 @@ -1042,14 +1072,14 @@ void tickDie(const Player& p, long mm) { // a short bright explosion...particles 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(p.position), getLED(p.position)+width), 0); - for(int i = getLED(p.position); i<= n; i++){ + int n = _max(map(((mm-stageStartTime)), 0, duration, getLED(killPos), getLED(killPos)+width), 0); + for(int i = getLED(killPos); i<= n; i++){ leds[i] = CRGB(255, brightness, brightness); } // fill to down - n = _max(map(((mm-stageStartTime)), 0, duration, getLED(p.position), getLED(p.position)-width), 0); - for(int i = getLED(p.position); i>= n; i--){ + n = _max(map(((mm-stageStartTime)), 0, duration, getLED(killPos), getLED(killPos)-width), 0); + for(int i = getLED(killPos); i>= n; i--){ leds[i] = CRGB(255, brightness, brightness); } } @@ -1226,6 +1256,9 @@ void getInput(){ // if(digitalRead(leftButtonPinNumber) == HIGH) joystickTilt = -90; // if(digitalRead(rightButtonPinNumber) == HIGH) joystickTilt = 90; // if(digitalRead(attackButtonPinNumber) == HIGH) joystickWobble = ATTACK_THRESHOLD; + + // NB: This is not multiplayer yet + int16_t ax, ay, az; int16_t gx, gy, gz; @@ -1273,6 +1306,8 @@ void getInput() { //bool right = digitalRead(rightButtonPinNumber) == LOW; bool right = left; + // Player 1 + joystickTilt[0] = 0; if (up) { joystickTilt[0] = 90 ; @@ -1287,7 +1322,7 @@ void getInput() { } - + // Player 2 up = digitalRead(upButtonPinNumber2) == LOW; down = digitalRead(downButtonPinNumber2) == LOW; diff --git a/TWANG32/colors.h b/TWANG32/colors.h new file mode 100644 index 0000000..4b39c0d --- /dev/null +++ b/TWANG32/colors.h @@ -0,0 +1,23 @@ +void random_player_color(Player& p) +{ + float h = (float)random(0, 100000) / 100000.0; + float s = 0.95f; // high saturation + float v = 1.0f; // max brightness + + float c = v * s; + float x = c * (1 - fabsf(fmodf(h * 6.0f, 2) - 1)); + float m = v - c; + + float r1=0, g1=0, b1=0; + + if (h < 1.0/6) { r1=c; g1=x; } + else if (h < 2.0/6) { r1=x; g1=c; } + else if (h < 3.0/6) { g1=c; b1=x; } + else if (h < 4.0/6) { g1=x; b1=c; } + else if (h < 5.0/6) { r1=x; b1=c; } + else { r1=c; b1=x; } + + p.setColor( (unsigned char)((r1 + m) * 255), + (unsigned char)((g1 + m) * 255), + (unsigned char)((b1 + m) * 255)); +}