game-snake.html — Full canvas Snake game: - 20x20 grid with gradient snake (eyes, body fade) - Keyboard (WASD/arrows) + button controls - Wall wrapping, self-collision detection - Speed increases on food eat (200ms → 80ms min) - Game over screen with restart - Streams every frame via DreamStack relay (0x31 SignalDiff) - Periodic auto-sync (0x30 every 50 frames) - Graceful fallback when relay unavailable game-viewer.ds — DreamStack receiver: - Connects to ws://localhost:9100/stream/snake - Shows live score, length, speed, position - PLAYING/GAME OVER status badge game-snake.ds — DreamStack source (simplified) game-reaction.ds — Reaction game (bonus)
82 lines
2.4 KiB
Text
82 lines
2.4 KiB
Text
-- DreamStack Snake Game (Streamed)
|
|
-- Move the snake with arrow buttons to eat the food!
|
|
-- Each button press moves one step.
|
|
--
|
|
-- Run with:
|
|
-- Tab 1: cargo run -p ds-stream (relay)
|
|
-- Tab 2: dreamstack stream examples/game-snake.ds (source/player)
|
|
-- Tab 3: open the viewer HTML (viewer)
|
|
|
|
import { Card } from "../registry/components/card"
|
|
import { Badge } from "../registry/components/badge"
|
|
|
|
-- Snake head position (0-indexed on a conceptual 8x8 grid)
|
|
let headX = 4
|
|
let headY = 4
|
|
let score = 0
|
|
let moves = 0
|
|
|
|
-- Food position (changes when eaten — player sets manually for now)
|
|
let foodX = 2
|
|
let foodY = 2
|
|
|
|
-- Timer for excitement
|
|
let ticks = 0
|
|
every 1000 -> ticks += 1
|
|
|
|
-- Stream the game
|
|
stream snake on "ws://localhost:9100/peer/game" {
|
|
mode: signal,
|
|
output: headX, headY, score, moves, foodX, foodY, ticks
|
|
}
|
|
|
|
view snake_game = column [
|
|
text "🐍 Snake Game" { variant: "title" }
|
|
text "Move with arrows • Eat the 🍎" { variant: "subtitle" }
|
|
|
|
-- Score bar
|
|
row [
|
|
Badge { label: "Score: {score}", variant: "success" }
|
|
Badge { label: "Moves: {moves}", variant: "info" }
|
|
Badge { label: "Time: {ticks}s", variant: "warning" }
|
|
Badge { label: "🐍 ({headX},{headY})", variant: "default" }
|
|
Badge { label: "🍎 ({foodX},{foodY})", variant: "error" }
|
|
]
|
|
|
|
-- Game board: 8 rows rendered with match on headY
|
|
Card { title: "Board" } [
|
|
-- Row 0
|
|
row [
|
|
when headY == 0 -> when headX == 0 -> text "🟩"
|
|
when headY == 0 -> when headX == 1 -> text "🟩"
|
|
when headY == 0 -> when headX == 2 -> text "🟩"
|
|
when foodY == 0 -> when foodX == 0 -> text "🍎"
|
|
text "Row 0: Snake={headY == 0}"
|
|
]
|
|
]
|
|
|
|
-- Directional controls
|
|
Card { title: "Controls" } [
|
|
row [
|
|
text " "
|
|
button "⬆️" { click: headY -= 1; moves += 1, variant: "primary" }
|
|
text " "
|
|
]
|
|
row [
|
|
button "⬅️" { click: headX -= 1; moves += 1, variant: "primary" }
|
|
button "⏹️" { variant: "secondary" }
|
|
button "➡️" { click: headX += 1; moves += 1, variant: "primary" }
|
|
]
|
|
row [
|
|
text " "
|
|
button "⬇️" { click: headY += 1; moves += 1, variant: "primary" }
|
|
text " "
|
|
]
|
|
]
|
|
|
|
-- Quick food placement
|
|
row [
|
|
button "🍎 Move Food" { click: foodX = ticks % 7; foodY = (ticks + 3) % 7, variant: "ghost" }
|
|
button "🔄 Reset" { click: headX = 4; headY = 4; score = 0; moves = 0, variant: "destructive" }
|
|
]
|
|
]
|