feat: add proof-of-concept
This commit is contained in:
@@ -0,0 +1,42 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <LibPrintf.h>
|
||||||
|
#include "joystick.hpp"
|
||||||
|
#include "display.hpp"
|
||||||
|
#include "menu.hpp"
|
||||||
|
#define ACTION_INTERVAL 60000 // 1 minute
|
||||||
|
#define MAXIMUM_STAT 100
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool dead;
|
||||||
|
bool menuOpen;
|
||||||
|
|
||||||
|
int hunger;
|
||||||
|
int joy;
|
||||||
|
int energy;
|
||||||
|
int cleanliness;
|
||||||
|
|
||||||
|
uint64_t lastActionTime;
|
||||||
|
bool shouldClear;
|
||||||
|
} GameState;
|
||||||
|
|
||||||
|
class Game {
|
||||||
|
public:
|
||||||
|
Game();
|
||||||
|
void begin();
|
||||||
|
void update();
|
||||||
|
void render();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void forceUpdate(String reason);
|
||||||
|
void feed();
|
||||||
|
void play();
|
||||||
|
void sleep();
|
||||||
|
void clean();
|
||||||
|
|
||||||
|
private:
|
||||||
|
GameState state;
|
||||||
|
Joystick joystick;
|
||||||
|
Display display;
|
||||||
|
String* items;
|
||||||
|
Menu menu;
|
||||||
|
};
|
||||||
+5
-10
@@ -3,20 +3,15 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "joystick.hpp"
|
#include "joystick.hpp"
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
String name;
|
|
||||||
void (*action)();
|
|
||||||
} Item;
|
|
||||||
|
|
||||||
class Menu {
|
class Menu {
|
||||||
public:
|
public:
|
||||||
Menu(Item* items);
|
Menu();
|
||||||
void updateCurrentItem(JoystickDirection& direction);
|
void setItems(String* items);
|
||||||
void execute();
|
bool updateCurrentItem(JoystickDirection& direction);
|
||||||
|
|
||||||
Item& getItemAt(size_t index);
|
String& getItemAt(size_t index);
|
||||||
size_t getCurrentItemIndex() const;
|
size_t getCurrentItemIndex() const;
|
||||||
private:
|
private:
|
||||||
Item items[MENU_ITEM_COUNT];
|
String items[MENU_ITEM_COUNT];
|
||||||
int currentItem;
|
int currentItem;
|
||||||
};
|
};
|
||||||
|
|||||||
+3
-3
@@ -17,12 +17,12 @@ void Display::drawMenu(Menu &menu) {
|
|||||||
size_t currentItemIndex = menu.getCurrentItemIndex();
|
size_t currentItemIndex = menu.getCurrentItemIndex();
|
||||||
for (size_t i = 0; i < MENU_ITEM_COUNT; i++) {
|
for (size_t i = 0; i < MENU_ITEM_COUNT; i++) {
|
||||||
lcd.setCursor(0, i);
|
lcd.setCursor(0, i);
|
||||||
Item& item = menu.getItemAt(i);
|
String item = menu.getItemAt(i);
|
||||||
|
|
||||||
if (i == currentItemIndex) {
|
if (i == currentItemIndex) {
|
||||||
lcd.print("> " + item.name);
|
lcd.print("> " + item);
|
||||||
} else {
|
} else {
|
||||||
lcd.print(" " + item.name);
|
lcd.print(" " + item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+151
@@ -0,0 +1,151 @@
|
|||||||
|
#include "game.hpp"
|
||||||
|
|
||||||
|
Game::Game() : joystick(), display(), menu() {
|
||||||
|
state = (GameState) {
|
||||||
|
.dead = false,
|
||||||
|
.menuOpen = false,
|
||||||
|
.hunger = 0,
|
||||||
|
.joy = 100,
|
||||||
|
.energy = 100,
|
||||||
|
.cleanliness = 100,
|
||||||
|
.lastActionTime = 0,
|
||||||
|
.shouldClear = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
String items[] = {
|
||||||
|
"Feed",
|
||||||
|
"Play",
|
||||||
|
"Sleep",
|
||||||
|
"Clean"
|
||||||
|
};
|
||||||
|
|
||||||
|
menu.setItems(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::begin() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
while (!Serial) {
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
display.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::update() {
|
||||||
|
// If the pet is dead, we don't need to update its state
|
||||||
|
if (state.dead) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isPressed = joystick.isPressed();
|
||||||
|
|
||||||
|
// If the menu is open, we don't need to update the pet's state
|
||||||
|
if (state.menuOpen) {
|
||||||
|
JoystickDirection direction = joystick.getDirection();
|
||||||
|
if (menu.updateCurrentItem(direction)) {
|
||||||
|
forceUpdate("Menu navigation");
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the joystick is pressed, execute the current menu item
|
||||||
|
if (isPressed) {
|
||||||
|
state.menuOpen = false;
|
||||||
|
// Based on the current menu item, perform the corresponding action
|
||||||
|
switch (menu.getCurrentItemIndex()) {
|
||||||
|
case 0:
|
||||||
|
feed();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
play();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
sleep();
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
clean();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
forceUpdate("Menu action");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the joystick is pressed and the menu is not open, open the menu
|
||||||
|
if (isPressed) {
|
||||||
|
state.menuOpen = true;
|
||||||
|
forceUpdate("Opening menu");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the pet's stats based on the time elapsed since the last action
|
||||||
|
uint64_t currentTime = millis();
|
||||||
|
if (currentTime - state.lastActionTime >= ACTION_INTERVAL) {
|
||||||
|
state.hunger += 10;
|
||||||
|
state.joy -= 5;
|
||||||
|
state.energy -= 5;
|
||||||
|
state.cleanliness -= 5;
|
||||||
|
state.lastActionTime = currentTime;
|
||||||
|
|
||||||
|
forceUpdate("Time-based stat update");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the pet has died from any of the conditions
|
||||||
|
bool starvedToDeath = state.hunger >= MAXIMUM_STAT;
|
||||||
|
bool diedOfBoredom = state.joy <= -MAXIMUM_STAT;
|
||||||
|
bool diedOfExhaustion = state.energy <= -MAXIMUM_STAT;
|
||||||
|
bool diedOfFilth = state.cleanliness <= -MAXIMUM_STAT;
|
||||||
|
|
||||||
|
state.dead = starvedToDeath || diedOfBoredom || diedOfExhaustion || diedOfFilth;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::render() {
|
||||||
|
if (state.shouldClear) {
|
||||||
|
display.clear();
|
||||||
|
state.shouldClear = false;
|
||||||
|
|
||||||
|
if (state.menuOpen) {
|
||||||
|
display.drawMenu(menu);
|
||||||
|
Serial.println("Rendering menu");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.menuOpen) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.dead) {
|
||||||
|
display.getLCD().print("Your pet has died.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
display.getLCD().setCursor(0, 0);
|
||||||
|
display.getLCD().print("H: " + String(state.hunger));
|
||||||
|
display.getLCD().setCursor(0, 1);
|
||||||
|
display.getLCD().print("J: " + String(state.joy));
|
||||||
|
display.getLCD().setCursor(0, 2);
|
||||||
|
display.getLCD().print("E: " + String(state.energy));
|
||||||
|
display.getLCD().setCursor(0, 3);
|
||||||
|
display.getLCD().print("C: " + String(state.cleanliness));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::forceUpdate(String reason) {
|
||||||
|
if (!state.shouldClear) {
|
||||||
|
Serial.println("Forcing update: " + reason);
|
||||||
|
state.shouldClear = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::feed() {
|
||||||
|
state.hunger += 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::play() {
|
||||||
|
state.joy += 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::sleep() {
|
||||||
|
state.energy += 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::clean() {
|
||||||
|
state.cleanliness += 20;
|
||||||
|
}
|
||||||
+6
-33
@@ -1,40 +1,13 @@
|
|||||||
#include <Arduino.h>
|
#include "game.hpp"
|
||||||
#include <LibPrintf.h>
|
|
||||||
#include "joystick.hpp"
|
|
||||||
#include "display.hpp"
|
|
||||||
|
|
||||||
Joystick joystick;
|
Game game;
|
||||||
Display display;
|
|
||||||
|
|
||||||
Item items[MENU_ITEM_COUNT] = {
|
|
||||||
{"Feed", []() { Serial.println("Feeding..."); }},
|
|
||||||
{"Play", []() { Serial.println("Playing..."); }},
|
|
||||||
{"Sleep", []() { Serial.println("Sleeping..."); }},
|
|
||||||
{"Clean", []() { Serial.println("Cleaning..."); }}
|
|
||||||
};
|
|
||||||
Menu menu(items);
|
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(9600);
|
game.begin();
|
||||||
while (!Serial) {
|
|
||||||
delay(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
display.begin();
|
|
||||||
pinMode(LED_BUILTIN, OUTPUT);
|
|
||||||
display.drawMenu(menu);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
JoystickDirection direction = joystick.getDirection();
|
game.update();
|
||||||
if (direction != JoystickDirection::CENTER) {
|
delay(100); // Small delay to prevent overwhelming the CPU
|
||||||
menu.updateCurrentItem(direction);
|
game.render();
|
||||||
display.drawMenu(menu);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (joystick.isPressed()) {
|
|
||||||
menu.execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
delay(250);
|
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-12
@@ -1,31 +1,28 @@
|
|||||||
#include "menu.hpp"
|
#include "menu.hpp"
|
||||||
|
|
||||||
Menu::Menu(Item* items) : currentItem(0) {
|
Menu::Menu() : currentItem(0) {}
|
||||||
|
|
||||||
|
void Menu::setItems(String* items) {
|
||||||
|
this->currentItem = 0;
|
||||||
for (int i = 0; i < MENU_ITEM_COUNT; i++) {
|
for (int i = 0; i < MENU_ITEM_COUNT; i++) {
|
||||||
this->items[i] = items[i];
|
this->items[i] = items[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Menu::updateCurrentItem(JoystickDirection &direction) {
|
bool Menu::updateCurrentItem(JoystickDirection &direction) {
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
case JoystickDirection::UP:
|
case JoystickDirection::UP:
|
||||||
currentItem = (currentItem - 1 + MENU_ITEM_COUNT) % MENU_ITEM_COUNT;
|
currentItem = (currentItem - 1 + MENU_ITEM_COUNT) % MENU_ITEM_COUNT;
|
||||||
break;
|
return true;
|
||||||
case JoystickDirection::DOWN:
|
case JoystickDirection::DOWN:
|
||||||
currentItem = (currentItem + 1) % MENU_ITEM_COUNT;
|
currentItem = (currentItem + 1) % MENU_ITEM_COUNT;
|
||||||
break;
|
return true;
|
||||||
default:
|
default:
|
||||||
break;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Menu::execute() {
|
String& Menu::getItemAt(size_t index) {
|
||||||
if (items[currentItem].action) {
|
|
||||||
items[currentItem].action();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item& Menu::getItemAt(size_t index) {
|
|
||||||
return items[index];
|
return items[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user