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
|
||||
{
|
||||
public:
|
||||
void Spawn(int startPoint, int endPoint, int dir);
|
||||
void Spawn(int startPoint, int endPoint, int speed);
|
||||
void Kill();
|
||||
int _startPoint;
|
||||
int _endPoint;
|
||||
int _dir;
|
||||
int _speed;
|
||||
bool _alive;
|
||||
};
|
||||
|
||||
void Conveyor::Spawn(int startPoint, int endPoint, int dir){
|
||||
void Conveyor::Spawn(int startPoint, int endPoint, int speed){
|
||||
_startPoint = startPoint;
|
||||
_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;
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
- 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:**
|
||||
|
||||
- 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
|
||||
- Digitized Audio
|
||||
- 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
|
||||
* 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
|
||||
* 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)
|
||||
* 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.
|
||||
250
TWANG32.ino
250
TWANG32.ino
@@ -6,13 +6,15 @@
|
||||
TWANG was originally created by Critters
|
||||
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<Wire.h>
|
||||
#include "Arduino.h"
|
||||
#include "RunningMedian.h"
|
||||
|
||||
// twang files
|
||||
@@ -26,6 +28,7 @@
|
||||
#include "iSin.h"
|
||||
#include "sound.h"
|
||||
#include "settings.h"
|
||||
#include "wifi_ap.h"
|
||||
//#include "SoundData.h";
|
||||
//#include "Game_Audio.h"
|
||||
|
||||
@@ -33,10 +36,28 @@
|
||||
#define DATA_PIN 16
|
||||
#define CLOCK_PIN 17
|
||||
#define LED_TYPE APA102
|
||||
#define LED_COLOR_ORDER BGR
|
||||
//#define LED_COLOR_ORDER BGR
|
||||
#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 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)
|
||||
@@ -136,26 +157,34 @@ int score = 0;
|
||||
|
||||
|
||||
void setup() {
|
||||
#ifdef DEBUG
|
||||
Serial.begin(115200);
|
||||
#endif
|
||||
Serial.begin(115200);
|
||||
Serial.print("\r\nTWANG32 VERSION: "); Serial.println(VERSION);
|
||||
|
||||
Wire.begin();
|
||||
accelgyro.initialize();
|
||||
|
||||
FastLED.addLeds<LED_TYPE, DATA_PIN, CLOCK_PIN, LED_COLOR_ORDER>(leds, NUM_LEDS);
|
||||
FastLED.setBrightness(BRIGHTNESS);
|
||||
FastLED.setDither(1);
|
||||
settings_init();
|
||||
|
||||
sound_init(DAC_AUDIO_PIN);
|
||||
Wire.begin();
|
||||
accelgyro.initialize();
|
||||
|
||||
stage = STARTUP;
|
||||
stageStartTime = millis();
|
||||
FastLED.addLeds<LED_TYPE, DATA_PIN, CLOCK_PIN, LED_COLOR_ORDER>(leds, NUM_LEDS);
|
||||
FastLED.setBrightness(user_settings.led_brightness);
|
||||
FastLED.setDither(1);
|
||||
|
||||
sound_init(DAC_AUDIO_PIN);
|
||||
|
||||
ap_setup();
|
||||
|
||||
stage = STARTUP;
|
||||
stageStartTime = millis();
|
||||
lives = user_settings.lives_per_level;
|
||||
}
|
||||
|
||||
void loop() {
|
||||
long mm = millis();
|
||||
int brightness = 0;
|
||||
|
||||
|
||||
ap_client_check(); // check for web client
|
||||
checkSerialInput();
|
||||
|
||||
if(stage == PLAY){
|
||||
if(attacking){
|
||||
@@ -175,7 +204,7 @@ void loop() {
|
||||
long frameTimer = mm;
|
||||
previousMillis = mm;
|
||||
|
||||
if(abs(joystickTilt) > JOYSTICK_DEADZONE){
|
||||
if(abs(joystickTilt) > user_settings.joystick_deadzone){
|
||||
lastInputTime = mm;
|
||||
if(stage == SCREENSAVER){
|
||||
levelNumber = -1;
|
||||
@@ -205,7 +234,7 @@ void loop() {
|
||||
if(attacking && attackMillis+ATTACK_DURATION < mm) attacking = 0;
|
||||
|
||||
// If not attacking, check if they should be
|
||||
if(!attacking && joystickWobble > ATTACK_THRESHOLD){
|
||||
if(!attacking && joystickWobble > user_settings.attack_threshold){
|
||||
attackMillis = mm;
|
||||
attacking = 1;
|
||||
}
|
||||
@@ -248,8 +277,9 @@ void loop() {
|
||||
drawAttack();
|
||||
drawExit();
|
||||
}else if(stage == DEAD){
|
||||
// DEAD
|
||||
// DEAD
|
||||
FastLED.clear();
|
||||
tickDie(mm);
|
||||
if(!tickParticles()){
|
||||
loadLevel();
|
||||
}
|
||||
@@ -261,15 +291,16 @@ void loop() {
|
||||
//tickComplete(mm);
|
||||
} else if (stage == GAMEOVER) {
|
||||
if (stageStartTime+GAMEOVER_FADE_DURATION > mm)
|
||||
{
|
||||
{
|
||||
tickGameover(mm);
|
||||
}
|
||||
else
|
||||
{
|
||||
FastLED.clear();
|
||||
score = 0; // reset the score
|
||||
FastLED.clear();
|
||||
save_game_stats(false);
|
||||
//score = 0; // reset the score
|
||||
levelNumber = 0;
|
||||
lives = LIVES_PER_LEVEL;
|
||||
lives = user_settings.lives_per_level;
|
||||
loadLevel();
|
||||
}
|
||||
}
|
||||
@@ -525,10 +556,9 @@ void cleanupLevel(){
|
||||
void levelComplete(){
|
||||
stageStartTime = millis();
|
||||
stage = WIN;
|
||||
//if(levelNumber == LEVEL_COUNT){
|
||||
|
||||
if (lastLevel) {
|
||||
stage = BOSS_KILLED;
|
||||
//save_game_stats(true);
|
||||
}
|
||||
if (levelNumber != 0) // no points for the first level
|
||||
{
|
||||
@@ -536,13 +566,13 @@ void levelComplete(){
|
||||
}
|
||||
}
|
||||
|
||||
void nextLevel(){
|
||||
|
||||
void nextLevel(){
|
||||
levelNumber ++;
|
||||
//if(levelNumber > LEVEL_COUNT)
|
||||
|
||||
if(lastLevel)
|
||||
levelNumber = 0;
|
||||
lives = LIVES_PER_LEVEL;
|
||||
|
||||
lives = user_settings.lives_per_level;
|
||||
loadLevel();
|
||||
}
|
||||
|
||||
@@ -555,8 +585,8 @@ void gameOver(){
|
||||
void die(){
|
||||
playerAlive = 0;
|
||||
if(levelNumber > 0)
|
||||
lives --;
|
||||
//updateLives();
|
||||
lives --;
|
||||
|
||||
if(lives == 0){
|
||||
stage = GAMEOVER;
|
||||
stageStartTime = millis();
|
||||
@@ -580,7 +610,7 @@ void tickStartup(long mm)
|
||||
FastLED.clear();
|
||||
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++){
|
||||
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
|
||||
{
|
||||
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 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);
|
||||
// for(int i = 0; i<= n; i++){
|
||||
|
||||
// leds[i] = CRGB(0, brightness, 0);
|
||||
@@ -750,7 +780,7 @@ bool tickParticles(){
|
||||
leds[getLED(particlePool[p]._pos)] += CRGB(brightness, brightness/2, brightness/2);\
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -758,28 +788,35 @@ bool tickParticles(){
|
||||
return stillActive;
|
||||
}
|
||||
|
||||
void tickConveyors(){
|
||||
int b, dir, n, i, ss, ee, led;
|
||||
void tickConveyors(){
|
||||
|
||||
//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;
|
||||
|
||||
// TODO should the visual speed be proportional to the conveyor speed?
|
||||
int levels = 5; // brightness levels in conveyor
|
||||
|
||||
|
||||
for(i = 0; i<CONVEYOR_COUNT; i++){
|
||||
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);
|
||||
ee = getLED(conveyorPool[i]._endPoint);
|
||||
for(led = ss; led<ee; led++){
|
||||
b = 5;
|
||||
n = (-led + (m/100)) % 5;
|
||||
if(dir == -1) n = (led + (m/100)) % 5;
|
||||
b = (5-n)/2.0;
|
||||
if(b > 0) leds[led] = CRGB(0, 0, b);
|
||||
|
||||
n = (-led + (m/100)) % levels;
|
||||
if(speed < 0)
|
||||
n = (led + (m/100)) % levels;
|
||||
|
||||
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){
|
||||
playerPositionModifier = dir;
|
||||
if(playerPosition > conveyorPool[i]._startPoint && playerPosition < conveyorPool[i]._endPoint){
|
||||
playerPositionModifier = speed;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -791,7 +828,7 @@ void tickComplete(long mm) // the boss is dead
|
||||
FastLED.clear();
|
||||
SFXcomplete();
|
||||
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--){
|
||||
brightness = (sin(((i*10)+mm)/500.0)+1)*255;
|
||||
leds[i].setHSV(brightness, 255, 50);
|
||||
@@ -802,7 +839,7 @@ void tickComplete(long mm) // the boss is dead
|
||||
leds[i].setHSV(brightness, 255, 50);
|
||||
}
|
||||
}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++){
|
||||
brightness = (sin(((i*10)+mm)/500.0)+1)*255;
|
||||
leds[i].setHSV(brightness, 255, 50);
|
||||
@@ -817,7 +854,7 @@ void tickBossKilled(long mm) // boss funeral
|
||||
int brightness = 0;
|
||||
FastLED.clear();
|
||||
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--){
|
||||
brightness = (sin(((i*10)+mm)/500.0)+1)*255;
|
||||
leds[i].setHSV(brightness, 255, 50);
|
||||
@@ -830,7 +867,7 @@ void tickBossKilled(long mm) // boss funeral
|
||||
}
|
||||
SFXbosskilled();
|
||||
}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++){
|
||||
brightness = (sin(((i*10)+mm)/500.0)+1)*255;
|
||||
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) {
|
||||
|
||||
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
|
||||
{
|
||||
// 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++){
|
||||
leds[i] = CRGB(255, 0, 0);
|
||||
}
|
||||
// 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--){
|
||||
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
|
||||
{
|
||||
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);
|
||||
|
||||
for(int i = 0; i<= n; i++){
|
||||
@@ -878,21 +937,21 @@ void tickWin(long mm) {
|
||||
int brightness = 0;
|
||||
FastLED.clear();
|
||||
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--){
|
||||
brightness = BRIGHTNESS;
|
||||
brightness = user_settings.led_brightness;
|
||||
leds[i] = CRGB(0, brightness, 0);
|
||||
}
|
||||
SFXwin();
|
||||
}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++){
|
||||
brightness = 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, BRIGHTNESS, 0);
|
||||
leds[0] = CRGB(0, user_settings.led_brightness, 0);
|
||||
}else{
|
||||
nextLevel();
|
||||
}
|
||||
@@ -967,6 +1026,19 @@ 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();
|
||||
}
|
||||
|
||||
// ---------------------------------
|
||||
// --------- SCREENSAVER -----------
|
||||
// ---------------------------------
|
||||
@@ -1012,50 +1084,24 @@ 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, gx, gy, gz, accel, gyro;
|
||||
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));
|
||||
|
||||
|
||||
// what orientation is used?
|
||||
if (JOYSTICK_ORIENTATION == 0) {
|
||||
accel = ax;
|
||||
gyro = gx;
|
||||
}
|
||||
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();
|
||||
joystickWobble = abs(MPUWobbleSamples.getHighest());
|
||||
|
||||
if(JOYSTICK_DIRECTION == 1) { // what direction is MPU facing
|
||||
joystickTilt = 0-joystickTilt;
|
||||
}
|
||||
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;
|
||||
MPUAngleSamples.add(a);
|
||||
MPUWobbleSamples.add(g);
|
||||
|
||||
|
||||
|
||||
#ifdef DEBUG // show input Data
|
||||
Serial.print("Tilt: "); Serial.println(joystickTilt);
|
||||
//Serial.print("Wobble: "); Serial.println(joystickWobble);
|
||||
#endif
|
||||
|
||||
joystickTilt = MPUAngleSamples.getMedian();
|
||||
if(JOYSTICK_DIRECTION == 1) {
|
||||
joystickTilt = 0-joystickTilt;
|
||||
}
|
||||
joystickWobble = abs(MPUWobbleSamples.getHighest());
|
||||
}
|
||||
|
||||
// ---------------------------------
|
||||
@@ -1082,7 +1128,7 @@ void SFXFreqSweepWarble(int duration, int elapsedTime, int freqStart, int freqEn
|
||||
if (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)
|
||||
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);
|
||||
if(playerPositionModifier < 0) f -= 500;
|
||||
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);
|
||||
}
|
||||
void SFXattacking(){
|
||||
@@ -1132,7 +1178,7 @@ void SFXattacking(){
|
||||
if(random8(5)== 0){
|
||||
freq *= 3;
|
||||
}
|
||||
sound(freq, MAX_VOLUME);
|
||||
sound(freq, user_settings.audio_volume);
|
||||
}
|
||||
void SFXdead(){
|
||||
SFXFreqSweepNoise(1000, millis()-killTime, 1000, 10, 200);
|
||||
@@ -1143,7 +1189,7 @@ void SFXgameover(){
|
||||
}
|
||||
|
||||
void SFXkill(){
|
||||
sound(2000, MAX_VOLUME);
|
||||
sound(2000, user_settings.audio_volume);
|
||||
}
|
||||
void SFXwin(){
|
||||
SFXFreqSweepWarble(WIN_OFF_DURATION, millis()-stageStartTime, 40, 400, 20);
|
||||
|
||||
376
settings.h
376
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
|
||||
#define MAX_PLAYER_SPEED 10 // Max move speed of the player
|
||||
#define LIVES_PER_LEVEL 3 // default lives per level
|
||||
const uint8_t MAX_PLAYER_SPEED = 10; // Max move speed of the player
|
||||
const uint8_t LIVES_PER_LEVEL = 3; // default lives per level
|
||||
|
||||
// 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
|
||||
|
||||
// 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
|
||||
|
||||
//TODO ... move all the settings to this file.
|
||||
enum ErrorNums{
|
||||
ERR_SETTING_NUM,
|
||||
ERR_SETTING_RANGE
|
||||
};
|
||||
|
||||
//EEPROMClass SETTINGS("eeprom", 0x100);
|
||||
|
||||
//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