Fixed bug with dead players being zombies (not visible but playing). Added option to change color at the beginning of level 1. Explosion animation now has player's color and takes place for all of them when they are killed (before only for last one). Final explosion animation and gameover now start where last player was killed.
This commit is contained in:
@@ -4,24 +4,29 @@
|
|||||||
class Particle
|
class Particle
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void Spawn(int pos);
|
void Spawn(int pos, int life, int aging_speed, const int color[3]);
|
||||||
void Tick(int USE_GRAVITY);
|
void Tick(int USE_GRAVITY);
|
||||||
void Kill();
|
void Kill();
|
||||||
bool Alive();
|
bool Alive();
|
||||||
int _pos;
|
int _pos;
|
||||||
int _power;
|
int _power;
|
||||||
|
int _color[3];
|
||||||
private:
|
private:
|
||||||
int _life;
|
int _life;
|
||||||
int _alive;
|
int _alive;
|
||||||
int _sp;
|
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;
|
_pos = pos;
|
||||||
_sp = random(-200, 200);
|
_sp = random(-life, life);
|
||||||
_power = 255;
|
_power = 255;
|
||||||
_alive = 1;
|
_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){
|
void Particle::Tick(int USE_GRAVITY){
|
||||||
@@ -33,7 +38,7 @@ void Particle::Tick(int USE_GRAVITY){
|
|||||||
_sp += _life/10;
|
_sp += _life/10;
|
||||||
}
|
}
|
||||||
if(USE_GRAVITY && _pos > 500) _sp -= 10;
|
if(USE_GRAVITY && _pos > 500) _sp -= 10;
|
||||||
_power = 100 - _life;
|
_power = 100 - _aging*_life;
|
||||||
if(_power <= 0){
|
if(_power <= 0){
|
||||||
Kill();
|
Kill();
|
||||||
}else{
|
}else{
|
||||||
|
|||||||
@@ -53,6 +53,7 @@
|
|||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "wifi_ap.h"
|
#include "wifi_ap.h"
|
||||||
|
#include "colors.h"
|
||||||
|
|
||||||
#if defined(FASTLED_VERSION) && (FASTLED_VERSION < 3001000)
|
#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."
|
||||||
@@ -89,6 +90,7 @@ int attack_width = DEFAULT_ATTACK_WIDTH;
|
|||||||
#define STARTUP_WIPEUP_DUR 200
|
#define STARTUP_WIPEUP_DUR 200
|
||||||
#define STARTUP_SPARKLE_DUR 1300
|
#define STARTUP_SPARKLE_DUR 1300
|
||||||
#define STARTUP_FADE_DUR 1500
|
#define STARTUP_FADE_DUR 1500
|
||||||
|
#define COLOR_SELECT_DUR 1000
|
||||||
|
|
||||||
#define GAMEOVER_SPREAD_DURATION 1000
|
#define GAMEOVER_SPREAD_DURATION 1000
|
||||||
#define GAMEOVER_FADE_DURATION 1500
|
#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 stageStartTime; // Stores the time the stage changed for stages that are time based
|
||||||
long killTime;
|
long killTime;
|
||||||
bool lastLevel = false;
|
bool lastLevel = false;
|
||||||
|
int killPos = 0;
|
||||||
|
|
||||||
int score = 0;
|
int score = 0;
|
||||||
|
|
||||||
@@ -256,8 +259,7 @@ void setup() {
|
|||||||
player[0].setColor(0,255,0);
|
player[0].setColor(0,255,0);
|
||||||
player[1].setColor(127,2,255);
|
player[1].setColor(127,2,255);
|
||||||
for (Player& p : player)
|
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();
|
checkSerialInput();
|
||||||
|
|
||||||
if(stage == PLAY){
|
if(stage == PLAY){
|
||||||
if(player[0].attacking){
|
bool attacking = false;
|
||||||
|
for (const Player& p: player) attacking = attacking || p.attacking;
|
||||||
|
|
||||||
|
if(attacking){
|
||||||
SFXattacking();
|
SFXattacking();
|
||||||
}else{
|
}else{
|
||||||
SFXtilt(joystickTilt[0]);
|
int tilt = -1000;
|
||||||
|
for (int i=0; i<NUM_PLAYERS; i++) tilt = max(joystickTilt[i], tilt);
|
||||||
|
SFXtilt(tilt);
|
||||||
}
|
}
|
||||||
}else if(stage == DEAD){
|
}else if(stage == DEAD){
|
||||||
SFXdead();
|
SFXdead();
|
||||||
@@ -284,12 +291,12 @@ void loop() {
|
|||||||
long frameTimer = mm;
|
long frameTimer = mm;
|
||||||
previousMillis = mm;
|
previousMillis = mm;
|
||||||
|
|
||||||
// check activity of any player
|
// check activity of any player, used to stop screensaver
|
||||||
bool isMoving = false;
|
bool isMoving = false;
|
||||||
for (int i=0; i < NUM_PLAYERS; i++) {
|
for (int i=0; i < NUM_PLAYERS; i++) {
|
||||||
isMoving = isMoving &&
|
isMoving = isMoving ||
|
||||||
(abs(joystickTilt[i]) > user_settings.joystick_deadzone) ||
|
((abs(joystickTilt[i]) > user_settings.joystick_deadzone) ||
|
||||||
(abs(joystickWobble[i]) >= user_settings.attack_threshold);
|
(abs(joystickWobble[i]) >= user_settings.attack_threshold));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isMoving)
|
if(isMoving)
|
||||||
@@ -321,7 +328,22 @@ void loop() {
|
|||||||
}else if(stage == PLAY){
|
}else if(stage == PLAY){
|
||||||
// PLAYING
|
// PLAYING
|
||||||
|
|
||||||
|
// allow selecting player color during first sec of first level
|
||||||
|
if (levelNumber == 0) {
|
||||||
|
if ((stageStartTime + COLOR_SELECT_DUR) > mm) {
|
||||||
for (Player& p : player) {
|
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 (p.captured) continue;
|
||||||
|
|
||||||
if (joystickWobble[p.Id()] >= user_settings.attack_threshold) p.startAttack(mm);
|
if (joystickWobble[p.Id()] >= user_settings.attack_threshold) p.startAttack(mm);
|
||||||
@@ -360,25 +382,26 @@ void loop() {
|
|||||||
|
|
||||||
// Ticks and draw calls
|
// Ticks and draw calls
|
||||||
FastLED.clear();
|
FastLED.clear();
|
||||||
|
|
||||||
|
// exploding players during PLAY stage
|
||||||
|
tickParticles();
|
||||||
|
|
||||||
for (Player& p : player)
|
for (Player& p : player)
|
||||||
tickConveyors(p);
|
tickConveyors(p);
|
||||||
|
|
||||||
tickSpawners();
|
tickSpawners();
|
||||||
tickBoss();
|
tickBoss();
|
||||||
tickLava();
|
tickLava();
|
||||||
for (Player& p : player)
|
|
||||||
if (!p.captured) tickEnemies(p);
|
for (Player& p : player) if (!p.captured) tickEnemies(p);
|
||||||
for (const Player& p : player) {
|
for (const Player& p : player) if (!p.captured) drawAttack(p);
|
||||||
if (p.Alive()) {
|
for (const Player& p : player) if (!p.captured) drawPlayer(p);
|
||||||
drawPlayer(p);
|
|
||||||
drawAttack(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
drawExit();
|
drawExit();
|
||||||
}else if(stage == DEAD){
|
}else if(stage == DEAD){
|
||||||
// DEAD
|
// DEAD
|
||||||
FastLED.clear();
|
FastLED.clear();
|
||||||
tickDie(player[0], mm); // TODO: fix me! Add whoDied function!
|
tickDie(mm);
|
||||||
if(!tickParticles()){
|
if(!tickParticles()){
|
||||||
loadLevel();
|
loadLevel();
|
||||||
}
|
}
|
||||||
@@ -702,8 +725,7 @@ void nextLevel(){
|
|||||||
for (Player& p : player)
|
for (Player& p : player)
|
||||||
p.Lives ( user_settings.lives_per_level );
|
p.Lives ( user_settings.lives_per_level );
|
||||||
|
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
for (Player& p : player) {
|
for (Player& p : player) {
|
||||||
if (!p.Alive()) p.Lives ( user_settings.lives_per_level );
|
if (!p.Alive()) p.Lives ( user_settings.lives_per_level );
|
||||||
}
|
}
|
||||||
@@ -732,6 +754,11 @@ void die(Player& p){
|
|||||||
allDead &= !pp.Alive();
|
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)
|
// someone is still playing the level, continue (an animation for the dead player should be added)
|
||||||
if(stillPlaying>0) return;
|
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
|
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();
|
stageStartTime = millis();
|
||||||
stage = DEAD;
|
stage = DEAD;
|
||||||
}
|
}
|
||||||
killTime = millis();
|
killTime = millis();
|
||||||
|
killPos = p.position;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
@@ -924,19 +949,24 @@ void tickLava(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool tickParticles(){
|
bool tickParticles(){
|
||||||
|
// TODO: the new version of this function is a bit stupid. Should be rewritten.
|
||||||
bool stillActive = false;
|
bool stillActive = false;
|
||||||
uint8_t brightness;
|
float brightness;
|
||||||
|
uint8_t r, g, b;
|
||||||
|
|
||||||
|
// loop over particles
|
||||||
for(int p = 0; p < PARTICLE_COUNT; p++){
|
for(int p = 0; p < PARTICLE_COUNT; p++){
|
||||||
if(particlePool[p].Alive()){
|
if(particlePool[p].Alive()){
|
||||||
particlePool[p].Tick(USE_GRAVITY);
|
particlePool[p].Tick(USE_GRAVITY);
|
||||||
|
|
||||||
if (particlePool[p]._power < 5)
|
if (particlePool[p]._power < 5) brightness = (float) (5 - particlePool[p]._power) * 10 / 255;
|
||||||
{
|
else brightness = (float) particlePool[p]._power / 255;
|
||||||
brightness = (5 - particlePool[p]._power) * 10;
|
|
||||||
leds[getLED(particlePool[p]._pos)] += CRGB(brightness, brightness/2, brightness/2);\
|
r = (uint8_t) ( particlePool[p]._color[0] * brightness);
|
||||||
}
|
g = (uint8_t) ( particlePool[p]._color[1] * brightness);
|
||||||
else
|
b = (uint8_t) ( particlePool[p]._color[2] * brightness);
|
||||||
leds[getLED(particlePool[p]._pos)] += CRGB(particlePool[p]._power, 0, 0);
|
|
||||||
|
leds[getLED(particlePool[p]._pos)] += CRGB(r, g, b);
|
||||||
|
|
||||||
stillActive = true;
|
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 duration = 200; // milliseconds
|
||||||
const int width = 20; // half width of the explosion
|
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
|
int brightness = map((mm-stageStartTime), 0, duration, 255, 150); // this allows a fade from white to red
|
||||||
|
|
||||||
// fill up
|
// fill up
|
||||||
int n = _max(map(((mm-stageStartTime)), 0, duration, getLED(p.position), getLED(p.position)+width), 0);
|
int n = _max(map(((mm-stageStartTime)), 0, duration, getLED(killPos), getLED(killPos)+width), 0);
|
||||||
for(int i = getLED(p.position); i<= n; i++){
|
for(int i = getLED(killPos); i<= n; i++){
|
||||||
leds[i] = CRGB(255, brightness, brightness);
|
leds[i] = CRGB(255, brightness, brightness);
|
||||||
}
|
}
|
||||||
|
|
||||||
// fill to down
|
// fill to down
|
||||||
n = _max(map(((mm-stageStartTime)), 0, duration, getLED(p.position), getLED(p.position)-width), 0);
|
n = _max(map(((mm-stageStartTime)), 0, duration, getLED(killPos), getLED(killPos)-width), 0);
|
||||||
for(int i = getLED(p.position); i>= n; i--){
|
for(int i = getLED(killPos); i>= n; i--){
|
||||||
leds[i] = CRGB(255, brightness, brightness);
|
leds[i] = CRGB(255, brightness, brightness);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1226,6 +1256,9 @@ void getInput(){
|
|||||||
// if(digitalRead(leftButtonPinNumber) == HIGH) joystickTilt = -90;
|
// if(digitalRead(leftButtonPinNumber) == HIGH) joystickTilt = -90;
|
||||||
// if(digitalRead(rightButtonPinNumber) == HIGH) joystickTilt = 90;
|
// if(digitalRead(rightButtonPinNumber) == HIGH) joystickTilt = 90;
|
||||||
// if(digitalRead(attackButtonPinNumber) == HIGH) joystickWobble = ATTACK_THRESHOLD;
|
// if(digitalRead(attackButtonPinNumber) == HIGH) joystickWobble = ATTACK_THRESHOLD;
|
||||||
|
|
||||||
|
// NB: This is not multiplayer yet
|
||||||
|
|
||||||
int16_t ax, ay, az;
|
int16_t ax, ay, az;
|
||||||
int16_t gx, gy, gz;
|
int16_t gx, gy, gz;
|
||||||
|
|
||||||
@@ -1273,6 +1306,8 @@ void getInput() {
|
|||||||
//bool right = digitalRead(rightButtonPinNumber) == LOW;
|
//bool right = digitalRead(rightButtonPinNumber) == LOW;
|
||||||
bool right = left;
|
bool right = left;
|
||||||
|
|
||||||
|
// Player 1
|
||||||
|
|
||||||
joystickTilt[0] = 0;
|
joystickTilt[0] = 0;
|
||||||
if (up) {
|
if (up) {
|
||||||
joystickTilt[0] = 90 ;
|
joystickTilt[0] = 90 ;
|
||||||
@@ -1287,7 +1322,7 @@ void getInput() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Player 2
|
||||||
|
|
||||||
up = digitalRead(upButtonPinNumber2) == LOW;
|
up = digitalRead(upButtonPinNumber2) == LOW;
|
||||||
down = digitalRead(downButtonPinNumber2) == LOW;
|
down = digitalRead(downButtonPinNumber2) == LOW;
|
||||||
|
|||||||
23
TWANG32/colors.h
Normal file
23
TWANG32/colors.h
Normal file
@@ -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));
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user