Added web server and serial port setup
- Access game stats via wifi access point and web server - Setup game preferences via serial port (EEPROM issue causes crashes...help me fix). Does not affect game normal play. - Updated to recent stuff on Arduino port.
This commit is contained in:
@@ -4,18 +4,18 @@
|
|||||||
class Conveyor
|
class Conveyor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void Spawn(int startPoint, int endPoint, int dir);
|
void Spawn(int startPoint, int endPoint, int speed);
|
||||||
void Kill();
|
void Kill();
|
||||||
int _startPoint;
|
int _startPoint;
|
||||||
int _endPoint;
|
int _endPoint;
|
||||||
int _dir;
|
int _speed;
|
||||||
bool _alive;
|
bool _alive;
|
||||||
};
|
};
|
||||||
|
|
||||||
void Conveyor::Spawn(int startPoint, int endPoint, int dir){
|
void Conveyor::Spawn(int startPoint, int endPoint, int speed){
|
||||||
_startPoint = startPoint;
|
_startPoint = startPoint;
|
||||||
_endPoint = endPoint;
|
_endPoint = endPoint;
|
||||||
_dir = constrain(dir, -MAX_PLAYER_SPEED+1, MAX_PLAYER_SPEED - 1); // must allow some player speed
|
_speed = constrain(speed, -MAX_PLAYER_SPEED+1, MAX_PLAYER_SPEED - 1); // must allow some player speed
|
||||||
_alive = true;
|
_alive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
16
README.md
16
README.md
@@ -13,12 +13,19 @@ This was ported from the [TWANG fork](https://github.com/bdring/TWANG) by bdring
|
|||||||
- DAC pins for better sound capabilities.
|
- DAC pins for better sound capabilities.
|
||||||
- Wifi and Bluetooth.
|
- Wifi and Bluetooth.
|
||||||
|
|
||||||
The current state of the code is a basic port of the Arduino version. Several of the libraries did not work, so ESP32 versions are included in the code.
|
**Current State**
|
||||||
|
|
||||||
|
- All of the Arduino version game features are functional.
|
||||||
|
- There is a serial port based setup feature, but the **EEPROM saving crashes randomly**. It does not affect game play, so I am leaving it in. **Help me fix this!**
|
||||||
|
- The game now has a wifi access port to get game stats. Connect a smartphone or computer to see them. Due to the EEPROM saving bug, thee stats reset often :-(
|
||||||
|
- **SSID:** TWANG_AP
|
||||||
|
- **Password:** esp32rocks
|
||||||
|
- **URL:** 192.168.4.1
|
||||||
|
|
||||||
**Coming Soon:**
|
**Coming Soon:**
|
||||||
|
|
||||||
- Wireless features
|
- Wireless features
|
||||||
- A wireless version of the serial port features of TWANG. I think the easiest way is to make it a Wifi access point with a simple web page interface. This allows control by any smartphone or computer with no client side work required.
|
- ~~A wireless version of the serial port features of TWANG. I think the easiest way is to make it a Wifi access point with a simple web page interface. This allows control by any smartphone or computer with no client side work required.~~
|
||||||
- 2 Player features by linking controllers. TBD
|
- 2 Player features by linking controllers. TBD
|
||||||
- Digitized Audio
|
- Digitized Audio
|
||||||
- Currently the port uses the same square wave tones of the the Arduino version.
|
- Currently the port uses the same square wave tones of the the Arduino version.
|
||||||
@@ -96,11 +103,10 @@ They all call different functions and variables to setup the level. Each one is
|
|||||||
* offtime: How long the lava is ON for
|
* offtime: How long the lava is ON for
|
||||||
* offset: How long (ms) after the level starts before the lava turns on, use this to create patterns with multiple lavas
|
* offset: How long (ms) after the level starts before the lava turns on, use this to create patterns with multiple lavas
|
||||||
|
|
||||||
**spawnConveyor(startPoint, endPoint, direction);** (2 conveyors max)
|
**spawnConveyor(startPoint, endPoint, speed);** (2 conveyors max)
|
||||||
* startPoint, endPoint: Same as lava
|
* startPoint, endPoint: Same as lava
|
||||||
* direction: The direction and speed of the travel. Negative moves to base and positive moves towards exit. Must be less than +/- max player speed.
|
* speed: The direction and speed of the travel. Negative moves to base and positive moves towards exit. Must be less than +/- max player speed.
|
||||||
|
|
||||||
**spawnBoss(); ** (only one, don't edit boss level)
|
**spawnBoss(); ** (only one, don't edit boss level)
|
||||||
* There are no parameters for a boss, they always spawn in the same place and have 3 lives. Tweak the values of Boss.h to modify
|
* There are no parameters for a boss, they always spawn in the same place and have 3 lives. Tweak the values of Boss.h to modify
|
||||||
|
|
||||||
Feel free to edit, comment on the YouTube video (link at top) if you have any questions.
|
|
||||||
214
TWANG32.ino
214
TWANG32.ino
@@ -6,13 +6,15 @@
|
|||||||
TWANG was originally created by Critters
|
TWANG was originally created by Critters
|
||||||
https://github.com/Critters/TWANG
|
https://github.com/Critters/TWANG
|
||||||
|
|
||||||
It was inspired by Robin Baumgartens Line Wobbler Game_Audio
|
It was inspired by Robin Baumgarten's Line Wobbler Game_Audio
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define VERSION "2018-03-21"
|
||||||
|
|
||||||
#include <FastLED.h>
|
#include <FastLED.h>
|
||||||
#include<Wire.h>
|
#include<Wire.h>
|
||||||
|
#include "Arduino.h"
|
||||||
#include "RunningMedian.h"
|
#include "RunningMedian.h"
|
||||||
|
|
||||||
// twang files
|
// twang files
|
||||||
@@ -26,6 +28,7 @@
|
|||||||
#include "iSin.h"
|
#include "iSin.h"
|
||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "wifi_ap.h"
|
||||||
//#include "SoundData.h";
|
//#include "SoundData.h";
|
||||||
//#include "Game_Audio.h"
|
//#include "Game_Audio.h"
|
||||||
|
|
||||||
@@ -33,10 +36,28 @@
|
|||||||
#define DATA_PIN 16
|
#define DATA_PIN 16
|
||||||
#define CLOCK_PIN 17
|
#define CLOCK_PIN 17
|
||||||
#define LED_TYPE APA102
|
#define LED_TYPE APA102
|
||||||
#define LED_COLOR_ORDER BGR
|
//#define LED_COLOR_ORDER BGR
|
||||||
#define NUM_LEDS 288
|
#define NUM_LEDS 288
|
||||||
|
|
||||||
#define BRIGHTNESS 150
|
// what type of LED Strip....pick one
|
||||||
|
#define USE_APA102
|
||||||
|
//#define USE_NEOPIXEL
|
||||||
|
|
||||||
|
#ifdef USE_APA102
|
||||||
|
#define LED_TYPE APA102
|
||||||
|
#define LED_COLOR_ORDER BGR // typically this will be the order, but switch it if not
|
||||||
|
#define CONVEYOR_BRIGHTNES 8
|
||||||
|
#define LAVA_OFF_BRIGHTNESS 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_NEOPIXEL
|
||||||
|
#define CONVEYOR_BRIGHTNES 40 // low neopixel values are nearly off, they need a higher value
|
||||||
|
#define LAVA_OFF_BRIGHTNESS 15
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//#define BRIGHTNESS 150
|
||||||
#define DIRECTION 1
|
#define DIRECTION 1
|
||||||
#define MIN_REDRAW_INTERVAL 16 // Min redraw interval (ms) 33 = 30fps / 16 = 63fps
|
#define MIN_REDRAW_INTERVAL 16 // Min redraw interval (ms) 33 = 30fps / 16 = 63fps
|
||||||
#define USE_GRAVITY 0 // 0/1 use gravity (LED strip going up wall)
|
#define USE_GRAVITY 0 // 0/1 use gravity (LED strip going up wall)
|
||||||
@@ -136,27 +157,35 @@ int score = 0;
|
|||||||
|
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
#ifdef DEBUG
|
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
#endif
|
Serial.print("\r\nTWANG32 VERSION: "); Serial.println(VERSION);
|
||||||
|
|
||||||
|
settings_init();
|
||||||
|
|
||||||
Wire.begin();
|
Wire.begin();
|
||||||
accelgyro.initialize();
|
accelgyro.initialize();
|
||||||
|
|
||||||
FastLED.addLeds<LED_TYPE, DATA_PIN, CLOCK_PIN, LED_COLOR_ORDER>(leds, NUM_LEDS);
|
FastLED.addLeds<LED_TYPE, DATA_PIN, CLOCK_PIN, LED_COLOR_ORDER>(leds, NUM_LEDS);
|
||||||
FastLED.setBrightness(BRIGHTNESS);
|
FastLED.setBrightness(user_settings.led_brightness);
|
||||||
FastLED.setDither(1);
|
FastLED.setDither(1);
|
||||||
|
|
||||||
sound_init(DAC_AUDIO_PIN);
|
sound_init(DAC_AUDIO_PIN);
|
||||||
|
|
||||||
|
ap_setup();
|
||||||
|
|
||||||
stage = STARTUP;
|
stage = STARTUP;
|
||||||
stageStartTime = millis();
|
stageStartTime = millis();
|
||||||
|
lives = user_settings.lives_per_level;
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
long mm = millis();
|
long mm = millis();
|
||||||
int brightness = 0;
|
int brightness = 0;
|
||||||
|
|
||||||
|
|
||||||
|
ap_client_check(); // check for web client
|
||||||
|
checkSerialInput();
|
||||||
|
|
||||||
if(stage == PLAY){
|
if(stage == PLAY){
|
||||||
if(attacking){
|
if(attacking){
|
||||||
SFXattacking();
|
SFXattacking();
|
||||||
@@ -175,7 +204,7 @@ void loop() {
|
|||||||
long frameTimer = mm;
|
long frameTimer = mm;
|
||||||
previousMillis = mm;
|
previousMillis = mm;
|
||||||
|
|
||||||
if(abs(joystickTilt) > JOYSTICK_DEADZONE){
|
if(abs(joystickTilt) > user_settings.joystick_deadzone){
|
||||||
lastInputTime = mm;
|
lastInputTime = mm;
|
||||||
if(stage == SCREENSAVER){
|
if(stage == SCREENSAVER){
|
||||||
levelNumber = -1;
|
levelNumber = -1;
|
||||||
@@ -205,7 +234,7 @@ void loop() {
|
|||||||
if(attacking && attackMillis+ATTACK_DURATION < mm) attacking = 0;
|
if(attacking && attackMillis+ATTACK_DURATION < mm) attacking = 0;
|
||||||
|
|
||||||
// If not attacking, check if they should be
|
// If not attacking, check if they should be
|
||||||
if(!attacking && joystickWobble > ATTACK_THRESHOLD){
|
if(!attacking && joystickWobble > user_settings.attack_threshold){
|
||||||
attackMillis = mm;
|
attackMillis = mm;
|
||||||
attacking = 1;
|
attacking = 1;
|
||||||
}
|
}
|
||||||
@@ -250,6 +279,7 @@ void loop() {
|
|||||||
}else if(stage == DEAD){
|
}else if(stage == DEAD){
|
||||||
// DEAD
|
// DEAD
|
||||||
FastLED.clear();
|
FastLED.clear();
|
||||||
|
tickDie(mm);
|
||||||
if(!tickParticles()){
|
if(!tickParticles()){
|
||||||
loadLevel();
|
loadLevel();
|
||||||
}
|
}
|
||||||
@@ -267,9 +297,10 @@ void loop() {
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
FastLED.clear();
|
FastLED.clear();
|
||||||
score = 0; // reset the score
|
save_game_stats(false);
|
||||||
|
//score = 0; // reset the score
|
||||||
levelNumber = 0;
|
levelNumber = 0;
|
||||||
lives = LIVES_PER_LEVEL;
|
lives = user_settings.lives_per_level;
|
||||||
loadLevel();
|
loadLevel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -525,10 +556,9 @@ void cleanupLevel(){
|
|||||||
void levelComplete(){
|
void levelComplete(){
|
||||||
stageStartTime = millis();
|
stageStartTime = millis();
|
||||||
stage = WIN;
|
stage = WIN;
|
||||||
//if(levelNumber == LEVEL_COUNT){
|
|
||||||
if (lastLevel) {
|
if (lastLevel) {
|
||||||
stage = BOSS_KILLED;
|
stage = BOSS_KILLED;
|
||||||
//save_game_stats(true);
|
|
||||||
}
|
}
|
||||||
if (levelNumber != 0) // no points for the first level
|
if (levelNumber != 0) // no points for the first level
|
||||||
{
|
{
|
||||||
@@ -537,12 +567,12 @@ void levelComplete(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nextLevel(){
|
void nextLevel(){
|
||||||
|
|
||||||
levelNumber ++;
|
levelNumber ++;
|
||||||
//if(levelNumber > LEVEL_COUNT)
|
|
||||||
if(lastLevel)
|
if(lastLevel)
|
||||||
levelNumber = 0;
|
levelNumber = 0;
|
||||||
lives = LIVES_PER_LEVEL;
|
|
||||||
|
lives = user_settings.lives_per_level;
|
||||||
loadLevel();
|
loadLevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -556,7 +586,7 @@ void die(){
|
|||||||
playerAlive = 0;
|
playerAlive = 0;
|
||||||
if(levelNumber > 0)
|
if(levelNumber > 0)
|
||||||
lives --;
|
lives --;
|
||||||
//updateLives();
|
|
||||||
if(lives == 0){
|
if(lives == 0){
|
||||||
stage = GAMEOVER;
|
stage = GAMEOVER;
|
||||||
stageStartTime = millis();
|
stageStartTime = millis();
|
||||||
@@ -580,7 +610,7 @@ void tickStartup(long mm)
|
|||||||
FastLED.clear();
|
FastLED.clear();
|
||||||
if(stageStartTime+STARTUP_WIPEUP_DUR > mm) // fill to the top with green
|
if(stageStartTime+STARTUP_WIPEUP_DUR > mm) // fill to the top with green
|
||||||
{
|
{
|
||||||
int n = min(map(((mm-stageStartTime)), 0, STARTUP_WIPEUP_DUR, 0, NUM_LEDS), NUM_LEDS); // fill from top to bottom
|
int n = _min(map(((mm-stageStartTime)), 0, STARTUP_WIPEUP_DUR, 0, NUM_LEDS), NUM_LEDS); // 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);
|
leds[i] = CRGB(0, 255, 0);
|
||||||
}
|
}
|
||||||
@@ -599,8 +629,8 @@ void tickStartup(long mm)
|
|||||||
}
|
}
|
||||||
else if (stageStartTime+STARTUP_FADE_DUR > mm) // fade it out to bottom
|
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, NUM_LEDS), 0); // fill from top to bottom
|
int n = _max(map(((mm-stageStartTime)), STARTUP_SPARKLE_DUR, STARTUP_FADE_DUR, 0, NUM_LEDS), 0); // fill from top to bottom
|
||||||
int brightness = max(map(((mm-stageStartTime)), STARTUP_SPARKLE_DUR, STARTUP_FADE_DUR, 255, 0), 0);
|
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);
|
// leds[i] = CRGB(0, brightness, 0);
|
||||||
@@ -750,7 +780,7 @@ bool tickParticles(){
|
|||||||
leds[getLED(particlePool[p]._pos)] += CRGB(brightness, brightness/2, brightness/2);\
|
leds[getLED(particlePool[p]._pos)] += CRGB(brightness, brightness/2, brightness/2);\
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
leds[getLED(particlePool[p]._pos)] += CRGB(particlePool[p]._power, 0, 0);\
|
leds[getLED(particlePool[p]._pos)] += CRGB(particlePool[p]._power, 0, 0);
|
||||||
|
|
||||||
stillActive = true;
|
stillActive = true;
|
||||||
}
|
}
|
||||||
@@ -759,27 +789,34 @@ bool tickParticles(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void tickConveyors(){
|
void tickConveyors(){
|
||||||
int b, dir, n, i, ss, ee, led;
|
|
||||||
long m = 10000+millis();
|
|
||||||
playerPositionModifier = 0;
|
|
||||||
|
|
||||||
//TODO should the visual speed be proportional to the conveyor speed?
|
//TODO should the visual speed be proportional to the conveyor speed?
|
||||||
|
|
||||||
|
int b, speed, n, i, ss, ee, led;
|
||||||
|
long m = 10000+millis();
|
||||||
|
playerPositionModifier = 0;
|
||||||
|
|
||||||
|
int levels = 5; // brightness levels in conveyor
|
||||||
|
|
||||||
|
|
||||||
for(i = 0; i<CONVEYOR_COUNT; i++){
|
for(i = 0; i<CONVEYOR_COUNT; i++){
|
||||||
if(conveyorPool[i]._alive){
|
if(conveyorPool[i]._alive){
|
||||||
dir = conveyorPool[i]._dir;
|
speed = constrain(conveyorPool[i]._speed, -MAX_PLAYER_SPEED+1, MAX_PLAYER_SPEED-1);
|
||||||
ss = getLED(conveyorPool[i]._startPoint);
|
ss = getLED(conveyorPool[i]._startPoint);
|
||||||
ee = getLED(conveyorPool[i]._endPoint);
|
ee = getLED(conveyorPool[i]._endPoint);
|
||||||
for(led = ss; led<ee; led++){
|
for(led = ss; led<ee; led++){
|
||||||
b = 5;
|
|
||||||
n = (-led + (m/100)) % 5;
|
n = (-led + (m/100)) % levels;
|
||||||
if(dir == -1) n = (led + (m/100)) % 5;
|
if(speed < 0)
|
||||||
b = (5-n)/2.0;
|
n = (led + (m/100)) % levels;
|
||||||
if(b > 0) leds[led] = CRGB(0, 0, b);
|
|
||||||
|
b = map(n, 5, 0, 0, CONVEYOR_BRIGHTNES);
|
||||||
|
if(b > 0)
|
||||||
|
leds[led] = CRGB(0, 0, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(playerPosition > conveyorPool[i]._startPoint && playerPosition < conveyorPool[i]._endPoint){
|
if(playerPosition > conveyorPool[i]._startPoint && playerPosition < conveyorPool[i]._endPoint){
|
||||||
playerPositionModifier = dir;
|
playerPositionModifier = speed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -791,7 +828,7 @@ void tickComplete(long mm) // the boss is dead
|
|||||||
FastLED.clear();
|
FastLED.clear();
|
||||||
SFXcomplete();
|
SFXcomplete();
|
||||||
if(stageStartTime+500 > mm){
|
if(stageStartTime+500 > mm){
|
||||||
int n = max(map(((mm-stageStartTime)), 0, 500, NUM_LEDS, 0), 0);
|
int n = _max(map(((mm-stageStartTime)), 0, 500, NUM_LEDS, 0), 0);
|
||||||
for(int i = NUM_LEDS; i>= n; i--){
|
for(int i = NUM_LEDS; i>= n; i--){
|
||||||
brightness = (sin(((i*10)+mm)/500.0)+1)*255;
|
brightness = (sin(((i*10)+mm)/500.0)+1)*255;
|
||||||
leds[i].setHSV(brightness, 255, 50);
|
leds[i].setHSV(brightness, 255, 50);
|
||||||
@@ -802,7 +839,7 @@ void tickComplete(long mm) // the boss is dead
|
|||||||
leds[i].setHSV(brightness, 255, 50);
|
leds[i].setHSV(brightness, 255, 50);
|
||||||
}
|
}
|
||||||
}else if(stageStartTime+5500 > mm){
|
}else if(stageStartTime+5500 > mm){
|
||||||
int n = max(map(((mm-stageStartTime)), 5000, 5500, NUM_LEDS, 0), 0);
|
int n = _max(map(((mm-stageStartTime)), 5000, 5500, NUM_LEDS, 0), 0);
|
||||||
for(int i = 0; i< n; i++){
|
for(int i = 0; i< n; i++){
|
||||||
brightness = (sin(((i*10)+mm)/500.0)+1)*255;
|
brightness = (sin(((i*10)+mm)/500.0)+1)*255;
|
||||||
leds[i].setHSV(brightness, 255, 50);
|
leds[i].setHSV(brightness, 255, 50);
|
||||||
@@ -817,7 +854,7 @@ void tickBossKilled(long mm) // boss funeral
|
|||||||
int brightness = 0;
|
int brightness = 0;
|
||||||
FastLED.clear();
|
FastLED.clear();
|
||||||
if(stageStartTime+500 > mm){
|
if(stageStartTime+500 > mm){
|
||||||
int n = max(map(((mm-stageStartTime)), 0, 500, NUM_LEDS, 0), 0);
|
int n = _max(map(((mm-stageStartTime)), 0, 500, NUM_LEDS, 0), 0);
|
||||||
for(int i = NUM_LEDS; i>= n; i--){
|
for(int i = NUM_LEDS; i>= n; i--){
|
||||||
brightness = (sin(((i*10)+mm)/500.0)+1)*255;
|
brightness = (sin(((i*10)+mm)/500.0)+1)*255;
|
||||||
leds[i].setHSV(brightness, 255, 50);
|
leds[i].setHSV(brightness, 255, 50);
|
||||||
@@ -830,7 +867,7 @@ void tickBossKilled(long mm) // boss funeral
|
|||||||
}
|
}
|
||||||
SFXbosskilled();
|
SFXbosskilled();
|
||||||
}else if(stageStartTime+7000 > mm){
|
}else if(stageStartTime+7000 > mm){
|
||||||
int n = max(map(((mm-stageStartTime)), 5000, 5500, NUM_LEDS, 0), 0);
|
int n = _max(map(((mm-stageStartTime)), 5000, 5500, NUM_LEDS, 0), 0);
|
||||||
for(int i = 0; i< n; i++){
|
for(int i = 0; i< n; i++){
|
||||||
brightness = (sin(((i*10)+mm)/500.0)+1)*255;
|
brightness = (sin(((i*10)+mm)/500.0)+1)*255;
|
||||||
leds[i].setHSV(brightness, 255, 50);
|
leds[i].setHSV(brightness, 255, 50);
|
||||||
@@ -841,6 +878,28 @@ void tickBossKilled(long mm) // boss funeral
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tickDie(long mm) { // a short bright explosion...particles persist after it.
|
||||||
|
const int duration = 100; // milliseconds
|
||||||
|
const int width = 10; // 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, 50); // 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) {
|
void tickGameover(long mm) {
|
||||||
|
|
||||||
int brightness = 0;
|
int brightness = 0;
|
||||||
@@ -848,12 +907,12 @@ void tickGameover(long mm) {
|
|||||||
if(stageStartTime+GAMEOVER_SPREAD_DURATION > mm) // Spread red from player position to top and bottom
|
if(stageStartTime+GAMEOVER_SPREAD_DURATION > mm) // Spread red from player position to top and bottom
|
||||||
{
|
{
|
||||||
// fill to top
|
// fill to top
|
||||||
int n = max(map(((mm-stageStartTime)), 0, GAMEOVER_SPREAD_DURATION, getLED(playerPosition), NUM_LEDS), 0);
|
int n = _max(map(((mm-stageStartTime)), 0, GAMEOVER_SPREAD_DURATION, getLED(playerPosition), NUM_LEDS), 0);
|
||||||
for(int i = getLED(playerPosition); i<= n; i++){
|
for(int i = getLED(playerPosition); i<= n; i++){
|
||||||
leds[i] = CRGB(255, 0, 0);
|
leds[i] = CRGB(255, 0, 0);
|
||||||
}
|
}
|
||||||
// fill to bottom
|
// fill to bottom
|
||||||
n = max(map(((mm-stageStartTime)), 0, GAMEOVER_SPREAD_DURATION, getLED(playerPosition), 0), 0);
|
n = _max(map(((mm-stageStartTime)), 0, GAMEOVER_SPREAD_DURATION, getLED(playerPosition), 0), 0);
|
||||||
for(int i = getLED(playerPosition); i>= n; i--){
|
for(int i = getLED(playerPosition); i>= n; i--){
|
||||||
leds[i] = CRGB(255, 0, 0);
|
leds[i] = CRGB(255, 0, 0);
|
||||||
}
|
}
|
||||||
@@ -861,7 +920,7 @@ void tickGameover(long mm) {
|
|||||||
}
|
}
|
||||||
else if(stageStartTime+GAMEOVER_FADE_DURATION > mm) // fade down to bottom and fade brightness
|
else if(stageStartTime+GAMEOVER_FADE_DURATION > mm) // fade down to bottom and fade brightness
|
||||||
{
|
{
|
||||||
int n = max(map(((mm-stageStartTime)), GAMEOVER_FADE_DURATION, GAMEOVER_SPREAD_DURATION, NUM_LEDS, 0), 0);
|
int n = _max(map(((mm-stageStartTime)), GAMEOVER_FADE_DURATION, GAMEOVER_SPREAD_DURATION, NUM_LEDS, 0), 0);
|
||||||
brightness = map(((mm-stageStartTime)), GAMEOVER_SPREAD_DURATION, GAMEOVER_FADE_DURATION, 200, 0);
|
brightness = map(((mm-stageStartTime)), GAMEOVER_SPREAD_DURATION, GAMEOVER_FADE_DURATION, 200, 0);
|
||||||
|
|
||||||
for(int i = 0; i<= n; i++){
|
for(int i = 0; i<= n; i++){
|
||||||
@@ -878,21 +937,21 @@ void tickWin(long mm) {
|
|||||||
int brightness = 0;
|
int brightness = 0;
|
||||||
FastLED.clear();
|
FastLED.clear();
|
||||||
if(stageStartTime+WIN_FILL_DURATION > mm){
|
if(stageStartTime+WIN_FILL_DURATION > mm){
|
||||||
int n = max(map(((mm-stageStartTime)), 0, WIN_FILL_DURATION, NUM_LEDS, 0), 0); // fill from top to bottom
|
int n = _max(map(((mm-stageStartTime)), 0, WIN_FILL_DURATION, NUM_LEDS, 0), 0); // fill from top to bottom
|
||||||
for(int i = NUM_LEDS; i>= n; i--){
|
for(int i = NUM_LEDS; i>= n; i--){
|
||||||
brightness = BRIGHTNESS;
|
brightness = user_settings.led_brightness;
|
||||||
leds[i] = CRGB(0, brightness, 0);
|
leds[i] = CRGB(0, brightness, 0);
|
||||||
}
|
}
|
||||||
SFXwin();
|
SFXwin();
|
||||||
}else if(stageStartTime+WIN_CLEAR_DURATION > mm){
|
}else if(stageStartTime+WIN_CLEAR_DURATION > mm){
|
||||||
int n = max(map(((mm-stageStartTime)), WIN_FILL_DURATION, WIN_CLEAR_DURATION, NUM_LEDS, 0), 0); // clear from top to bottom
|
int n = _max(map(((mm-stageStartTime)), WIN_FILL_DURATION, WIN_CLEAR_DURATION, NUM_LEDS, 0), 0); // clear from top to bottom
|
||||||
for(int i = 0; i< n; i++){
|
for(int i = 0; i< n; i++){
|
||||||
brightness = BRIGHTNESS;
|
brightness = user_settings.led_brightness;
|
||||||
leds[i] = CRGB(0, brightness, 0);
|
leds[i] = CRGB(0, brightness, 0);
|
||||||
}
|
}
|
||||||
SFXwin();
|
SFXwin();
|
||||||
}else if(stageStartTime+WIN_OFF_DURATION > mm){ // wait a while with leds off
|
}else if(stageStartTime+WIN_OFF_DURATION > mm){ // wait a while with leds off
|
||||||
leds[0] = CRGB(0, BRIGHTNESS, 0);
|
leds[0] = CRGB(0, user_settings.led_brightness, 0);
|
||||||
}else{
|
}else{
|
||||||
nextLevel();
|
nextLevel();
|
||||||
}
|
}
|
||||||
@@ -967,6 +1026,19 @@ void updateLives(){
|
|||||||
drawLives();
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------
|
// ---------------------------------
|
||||||
// --------- SCREENSAVER -----------
|
// --------- SCREENSAVER -----------
|
||||||
// ---------------------------------
|
// ---------------------------------
|
||||||
@@ -1012,50 +1084,24 @@ 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;
|
||||||
|
int16_t ax, ay, az;
|
||||||
int16_t ax, ay, az, gx, gy, gz, accel, gyro;
|
int16_t gx, gy, gz;
|
||||||
|
|
||||||
accelgyro.getMotion6(&ax, &ay, &az, &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));
|
||||||
|
|
||||||
|
if(abs(a) < user_settings.joystick_deadzone) a = 0;
|
||||||
// what orientation is used?
|
if(a > 0) a -= user_settings.joystick_deadzone;
|
||||||
if (JOYSTICK_ORIENTATION == 0) {
|
if(a < 0) a += user_settings.joystick_deadzone;
|
||||||
accel = ax;
|
MPUAngleSamples.add(a);
|
||||||
gyro = gx;
|
MPUWobbleSamples.add(g);
|
||||||
}
|
|
||||||
else if (JOYSTICK_ORIENTATION == 1) {
|
|
||||||
accel = ay;
|
|
||||||
gyro = gy;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
accel = ay;
|
|
||||||
gyro = gy;
|
|
||||||
}
|
|
||||||
|
|
||||||
accel = accel / 166; // adjust it to degrees.
|
|
||||||
|
|
||||||
// apply the deadzone
|
|
||||||
if(abs(accel) < JOYSTICK_DEADZONE) accel = 0;
|
|
||||||
if(accel > 0) accel -= JOYSTICK_DEADZONE;
|
|
||||||
if(accel < 0) accel += JOYSTICK_DEADZONE;
|
|
||||||
|
|
||||||
MPUAngleSamples.add(accel);
|
|
||||||
MPUWobbleSamples.add(gyro);
|
|
||||||
|
|
||||||
joystickTilt = MPUAngleSamples.getMedian();
|
joystickTilt = MPUAngleSamples.getMedian();
|
||||||
joystickWobble = abs(MPUWobbleSamples.getHighest());
|
if(JOYSTICK_DIRECTION == 1) {
|
||||||
|
|
||||||
if(JOYSTICK_DIRECTION == 1) { // what direction is MPU facing
|
|
||||||
joystickTilt = 0-joystickTilt;
|
joystickTilt = 0-joystickTilt;
|
||||||
}
|
}
|
||||||
|
joystickWobble = abs(MPUWobbleSamples.getHighest());
|
||||||
|
|
||||||
|
|
||||||
#ifdef DEBUG // show input Data
|
|
||||||
Serial.print("Tilt: "); Serial.println(joystickTilt);
|
|
||||||
//Serial.print("Wobble: "); Serial.println(joystickWobble);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------
|
// ---------------------------------
|
||||||
@@ -1082,7 +1128,7 @@ void SFXFreqSweepWarble(int duration, int elapsedTime, int freqStart, int freqEn
|
|||||||
if (warble)
|
if (warble)
|
||||||
warble = map(sin(millis()/20.0)*1000.0, -1000, 1000, 0, warble);
|
warble = map(sin(millis()/20.0)*1000.0, -1000, 1000, 0, warble);
|
||||||
|
|
||||||
sound(freq + warble, MAX_VOLUME);
|
sound(freq + warble, user_settings.audio_volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1111,7 +1157,7 @@ void SFXFreqSweepNoise(int duration, int elapsedTime, int freqStart, int freqEnd
|
|||||||
if (noiseFactor)
|
if (noiseFactor)
|
||||||
noiseFactor = noiseFactor - random8(noiseFactor / 2);
|
noiseFactor = noiseFactor - random8(noiseFactor / 2);
|
||||||
|
|
||||||
sound(freq + noiseFactor, MAX_VOLUME);
|
sound(freq + noiseFactor, user_settings.audio_volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1124,7 +1170,7 @@ void SFXtilt(int amount){
|
|||||||
int f = map(abs(amount), 0, 90, 80, 900)+random8(100);
|
int f = map(abs(amount), 0, 90, 80, 900)+random8(100);
|
||||||
if(playerPositionModifier < 0) f -= 500;
|
if(playerPositionModifier < 0) f -= 500;
|
||||||
if(playerPositionModifier > 0) f += 200;
|
if(playerPositionModifier > 0) f += 200;
|
||||||
int vol = map(abs(amount), 0, 90, MAX_VOLUME / 2, MAX_VOLUME * 3/4);
|
int vol = map(abs(amount), 0, 90, user_settings.audio_volume / 2, user_settings.audio_volume * 3/4);
|
||||||
sound(f,vol);
|
sound(f,vol);
|
||||||
}
|
}
|
||||||
void SFXattacking(){
|
void SFXattacking(){
|
||||||
@@ -1132,7 +1178,7 @@ void SFXattacking(){
|
|||||||
if(random8(5)== 0){
|
if(random8(5)== 0){
|
||||||
freq *= 3;
|
freq *= 3;
|
||||||
}
|
}
|
||||||
sound(freq, MAX_VOLUME);
|
sound(freq, user_settings.audio_volume);
|
||||||
}
|
}
|
||||||
void SFXdead(){
|
void SFXdead(){
|
||||||
SFXFreqSweepNoise(1000, millis()-killTime, 1000, 10, 200);
|
SFXFreqSweepNoise(1000, millis()-killTime, 1000, 10, 200);
|
||||||
@@ -1143,7 +1189,7 @@ void SFXgameover(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SFXkill(){
|
void SFXkill(){
|
||||||
sound(2000, MAX_VOLUME);
|
sound(2000, user_settings.audio_volume);
|
||||||
}
|
}
|
||||||
void SFXwin(){
|
void SFXwin(){
|
||||||
SFXFreqSweepWarble(WIN_OFF_DURATION, millis()-stageStartTime, 40, 400, 20);
|
SFXFreqSweepWarble(WIN_OFF_DURATION, millis()-stageStartTime, 40, 400, 20);
|
||||||
|
|||||||
374
settings.h
374
settings.h
@@ -1,6 +1,19 @@
|
|||||||
|
#ifndef SETTINGS_H
|
||||||
|
#define SETTINGS_H
|
||||||
|
|
||||||
|
#include <EEPROM.h>
|
||||||
|
|
||||||
|
// change this whenever the saved settings are not compatible with a change
|
||||||
|
// It forces a reset from defaults.
|
||||||
|
#define SETTINGS_VERSION 1
|
||||||
|
#define EEPROM_SIZE 256
|
||||||
|
|
||||||
|
// LEDS
|
||||||
|
#define BRIGHTNESS 150
|
||||||
|
|
||||||
// PLAYER
|
// PLAYER
|
||||||
#define MAX_PLAYER_SPEED 10 // Max move speed of the player
|
const uint8_t MAX_PLAYER_SPEED = 10; // Max move speed of the player
|
||||||
#define LIVES_PER_LEVEL 3 // default lives per level
|
const uint8_t LIVES_PER_LEVEL = 3; // default lives per level
|
||||||
|
|
||||||
// JOYSTICK
|
// JOYSTICK
|
||||||
#define JOYSTICK_ORIENTATION 1 // 0, 1 or 2 to set the axis of the joystick
|
#define JOYSTICK_ORIENTATION 1 // 0, 1 or 2 to set the axis of the joystick
|
||||||
@@ -9,7 +22,362 @@
|
|||||||
#define JOYSTICK_DEADZONE 8 // Angle to ignore
|
#define JOYSTICK_DEADZONE 8 // Angle to ignore
|
||||||
|
|
||||||
// AUDIO
|
// AUDIO
|
||||||
#define MAX_VOLUME 20 // 0 to 255
|
#define MAX_VOLUME 5 // 0 to 255
|
||||||
#define DAC_AUDIO_PIN 25 // should be 25 or 26 only
|
#define DAC_AUDIO_PIN 25 // should be 25 or 26 only
|
||||||
|
|
||||||
|
enum ErrorNums{
|
||||||
|
ERR_SETTING_NUM,
|
||||||
|
ERR_SETTING_RANGE
|
||||||
|
};
|
||||||
|
|
||||||
|
//EEPROMClass SETTINGS("eeprom", 0x100);
|
||||||
|
|
||||||
//TODO ... move all the settings to this file.
|
//TODO ... move all the settings to this file.
|
||||||
|
|
||||||
|
// Function prototypes
|
||||||
|
//void reset_settings();
|
||||||
|
void settings_init();
|
||||||
|
void show_game_stats();
|
||||||
|
void settings_eeprom_write();
|
||||||
|
void settings_eeprom_read();
|
||||||
|
void change_setting(char *line);
|
||||||
|
void processSerial(char inChar);
|
||||||
|
void printError(int reason);
|
||||||
|
void show_settings_menu();
|
||||||
|
void reset_settings();
|
||||||
|
|
||||||
|
SemaphoreHandle_t xMutex;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t settings_version; // stores the settings format version
|
||||||
|
|
||||||
|
//due to the fastLED classes there is not much we can change dynamically
|
||||||
|
uint8_t led_brightness;
|
||||||
|
|
||||||
|
uint8_t joystick_deadzone;
|
||||||
|
uint16_t attack_threshold;
|
||||||
|
|
||||||
|
uint8_t audio_volume;
|
||||||
|
|
||||||
|
uint8_t lives_per_level;
|
||||||
|
|
||||||
|
// saved statistics
|
||||||
|
uint16_t games_played;
|
||||||
|
uint32_t total_points;
|
||||||
|
uint16_t high_score;
|
||||||
|
uint16_t boss_kills;
|
||||||
|
|
||||||
|
}settings_t;
|
||||||
|
|
||||||
|
settings_t user_settings;
|
||||||
|
|
||||||
|
#define READ_BUFFER_LEN 10
|
||||||
|
#define CARRIAGE_RETURN 13
|
||||||
|
char readBuffer[READ_BUFFER_LEN];
|
||||||
|
uint8_t readIndex = 0;
|
||||||
|
|
||||||
|
void settings_init() {
|
||||||
|
|
||||||
|
//if (!EEPROM.begin(EEPROM_SIZE))
|
||||||
|
//{
|
||||||
|
// Serial.println("failed to initialize EEPROM");
|
||||||
|
//}
|
||||||
|
|
||||||
|
settings_eeprom_read();
|
||||||
|
show_settings_menu();
|
||||||
|
show_game_stats();
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkSerialInput() {
|
||||||
|
if (Serial.available()) {
|
||||||
|
processSerial(Serial.read());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void processSerial(char inChar)
|
||||||
|
{
|
||||||
|
readBuffer[readIndex] = inChar;
|
||||||
|
switch(readBuffer[readIndex]){
|
||||||
|
case '?':
|
||||||
|
readIndex = 0;
|
||||||
|
show_settings_menu();
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'R':
|
||||||
|
readIndex = 0;
|
||||||
|
reset_settings();
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'P':
|
||||||
|
user_settings.games_played = 0;
|
||||||
|
user_settings.total_points = 0;
|
||||||
|
user_settings.high_score = 0;
|
||||||
|
user_settings.boss_kills = 0;
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '!':
|
||||||
|
ESP.restart();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'E':
|
||||||
|
settings_eeprom_write();
|
||||||
|
delay(1000);
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readBuffer[readIndex] == CARRIAGE_RETURN) {
|
||||||
|
if (readIndex < 3) {
|
||||||
|
// not enough characters
|
||||||
|
readIndex = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
readBuffer[readIndex] = 0; // mark it as the end of the string
|
||||||
|
change_setting(readBuffer);
|
||||||
|
readIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (readIndex >= READ_BUFFER_LEN) {
|
||||||
|
readIndex = 0; // too many characters. Reset and try again
|
||||||
|
}
|
||||||
|
else
|
||||||
|
readIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void change_setting(char *line) {
|
||||||
|
// line formate should be ss=nn
|
||||||
|
// ss is always a 2 character integer
|
||||||
|
// nn starts at index 3 and can be up to a 5 character unsigned integer
|
||||||
|
|
||||||
|
//12=12345
|
||||||
|
//01234567
|
||||||
|
|
||||||
|
char setting_val[6];
|
||||||
|
char param;
|
||||||
|
uint16_t newValue;
|
||||||
|
Serial.print("Read Buffer: "); Serial.println(readBuffer);
|
||||||
|
|
||||||
|
if (readBuffer[1] != '='){ // check if the equals sign is there
|
||||||
|
Serial.print("Missing '=' in command");
|
||||||
|
readIndex = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// move the value characters into a char array while verifying they are digits
|
||||||
|
for(int i=0; i<5; i++) {
|
||||||
|
if (i+2 < readIndex) {
|
||||||
|
if (isDigit(readBuffer[i+2]))
|
||||||
|
setting_val[i] = readBuffer[i+2];
|
||||||
|
else {
|
||||||
|
Serial.println("Invalid setting value");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
setting_val[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
param = readBuffer[0];
|
||||||
|
newValue = atoi(setting_val); // convert the val section to an integer
|
||||||
|
|
||||||
|
memset(readBuffer,0,sizeof(readBuffer));
|
||||||
|
|
||||||
|
switch (param) {
|
||||||
|
case 'B': // brightness
|
||||||
|
if(newValue >=5 && newValue <=255)
|
||||||
|
user_settings.led_brightness = (uint8_t)newValue;
|
||||||
|
else {
|
||||||
|
printError(ERR_SETTING_RANGE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'S': // sound
|
||||||
|
if (newValue >=0 && newValue < 255)
|
||||||
|
user_settings.audio_volume = (uint8_t)newValue;
|
||||||
|
else {
|
||||||
|
printError(ERR_SETTING_RANGE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'D': // deadzone, joystick
|
||||||
|
if(newValue >=3 && newValue <=12)
|
||||||
|
user_settings.joystick_deadzone = (uint8_t)newValue;
|
||||||
|
else {
|
||||||
|
printError(ERR_SETTING_RANGE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'A': // attack threshold, joystick
|
||||||
|
if(newValue >=20000 && newValue <=35000)
|
||||||
|
user_settings.attack_threshold = (uint16_t)newValue;
|
||||||
|
else {
|
||||||
|
printError(ERR_SETTING_RANGE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'L': // lives per level
|
||||||
|
if (newValue >= 3 && newValue <= 9)
|
||||||
|
user_settings.lives_per_level = (uint8_t)newValue;
|
||||||
|
else {
|
||||||
|
printError(ERR_SETTING_RANGE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Serial.print("Command Error: ");
|
||||||
|
Serial.println(readBuffer[0]);
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
show_settings_menu();
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset_settings() {
|
||||||
|
user_settings.settings_version = SETTINGS_VERSION;
|
||||||
|
|
||||||
|
user_settings.led_brightness = BRIGHTNESS;
|
||||||
|
|
||||||
|
user_settings.joystick_deadzone = JOYSTICK_DEADZONE;
|
||||||
|
user_settings.attack_threshold = ATTACK_THRESHOLD;
|
||||||
|
|
||||||
|
user_settings.audio_volume = MAX_VOLUME;
|
||||||
|
|
||||||
|
user_settings.lives_per_level = LIVES_PER_LEVEL;
|
||||||
|
|
||||||
|
user_settings.games_played = 0;
|
||||||
|
user_settings.total_points = 0;
|
||||||
|
user_settings.high_score = 0;
|
||||||
|
user_settings.boss_kills = 0;
|
||||||
|
|
||||||
|
settings_eeprom_write();
|
||||||
|
}
|
||||||
|
|
||||||
|
void show_settings_menu() {
|
||||||
|
Serial.println("\r\n====== TWANG Settings Menu ========");
|
||||||
|
Serial.println("= Current values are shown =");
|
||||||
|
Serial.println("= Send new values like B=150 =");
|
||||||
|
Serial.println("= with a carriage return =");
|
||||||
|
Serial.println("===================================");
|
||||||
|
|
||||||
|
Serial.print("\r\nB=");
|
||||||
|
Serial.print(user_settings.led_brightness);
|
||||||
|
Serial.println(" (LED Brightness 5-255)");
|
||||||
|
|
||||||
|
Serial.print("S=");
|
||||||
|
Serial.print(user_settings.audio_volume);
|
||||||
|
Serial.println(" (Sound Volume 0-10)");
|
||||||
|
|
||||||
|
Serial.print("D=");
|
||||||
|
Serial.print(user_settings.joystick_deadzone);
|
||||||
|
Serial.println(" (Joystick Deadzone 3-12)");
|
||||||
|
|
||||||
|
Serial.print("A=");
|
||||||
|
Serial.print(user_settings.attack_threshold);
|
||||||
|
Serial.println(" (Attack Sensitivity 20000-35000)");
|
||||||
|
|
||||||
|
Serial.print("L=");
|
||||||
|
Serial.print(user_settings.lives_per_level);
|
||||||
|
Serial.println(" (Lives per Level (3-9))");
|
||||||
|
|
||||||
|
Serial.println("\r\n(Send...)");
|
||||||
|
Serial.println(" ? to show current settings");
|
||||||
|
Serial.println(" R to reset everything to defaults)");
|
||||||
|
Serial.println(" P to reset play statistics)");
|
||||||
|
Serial.println(" E to write changes to eeprom)");
|
||||||
|
Serial.println(" ! to restart with current settings");
|
||||||
|
|
||||||
|
show_game_stats();
|
||||||
|
}
|
||||||
|
|
||||||
|
void show_game_stats()
|
||||||
|
{
|
||||||
|
Serial.println("\r\n ===== Play statistics ======");
|
||||||
|
Serial.print("Games played: ");Serial.println(user_settings.games_played);
|
||||||
|
if (user_settings.games_played > 0) {
|
||||||
|
Serial.print("Average Score: ");Serial.println(user_settings.total_points / user_settings.games_played);
|
||||||
|
}
|
||||||
|
Serial.print("High Score: ");Serial.println(user_settings.high_score);
|
||||||
|
Serial.print("Boss kills: ");Serial.println(user_settings.boss_kills);
|
||||||
|
}
|
||||||
|
|
||||||
|
void settings_eeprom_read()
|
||||||
|
{
|
||||||
|
Serial.println("Begin EEPROM Read");
|
||||||
|
|
||||||
|
EEPROM.begin(EEPROM_SIZE);
|
||||||
|
|
||||||
|
uint8_t ver = EEPROM.read(0);
|
||||||
|
uint8_t temp[sizeof(user_settings)];
|
||||||
|
|
||||||
|
if (ver != SETTINGS_VERSION) {
|
||||||
|
Serial.print("Error: EEPROM settings read failed:"); Serial.println(ver);
|
||||||
|
Serial.println("Loading defaults...");
|
||||||
|
reset_settings();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.print("Settings version: "); Serial.println(ver);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0; i<sizeof(user_settings); i++)
|
||||||
|
{
|
||||||
|
temp[i] = EEPROM.read(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy((char*)&user_settings, temp, sizeof(user_settings));
|
||||||
|
|
||||||
|
EEPROM.end();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void settings_eeprom_write() {
|
||||||
|
|
||||||
|
EEPROM.begin(EEPROM_SIZE);
|
||||||
|
|
||||||
|
uint8_t temp[sizeof(user_settings)];
|
||||||
|
memcpy(temp, (uint8_t*)&user_settings, sizeof(user_settings));
|
||||||
|
|
||||||
|
Serial.println("Writing settings...");
|
||||||
|
|
||||||
|
|
||||||
|
for (int i=0; i<sizeof(user_settings); i++)
|
||||||
|
{
|
||||||
|
EEPROM.write(i, temp[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
EEPROM.commit();
|
||||||
|
|
||||||
|
EEPROM.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void printError(int reason) {
|
||||||
|
|
||||||
|
switch(reason) {
|
||||||
|
case ERR_SETTING_NUM:
|
||||||
|
Serial.print("Error: Invalid setting number");
|
||||||
|
break;
|
||||||
|
case ERR_SETTING_RANGE:
|
||||||
|
Serial.print("Error: Setting out of range");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Serial.print("Error:");Serial.println(reason);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
65
wifi_ap.h
Normal file
65
wifi_ap.h
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#include <WiFi.h>
|
||||||
|
|
||||||
|
const char* ssid = "TWANG_AP";
|
||||||
|
const char* passphrase = "esp32rocks";
|
||||||
|
|
||||||
|
WiFiServer server(80);
|
||||||
|
|
||||||
|
void ap_setup() {
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up an access point
|
||||||
|
* @param ssid Pointer to the SSID (max 63 char).
|
||||||
|
* @param passphrase (for WPA2 min 8 char, for open use NULL)
|
||||||
|
* @param channel WiFi channel number, 1 - 13.
|
||||||
|
* @param ssid_hidden Network cloaking (0 = broadcast SSID, 1 = hide SSID)
|
||||||
|
*/
|
||||||
|
ret = WiFi.softAP(ssid, passphrase, 2, 0);
|
||||||
|
|
||||||
|
Serial.println("\r\nWiFi AP online ...");
|
||||||
|
server.begin();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendStatsPage(WiFiClient client) {
|
||||||
|
Serial.println("printUploadForm");
|
||||||
|
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
|
||||||
|
// and a content-type so the client knows what's coming, then a blank line:
|
||||||
|
client.println("HTTP/1.1 200 OK");
|
||||||
|
client.println("Content-type:text/html");
|
||||||
|
client.println();
|
||||||
|
client.println("<html>");
|
||||||
|
client.println("<body>");
|
||||||
|
client.println("<h1>TWANG32 Play Stats</h1>");
|
||||||
|
client.println("<ul>");
|
||||||
|
|
||||||
|
client.print("<li>Games played: "); client.print(user_settings.games_played); client.println("</li>");
|
||||||
|
if (user_settings.games_played > 0) { // prevent divide by 0
|
||||||
|
client.print("<li>Average score: "); client.print(user_settings.total_points / user_settings.games_played); client.println("</li>");
|
||||||
|
}
|
||||||
|
client.print("<li>High score: "); client.print(user_settings.high_score); client.println("</li>");
|
||||||
|
client.print("<li>Boss kills: "); client.print(user_settings.boss_kills); client.println("</li>");
|
||||||
|
|
||||||
|
client.println("</ul>");
|
||||||
|
client.println("</body>");
|
||||||
|
client.println("</html>");
|
||||||
|
client.println();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ap_client_check(){
|
||||||
|
int cnt;
|
||||||
|
bool newconn=false;
|
||||||
|
int stat;
|
||||||
|
WiFiClient client = server.available(); // listen for incoming clients
|
||||||
|
|
||||||
|
if (client) { // if you get a client,
|
||||||
|
sendStatsPage(client);
|
||||||
|
Serial.println("printUploadForm");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user