removed
This commit is contained in:
@ -1,293 +0,0 @@
|
||||
# Spacetris — COOPERATE Mode
|
||||
## Middle SYNC Line Effect (SDL3)
|
||||
### VS Code Copilot AI Agent Integration Guide
|
||||
|
||||
> Goal: Implement a **visual SYNC divider line** in COOPERATE mode that communicates cooperation state between two players.
|
||||
> This effect must be lightweight, performant, and decoupled from gameplay logic.
|
||||
|
||||
---
|
||||
|
||||
## 1. Concept Overview
|
||||
|
||||
The **SYNC Line** is the vertical divider between the two halves of the COOPERATE grid.
|
||||
|
||||
It must:
|
||||
- Always be visible
|
||||
- React when one side is ready
|
||||
- Pulse when both sides are ready
|
||||
- Flash on line clear
|
||||
- Provide instant, text-free feedback
|
||||
|
||||
No shaders. No textures. SDL3 only.
|
||||
|
||||
---
|
||||
|
||||
## 2. Visual States
|
||||
|
||||
Define these states:
|
||||
|
||||
```cpp
|
||||
enum class SyncState {
|
||||
Idle, // no side ready
|
||||
LeftReady, // left half complete
|
||||
RightReady, // right half complete
|
||||
Synced, // both halves complete
|
||||
ClearFlash // row cleared
|
||||
};
|
||||
````
|
||||
|
||||
---
|
||||
|
||||
## 3. Color Language
|
||||
|
||||
| State | Color | Meaning |
|
||||
| ------------------ | --------------- | ------------------- |
|
||||
| Idle | Blue | Neutral |
|
||||
| Left / Right Ready | Yellow | Waiting for partner |
|
||||
| Synced | Green (pulsing) | Perfect cooperation |
|
||||
| ClearFlash | White | Successful clear |
|
||||
|
||||
---
|
||||
|
||||
## 4. Geometry
|
||||
|
||||
The SYNC line is a simple rectangle:
|
||||
|
||||
```cpp
|
||||
SDL_FRect syncLine;
|
||||
syncLine.x = gridCenterX - 2;
|
||||
syncLine.y = gridTopY;
|
||||
syncLine.w = 4;
|
||||
syncLine.h = gridHeight;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Rendering Rules
|
||||
|
||||
* Always render every frame
|
||||
* Use alpha blending
|
||||
* Pulse alpha when synced
|
||||
* Flash briefly on clear
|
||||
|
||||
---
|
||||
|
||||
## 6. SyncLineRenderer Class (Required)
|
||||
|
||||
### Header
|
||||
|
||||
```cpp
|
||||
#pragma once
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
enum class SyncState {
|
||||
Idle,
|
||||
LeftReady,
|
||||
RightReady,
|
||||
Synced,
|
||||
ClearFlash
|
||||
};
|
||||
|
||||
class SyncLineRenderer {
|
||||
public:
|
||||
SyncLineRenderer();
|
||||
|
||||
void SetRect(const SDL_FRect& rect);
|
||||
void SetState(SyncState state);
|
||||
void TriggerClearFlash();
|
||||
|
||||
void Update(float deltaTime);
|
||||
void Render(SDL_Renderer* renderer);
|
||||
|
||||
private:
|
||||
SDL_FRect m_rect;
|
||||
SyncState m_state;
|
||||
|
||||
float m_flashTimer;
|
||||
float m_time;
|
||||
|
||||
static constexpr float FLASH_DURATION = 0.15f;
|
||||
|
||||
SDL_Color GetBaseColor() const;
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Implementation
|
||||
|
||||
```cpp
|
||||
#include "SyncLineRenderer.h"
|
||||
#include <cmath>
|
||||
|
||||
SyncLineRenderer::SyncLineRenderer()
|
||||
: m_state(SyncState::Idle),
|
||||
m_flashTimer(0.0f),
|
||||
m_time(0.0f) {}
|
||||
|
||||
void SyncLineRenderer::SetRect(const SDL_FRect& rect) {
|
||||
m_rect = rect;
|
||||
}
|
||||
|
||||
void SyncLineRenderer::SetState(SyncState state) {
|
||||
if (state != SyncState::ClearFlash)
|
||||
m_state = state;
|
||||
}
|
||||
|
||||
void SyncLineRenderer::TriggerClearFlash() {
|
||||
m_state = SyncState::ClearFlash;
|
||||
m_flashTimer = FLASH_DURATION;
|
||||
}
|
||||
|
||||
void SyncLineRenderer::Update(float deltaTime) {
|
||||
m_time += deltaTime;
|
||||
|
||||
if (m_state == SyncState::ClearFlash) {
|
||||
m_flashTimer -= deltaTime;
|
||||
if (m_flashTimer <= 0.0f) {
|
||||
m_state = SyncState::Idle;
|
||||
m_flashTimer = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Color SyncLineRenderer::GetBaseColor() const {
|
||||
switch (m_state) {
|
||||
case SyncState::LeftReady:
|
||||
case SyncState::RightReady:
|
||||
return {255, 220, 100, 200}; // yellow
|
||||
|
||||
case SyncState::Synced:
|
||||
return {100, 255, 120, 220}; // green
|
||||
|
||||
case SyncState::ClearFlash:
|
||||
return {255, 255, 255, 255}; // white
|
||||
|
||||
default:
|
||||
return {80, 180, 255, 180}; // idle blue
|
||||
}
|
||||
}
|
||||
|
||||
void SyncLineRenderer::Render(SDL_Renderer* renderer) {
|
||||
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
|
||||
|
||||
SDL_Color color = GetBaseColor();
|
||||
|
||||
if (m_state == SyncState::Synced) {
|
||||
float pulse = 0.5f + 0.5f * std::sinf(m_time * 6.0f);
|
||||
color.a = static_cast<Uint8>(160 + pulse * 80);
|
||||
}
|
||||
|
||||
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
|
||||
SDL_RenderFillRect(renderer, &m_rect);
|
||||
|
||||
if (m_state == SyncState::ClearFlash) {
|
||||
SDL_FRect glow = m_rect;
|
||||
glow.x -= 3;
|
||||
glow.w += 6;
|
||||
|
||||
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 180);
|
||||
SDL_RenderFillRect(renderer, &glow);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Integration Flow
|
||||
|
||||
### Initialization
|
||||
|
||||
```cpp
|
||||
SyncLineRenderer syncLine;
|
||||
syncLine.SetRect({
|
||||
gridCenterX - 2.0f,
|
||||
gridTopY,
|
||||
4.0f,
|
||||
gridHeight
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Update Loop
|
||||
|
||||
```cpp
|
||||
syncLine.Update(deltaTime);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Game Logic → Sync State Mapping
|
||||
|
||||
```cpp
|
||||
if (leftRowReady && rightRowReady)
|
||||
syncLine.SetState(SyncState::Synced);
|
||||
else if (leftRowReady)
|
||||
syncLine.SetState(SyncState::LeftReady);
|
||||
else if (rightRowReady)
|
||||
syncLine.SetState(SyncState::RightReady);
|
||||
else
|
||||
syncLine.SetState(SyncState::Idle);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### On Line Clear Event
|
||||
|
||||
```cpp
|
||||
syncLine.TriggerClearFlash();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Render Loop
|
||||
|
||||
```cpp
|
||||
syncLine.Render(renderer);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Performance Requirements
|
||||
|
||||
* ≤ 2 draw calls per frame
|
||||
* No textures
|
||||
* No dynamic allocations
|
||||
* No blocking logic
|
||||
* Suitable for 60–240 FPS
|
||||
|
||||
---
|
||||
|
||||
## 9. UX Rationale
|
||||
|
||||
* Color communicates state without text
|
||||
* Pulse indicates readiness
|
||||
* Flash provides satisfaction on success
|
||||
* Reinforces cooperation visually
|
||||
|
||||
---
|
||||
|
||||
## 10. Acceptance Criteria
|
||||
|
||||
* Divider is always visible
|
||||
* State changes are instantly readable
|
||||
* Flash triggers exactly on cooperative line clear
|
||||
* No performance impact
|
||||
* Clean separation from gameplay logic
|
||||
|
||||
---
|
||||
|
||||
## 11. Optional Future Enhancements (Not Required)
|
||||
|
||||
* Vertical energy particles
|
||||
* Sound hooks on SYNC / CLEAR
|
||||
* Combo-based intensity
|
||||
* Color-blind palette
|
||||
* Gradient or glow variants
|
||||
|
||||
---
|
||||
|
||||
## Summary for Copilot
|
||||
|
||||
Implement a `SyncLineRenderer` class in SDL3 to render the cooperative divider line. The line reflects cooperation state through color, pulse, and flash effects. The renderer must be lightweight, stateless with gameplay, and fully driven by external state updates.
|
||||
@ -1,213 +0,0 @@
|
||||
# Spacetris — Supabase Highscore Integration
|
||||
## VS Code Copilot AI Agent Prompt
|
||||
|
||||
You are integrating Supabase highscores into a native C++ SDL3 game called **Spacetris**.
|
||||
|
||||
This is a REST-only integration using Supabase PostgREST.
|
||||
Do NOT use any Supabase JS SDKs.
|
||||
|
||||
---
|
||||
|
||||
## 1. Goal
|
||||
|
||||
Implement a highscore backend using Supabase for these game modes:
|
||||
- classic
|
||||
- challenge
|
||||
- cooperate
|
||||
- versus
|
||||
|
||||
Highscores must be:
|
||||
- Submitted asynchronously on game over
|
||||
- Fetched asynchronously for leaderboard screens
|
||||
- Non-blocking (never stall render loop)
|
||||
- Offline-safe (fail silently)
|
||||
|
||||
---
|
||||
|
||||
## 2. Supabase Configuration
|
||||
|
||||
The following constants are provided at build time:
|
||||
|
||||
```cpp
|
||||
const std::string SUPABASE_URL = "https://xzxpmvyamjvtxpwnjpad.supabase.co";
|
||||
const std::string SUPABASE_ANON_KEY = "sb_publishable_GqQx844xYDizO9-ytlBXfA_MVT6N7yA";
|
||||
````
|
||||
|
||||
All requests go to:
|
||||
|
||||
```
|
||||
{SUPABASE_URL}/rest/v1/highscores
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Database Schema (Already Exists)
|
||||
|
||||
The Supabase table `highscores` has the following fields:
|
||||
|
||||
* score (integer)
|
||||
* lines (integer)
|
||||
* level (integer)
|
||||
* time_sec (integer)
|
||||
* name (string)
|
||||
* game_type ("classic", "versus", "cooperate", "challenge")
|
||||
* timestamp (integer, UNIX epoch seconds)
|
||||
|
||||
---
|
||||
|
||||
## 4. Data Model in C++
|
||||
|
||||
Create a struct matching the database schema:
|
||||
|
||||
```cpp
|
||||
struct HighscoreEntry {
|
||||
int score;
|
||||
int lines;
|
||||
int level;
|
||||
int timeSec;
|
||||
std::string name;
|
||||
std::string gameType;
|
||||
int timestamp;
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. HTTP Layer Requirements
|
||||
|
||||
* Use **libcurl**
|
||||
* Use **JSON** (nlohmann::json or equivalent)
|
||||
* All network calls must run in a worker thread
|
||||
* Never block the SDL main loop
|
||||
|
||||
Required HTTP headers:
|
||||
|
||||
```
|
||||
apikey: SUPABASE_ANON_KEY
|
||||
Authorization: Bearer SUPABASE_ANON_KEY
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Submit Highscore (POST)
|
||||
|
||||
Implement:
|
||||
|
||||
```cpp
|
||||
void SubmitHighscoreAsync(const HighscoreEntry& entry);
|
||||
```
|
||||
|
||||
Behavior:
|
||||
|
||||
* Convert entry to JSON
|
||||
* POST to `/rest/v1/highscores`
|
||||
* On failure:
|
||||
|
||||
* Log error
|
||||
* Do NOT crash
|
||||
* Optionally store JSON locally for retry
|
||||
|
||||
Example JSON payload:
|
||||
|
||||
```json
|
||||
{
|
||||
"score": 123456,
|
||||
"lines": 240,
|
||||
"level": 37,
|
||||
"time_sec": 1820,
|
||||
"name": "P1 & P2",
|
||||
"game_type": "cooperate",
|
||||
"timestamp": 1710000000
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Fetch Leaderboard (GET)
|
||||
|
||||
Implement:
|
||||
|
||||
```cpp
|
||||
std::vector<HighscoreEntry> FetchHighscores(
|
||||
const std::string& gameType,
|
||||
int limit
|
||||
);
|
||||
```
|
||||
|
||||
REST query examples:
|
||||
|
||||
Classic:
|
||||
|
||||
```
|
||||
?game_type=eq.classic&order=score.desc&limit=20
|
||||
```
|
||||
|
||||
Challenge:
|
||||
|
||||
```
|
||||
?game_type=eq.challenge&order=level.desc,time_sec.asc&limit=20
|
||||
```
|
||||
|
||||
Cooperate:
|
||||
|
||||
```
|
||||
?game_type=eq.cooperate&order=score.desc&limit=20
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Threading Model
|
||||
|
||||
* Use `std::thread` or a simple job queue
|
||||
* Network calls must not run on the render thread
|
||||
* Use mutex or lock-free queue to pass results back to UI
|
||||
|
||||
---
|
||||
|
||||
## 9. Error Handling Rules
|
||||
|
||||
* If Supabase is unreachable:
|
||||
|
||||
* Game continues normally
|
||||
* Leaderboard screen shows "Offline"
|
||||
* Never block gameplay
|
||||
* Never show raw network errors to player
|
||||
|
||||
---
|
||||
|
||||
## 10. Security Constraints
|
||||
|
||||
* API key is public (acceptable for highscores)
|
||||
* Obfuscate key in binary if possible
|
||||
* Do NOT trust client-side data (future server validation planned)
|
||||
|
||||
---
|
||||
|
||||
## 11. File Structure Suggestion
|
||||
|
||||
```
|
||||
/network
|
||||
supabase_client.h
|
||||
supabase_client.cpp
|
||||
|
||||
/highscores
|
||||
highscore_submit.cpp
|
||||
highscore_fetch.cpp
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. Acceptance Criteria
|
||||
|
||||
* Highscores are submitted after game over
|
||||
* Leaderboards load without blocking gameplay
|
||||
* Works for all four game types
|
||||
* Offline mode does not crash or freeze
|
||||
* Code is clean, modular, and SDL3-safe
|
||||
|
||||
---
|
||||
|
||||
## 13. Summary for the Agent
|
||||
|
||||
Integrate Supabase highscores into Spacetris using REST calls from C++ with libcurl. Use async submission and fetching. Support classic, challenge, cooperate, and versus modes. Ensure non-blocking behavior and graceful offline handling.
|
||||
Reference in New Issue
Block a user