New Apps - Lot 1 (#27)
* New Apps - Lot 1 Trying to mix it up a little with some fun, useful and just weird. Adds more new apps... Brainfuck Breakout Magic 8 Ball Todo List Also re-organised the app name part of main.yml * Fix build? * fixes * and some more * Update Brainfuck.cpp * i heard you like fixes with your fixes * no hard coded paths
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
if (DEFINED ENV{TACTILITY_SDK_PATH})
|
||||
set(TACTILITY_SDK_PATH $ENV{TACTILITY_SDK_PATH})
|
||||
else()
|
||||
set(TACTILITY_SDK_PATH "../../release/TactilitySDK")
|
||||
message(WARNING "⚠️ TACTILITY_SDK_PATH environment variable is not set, defaulting to ${TACTILITY_SDK_PATH}")
|
||||
endif()
|
||||
|
||||
include("${TACTILITY_SDK_PATH}/TactilitySDK.cmake")
|
||||
set(EXTRA_COMPONENT_DIRS ${TACTILITY_SDK_PATH})
|
||||
|
||||
project(Breakout)
|
||||
tactility_project(Breakout)
|
||||
@@ -0,0 +1,135 @@
|
||||
# Breakout
|
||||
|
||||
A classic brick-breaking arcade game inspired by Arkanoid, built for Tactility devices. Features power-up capsules, multi-hit bricks, multi-ball action, and responsive scaling across all screen sizes.
|
||||
|
||||
## Features
|
||||
|
||||
- **8 brick colors** with per-color scoring (50-120 points)
|
||||
- **Silver bricks** that take multiple hits to break (level 3+)
|
||||
- **Gold bricks** that are indestructible (level 5+)
|
||||
- **7 power-up capsules** that drop from destroyed bricks
|
||||
- **12 handcrafted level patterns** + seeded procedural generation (level 13+)
|
||||
- **High score** persistence across sessions
|
||||
- **Sound toggle** with persistent setting
|
||||
- **Responsive scaling** for all Tactility devices (Cardputer to 800x480+ panels)
|
||||
- Touch, Trackball and Keyboard input support
|
||||
|
||||
## Levels
|
||||
|
||||
Each level has a unique brick layout pattern. Colors rotate each level, and Silver/Gold bricks are added as difficulty increases.
|
||||
|
||||
```text
|
||||
Level 1: Full Grid Level 2: Checkerboard Level 3: Diamond
|
||||
[][][][][][][][] [] [] [] [] [] [][][][][][]
|
||||
[][][][][][][][] [] [] [] [] [] [][][][]
|
||||
[][][][][][][][] [] [] [] [] [] [][][][][][]
|
||||
[][][][][][][][] [] [] [] [] [] [][][][]
|
||||
|
||||
Level 4: Stripes Level 5: Pyramid Level 6: Inverted V
|
||||
[][][][][][][][] [][][][][][][][] []
|
||||
. [][][][][] . [][][][]
|
||||
[][][][][][][][] . [][][] . [][][][][][]
|
||||
. [] . [][][][][][][][]
|
||||
|
||||
Level 7: Vert Stripes Level 8: Zigzag Level 9: Blocks
|
||||
[] [] [] [] [] [][] . [][] . [][] . [][] .
|
||||
[] [] [] [] [] . [][] . [][] [][] . [][] .
|
||||
[] [] [] [] [] [][] . [][] . . [][] . [][]
|
||||
[] [] [] [] [] . [][] . [][] . [][] . [][]
|
||||
|
||||
Level 10: Double Diamond Level 11: Border Frame Level 12: Center Cross
|
||||
[][] [][] [][][][][][][][] [] []
|
||||
[][][] [][][] [][][][][][]
|
||||
[][] [][] [][][][][][][][] [] []
|
||||
[][][] [][][] [][][][][][]
|
||||
```
|
||||
|
||||
After level 12, layouts are **procedurally generated** using a seeded algorithm — the same level number always produces the same layout.
|
||||
|
||||
## Power-Up Capsules
|
||||
|
||||
Capsules drop from destroyed bricks (~15% chance) and fall toward the paddle. Catch them to activate!
|
||||
|
||||
```text
|
||||
Capsule drops from brick: Catch with paddle:
|
||||
|
||||
[brick] |C|
|
||||
|C| =============
|
||||
|C| ^^^paddle^^^
|
||||
|C|
|
||||
v
|
||||
=============
|
||||
```
|
||||
|
||||
| Capsule | Color | Letter | Effect |
|
||||
|---------|-------|--------|--------|
|
||||
| Laser | `Red` | **L** | Paddle auto-fires lasers upward, destroying bricks on contact |
|
||||
| Extend | `Blue` | **E** | Paddle width increases by 50% |
|
||||
| Catch | `Green` | **C** | Ball sticks to paddle on contact, auto-releases after 3 seconds |
|
||||
| Slow | `Orange` | **S** | Ball speed reduced to 60%, gradually recovers over 5 seconds |
|
||||
| BreakOut | `Pink` | **B** | Opens exit on right wall — move paddle to exit for +10,000 pts |
|
||||
| Split | `Cyan` | **D** | Splits ball into 3! Life lost only when ALL balls are gone |
|
||||
| Extra Life | `Grey` | **+** | +1 life (rarest drop) |
|
||||
|
||||
Power-ups reset on life lost or level clear. No capsules drop while multiple balls are active.
|
||||
|
||||
## Brick Types
|
||||
|
||||
```text
|
||||
Normal bricks: Silver bricks: Gold bricks:
|
||||
+-----------+ +===========+ +###########+
|
||||
| colored | | multi-hit | | unbreakable|
|
||||
+-----------+ +===========+ +###########+
|
||||
1 hit, gone 2-3 hits indestructible
|
||||
50-120 pts 50 x level bounces ball
|
||||
```
|
||||
|
||||
| Type | Appears | Hits | Score | Visual |
|
||||
|------|---------|------|-------|--------|
|
||||
| Normal | All levels | 1 | 50-120 (by color) | Colored, no border |
|
||||
| Silver | Level 3+ | 2 (lvl 3-6), 3 (lvl 7+) | 50 x level | Grey with white border, darkens on hit |
|
||||
| Gold | Level 5+ | Indestructible | - | Amber with gold border |
|
||||
|
||||
## Scoring
|
||||
|
||||
| Source | Points |
|
||||
|--------|--------|
|
||||
| Purple brick | 50 |
|
||||
| Orange brick | 60 |
|
||||
| Cyan brick | 70 |
|
||||
| Green brick | 80 |
|
||||
| Red brick | 90 |
|
||||
| Blue brick | 100 |
|
||||
| Pink brick | 110 |
|
||||
| Yellow brick | 120 |
|
||||
| Silver brick | 50 x level |
|
||||
| BreakOut exit | 10,000 |
|
||||
|
||||
Ball speed increases by +0.15 for every 5 bricks destroyed, and +0.3 per level.
|
||||
|
||||
## Controls
|
||||
|
||||
**Touchscreen:** Touch/drag to move paddle, tap to launch ball or release caught ball
|
||||
**Trackball:** Move trackball left and right to move paddle, press to launch ball or release caught ball
|
||||
|
||||
**Keyboard:**
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| `LEFT` / `a` / `,` | Move paddle left |
|
||||
| `RIGHT` / `d` / `/` | Move paddle right |
|
||||
| `SPACE` / `ENTER` | Launch ball / release caught ball / pause |
|
||||
|
||||
**Toolbar:** Pause button and sound toggle button
|
||||
|
||||
## Requirements
|
||||
|
||||
- Tactility SDK 0.7.0-dev
|
||||
- ESP32, ESP32-S3, ESP32-C6, or ESP32-P4
|
||||
|
||||
## Building
|
||||
|
||||
```bash
|
||||
python tactility.py build
|
||||
# or build + install + run:
|
||||
python tactility.py bir <device-ip>
|
||||
```
|
||||
@@ -0,0 +1,10 @@
|
||||
file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
|
||||
file(GLOB_RECURSE SFX_ENGINE_FILES ../../../Libraries/SfxEngine/Source/*.c*)
|
||||
|
||||
idf_component_register(
|
||||
SRCS ${SOURCE_FILES} ${SFX_ENGINE_FILES}
|
||||
# Library headers must be included directly,
|
||||
# because all regular dependencies get stripped by elf_loader's cmake script
|
||||
INCLUDE_DIRS ../../../Libraries/TactilityCpp/Include ../../../Libraries/SfxEngine/Include
|
||||
REQUIRES TactilitySDK
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,184 @@
|
||||
/**
|
||||
* @file Breakout.h
|
||||
* @brief Breakout arcade game for Tactility
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <tt_app.h>
|
||||
#include <lvgl.h>
|
||||
#include <TactilityCpp/App.h>
|
||||
|
||||
class SfxEngine;
|
||||
|
||||
enum class GameState { Ready, Playing, Paused, GameOver };
|
||||
enum class BrickType : uint8_t { Normal, Silver, Gold };
|
||||
enum class PowerUpType : uint8_t { Laser, Extend, Catch, Slow, BreakOut, Split, ExtraLife };
|
||||
|
||||
static constexpr int TICK_MS = 25;
|
||||
static constexpr int MAX_COLS = 12;
|
||||
static constexpr int MAX_ROWS = 5;
|
||||
static constexpr int MAX_BRICKS = MAX_COLS * MAX_ROWS;
|
||||
static constexpr int INITIAL_LIVES = 10;
|
||||
static constexpr int MAX_CAPSULES = 4;
|
||||
static constexpr int MAX_BALLS = 3;
|
||||
static constexpr int MAX_LASERS = 2;
|
||||
|
||||
// Per-color scoring (Purple=50 through Yellow=120)
|
||||
static constexpr int COLOR_SCORES[] = { 50, 60, 70, 80, 90, 100, 110, 120 };
|
||||
|
||||
struct Capsule {
|
||||
float x, y;
|
||||
PowerUpType type;
|
||||
bool active;
|
||||
};
|
||||
|
||||
struct BallState {
|
||||
float x, y, vx, vy;
|
||||
bool active;
|
||||
lv_obj_t* obj;
|
||||
};
|
||||
|
||||
struct Laser {
|
||||
float x, y;
|
||||
bool active;
|
||||
lv_obj_t* obj;
|
||||
};
|
||||
|
||||
class Breakout final : public App {
|
||||
|
||||
private:
|
||||
// UI pointers (nulled in onHide)
|
||||
lv_obj_t* gameArea = nullptr;
|
||||
lv_obj_t* paddle = nullptr;
|
||||
lv_obj_t* bricks[MAX_BRICKS] = {};
|
||||
lv_obj_t* scoreLabel = nullptr;
|
||||
lv_obj_t* livesLabel = nullptr;
|
||||
lv_obj_t* messageLabel = nullptr;
|
||||
lv_timer_t* gameTimer = nullptr;
|
||||
lv_obj_t* soundBtnIcon = nullptr;
|
||||
|
||||
// Capsule UI
|
||||
lv_obj_t* capsuleObjs[MAX_CAPSULES] = {};
|
||||
lv_obj_t* capsuleLabels[MAX_CAPSULES] = {};
|
||||
|
||||
// Laser UI
|
||||
Laser lasers[MAX_LASERS] = {};
|
||||
|
||||
// BreakOut exit
|
||||
lv_obj_t* exitIndicator = nullptr;
|
||||
|
||||
// Sfx
|
||||
SfxEngine* sfxEngine = nullptr;
|
||||
|
||||
// Game state (persists across hide/show)
|
||||
GameState state = GameState::Ready;
|
||||
int score = 0;
|
||||
int lives = INITIAL_LIVES;
|
||||
int level = 1;
|
||||
int bricksRemaining = 0;
|
||||
int destroyedCount = 0;
|
||||
bool brickAlive[MAX_BRICKS] = {};
|
||||
BrickType brickType[MAX_BRICKS] = {};
|
||||
int brickHits[MAX_BRICKS] = {};
|
||||
int brickColorIndex[MAX_BRICKS] = {};
|
||||
bool needsInit = true;
|
||||
|
||||
// Multi-ball
|
||||
BallState balls[MAX_BALLS] = {};
|
||||
int activeBallCount = 1;
|
||||
|
||||
// Capsules
|
||||
Capsule capsules[MAX_CAPSULES] = {};
|
||||
int capsuleW = 0, capsuleH = 0;
|
||||
float capsuleFallSpeed = 0;
|
||||
|
||||
// Power-up state
|
||||
bool catchActive = false;
|
||||
int catchBallIndex = -1;
|
||||
float catchOffsetX = 0;
|
||||
int catchAutoReleaseTicks = 0;
|
||||
|
||||
float originalBallSpeed = 0;
|
||||
int slowRecoveryTicks = 0;
|
||||
|
||||
int originalPaddleW = 0;
|
||||
bool extendActive = false;
|
||||
|
||||
bool laserActive = false;
|
||||
int laserCooldown = 0;
|
||||
int laserW = 0, laserH = 0;
|
||||
float laserSpeed = 0;
|
||||
|
||||
bool exitOpen = false;
|
||||
|
||||
float baseBallSpeed = 0;
|
||||
|
||||
// Paddle
|
||||
float paddleX = 0;
|
||||
|
||||
// Layout dimensions (calculated in onShow)
|
||||
int areaW = 0, areaH = 0;
|
||||
int cols = 0, rows = 0;
|
||||
int brickW = 0, brickH = 0;
|
||||
int brickGap = 0;
|
||||
int brickOffsetX = 0, brickOffsetY = 0;
|
||||
int ballSize = 0;
|
||||
int paddleW = 0, paddleH = 0;
|
||||
int paddleYPos = 0;
|
||||
float ballSpeed = 0;
|
||||
float paddleSpeed = 0;
|
||||
|
||||
// Static callbacks
|
||||
static void onTick(lv_timer_t* timer);
|
||||
static void onPressed(lv_event_t* e);
|
||||
static void onClicked(lv_event_t* e);
|
||||
static void onKey(lv_event_t* e);
|
||||
static void onFocused(lv_event_t* e);
|
||||
static void onPauseClicked(lv_event_t* e);
|
||||
static void onSoundToggled(lv_event_t* e);
|
||||
|
||||
// Game logic
|
||||
void startGame();
|
||||
void nextLevel();
|
||||
void resetBall();
|
||||
void launchBall();
|
||||
void update();
|
||||
void checkLaserBrickCollisions();
|
||||
void loseLife();
|
||||
void winLevel();
|
||||
void createBricks();
|
||||
void setupLevelPattern();
|
||||
void refreshBricks();
|
||||
void updateScoreDisplay();
|
||||
void updateMessage();
|
||||
void togglePause();
|
||||
void updateSoundIcon();
|
||||
|
||||
// Capsule system
|
||||
void spawnCapsule(float x, float y);
|
||||
void updateCapsules();
|
||||
void activatePowerUp(PowerUpType type);
|
||||
void clearPowerUps();
|
||||
void createCapsuleObjs();
|
||||
|
||||
// Multi-ball
|
||||
void updateBalls();
|
||||
void splitBalls();
|
||||
|
||||
// Laser
|
||||
void updateLasers();
|
||||
void fireLaser();
|
||||
void createLaserObjs();
|
||||
|
||||
// BreakOut exit
|
||||
void openExit();
|
||||
void closeExit();
|
||||
|
||||
// Brick helpers
|
||||
void hitBrick(int idx);
|
||||
int scoreBrick(int idx);
|
||||
|
||||
public:
|
||||
void onShow(AppHandle context, lv_obj_t* parent) override;
|
||||
void onHide(AppHandle context) override;
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
#include "Breakout.h"
|
||||
#include <TactilityCpp/App.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
registerApp<Breakout>();
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
[manifest]
|
||||
version=0.1
|
||||
[target]
|
||||
sdk=0.7.0-dev
|
||||
platforms=esp32,esp32s3,esp32c6,esp32p4
|
||||
[app]
|
||||
id=one.tactility.breakout
|
||||
versionName=0.1.0
|
||||
versionCode=1
|
||||
name=Breakout
|
||||
description=Classic brick-breaking arcade game
|
||||
Reference in New Issue
Block a user