Edit Game Settings via Wfi

- Several settings can be updates via wifi during game play
- Some seetings code cleanup
This commit is contained in:
bdring
2018-03-28 12:41:31 -05:00
parent a85100afd9
commit 1959787e9b
4 changed files with 169 additions and 67 deletions

View File

@@ -20,11 +20,20 @@ This was ported from the [TWANG fork](https://github.com/bdring/TWANG) by bdring
- **SSID:** TWANG_AP - **SSID:** TWANG_AP
- **Password:** esp32rocks - **Password:** esp32rocks
- **URL:** 192.168.4.1 - **URL:** 192.168.4.1
- You can update these settings over wifi
- LED Brightness
- Audio Volume
- Joystick Deadzone (removes drift)
- Attack Threshold (twang sensitivity)
- Lives Per Level
**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.~~ ![](http://www.buildlog.net/blog/wp-content/uploads/2018/03/20180328_122254.jpg)
Coming Soon:**
- Wireless features~~
- 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.

View File

@@ -6,7 +6,7 @@
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 Baumgarten's Line Wobbler Game_Audio It was inspired by Robin Baumgarten's Line Wobbler Game
*/ */
@@ -288,7 +288,6 @@ void loop() {
tickWin(mm); tickWin(mm);
}else if(stage == BOSS_KILLED){ }else if(stage == BOSS_KILLED){
tickBossKilled(mm); tickBossKilled(mm);
//tickComplete(mm);
} else if (stage == GAMEOVER) { } else if (stage == GAMEOVER) {
if (stageStartTime+GAMEOVER_FADE_DURATION > mm) if (stageStartTime+GAMEOVER_FADE_DURATION > mm)
{ {
@@ -297,7 +296,7 @@ void loop() {
else else
{ {
FastLED.clear(); FastLED.clear();
save_game_stats(false); save_game_stats(false); // boss not killed
//score = 0; // reset the score //score = 0; // reset the score
levelNumber = 0; levelNumber = 0;
lives = user_settings.lives_per_level; lives = user_settings.lives_per_level;
@@ -874,6 +873,7 @@ void tickBossKilled(long mm) // boss funeral
} }
SFXcomplete(); SFXcomplete();
}else{ }else{
save_game_stats(true); // true = boss was killed
nextLevel(); nextLevel();
} }
} }
@@ -1018,11 +1018,6 @@ bool inLava(int pos){
} }
void updateLives(){ void updateLives(){
// Updates the life LEDs to show how many lives the player has left
//for(int i = 0; i<LIFE_LEDS; i++){
// digitalWrite(lifeLEDs[i], lives>i?HIGH:LOW);
//}
drawLives(); drawLives();
} }

View File

@@ -10,20 +10,36 @@
#define EEPROM_SIZE 256 #define EEPROM_SIZE 256
// LEDS // LEDS
#define BRIGHTNESS 150 #define DEFAULT_BRIGHTNESS 150
#define MIN_BRIGHTNESS 10
#define MAX_BRIGHTNESS 255
// PLAYER // PLAYER
const uint8_t MAX_PLAYER_SPEED = 10; // Max move speed of the player const uint8_t MAX_PLAYER_SPEED = 10; // Max move speed of the player
const uint8_t LIVES_PER_LEVEL = 3; // default lives per level const uint8_t LIVES_PER_LEVEL = 3; // default lives per level
#define MIN_LIVES_PER_LEVEL 3
#define MAX_LIVES_PER_LEVEL 9
// 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
#define JOYSTICK_DIRECTION 1 // 0/1 to flip joystick direction #define JOYSTICK_DIRECTION 1 // 0/1 to flip joystick direction
#define ATTACK_THRESHOLD 30000 // The threshold that triggers an attack #define DEFAULT_ATTACK_THRESHOLD 30000 // The threshold that triggers an attack
#define JOYSTICK_DEADZONE 8 // Angle to ignore #define MIN_ATTACK_THRESHOLD 20000
#define MAX_ATTACK_THRESHOLD 30000
#define DEFAULT_JOYSTICK_DEADZONE 8 // Angle to ignore
#define MIN_JOYSTICK_DEADZONE 3
#define MAX_JOYSTICK_DEADZONE 12
// AUDIO // AUDIO
#define MAX_VOLUME 180 // 0 to 255 #define DEFAULT_VOLUME 180 // 0 to 255
#define MIN_VOLUME 0
#define MAX_VOLUME 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{ enum ErrorNums{
@@ -80,11 +96,6 @@ uint8_t readIndex = 0;
void settings_init() { void settings_init() {
//if (!EEPROM.begin(EEPROM_SIZE))
//{
// Serial.println("failed to initialize EEPROM");
//}
settings_eeprom_read(); settings_eeprom_read();
show_settings_menu(); show_settings_menu();
show_game_stats(); show_game_stats();
@@ -187,11 +198,12 @@ void change_setting(char *line) {
switch (param) { switch (param) {
case 'B': // brightness case 'B': // brightness
if(newValue >=5 && newValue <=255) { if(newValue >= MIN_BRIGHTNESS && newValue <= MAX_BRIGHTNESS) {
user_settings.led_brightness = (uint8_t)newValue; user_settings.led_brightness = (uint8_t)newValue;
settings_eeprom_write(); settings_eeprom_write();
delay(1000); FastLED.setBrightness(user_settings.led_brightness);
ESP.restart(); // this one requires a restart right now //delay(1000);
//ESP.restart(); // this one requires a restart right now
} }
else { else {
printError(ERR_SETTING_RANGE); printError(ERR_SETTING_RANGE);
@@ -200,7 +212,7 @@ void change_setting(char *line) {
break; break;
case 'S': // sound case 'S': // sound
if (newValue >=0 && newValue < 255) if (newValue >=MIN_VOLUME && newValue <= MAX_VOLUME)
user_settings.audio_volume = (uint8_t)newValue; user_settings.audio_volume = (uint8_t)newValue;
else { else {
printError(ERR_SETTING_RANGE); printError(ERR_SETTING_RANGE);
@@ -209,7 +221,7 @@ void change_setting(char *line) {
break; break;
case 'D': // deadzone, joystick case 'D': // deadzone, joystick
if(newValue >=3 && newValue <=12) if(newValue >=MIN_JOYSTICK_DEADZONE && newValue <=MAX_JOYSTICK_DEADZONE)
user_settings.joystick_deadzone = (uint8_t)newValue; user_settings.joystick_deadzone = (uint8_t)newValue;
else { else {
printError(ERR_SETTING_RANGE); printError(ERR_SETTING_RANGE);
@@ -218,7 +230,7 @@ void change_setting(char *line) {
break; break;
case 'A': // attack threshold, joystick case 'A': // attack threshold, joystick
if(newValue >=20000 && newValue <=35000) if(newValue >=MIN_ATTACK_THRESHOLD && newValue <=MAX_ATTACK_THRESHOLD)
user_settings.attack_threshold = (uint16_t)newValue; user_settings.attack_threshold = (uint16_t)newValue;
else { else {
printError(ERR_SETTING_RANGE); printError(ERR_SETTING_RANGE);
@@ -249,12 +261,12 @@ void change_setting(char *line) {
void reset_settings() { void reset_settings() {
user_settings.settings_version = SETTINGS_VERSION; user_settings.settings_version = SETTINGS_VERSION;
user_settings.led_brightness = BRIGHTNESS; user_settings.led_brightness = DEFAULT_BRIGHTNESS;
user_settings.joystick_deadzone = JOYSTICK_DEADZONE; user_settings.joystick_deadzone = DEFAULT_JOYSTICK_DEADZONE;
user_settings.attack_threshold = ATTACK_THRESHOLD; user_settings.attack_threshold = DEFAULT_ATTACK_THRESHOLD;
user_settings.audio_volume = MAX_VOLUME; user_settings.audio_volume = DEFAULT_VOLUME;
user_settings.lives_per_level = LIVES_PER_LEVEL; user_settings.lives_per_level = LIVES_PER_LEVEL;
@@ -297,10 +309,6 @@ void show_settings_menu() {
Serial.println(" ? to show current settings"); Serial.println(" ? to show current settings");
Serial.println(" R to reset everything to defaults)"); Serial.println(" R to reset everything to defaults)");
Serial.println(" P to reset play statistics)"); 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() void show_game_stats()
@@ -314,9 +322,7 @@ void show_game_stats()
Serial.print("Boss kills: ");Serial.println(user_settings.boss_kills); Serial.print("Boss kills: ");Serial.println(user_settings.boss_kills);
} }
void settings_eeprom_read() void settings_eeprom_read() {
{
Serial.println("Begin EEPROM Read");
EEPROM.begin(EEPROM_SIZE); EEPROM.begin(EEPROM_SIZE);
@@ -338,9 +344,11 @@ void settings_eeprom_read()
temp[i] = EEPROM.read(i); temp[i] = EEPROM.read(i);
} }
EEPROM.end();
memcpy((char*)&user_settings, temp, sizeof(user_settings)); memcpy((char*)&user_settings, temp, sizeof(user_settings));
EEPROM.end();
} }
@@ -353,9 +361,6 @@ void settings_eeprom_write() {
uint8_t temp[sizeof(user_settings)]; uint8_t temp[sizeof(user_settings)];
memcpy(temp, (uint8_t*)&user_settings, 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++) for (int i=0; i<sizeof(user_settings); i++)
{ {
EEPROM.write(i, temp[i]); EEPROM.write(i, temp[i]);

103
wifi_ap.h
View File

@@ -1,10 +1,14 @@
#include <WiFi.h> #include <WiFi.h>
#include "settings.h"
const char* ssid = "TWANG_AP"; const char* ssid = "TWANG_AP";
const char* passphrase = "esp32rocks"; const char* passphrase = "esp32rocks";
WiFiServer server(80); WiFiServer server(80);
char linebuf[80];
int charcount=0;
void ap_setup() { void ap_setup() {
bool ret; bool ret;
@@ -19,14 +23,13 @@ void ap_setup() {
*/ */
ret = WiFi.softAP(ssid, passphrase, 2, 0); ret = WiFi.softAP(ssid, passphrase, 2, 0);
Serial.println("\r\nWiFi AP online ..."); //Serial.println("\r\nWiFi AP online ...");
server.begin(); server.begin();
} }
void sendStatsPage(WiFiClient client) { void sendStatsPage(WiFiClient client) {
Serial.println("printUploadForm");
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK) // 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: // and a content-type so the client knows what's coming, then a blank line:
client.println("HTTP/1.1 200 OK"); client.println("HTTP/1.1 200 OK");
@@ -37,6 +40,7 @@ void sendStatsPage(WiFiClient client) {
client.println("<h1>TWANG32 Play Stats</h1>"); client.println("<h1>TWANG32 Play Stats</h1>");
client.println("<ul>"); client.println("<ul>");
client.print("<li>Games played: "); client.print(user_settings.games_played); client.println("</li>"); client.print("<li>Games played: "); client.print(user_settings.games_played); client.println("</li>");
if (user_settings.games_played > 0) { // prevent divide by 0 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>Average score: "); client.print(user_settings.total_points / user_settings.games_played); client.println("</li>");
@@ -44,7 +48,32 @@ void sendStatsPage(WiFiClient client) {
client.print("<li>High score: "); client.print(user_settings.high_score); 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.print("<li>Boss kills: "); client.print(user_settings.boss_kills); client.println("</li>");
client.println("</ul>"); client.print("<h2>Adjustable Settings </h2>");
client.print("<table>");
client.print("<tr><td>Brightness</td><td><form><input type='text' name='B' value='");
client.print(user_settings.led_brightness);
client.print ("' size='4'><input type='submit'></form></td></tr>");
client.print("<tr><td>Sound Volume</td><td><form><input type='text' name='S' value='");
client.print(user_settings.audio_volume);
client.print("' size='4'><input type='submit'></form></td></tr>");
client.print("<tr><td>Joystick Deadzone (3-12)</td><td><form><input type='text' name='D' value='");
client.print(user_settings.joystick_deadzone);
client.print("' size='4'><input type='submit'></form></td></tr>");
client.print("<tr><td>Attack Sensitivity (20000-35000)</td><td><form><input type='text' name='A' value='");
client.print(user_settings.attack_threshold);
client.print("' size='4'><input type='submit'></form></td></tr>");
client.print("<tr><td>Lives Per Level (3-9)</td><td><form><input type='text' name='L' value='");
client.print(user_settings.lives_per_level);
client.print("' size='4'><input type='submit'></form></td></tr>");
client.print("</table>");
client.println("</body>"); client.println("</body>");
client.println("</html>"); client.println("</html>");
client.println(); client.println();
@@ -57,9 +86,73 @@ void ap_client_check(){
int stat; int stat;
WiFiClient client = server.available(); // listen for incoming clients WiFiClient client = server.available(); // listen for incoming clients
if (client) { // if you get a client, //if (client) { // if you get a client,
// sendStatsPage(client);
// Serial.println("printUploadForm");
//}
bool currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
//Serial.write(c);
linebuf[charcount]=c;
if (charcount<sizeof(linebuf)-1)
charcount++;
if (c == '\n' && currentLineIsBlank) {
sendStatsPage(client); sendStatsPage(client);
Serial.println("printUploadForm"); break;
}
if (c == '\n') {
// you're starting a new line
currentLineIsBlank = true;
if (strstr(linebuf,"GET /?") > 0)
{
String line = String(linebuf);
int start = line.indexOf('=', 0) + 1;
int finish = line.indexOf('H', start)-1;
String val = line.substring(start, finish);
// if it is not numeric, it will convert to 0.
// The constrain functions will make it 0 or the min value
if (strstr(linebuf,"B=") > 0){ // typically look like this "GET /?S=100 HTTP/1.1"
user_settings.led_brightness = constrain(val.toInt(), MIN_BRIGHTNESS, MAX_BRIGHTNESS);
FastLED.setBrightness(user_settings.led_brightness);
settings_eeprom_write();
}
else if (strstr(linebuf,"S=") > 0){
//String val = line.substring(start, finish);
user_settings.audio_volume = constrain(val.toInt(), MIN_VOLUME, MAX_VOLUME);
settings_eeprom_write();
}
else if (strstr(linebuf,"D=") > 0){
user_settings.joystick_deadzone = constrain(val.toInt(), MIN_JOYSTICK_DEADZONE, MAX_JOYSTICK_DEADZONE);
settings_eeprom_write();
}
else if (strstr(linebuf,"A=") > 0){
user_settings.attack_threshold = constrain(val.toInt(), MIN_ATTACK_THRESHOLD, MAX_ATTACK_THRESHOLD);
settings_eeprom_write();
}
else if (strstr(linebuf,"L=") > 0){
user_settings.lives_per_level = constrain(val.toInt(), MIN_LIVES_PER_LEVEL, MAX_LIVES_PER_LEVEL);
settings_eeprom_write();
}
}
// you're starting a new line
currentLineIsBlank = true;
memset(linebuf,0,sizeof(linebuf));
charcount=0;
} else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
} }
} }