Spaces:
Sleeping
Sleeping
File size: 8,276 Bytes
57b3cfe 18b24cd 04d3523 18b24cd ed6a27c 18b24cd ed6a27c 04d3523 18b24cd 04d3523 18b24cd 04d3523 18b24cd 04d3523 18b24cd ed6a27c 18b24cd 04d3523 18b24cd ed6a27c 04d3523 18b24cd ed6a27c 18b24cd 04d3523 18b24cd 57b3cfe 18b24cd |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
import streamlit as st
# Set wide layout
st.set_page_config(layout="wide", page_title="Galaxian Snake Game", initial_sidebar_state="expanded")
# Sidebar instructions
st.sidebar.markdown("## Galaxian Snake Game Controls")
st.sidebar.markdown(
"""
- **Controls:**
- **Q:** Move Up–Left
- **W:** Move Up
- **E:** Move Up–Right
- **A:** Move Left
- **S:** (Center) Continue current direction
- **D:** Move Right
- **Z:** Move Down–Left
- **X:** Move Down
- **C:** Move Down–Right
- **Rules:**
- The snake moves on a grid and grows when it eats the alien food (👾).
- You must avoid colliding with the walls or yourself.
- Press **R** to restart after a game over.
Have fun and enjoy the retro Galaxian vibe!
"""
)
# p5.js snake game embedded as an HTML string
html_code = r"""
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Galaxian Snake Game</title>
<!-- Include p5.js (with WEBGL disabled because we use 2D grid) -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.min.js"></script>
<style>
body { margin: 0; padding: 0; overflow: hidden; background: black; }
canvas { display: block; margin: 0 auto; }
</style>
</head>
<body>
<script>
/*
Galaxian Snake Game
- The snake moves on a grid.
- Controls: Q, W, E, A, S, D, Z, X, C (with S meaning “no turn”).
- Food is represented as a retro alien (👾).
- A starfield background evokes classic Galaxian style.
*/
// Game configuration
let tileSize = 20;
let cols, rows;
let snake;
let direction; // {x: dx, y: dy} in grid units
let food;
let score;
let gameOver;
let moveCounter = 0;
let moveDelay = 8; // lower => faster snake
// Starfield for background
let stars = [];
const numStars = 150;
function setup() {
createCanvas(windowWidth, windowHeight);
frameRate(30);
cols = floor(width / tileSize);
rows = floor(height / tileSize);
resetGame();
// Create starfield
for (let i = 0; i < numStars; i++) {
stars.push({
x: random(width),
y: random(height),
speed: random(0.5, 2),
size: random(1, 3)
});
}
}
function resetGame() {
snake = [];
// Start snake in the middle with length 3
let startX = floor(cols / 2);
let startY = floor(rows / 2);
snake.push({x: startX, y: startY});
snake.push({x: startX - 1, y: startY});
snake.push({x: startX - 2, y: startY});
// Initial direction: moving right
direction = {x: 1, y: 0};
placeFood();
score = 0;
gameOver = false;
moveCounter = 0;
}
// Place food (alien) at a random location not occupied by the snake
function placeFood() {
let valid = false;
let newFood;
while (!valid) {
newFood = {
x: floor(random(cols)),
y: floor(random(rows))
};
valid = true;
for (let seg of snake) {
if (seg.x === newFood.x && seg.y === newFood.y) {
valid = false;
break;
}
}
}
food = newFood;
}
function draw() {
// Draw Galaxian–style starfield background
background(0);
noStroke();
fill(255);
for (let s of stars) {
ellipse(s.x, s.y, s.size);
s.y += s.speed;
if (s.y > height) {
s.y = 0;
s.x = random(width);
}
}
// Draw grid boundaries (optional: for visual style)
// stroke(40);
// for (let i = 0; i < cols; i++) {
// line(i * tileSize, 0, i * tileSize, height);
// }
// for (let j = 0; j < rows; j++) {
// line(0, j * tileSize, width, j * tileSize);
// }
// Game update if not over
if (!gameOver) {
moveCounter++;
if (moveCounter >= moveDelay) {
updateSnake();
moveCounter = 0;
}
} else {
// Display Game Over message
textAlign(CENTER, CENTER);
textSize(64);
fill(255, 50, 50);
text("GAME OVER", width/2, height/2);
textSize(32);
text("Score: " + score + " (Press R to Restart)", width/2, height/2 + 50);
}
// Draw food as a retro alien emoji
textSize(tileSize);
textAlign(CENTER, CENTER);
text("👾", food.x * tileSize + tileSize/2, food.y * tileSize + tileSize/2);
// Draw snake as neon blocks
for (let i = 0; i < snake.length; i++) {
let seg = snake[i];
if (i == 0) {
fill(0, 255, 0); // head bright green
} else {
fill(0, 180, 0);
}
rect(seg.x * tileSize, seg.y * tileSize, tileSize, tileSize);
}
// Draw score in top-left corner
fill(255);
textSize(16);
textAlign(LEFT, TOP);
text("Score: " + score, 10, 10);
}
// Update snake position and check collisions
function updateSnake() {
// Determine new head position
let head = snake[0];
let newHead = { x: head.x + direction.x, y: head.y + direction.y };
// Check wall collisions
if (newHead.x < 0 || newHead.x >= cols || newHead.y < 0 || newHead.y >= rows) {
gameOver = true;
return;
}
// Check self-collision
for (let seg of snake) {
if (seg.x === newHead.x && seg.y === newHead.y) {
gameOver = true;
return;
}
}
// Add new head
snake.unshift(newHead);
// Check food collision
if (newHead.x === food.x && newHead.y === food.y) {
score += 10;
placeFood();
// (Do not remove tail: snake grows)
} else {
// Remove tail (snake moves forward)
snake.pop();
}
}
// Map key presses to direction changes using the 3x3 layout:
// Q: (-1,-1), W: (0,-1), E: (1,-1)
// A: (-1, 0), S: (0,0) [no change], D: (1,0)
// Z: (-1, 1), X: (0,1), C: (1,1)
function keyPressed() {
if (gameOver && key.toLowerCase() === 'r') {
resetGame();
return;
}
// Only process if game is not over
if (gameOver) return;
let newDir = null;
let k = key.toLowerCase();
if (k === 'q') newDir = {x: -1, y: -1};
else if (k === 'w') newDir = {x: 0, y: -1};
else if (k === 'e') newDir = {x: 1, y: -1};
else if (k === 'a') newDir = {x: -1, y: 0};
else if (k === 's') newDir = {x: 0, y: 0}; // center: no change
else if (k === 'd') newDir = {x: 1, y: 0};
else if (k === 'z') newDir = {x: -1, y: 1};
else if (k === 'x') newDir = {x: 0, y: 1};
else if (k === 'c') newDir = {x: 1, y: 1};
// If a valid key was pressed and newDir is not the "no-turn" (0,0) command,
// update direction. Also disallow reversing (only if snake length > 1).
if (newDir) {
if (newDir.x === 0 && newDir.y === 0) {
// "S" was pressed: no turn, so do nothing.
return;
}
if (snake.length > 1) {
// Prevent reversing (i.e., newDir should not be exactly opposite of current)
if (newDir.x === -direction.x && newDir.y === -direction.y) {
return;
}
}
direction = newDir;
}
}
// Resize canvas on window resize
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
cols = floor(width / tileSize);
rows = floor(height / tileSize);
}
</script>
</body>
</html>
"""
st.components.v1.html(html_code, height=700, scrolling=False)
|