LukasBe commited on
Commit
805fd19
·
verified ·
1 Parent(s): 793742e

Add 2 files

Browse files
Files changed (2) hide show
  1. index.html +431 -1
  2. prompts.txt +2 -1
index.html CHANGED
@@ -217,6 +217,61 @@
217
  0% { transform: scale(0); opacity: 1; }
218
  100% { transform: scale(3); opacity: 0; }
219
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
  </style>
221
  </head>
222
  <body class="bg-gray-900 text-white font-sans overflow-hidden">
@@ -240,11 +295,114 @@
240
  <button id="startButton" class="bg-gradient-to-r from-yellow-500 to-yellow-600 hover:from-yellow-400 hover:to-yellow-500 text-4xl text-gray-900 font-bold py-5 px-16 rounded-full transition-all transform hover:scale-105 shadow-lg glow relative z-10">
241
  START COOKING
242
  </button>
 
 
 
243
  <div class="absolute bottom-8 text-gray-400 text-sm z-10">
244
  Tap the beat when ingredients reach the counter
245
  </div>
246
  </div>
247
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
248
  <!-- Game Screen -->
249
  <div id="gameScreen" class="fixed inset-0 hidden flex flex-col">
250
  <!-- Kitchen ambient light -->
@@ -258,6 +416,9 @@
258
  <div id="comboContainer" class="text-4xl font-bold combo-text hidden">
259
  🔥 <span id="combo">0</span>x
260
  </div>
 
 
 
261
  </div>
262
 
263
  <!-- Game Area -->
@@ -361,6 +522,28 @@
361
  const energyWaves = document.getElementById('energyWaves');
362
  const screenFlash = document.getElementById('screenFlash');
363
  const startScreenBg = document.getElementById('startScreenBg');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
364
 
365
  // Initialize audio context
366
  function initAudio() {
@@ -595,7 +778,7 @@
595
  particle.style.transition = `all ${duration}s ease-out`;
596
  particle.style.boxShadow = `0 0 ${size/2}px ${color}`;
597
 
598
- document.body.appendChild(particle);
599
 
600
  setTimeout(() => {
601
  particle.style.opacity = '0';
@@ -1064,6 +1247,136 @@
1064
  }
1065
  }
1066
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1067
  // Initialize game
1068
  function initGame() {
1069
  initAudio();
@@ -1083,6 +1396,12 @@
1083
  startScreenBg.appendChild(element);
1084
  }
1085
 
 
 
 
 
 
 
1086
  // Start button
1087
  startButton.addEventListener('click', () => {
1088
  startScreen.classList.add('opacity-0');
@@ -1099,6 +1418,117 @@
1099
  startSequence();
1100
  });
1101
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1102
  // Tap input
1103
  gameArea.addEventListener('click', handleTap);
1104
 
 
217
  0% { transform: scale(0); opacity: 1; }
218
  100% { transform: scale(3); opacity: 0; }
219
  }
220
+
221
+ /* Settings panel */
222
+ .settings-panel {
223
+ transition: all 0.3s ease;
224
+ transform: translateY(100%);
225
+ }
226
+
227
+ .settings-panel.open {
228
+ transform: translateY(0);
229
+ }
230
+
231
+ .settings-overlay {
232
+ background-color: rgba(0, 0, 0, 0.7);
233
+ }
234
+
235
+ /* Range slider styling */
236
+ input[type="range"] {
237
+ -webkit-appearance: none;
238
+ height: 8px;
239
+ background: #4a5568;
240
+ border-radius: 4px;
241
+ }
242
+
243
+ input[type="range"]::-webkit-slider-thumb {
244
+ -webkit-appearance: none;
245
+ appearance: none;
246
+ width: 20px;
247
+ height: 20px;
248
+ border-radius: 50%;
249
+ background: #f6ad55;
250
+ cursor: pointer;
251
+ }
252
+
253
+ input[type="range"]::-moz-range-thumb {
254
+ width: 20px;
255
+ height: 20px;
256
+ border-radius: 50%;
257
+ background: #f6ad55;
258
+ cursor: pointer;
259
+ }
260
+
261
+ /* Preset buttons */
262
+ .preset-btn {
263
+ transition: all 0.2s ease;
264
+ }
265
+
266
+ .preset-btn:hover {
267
+ transform: translateY(-2px);
268
+ }
269
+
270
+ .preset-btn.active {
271
+ background-color: #f6ad55;
272
+ color: #1a202c;
273
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
274
+ }
275
  </style>
276
  </head>
277
  <body class="bg-gray-900 text-white font-sans overflow-hidden">
 
295
  <button id="startButton" class="bg-gradient-to-r from-yellow-500 to-yellow-600 hover:from-yellow-400 hover:to-yellow-500 text-4xl text-gray-900 font-bold py-5 px-16 rounded-full transition-all transform hover:scale-105 shadow-lg glow relative z-10">
296
  START COOKING
297
  </button>
298
+ <button id="settingsButton" class="absolute top-4 right-4 bg-gray-800 hover:bg-gray-700 text-yellow-400 text-2xl p-3 rounded-full transition-all transform hover:scale-110 shadow-lg">
299
+ ⚙️
300
+ </button>
301
  <div class="absolute bottom-8 text-gray-400 text-sm z-10">
302
  Tap the beat when ingredients reach the counter
303
  </div>
304
  </div>
305
 
306
+ <!-- Settings Panel -->
307
+ <div id="settingsPanel" class="fixed inset-0 z-20 flex items-end settings-overlay hidden">
308
+ <div class="settings-panel bg-gray-800 w-full rounded-t-3xl p-6 max-h-[80vh] overflow-y-auto">
309
+ <div class="flex justify-between items-center mb-6">
310
+ <h3 class="text-3xl font-bold text-yellow-400">Game Settings</h3>
311
+ <button id="closeSettings" class="text-2xl p-2 rounded-full hover:bg-gray-700">
312
+
313
+ </button>
314
+ </div>
315
+
316
+ <div class="space-y-8">
317
+ <!-- Presets Section -->
318
+ <div>
319
+ <h4 class="text-xl font-semibold mb-4 text-gray-300">Presets</h4>
320
+ <div class="grid grid-cols-3 gap-3">
321
+ <button data-preset="easy" class="preset-btn bg-gray-700 hover:bg-gray-600 py-3 rounded-lg">
322
+ Easy
323
+ </button>
324
+ <button data-preset="medium" class="preset-btn bg-gray-700 hover:bg-gray-600 py-3 rounded-lg active">
325
+ Medium
326
+ </button>
327
+ <button data-preset="hard" class="preset-btn bg-gray-700 hover:bg-gray-600 py-3 rounded-lg">
328
+ Hard
329
+ </button>
330
+ </div>
331
+ </div>
332
+
333
+ <!-- Speed Settings -->
334
+ <div>
335
+ <div class="flex justify-between items-center mb-2">
336
+ <label for="speedRange" class="text-lg font-medium">Speed: <span id="speedValue">2.0</span>s</label>
337
+ </div>
338
+ <input type="range" id="speedRange" min="0.5" max="4" step="0.1" value="2" class="w-full">
339
+ </div>
340
+
341
+ <!-- BPM Settings -->
342
+ <div>
343
+ <div class="flex justify-between items-center mb-2">
344
+ <label for="bpmRange" class="text-lg font-medium">Tempo: <span id="bpmValue">128</span> BPM</label>
345
+ </div>
346
+ <input type="range" id="bpmRange" min="60" max="200" step="1" value="128" class="w-full">
347
+ </div>
348
+
349
+ <!-- Perfect Window -->
350
+ <div>
351
+ <div class="flex justify-between items-center mb-2">
352
+ <label for="perfectRange" class="text-lg font-medium">Perfect Window: <span id="perfectValue">80</span>ms</label>
353
+ </div>
354
+ <input type="range" id="perfectRange" min="20" max="150" step="5" value="80" class="w-full">
355
+ </div>
356
+
357
+ <!-- Good Window -->
358
+ <div>
359
+ <div class="flex justify-between items-center mb-2">
360
+ <label for="goodRange" class="text-lg font-medium">Good Window: <span id="goodValue">160</span>ms</label>
361
+ </div>
362
+ <input type="range" id="goodRange" min="50" max="300" step="5" value="160" class="w-full">
363
+ </div>
364
+
365
+ <!-- Number of Ingredients -->
366
+ <div>
367
+ <div class="flex justify-between items-center mb-2">
368
+ <label for="ingredientsRange" class="text-lg font-medium">Ingredients: <span id="ingredientsValue">10</span></label>
369
+ </div>
370
+ <input type="range" id="ingredientsRange" min="4" max="20" step="1" value="10" class="w-full">
371
+ </div>
372
+
373
+ <!-- Sequence Length -->
374
+ <div>
375
+ <div class="flex justify-between items-center mb-2">
376
+ <label for="sequenceRange" class="text-lg font-medium">Sequence Length: <span id="sequenceValue">16</span> beats</label>
377
+ </div>
378
+ <input type="range" id="sequenceRange" min="8" max="32" step="4" value="16" class="w-full">
379
+ </div>
380
+
381
+ <!-- Save/Load Section -->
382
+ <div class="pt-4 border-t border-gray-700">
383
+ <h4 class="text-xl font-semibold mb-4 text-gray-300">Save/Load</h4>
384
+ <div class="grid grid-cols-2 gap-4">
385
+ <div>
386
+ <label for="presetName" class="block text-sm font-medium mb-1">Preset Name</label>
387
+ <input type="text" id="presetName" placeholder="e.g. Level1" class="w-full bg-gray-700 rounded px-3 py-2 text-white">
388
+ </div>
389
+ <div class="flex items-end">
390
+ <button id="savePreset" class="bg-yellow-600 hover:bg-yellow-500 text-white px-4 py-2 rounded w-full">
391
+ Save
392
+ </button>
393
+ </div>
394
+ </div>
395
+ <div class="mt-4">
396
+ <label for="loadPreset" class="block text-sm font-medium mb-1">Load Preset</label>
397
+ <select id="loadPreset" class="w-full bg-gray-700 rounded px-3 py-2 text-white">
398
+ <option value="">Select a preset</option>
399
+ </select>
400
+ </div>
401
+ </div>
402
+ </div>
403
+ </div>
404
+ </div>
405
+
406
  <!-- Game Screen -->
407
  <div id="gameScreen" class="fixed inset-0 hidden flex flex-col">
408
  <!-- Kitchen ambient light -->
 
416
  <div id="comboContainer" class="text-4xl font-bold combo-text hidden">
417
  🔥 <span id="combo">0</span>x
418
  </div>
419
+ <button id="gameSettingsButton" class="bg-gray-800 hover:bg-gray-700 text-yellow-400 text-xl p-2 rounded-full transition-all transform hover:scale-110 shadow-lg">
420
+ ⚙️
421
+ </button>
422
  </div>
423
 
424
  <!-- Game Area -->
 
522
  const energyWaves = document.getElementById('energyWaves');
523
  const screenFlash = document.getElementById('screenFlash');
524
  const startScreenBg = document.getElementById('startScreenBg');
525
+ const settingsButton = document.getElementById('settingsButton');
526
+ const gameSettingsButton = document.getElementById('gameSettingsButton');
527
+ const settingsPanel = document.getElementById('settingsPanel');
528
+ const closeSettings = document.getElementById('closeSettings');
529
+
530
+ // Settings elements
531
+ const speedRange = document.getElementById('speedRange');
532
+ const speedValue = document.getElementById('speedValue');
533
+ const bpmRange = document.getElementById('bpmRange');
534
+ const bpmValue = document.getElementById('bpmValue');
535
+ const perfectRange = document.getElementById('perfectRange');
536
+ const perfectValue = document.getElementById('perfectValue');
537
+ const goodRange = document.getElementById('goodRange');
538
+ const goodValue = document.getElementById('goodValue');
539
+ const ingredientsRange = document.getElementById('ingredientsRange');
540
+ const ingredientsValue = document.getElementById('ingredientsValue');
541
+ const sequenceRange = document.getElementById('sequenceRange');
542
+ const sequenceValue = document.getElementById('sequenceValue');
543
+ const presetName = document.getElementById('presetName');
544
+ const savePreset = document.getElementById('savePreset');
545
+ const loadPreset = document.getElementById('loadPreset');
546
+ const presetButtons = document.querySelectorAll('[data-preset]');
547
 
548
  // Initialize audio context
549
  function initAudio() {
 
778
  particle.style.transition = `all ${duration}s ease-out`;
779
  particle.style.boxShadow = `0 0 ${size/2}px ${color}`;
780
 
781
+ document.body.appendChild(article);
782
 
783
  setTimeout(() => {
784
  particle.style.opacity = '0';
 
1247
  }
1248
  }
1249
 
1250
+ // Load presets from localStorage
1251
+ function loadPresets() {
1252
+ const presets = JSON.parse(localStorage.getItem('rhythmChefPresets')) || {};
1253
+ const select = document.getElementById('loadPreset');
1254
+
1255
+ // Clear existing options except the first one
1256
+ while (select.options.length > 1) {
1257
+ select.remove(1);
1258
+ }
1259
+
1260
+ // Add presets to dropdown
1261
+ for (const [name, preset] of Object.entries(presets)) {
1262
+ const option = document.createElement('option');
1263
+ option.value = name;
1264
+ option.textContent = name;
1265
+ select.appendChild(option);
1266
+ }
1267
+ }
1268
+
1269
+ // Save preset to localStorage
1270
+ function savePresetToStorage(name) {
1271
+ const presets = JSON.parse(localStorage.getItem('rhythmChefPresets')) || {};
1272
+
1273
+ presets[name] = {
1274
+ bpm: gameState.bpm,
1275
+ cueSpeed: gameState.cueSpeed,
1276
+ perfectWindow: gameState.perfectWindow,
1277
+ goodWindow: gameState.goodWindow,
1278
+ ingredients: gameState.ingredients,
1279
+ sequence: gameState.sequence
1280
+ };
1281
+
1282
+ localStorage.setItem('rhythmChefPresets', JSON.stringify(presets));
1283
+ loadPresets();
1284
+ }
1285
+
1286
+ // Load preset from localStorage
1287
+ function loadPresetFromStorage(name) {
1288
+ const presets = JSON.parse(localStorage.getItem('rhythmChefPresets')) || {};
1289
+ const preset = presets[name];
1290
+
1291
+ if (preset) {
1292
+ gameState.bpm = preset.bpm;
1293
+ gameState.cueSpeed = preset.cueSpeed;
1294
+ gameState.perfectWindow = preset.perfectWindow;
1295
+ gameState.goodWindow = preset.goodWindow;
1296
+ gameState.ingredients = preset.ingredients;
1297
+ gameState.sequence = preset.sequence;
1298
+
1299
+ // Update UI to match
1300
+ bpmRange.value = gameState.bpm;
1301
+ bpmValue.textContent = gameState.bpm;
1302
+ speedRange.value = gameState.cueSpeed;
1303
+ speedValue.textContent = gameState.cueSpeed.toFixed(1);
1304
+ perfectRange.value = gameState.perfectWindow;
1305
+ perfectValue.textContent = gameState.perfectWindow;
1306
+ goodRange.value = gameState.goodWindow;
1307
+ goodValue.textContent = gameState.goodWindow;
1308
+ ingredientsRange.value = gameState.ingredients.length;
1309
+ ingredientsValue.textContent = gameState.ingredients.length;
1310
+ sequenceRange.value = gameState.sequence.length;
1311
+ sequenceValue.textContent = gameState.sequence.length;
1312
+
1313
+ // Update preset name field
1314
+ presetName.value = name;
1315
+
1316
+ return true;
1317
+ }
1318
+ return false;
1319
+ }
1320
+
1321
+ // Apply preset settings
1322
+ function applyPreset(presetName) {
1323
+ switch(presetName) {
1324
+ case 'easy':
1325
+ gameState.bpm = 100;
1326
+ gameState.cueSpeed = 2.5;
1327
+ gameState.perfectWindow = 100;
1328
+ gameState.goodWindow = 200;
1329
+ gameState.ingredients = ['🍅', '🧀', '🍄', '🥩', '🥬', '🍞'];
1330
+ gameState.sequence = Array(16).fill().map((_, i) => ({ beat: i + 1, type: 'tap' }));
1331
+ break;
1332
+ case 'medium':
1333
+ gameState.bpm = 128;
1334
+ gameState.cueSpeed = 2;
1335
+ gameState.perfectWindow = 80;
1336
+ gameState.goodWindow = 160;
1337
+ gameState.ingredients = ['🍅', '🧀', '🍄', '🥩', '🥬', '🍞', '🥚', '🦐', '🌽', '🧅'];
1338
+ gameState.sequence = [
1339
+ { beat: 1, type: 'tap' }, { beat: 2, type: 'tap' }, { beat: 3, type: 'tap' }, { beat: 4, type: 'tap' },
1340
+ { beat: 5.5, type: 'tap' }, { beat: 6.5, type: 'tap' }, { beat: 7, type: 'tap' }, { beat: 8, type: 'tap' },
1341
+ { beat: 9, type: 'tap' }, { beat: 10, type: 'tap' }, { beat: 11.5, type: 'tap' }, { beat: 12.5, type: 'tap' },
1342
+ { beat: 13, type: 'tap' }, { beat: 14, type: 'tap' }, { beat: 15, type: 'tap' }, { beat: 16, type: 'tap' }
1343
+ ];
1344
+ break;
1345
+ case 'hard':
1346
+ gameState.bpm = 160;
1347
+ gameState.cueSpeed = 1.5;
1348
+ gameState.perfectWindow = 60;
1349
+ gameState.goodWindow = 120;
1350
+ gameState.ingredients = ['🍅', '🧀', '🍄', '🥩', '🥬', '🍞', '🥚', '🦐', '🌽', '🧅', '🥕', '🍠', '🥦', '🥒', '🍆'];
1351
+ gameState.sequence = [
1352
+ { beat: 1, type: 'tap' }, { beat: 1.5, type: 'tap' }, { beat: 2, type: 'tap' }, { beat: 2.5, type: 'tap' },
1353
+ { beat: 3, type: 'tap' }, { beat: 3.5, type: 'tap' }, { beat: 4, type: 'tap' }, { beat: 4.5, type: 'tap' },
1354
+ { beat: 5, type: 'tap' }, { beat: 5.5, type: 'tap' }, { beat: 6, type: 'tap' }, { beat: 6.5, type: 'tap' },
1355
+ { beat: 7, type: 'tap' }, { beat: 7.5, type: 'tap' }, { beat: 8, type: 'tap' }, { beat: 8.5, type: 'tap' }
1356
+ ];
1357
+ break;
1358
+ }
1359
+
1360
+ // Update UI to match
1361
+ bpmRange.value = gameState.bpm;
1362
+ bpmValue.textContent = gameState.bpm;
1363
+ speedRange.value = gameState.cueSpeed;
1364
+ speedValue.textContent = gameState.cueSpeed.toFixed(1);
1365
+ perfectRange.value = gameState.perfectWindow;
1366
+ perfectValue.textContent = gameState.perfectWindow;
1367
+ goodRange.value = gameState.goodWindow;
1368
+ goodValue.textContent = gameState.goodWindow;
1369
+ ingredientsRange.value = gameState.ingredients.length;
1370
+ ingredientsValue.textContent = gameState.ingredients.length;
1371
+ sequenceRange.value = gameState.sequence.length;
1372
+ sequenceValue.textContent = gameState.sequence.length;
1373
+
1374
+ // Update active preset button
1375
+ presetButtons.forEach(btn => {
1376
+ btn.classList.toggle('active', btn.dataset.preset === presetName);
1377
+ });
1378
+ }
1379
+
1380
  // Initialize game
1381
  function initGame() {
1382
  initAudio();
 
1396
  startScreenBg.appendChild(element);
1397
  }
1398
 
1399
+ // Load presets
1400
+ loadPresets();
1401
+
1402
+ // Apply medium preset by default
1403
+ applyPreset('medium');
1404
+
1405
  // Start button
1406
  startButton.addEventListener('click', () => {
1407
  startScreen.classList.add('opacity-0');
 
1418
  startSequence();
1419
  });
1420
 
1421
+ // Settings button
1422
+ settingsButton.addEventListener('click', () => {
1423
+ settingsPanel.classList.remove('hidden');
1424
+ setTimeout(() => {
1425
+ settingsPanel.querySelector('.settings-panel').classList.add('open');
1426
+ }, 10);
1427
+ });
1428
+
1429
+ // Game settings button
1430
+ gameSettingsButton.addEventListener('click', () => {
1431
+ settingsPanel.classList.remove('hidden');
1432
+ setTimeout(() => {
1433
+ settingsPanel.querySelector('.settings-panel').classList.add('open');
1434
+ }, 10);
1435
+ });
1436
+
1437
+ // Close settings
1438
+ closeSettings.addEventListener('click', () => {
1439
+ settingsPanel.querySelector('.settings-panel').classList.remove('open');
1440
+ setTimeout(() => {
1441
+ settingsPanel.classList.add('hidden');
1442
+ }, 300);
1443
+ });
1444
+
1445
+ // Preset buttons
1446
+ presetButtons.forEach(btn => {
1447
+ btn.addEventListener('click', () => {
1448
+ applyPreset(btn.dataset.preset);
1449
+ });
1450
+ });
1451
+
1452
+ // Range inputs
1453
+ speedRange.addEventListener('input', () => {
1454
+ gameState.cueSpeed = parseFloat(speedRange.value);
1455
+ speedValue.textContent = gameState.cueSpeed.toFixed(1);
1456
+ });
1457
+
1458
+ bpmRange.addEventListener('input', () => {
1459
+ gameState.bpm = parseInt(bpmRange.value);
1460
+ bpmValue.textContent = gameState.bpm;
1461
+ });
1462
+
1463
+ perfectRange.addEventListener('input', () => {
1464
+ gameState.perfectWindow = parseInt(perfectRange.value);
1465
+ perfectValue.textContent = gameState.perfectWindow;
1466
+ });
1467
+
1468
+ goodRange.addEventListener('input', () => {
1469
+ gameState.goodWindow = parseInt(goodRange.value);
1470
+ goodValue.textContent = gameState.goodWindow;
1471
+ });
1472
+
1473
+ ingredientsRange.addEventListener('input', () => {
1474
+ const count = parseInt(ingredientsRange.value);
1475
+ ingredientsValue.textContent = count;
1476
+
1477
+ // Basic ingredients that are always available
1478
+ const baseIngredients = ['🍅', '🧀', '🍄', '🥩', '🥬', '🍞', '🥚'];
1479
+
1480
+ // Additional ingredients that can be added
1481
+ const extraIngredients = ['🦐', '🌽', '🧅', '🥕', '🍠', '🥦', '🥒', '🍆', '🍍', '🥑'];
1482
+
1483
+ // Create the ingredient list based on count
1484
+ gameState.ingredients = [...baseIngredients];
1485
+ if (count > baseIngredients.length) {
1486
+ const needed = count - baseIngredients.length;
1487
+ gameState.ingredients.push(...extraIngredients.slice(0, Math.min(needed, extraIngredients.length)));
1488
+ } else {
1489
+ gameState.ingredients = gameState.ingredients.slice(0, count);
1490
+ }
1491
+ });
1492
+
1493
+ sequenceRange.addEventListener('input', () => {
1494
+ const length = parseInt(sequenceRange.value);
1495
+ sequenceValue.textContent = length;
1496
+
1497
+ // Create a simple sequence with the specified length
1498
+ gameState.sequence = Array(length).fill().map((_, i) => {
1499
+ // Alternate between whole beats and half beats for variety
1500
+ const beat = i % 2 === 0 ? i + 1 : i + 0.5;
1501
+ return { beat, type: 'tap' };
1502
+ });
1503
+ });
1504
+
1505
+ // Save preset
1506
+ savePreset.addEventListener('click', () => {
1507
+ const name = presetName.value.trim();
1508
+ if (name) {
1509
+ savePresetToStorage(name);
1510
+ presetName.value = '';
1511
+
1512
+ // Show confirmation
1513
+ const feedback = document.createElement('div');
1514
+ feedback.textContent = 'Preset saved!';
1515
+ feedback.className = 'text-green-400 text-sm mt-2';
1516
+ savePreset.parentNode.appendChild(feedback);
1517
+
1518
+ setTimeout(() => {
1519
+ feedback.remove();
1520
+ }, 2000);
1521
+ }
1522
+ });
1523
+
1524
+ // Load preset
1525
+ loadPreset.addEventListener('change', () => {
1526
+ if (loadPreset.value) {
1527
+ loadPresetFromStorage(loadPreset.value);
1528
+ presetName.value = loadPreset.value;
1529
+ }
1530
+ });
1531
+
1532
  // Tap input
1533
  gameArea.addEventListener('click', handleTap);
1534
 
prompts.txt CHANGED
@@ -1,3 +1,4 @@
1
  Okay, here is a detailed, implementation-grade plan for building an interactive demonstrator for the core game mechanics of **Rhythm Chef: Beat Bites**. This focuses on creating a minimal viable product (MVP) specifically for user feedback on the core rhythm interaction feel, keeping the codebase limited. **Assumptions:** * **Engine:** Unity (common choice for hypercasual, good for rapid prototyping). * **Language:** C#. * **Target Platform:** Android (easy for distributing APKs for testing). * **Input Focus:** Start with **Tap** only for simplicity. Hold/Swipe can be added later if the Tap feels good. **I. Demonstrator Objectives** 1. Implement the core rhythm interaction: spawning cues, moving cues, detecting timed player input within a target zone. 2. Provide immediate, clear visual and audio feedback for successful hits and misses. 3. Synchronize cue movement and required input timing to a consistent beat (can be a simple metronome track or internal timer). 4. Allow a user to play through a short, predefined sequence of cues. 5. Keep the scope strictly limited to the core mechanic loop for fast iteration and focused feedback. **II. Scope Definition** * **IN SCOPE:** * Single, non-scrolling conveyor belt or lane for cues. * One type of cue requiring a **Tap** input. * One clearly defined target zone. * Precise timing mechanism for cue spawning and hit detection. * Simple visual representation of cues (e.g., colored circles/squares representing ingredients/actions). * Visual feedback (e.g., color change, simple particle effect, text popup like "Perfect!"/"Miss!"). * Basic audio feedback (hit sound, miss sound, beat/metronome sound). * A predefined, short sequence (~15-30 seconds) of Tap cues. * Minimal UI: Start Button, potentially a simple score/combo counter (optional but helpful). * **OUT OF SCOPE:** * Multiple lanes or complex patterns. * Hold or Swipe input types. * Multiple cue types/actions (chop, fry, etc.). * Any meta-game (restaurant, currency, upgrades). * Scoring beyond basic hit/miss feedback (no stars, complex calculations). * Multiple songs or difficulty levels. * Polished art assets (use placeholders). * Advanced UI, menus, settings. * Saving/loading progress. * Performance optimization beyond basic functionality. **III. Key Components & Implementation Details** 1. **`GameManager.cs`** * **Purpose:** Controls the overall state, timing, and sequence playback. * **Properties:** * `float bpm`: Beats per minute for the rhythm. * `float cueSpeed`: Speed at which cues travel towards the target. * `float targetZonePosition`: Y-coordinate (or X if horizontal) of the target zone center. * `float spawnPosition`: Y-coordinate (or X) where cues appear. * `GameObject cuePrefab`: Prefab for the visual cue object. * `Transform cueSpawnPoint`: Transform where cues are instantiated. * `AudioSource metronomeSource`: Optional, for playing a beat sound. * `List<CueData> sequence`: Holds the predefined sequence of cues (timing). * `float songStartTime`: Time when the sequence began (using `AudioSettings.dspTime` or `Time.timeSinceLevelLoad`). * `int currentSequenceIndex`: Tracks the next cue to spawn. * `bool isPlaying`: Game state flag. * **Methods:** * `StartSequence()`: Initializes timing, resets index, sets `isPlaying = true`. Starts metronome if used. * `Update()`: * If `isPlaying`, check `sequence` if it's time to spawn the `currentSequenceIndex` cue based on `bpm` and `songStartTime`. * If spawning, instantiate `cuePrefab` at `cueSpawnPoint`, calculate its `targetTime` (arrival time at target zone), and pass necessary data to the cue's script. Increment `currentSequenceIndex`. * Handles end of sequence. * `StopSequence()`: Sets `isPlaying = false`. 2. **`CueData.cs` (or Struct)** * **Purpose:** Simple data structure to define a single cue in the sequence. * **Properties:** * `float beatTimestamp`: The beat number (e.g., 1, 1.5, 2) within the sequence when this cue should *hit* the target zone. * `CueType type`: Enum (e.g., `Tap`). (Initially only Tap needed). 3. **`CueObject.cs` (attached to `cuePrefab`)** * **Purpose:** Represents a single moving cue. * **Properties:** * `float speed`: Movement speed (set by `GameManager`). * `float targetTime`: The exact game time (`Time.timeSinceLevelLoad` or `dspTime`) this cue should ideally be hit. * `bool isHit`: Flag to prevent multiple hits. * `bool canBeHit`: Flag to indicate if it's currently within the hittable window around the target zone. * **Methods:** * `Initialize(float targetTime, float speed)`: Called by `GameManager` on spawn. * `Update()`: * Move the cue downwards (or towards the target) at `speed * Time.deltaTime`. * Check if the cue has passed the target zone *without* being hit and *after* its hittable window - trigger a Miss condition if so and destroy/disable self. * `OnTriggerEnter/Exit2D(Collider2D other)`: If using physics triggers for the target zone, set `canBeHit = true/false`. * `ProcessHit()`: Called by `InputHandler` when a hit is registered on this cue. Sets `isHit = true`, triggers success feedback, potentially disables the cue visually, and schedules destruction. 4. **`TargetZone.cs` (attached to a GameObject with a Collider2D)** * **Purpose:** Defines the area where input is registered and cues are evaluated. * **Properties:** * `float perfectWindow`: Time window (+/- seconds) for a perfect hit. * `float okWindow`: Time window (+/- seconds) for an acceptable (non-miss) hit. (Keep simple first: just Perfect/Miss). * **Methods:** * `OnTriggerEnter2D/Exit2D(Collider2D other)`: Detects `CueObject` entering/leaving the zone's collider. Could be used by `CueObject` to set its `canBeHit` flag. * **Note:** Hit timing validation logic might live more centrally in `InputHandler` or `GameManager` rather than distributed here. 5. **`InputHandler.cs`** * **Purpose:** Detects player input and checks if it corresponds to a hittable cue. * **Properties:** * `TargetZone targetZone`: Reference to the target zone script/object. * `LayerMask cueLayer`: Physics layer for cues. * **Methods:** * `Update()`: * Check for Tap input (`Input.GetMouseButtonDown(0)` or `Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began`). * If Tap detected: * Determine the current game time (`Time.timeSinceLevelLoad` or `AudioSettings.dspTime`). * Find the "closest" active `CueObject` that is currently `canBeHit` (e.g., using Physics2D overlap checks near the target zone, or iterating through active cues and checking position/timing). * If a potential cue is found: * Calculate `timeDifference = currentTime - cue.targetTime`. * If `Mathf.Abs(timeDifference) <= targetZone.perfectWindow`: * Call `cue.ProcessHit()`. * Trigger "Perfect" feedback via `FeedbackManager`. * Else (if outside window but maybe an OK window exists later): * Trigger "Miss" feedback via `FeedbackManager` (or OK if implementing). * Potentially destroy/disable the cue to prevent late hits. * Else (no cue was hittable): * Optional: Trigger a generic "Miss" feedback for tapping empty space. 6. **`FeedbackManager.cs` (Singleton or easily accessible)** * **Purpose:** Centralized handler for triggering visual/audio feedback. * **Properties:** * `GameObject perfectHitEffectPrefab`: Particle effect/animation for perfect hits. * `GameObject missEffectPrefab`: Effect for misses. * `AudioClip hitSound`: Sound for successful hit. * `AudioClip missSound`: Sound for miss/error. * `AudioSource feedbackAudioSource`: Source to play feedback sounds. * `TextMeshProUGUI feedbackText`: UI Text element to display "Perfect!"/"Miss!". * **Methods:** * `ShowHitFeedback(Vector3 position)`: Instantiate `perfectHitEffectPrefab` at `position`, play `hitSound`, show "Perfect!" text briefly. * `ShowMissFeedback(Vector3 position)`: Instantiate `missEffectPrefab` at `position`, play `missSound`, show "Miss!" text briefly. **IV. Timing Implementation (CRITICAL)** * **Consistency is Key:** Use a consistent time source. * **Option A (Simpler):** `Time.timeSinceLevelLoad`. Easier for basic logic but can drift slightly from audio. Good enough for a demonstrator. * **Option B (More Accurate):** `AudioSettings.dspTime`. Provides highly accurate timing synced with the audio engine. Requires careful handling, especially when scheduling future events based on audio playback. * **Calculations:** * Convert `bpm` to seconds per beat (`60f / bpm`). * Calculate cue `targetTime`: `songStartTime + cue.beatTimestamp * secondsPerBeat`. * Calculate spawn time: `targetTime - travelDuration`, where `travelDuration` is `distance / cueSpeed`. Spawn the cue at this calculated spawn time. **V. UI Implementation (Minimal)** * Canvas with: * `Button` to call `GameManager.StartSequence()`. * `TextMeshProUGUI` (optional) for Score/Combo (incremented in `FeedbackManager` on hit, reset on miss). * `TextMeshProUGUI` for "Perfect!"/"Miss!" feedback text (controlled by `FeedbackManager`). **VI. Placeholder Assets** * **Cue:** Simple white Circle or Square sprite. * **Target Zone:** Semi-transparent rectangle/line across the lane. * **Hit Effect:** Simple particle burst (e.g., Unity's default particle system emitting a few sparks) or a quick scaling/fading circle. * **Miss Effect:** Red flash or different particle effect. * **Audio:** * Metronome: Simple "tick" sound. * Hit Sound: Short, satisfying "click" or "pop". * Miss Sound: Dull "thud" or "buzz". **VII. Build & Test Plan** 1. Implement core components (`GameManager`, `CueObject`, `InputHandler`, `TargetZone`, `FeedbackManager`). 2. Define a simple `sequence` in `GameManager` (e.g., 10 taps on consecutive beats). 3. Use precise timing based on `Time.timeSinceLevelLoad` initially. 4. Integrate basic visual and audio feedback. 5. Test internally: Does it *feel* responsive? Is the timing right? 6. Refine timing windows (`perfectWindow`) based on feel. 7. Build an Android APK. 8. Distribute APK to testers. 9. Gather feedback specifically on: * Timing sensitivity (too strict, too lenient?). * Clarity of visual cues. * Effectiveness of feedback (did they know if they hit/missed?). * Overall satisfaction/fun of the core interaction. **VIII. Success Criteria for Demonstrator** * The demonstrator runs smoothly on a target Android device. * Cues spawn and travel predictably, synchronized with the beat. * User taps near the target zone trigger immediate hit/miss feedback. * Feedback (visual and audio) is clear and correctly corresponds to input timing accuracy. * Testers can understand the core mechanic and provide feedback on its "feel" within 5 minutes of playing. * The codebase is minimal and focused solely on the described scope. Okay, here's an ASCII art representation of the UI and user flow for the **Rhythm Chef: Beat Bites** core mechanics demonstrator. **1. User Flow Diagram** ```ascii +-------------------+ +----------------------+ +----------------------+ | Start Screen | ---+->| Gameplay Loop |---+->| End Screen (Simple)| | (Title, [Start]) | User | (Cues, Target, Input)| User | (Score?, [Restart])| +-------------------+ Taps | | Finishes Sequence +----------------------+ Start +--<-------------------+ Or Fails | (Optional) | | | | Back to Start Screen | +----------------------+ +----------------------+ ``` **2. UI Mockups (ASCII Art)** **A. Start Screen** ```ascii +-----------------------------------------+ | | | // RHYTHM CHEF: BEAT BITES // | | (Core Demo) | | | | | | | | | | +-----------+ | | | [ START ]| | | +-----------+ | | | | | +-----------------------------------------+ User taps [ START ] --> Transitions to Gameplay Screen ``` **B. Gameplay Screen (Mid-Sequence)** * Imagine cues `(*)` moving downwards `v` towards the `TARGET ZONE`. * The player needs to tap when a cue is inside the `TARGET ZONE`. ```ascii +-----------------------------------------+ | SCORE: 005 COMBO: 3x | <--- Optional Score/Combo Display |-----------------------------------------| | | | | | (*) | <--- Incoming Cue 1 | v | | | | | | (*) | <--- Incoming Cue 2 | v | | | | ===================================== | \ | | TARGET ZONE | | <--- The Area to Tap In | ===================================== | / | v | | (*) | <--- Cue that just passed (or was missed) | | | | | | |-----------------------------------------| | FEEDBACK: | <--- Area for text feedback +-----------------------------------------+ ``` **C. Gameplay Screen (Moment of Tap - Perfect Hit)** * Player taps as `(*)` enters the `TARGET ZONE`. * Visual & text feedback appears. ```ascii +-----------------------------------------+ | SCORE: 006 COMBO: 4x | <--- Score/Combo Updated |-----------------------------------------| | | | | | (*) | | v | | | | | | (*) | | v | | | | ===================================== | | | > > > PERFECT! < < < | | <--- Cue hit inside, feedback shown | ===================================== | | | | | (Effect) | <--- Visual effect (e.g., ASCII explosion *`*`) | | | | |-----------------------------------------| | FEEDBACK: Perfect! | <--- Text feedback updated +-----------------------------------------+ ``` **D. Gameplay Screen (Moment of Tap - Miss)** * Player taps too early/late, or misses a cue. ```ascii +-----------------------------------------+ | SCORE: 006 COMBO: 0x | <--- Combo Reset |-----------------------------------------| | | | | | (*) | | v | | | | | | (*) | | v | | | | ===================================== | | | TARGET ZONE | | | ===================================== | | v | | (X) | <--- Missed cue indication / effect | | | | |-----------------------------------------| | FEEDBACK: Miss! | <--- Text feedback updated +-----------------------------------------+ ``` **E. End Screen (Simple Demo End)** * Appears after the predefined sequence finishes. ```ascii +-----------------------------------------+ | | | SEQUENCE COMPLETE! | | | | (Final Score: 025) | <--- Optional final score | | | | | +-------------+ | | | [ RESTART ] | | | +-------------+ | | | | | +-----------------------------------------+ User taps [ RESTART ] --> Transitions back to Gameplay Screen (restarts sequence) (Or could go back to the Start Screen) ``` This ASCII representation outlines the essential visual elements and the flow between them for the core mechanics demonstrator, focusing on clarity for user feedback on the rhythm interaction. Okay, here are specific pixel-based dimensions and positions for the UI elements based on a **reference screen resolution of 1080x1920 pixels (Width x Height - Portrait Orientation)**. **Important Considerations:** * **Reference Only:** These are *fixed pixel values* for the specified reference resolution. In a real implementation (e.g., using Unity Canvas), you would use anchors, pivots, and potentially scaling components (like Canvas Scaler UI Scale Mode) to ensure the UI adapts correctly to different screen sizes and aspect ratios. * **Origin Point:** Assume the (0, 0) coordinate is the **bottom-left** corner of the screen, common in some UI systems, or **top-left** (common in others - I will specify based on typical Unity Canvas usage: **(0,0) is Bottom-Left, (1080, 1920) is Top-Right** unless stated otherwise). Positions usually refer to the object's **pivot point** (often the center, unless specified). * **Font Sizes:** Pixel sizes for fonts are approximate and depend heavily on the specific font file used. * **Actors:** Actors like Cues and Effects have positions that change dynamically or are instantiated at specific world/UI coordinates. --- **A. Start Screen (1080x1920)** * **Widget:** `Title Text` (e.g., "RHYTHM CHEF: BEAT BITES") * **Position (Pivot: Center):** (540, 1600) `(Center X, ~83% Height)` * **Dimensions:** Auto-sized by text, constrained if needed. * **Font Size:** 90px * **Anchor Preset (Unity):** Top-Center * **Widget:** `Subtitle Text` (e.g., "(Core Demo)") * **Position (Pivot: Center):** (540, 1480) `(Center X, below Title)` * **Dimensions:** Auto-sized by text. * **Font Size:** 40px * **Anchor Preset (Unity):** Top-Center * **Widget:** `Start Button` * **Position (Pivot: Center):** (540, 400) `(Center X, ~21% Height)` * **Dimensions:** 450px (Width) x 150px (Height) * **Anchor Preset (Unity):** Bottom-Center * **Widget:** `Start Button Text` (e.g., "[ START ]") * **Position:** Centered within the Start Button. * **Font Size:** 60px --- **B. Gameplay Screen (1080x1920)** * **Widget:** `Score Text Label` (e.g., "SCORE:") * **Position (Pivot: Top-Left):** (40, 1880) `(Padding Left, Padding Top)` * **Dimensions:** Auto-sized by text. * **Font Size:** 50px * **Anchor Preset (Unity):** Top-Left * **Widget:** `Score Value Text` (e.g., "000") * **Position (Pivot: Top-Left):** (200, 1880) `(Right of Label, Same Top)` * **Dimensions:** Auto-sized by text (allow space for growth). * **Font Size:** 50px * **Anchor Preset (Unity):** Top-Left * **Widget:** `Combo Text Label` (e.g., "COMBO:") * **Position (Pivot: Top-Right):** (900, 1880) `(Approx position, adjust based on Value width)` * **Dimensions:** Auto-sized by text. * **Font Size:** 50px * **Anchor Preset (Unity):** Top-Right * **Widget:** `Combo Value Text` (e.g., "0x") * **Position (Pivot: Top-Right):** (1040, 1880) `(Padding Right, Same Top)` * **Dimensions:** Auto-sized by text (allow space for growth). * **Font Size:** 50px * **Anchor Preset (Unity):** Top-Right * **Area:** `Cue Travel Area` (Logical, no visual widget) * **Bounds:** Approx X = Center (e.g., 540), Y from 1800 (Spawn) down to ~200 (Despawn below target). * **Widget:** `Target Zone Visual` (The horizontal bar indicator) * **Position (Pivot: Center):** (540, 400) `(Center X, Defined Y)` * **Dimensions:** 900px (Width) x 80px (Height) * **Anchor Preset (Unity):** Position manually or Bottom-Center with Y offset. * **Note:** The *logical* hit detection center Y might be exactly 400. The timing windows (`perfectWindow`, `okWindow`) define the tolerance around this point in *time*, not necessarily pixels vertically (though they are related via cue speed). * **Actor:** `Cue Object` (Visual representation) * **Position:** Dynamic. Spawns near Y=1800, travels downwards to Y=400 (target). X is typically centered (540). * **Dimensions:** 80px (Width) x 80px (Height) (Example, adjust for visual clarity) * **Widget:** `Feedback Text` (e.g., "Perfect!", "Miss!") * **Position (Pivot: Center):** (540, 600) `(Center X, Above Target Zone)` * **Dimensions:** Auto-sized by text. * **Font Size:** 70px * **Anchor Preset (Unity):** Position manually or relative to Target Zone. (Appears temporarily). * **Actor:** `Hit/Miss Feedback Effect` (Particles/Animation) * **Position:** Instantiated at the Cue's position *when* the hit/miss occurs (approx X=540, Y=400). * **Dimensions:** Dynamic based on the effect design (e.g., expands to 150x150px briefly). --- **C. End Screen (1080x1920)** * **Widget:** `Completion Text` (e.g., "SEQUENCE COMPLETE!") * **Position (Pivot: Center):** (540, 1200) `(Center X, ~62% Height)` * **Dimensions:** Auto-sized by text. * **Font Size:** 70px * **Anchor Preset (Unity):** Center * **Widget:** `Final Score Text` (Optional, e.g., "Final Score: 025") * **Position (Pivot: Center):** (540, 1050) `(Center X, below Completion text)` * **Dimensions:** Auto-sized by text. * **Font Size:** 50px * **Anchor Preset (Unity):** Center * **Widget:** `Restart Button` * **Position (Pivot: Center):** (540, 400) `(Center X, ~21% Height - same as Start Button)` * **Dimensions:** 450px (Width) x 150px (Height) * **Anchor Preset (Unity):** Bottom-Center * **Widget:** `Restart Button Text` (e.g., "[ RESTART ]") * **Position:** Centered within the Restart Button. * **Font Size:** 60px --- Remember to implement proper UI scaling and anchoring in your chosen game engine to handle various device resolutions effectively beyond this 1080x1920 reference.
2
  Make the look and feel 100 times better, employ procedural graphics and emojis as sprites.
3
- Act as graphical effect engineer and add many more cool effect to the game play, make it explode with cool effects, particles etc., background effect ...
 
 
1
  Okay, here is a detailed, implementation-grade plan for building an interactive demonstrator for the core game mechanics of **Rhythm Chef: Beat Bites**. This focuses on creating a minimal viable product (MVP) specifically for user feedback on the core rhythm interaction feel, keeping the codebase limited. **Assumptions:** * **Engine:** Unity (common choice for hypercasual, good for rapid prototyping). * **Language:** C#. * **Target Platform:** Android (easy for distributing APKs for testing). * **Input Focus:** Start with **Tap** only for simplicity. Hold/Swipe can be added later if the Tap feels good. **I. Demonstrator Objectives** 1. Implement the core rhythm interaction: spawning cues, moving cues, detecting timed player input within a target zone. 2. Provide immediate, clear visual and audio feedback for successful hits and misses. 3. Synchronize cue movement and required input timing to a consistent beat (can be a simple metronome track or internal timer). 4. Allow a user to play through a short, predefined sequence of cues. 5. Keep the scope strictly limited to the core mechanic loop for fast iteration and focused feedback. **II. Scope Definition** * **IN SCOPE:** * Single, non-scrolling conveyor belt or lane for cues. * One type of cue requiring a **Tap** input. * One clearly defined target zone. * Precise timing mechanism for cue spawning and hit detection. * Simple visual representation of cues (e.g., colored circles/squares representing ingredients/actions). * Visual feedback (e.g., color change, simple particle effect, text popup like "Perfect!"/"Miss!"). * Basic audio feedback (hit sound, miss sound, beat/metronome sound). * A predefined, short sequence (~15-30 seconds) of Tap cues. * Minimal UI: Start Button, potentially a simple score/combo counter (optional but helpful). * **OUT OF SCOPE:** * Multiple lanes or complex patterns. * Hold or Swipe input types. * Multiple cue types/actions (chop, fry, etc.). * Any meta-game (restaurant, currency, upgrades). * Scoring beyond basic hit/miss feedback (no stars, complex calculations). * Multiple songs or difficulty levels. * Polished art assets (use placeholders). * Advanced UI, menus, settings. * Saving/loading progress. * Performance optimization beyond basic functionality. **III. Key Components & Implementation Details** 1. **`GameManager.cs`** * **Purpose:** Controls the overall state, timing, and sequence playback. * **Properties:** * `float bpm`: Beats per minute for the rhythm. * `float cueSpeed`: Speed at which cues travel towards the target. * `float targetZonePosition`: Y-coordinate (or X if horizontal) of the target zone center. * `float spawnPosition`: Y-coordinate (or X) where cues appear. * `GameObject cuePrefab`: Prefab for the visual cue object. * `Transform cueSpawnPoint`: Transform where cues are instantiated. * `AudioSource metronomeSource`: Optional, for playing a beat sound. * `List<CueData> sequence`: Holds the predefined sequence of cues (timing). * `float songStartTime`: Time when the sequence began (using `AudioSettings.dspTime` or `Time.timeSinceLevelLoad`). * `int currentSequenceIndex`: Tracks the next cue to spawn. * `bool isPlaying`: Game state flag. * **Methods:** * `StartSequence()`: Initializes timing, resets index, sets `isPlaying = true`. Starts metronome if used. * `Update()`: * If `isPlaying`, check `sequence` if it's time to spawn the `currentSequenceIndex` cue based on `bpm` and `songStartTime`. * If spawning, instantiate `cuePrefab` at `cueSpawnPoint`, calculate its `targetTime` (arrival time at target zone), and pass necessary data to the cue's script. Increment `currentSequenceIndex`. * Handles end of sequence. * `StopSequence()`: Sets `isPlaying = false`. 2. **`CueData.cs` (or Struct)** * **Purpose:** Simple data structure to define a single cue in the sequence. * **Properties:** * `float beatTimestamp`: The beat number (e.g., 1, 1.5, 2) within the sequence when this cue should *hit* the target zone. * `CueType type`: Enum (e.g., `Tap`). (Initially only Tap needed). 3. **`CueObject.cs` (attached to `cuePrefab`)** * **Purpose:** Represents a single moving cue. * **Properties:** * `float speed`: Movement speed (set by `GameManager`). * `float targetTime`: The exact game time (`Time.timeSinceLevelLoad` or `dspTime`) this cue should ideally be hit. * `bool isHit`: Flag to prevent multiple hits. * `bool canBeHit`: Flag to indicate if it's currently within the hittable window around the target zone. * **Methods:** * `Initialize(float targetTime, float speed)`: Called by `GameManager` on spawn. * `Update()`: * Move the cue downwards (or towards the target) at `speed * Time.deltaTime`. * Check if the cue has passed the target zone *without* being hit and *after* its hittable window - trigger a Miss condition if so and destroy/disable self. * `OnTriggerEnter/Exit2D(Collider2D other)`: If using physics triggers for the target zone, set `canBeHit = true/false`. * `ProcessHit()`: Called by `InputHandler` when a hit is registered on this cue. Sets `isHit = true`, triggers success feedback, potentially disables the cue visually, and schedules destruction. 4. **`TargetZone.cs` (attached to a GameObject with a Collider2D)** * **Purpose:** Defines the area where input is registered and cues are evaluated. * **Properties:** * `float perfectWindow`: Time window (+/- seconds) for a perfect hit. * `float okWindow`: Time window (+/- seconds) for an acceptable (non-miss) hit. (Keep simple first: just Perfect/Miss). * **Methods:** * `OnTriggerEnter2D/Exit2D(Collider2D other)`: Detects `CueObject` entering/leaving the zone's collider. Could be used by `CueObject` to set its `canBeHit` flag. * **Note:** Hit timing validation logic might live more centrally in `InputHandler` or `GameManager` rather than distributed here. 5. **`InputHandler.cs`** * **Purpose:** Detects player input and checks if it corresponds to a hittable cue. * **Properties:** * `TargetZone targetZone`: Reference to the target zone script/object. * `LayerMask cueLayer`: Physics layer for cues. * **Methods:** * `Update()`: * Check for Tap input (`Input.GetMouseButtonDown(0)` or `Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began`). * If Tap detected: * Determine the current game time (`Time.timeSinceLevelLoad` or `AudioSettings.dspTime`). * Find the "closest" active `CueObject` that is currently `canBeHit` (e.g., using Physics2D overlap checks near the target zone, or iterating through active cues and checking position/timing). * If a potential cue is found: * Calculate `timeDifference = currentTime - cue.targetTime`. * If `Mathf.Abs(timeDifference) <= targetZone.perfectWindow`: * Call `cue.ProcessHit()`. * Trigger "Perfect" feedback via `FeedbackManager`. * Else (if outside window but maybe an OK window exists later): * Trigger "Miss" feedback via `FeedbackManager` (or OK if implementing). * Potentially destroy/disable the cue to prevent late hits. * Else (no cue was hittable): * Optional: Trigger a generic "Miss" feedback for tapping empty space. 6. **`FeedbackManager.cs` (Singleton or easily accessible)** * **Purpose:** Centralized handler for triggering visual/audio feedback. * **Properties:** * `GameObject perfectHitEffectPrefab`: Particle effect/animation for perfect hits. * `GameObject missEffectPrefab`: Effect for misses. * `AudioClip hitSound`: Sound for successful hit. * `AudioClip missSound`: Sound for miss/error. * `AudioSource feedbackAudioSource`: Source to play feedback sounds. * `TextMeshProUGUI feedbackText`: UI Text element to display "Perfect!"/"Miss!". * **Methods:** * `ShowHitFeedback(Vector3 position)`: Instantiate `perfectHitEffectPrefab` at `position`, play `hitSound`, show "Perfect!" text briefly. * `ShowMissFeedback(Vector3 position)`: Instantiate `missEffectPrefab` at `position`, play `missSound`, show "Miss!" text briefly. **IV. Timing Implementation (CRITICAL)** * **Consistency is Key:** Use a consistent time source. * **Option A (Simpler):** `Time.timeSinceLevelLoad`. Easier for basic logic but can drift slightly from audio. Good enough for a demonstrator. * **Option B (More Accurate):** `AudioSettings.dspTime`. Provides highly accurate timing synced with the audio engine. Requires careful handling, especially when scheduling future events based on audio playback. * **Calculations:** * Convert `bpm` to seconds per beat (`60f / bpm`). * Calculate cue `targetTime`: `songStartTime + cue.beatTimestamp * secondsPerBeat`. * Calculate spawn time: `targetTime - travelDuration`, where `travelDuration` is `distance / cueSpeed`. Spawn the cue at this calculated spawn time. **V. UI Implementation (Minimal)** * Canvas with: * `Button` to call `GameManager.StartSequence()`. * `TextMeshProUGUI` (optional) for Score/Combo (incremented in `FeedbackManager` on hit, reset on miss). * `TextMeshProUGUI` for "Perfect!"/"Miss!" feedback text (controlled by `FeedbackManager`). **VI. Placeholder Assets** * **Cue:** Simple white Circle or Square sprite. * **Target Zone:** Semi-transparent rectangle/line across the lane. * **Hit Effect:** Simple particle burst (e.g., Unity's default particle system emitting a few sparks) or a quick scaling/fading circle. * **Miss Effect:** Red flash or different particle effect. * **Audio:** * Metronome: Simple "tick" sound. * Hit Sound: Short, satisfying "click" or "pop". * Miss Sound: Dull "thud" or "buzz". **VII. Build & Test Plan** 1. Implement core components (`GameManager`, `CueObject`, `InputHandler`, `TargetZone`, `FeedbackManager`). 2. Define a simple `sequence` in `GameManager` (e.g., 10 taps on consecutive beats). 3. Use precise timing based on `Time.timeSinceLevelLoad` initially. 4. Integrate basic visual and audio feedback. 5. Test internally: Does it *feel* responsive? Is the timing right? 6. Refine timing windows (`perfectWindow`) based on feel. 7. Build an Android APK. 8. Distribute APK to testers. 9. Gather feedback specifically on: * Timing sensitivity (too strict, too lenient?). * Clarity of visual cues. * Effectiveness of feedback (did they know if they hit/missed?). * Overall satisfaction/fun of the core interaction. **VIII. Success Criteria for Demonstrator** * The demonstrator runs smoothly on a target Android device. * Cues spawn and travel predictably, synchronized with the beat. * User taps near the target zone trigger immediate hit/miss feedback. * Feedback (visual and audio) is clear and correctly corresponds to input timing accuracy. * Testers can understand the core mechanic and provide feedback on its "feel" within 5 minutes of playing. * The codebase is minimal and focused solely on the described scope. Okay, here's an ASCII art representation of the UI and user flow for the **Rhythm Chef: Beat Bites** core mechanics demonstrator. **1. User Flow Diagram** ```ascii +-------------------+ +----------------------+ +----------------------+ | Start Screen | ---+->| Gameplay Loop |---+->| End Screen (Simple)| | (Title, [Start]) | User | (Cues, Target, Input)| User | (Score?, [Restart])| +-------------------+ Taps | | Finishes Sequence +----------------------+ Start +--<-------------------+ Or Fails | (Optional) | | | | Back to Start Screen | +----------------------+ +----------------------+ ``` **2. UI Mockups (ASCII Art)** **A. Start Screen** ```ascii +-----------------------------------------+ | | | // RHYTHM CHEF: BEAT BITES // | | (Core Demo) | | | | | | | | | | +-----------+ | | | [ START ]| | | +-----------+ | | | | | +-----------------------------------------+ User taps [ START ] --> Transitions to Gameplay Screen ``` **B. Gameplay Screen (Mid-Sequence)** * Imagine cues `(*)` moving downwards `v` towards the `TARGET ZONE`. * The player needs to tap when a cue is inside the `TARGET ZONE`. ```ascii +-----------------------------------------+ | SCORE: 005 COMBO: 3x | <--- Optional Score/Combo Display |-----------------------------------------| | | | | | (*) | <--- Incoming Cue 1 | v | | | | | | (*) | <--- Incoming Cue 2 | v | | | | ===================================== | \ | | TARGET ZONE | | <--- The Area to Tap In | ===================================== | / | v | | (*) | <--- Cue that just passed (or was missed) | | | | | | |-----------------------------------------| | FEEDBACK: | <--- Area for text feedback +-----------------------------------------+ ``` **C. Gameplay Screen (Moment of Tap - Perfect Hit)** * Player taps as `(*)` enters the `TARGET ZONE`. * Visual & text feedback appears. ```ascii +-----------------------------------------+ | SCORE: 006 COMBO: 4x | <--- Score/Combo Updated |-----------------------------------------| | | | | | (*) | | v | | | | | | (*) | | v | | | | ===================================== | | | > > > PERFECT! < < < | | <--- Cue hit inside, feedback shown | ===================================== | | | | | (Effect) | <--- Visual effect (e.g., ASCII explosion *`*`) | | | | |-----------------------------------------| | FEEDBACK: Perfect! | <--- Text feedback updated +-----------------------------------------+ ``` **D. Gameplay Screen (Moment of Tap - Miss)** * Player taps too early/late, or misses a cue. ```ascii +-----------------------------------------+ | SCORE: 006 COMBO: 0x | <--- Combo Reset |-----------------------------------------| | | | | | (*) | | v | | | | | | (*) | | v | | | | ===================================== | | | TARGET ZONE | | | ===================================== | | v | | (X) | <--- Missed cue indication / effect | | | | |-----------------------------------------| | FEEDBACK: Miss! | <--- Text feedback updated +-----------------------------------------+ ``` **E. End Screen (Simple Demo End)** * Appears after the predefined sequence finishes. ```ascii +-----------------------------------------+ | | | SEQUENCE COMPLETE! | | | | (Final Score: 025) | <--- Optional final score | | | | | +-------------+ | | | [ RESTART ] | | | +-------------+ | | | | | +-----------------------------------------+ User taps [ RESTART ] --> Transitions back to Gameplay Screen (restarts sequence) (Or could go back to the Start Screen) ``` This ASCII representation outlines the essential visual elements and the flow between them for the core mechanics demonstrator, focusing on clarity for user feedback on the rhythm interaction. Okay, here are specific pixel-based dimensions and positions for the UI elements based on a **reference screen resolution of 1080x1920 pixels (Width x Height - Portrait Orientation)**. **Important Considerations:** * **Reference Only:** These are *fixed pixel values* for the specified reference resolution. In a real implementation (e.g., using Unity Canvas), you would use anchors, pivots, and potentially scaling components (like Canvas Scaler UI Scale Mode) to ensure the UI adapts correctly to different screen sizes and aspect ratios. * **Origin Point:** Assume the (0, 0) coordinate is the **bottom-left** corner of the screen, common in some UI systems, or **top-left** (common in others - I will specify based on typical Unity Canvas usage: **(0,0) is Bottom-Left, (1080, 1920) is Top-Right** unless stated otherwise). Positions usually refer to the object's **pivot point** (often the center, unless specified). * **Font Sizes:** Pixel sizes for fonts are approximate and depend heavily on the specific font file used. * **Actors:** Actors like Cues and Effects have positions that change dynamically or are instantiated at specific world/UI coordinates. --- **A. Start Screen (1080x1920)** * **Widget:** `Title Text` (e.g., "RHYTHM CHEF: BEAT BITES") * **Position (Pivot: Center):** (540, 1600) `(Center X, ~83% Height)` * **Dimensions:** Auto-sized by text, constrained if needed. * **Font Size:** 90px * **Anchor Preset (Unity):** Top-Center * **Widget:** `Subtitle Text` (e.g., "(Core Demo)") * **Position (Pivot: Center):** (540, 1480) `(Center X, below Title)` * **Dimensions:** Auto-sized by text. * **Font Size:** 40px * **Anchor Preset (Unity):** Top-Center * **Widget:** `Start Button` * **Position (Pivot: Center):** (540, 400) `(Center X, ~21% Height)` * **Dimensions:** 450px (Width) x 150px (Height) * **Anchor Preset (Unity):** Bottom-Center * **Widget:** `Start Button Text` (e.g., "[ START ]") * **Position:** Centered within the Start Button. * **Font Size:** 60px --- **B. Gameplay Screen (1080x1920)** * **Widget:** `Score Text Label` (e.g., "SCORE:") * **Position (Pivot: Top-Left):** (40, 1880) `(Padding Left, Padding Top)` * **Dimensions:** Auto-sized by text. * **Font Size:** 50px * **Anchor Preset (Unity):** Top-Left * **Widget:** `Score Value Text` (e.g., "000") * **Position (Pivot: Top-Left):** (200, 1880) `(Right of Label, Same Top)` * **Dimensions:** Auto-sized by text (allow space for growth). * **Font Size:** 50px * **Anchor Preset (Unity):** Top-Left * **Widget:** `Combo Text Label` (e.g., "COMBO:") * **Position (Pivot: Top-Right):** (900, 1880) `(Approx position, adjust based on Value width)` * **Dimensions:** Auto-sized by text. * **Font Size:** 50px * **Anchor Preset (Unity):** Top-Right * **Widget:** `Combo Value Text` (e.g., "0x") * **Position (Pivot: Top-Right):** (1040, 1880) `(Padding Right, Same Top)` * **Dimensions:** Auto-sized by text (allow space for growth). * **Font Size:** 50px * **Anchor Preset (Unity):** Top-Right * **Area:** `Cue Travel Area` (Logical, no visual widget) * **Bounds:** Approx X = Center (e.g., 540), Y from 1800 (Spawn) down to ~200 (Despawn below target). * **Widget:** `Target Zone Visual` (The horizontal bar indicator) * **Position (Pivot: Center):** (540, 400) `(Center X, Defined Y)` * **Dimensions:** 900px (Width) x 80px (Height) * **Anchor Preset (Unity):** Position manually or Bottom-Center with Y offset. * **Note:** The *logical* hit detection center Y might be exactly 400. The timing windows (`perfectWindow`, `okWindow`) define the tolerance around this point in *time*, not necessarily pixels vertically (though they are related via cue speed). * **Actor:** `Cue Object` (Visual representation) * **Position:** Dynamic. Spawns near Y=1800, travels downwards to Y=400 (target). X is typically centered (540). * **Dimensions:** 80px (Width) x 80px (Height) (Example, adjust for visual clarity) * **Widget:** `Feedback Text` (e.g., "Perfect!", "Miss!") * **Position (Pivot: Center):** (540, 600) `(Center X, Above Target Zone)` * **Dimensions:** Auto-sized by text. * **Font Size:** 70px * **Anchor Preset (Unity):** Position manually or relative to Target Zone. (Appears temporarily). * **Actor:** `Hit/Miss Feedback Effect` (Particles/Animation) * **Position:** Instantiated at the Cue's position *when* the hit/miss occurs (approx X=540, Y=400). * **Dimensions:** Dynamic based on the effect design (e.g., expands to 150x150px briefly). --- **C. End Screen (1080x1920)** * **Widget:** `Completion Text` (e.g., "SEQUENCE COMPLETE!") * **Position (Pivot: Center):** (540, 1200) `(Center X, ~62% Height)` * **Dimensions:** Auto-sized by text. * **Font Size:** 70px * **Anchor Preset (Unity):** Center * **Widget:** `Final Score Text` (Optional, e.g., "Final Score: 025") * **Position (Pivot: Center):** (540, 1050) `(Center X, below Completion text)` * **Dimensions:** Auto-sized by text. * **Font Size:** 50px * **Anchor Preset (Unity):** Center * **Widget:** `Restart Button` * **Position (Pivot: Center):** (540, 400) `(Center X, ~21% Height - same as Start Button)` * **Dimensions:** 450px (Width) x 150px (Height) * **Anchor Preset (Unity):** Bottom-Center * **Widget:** `Restart Button Text` (e.g., "[ RESTART ]") * **Position:** Centered within the Restart Button. * **Font Size:** 60px --- Remember to implement proper UI scaling and anchoring in your chosen game engine to handle various device resolutions effectively beyond this 1080x1920 reference.
2
  Make the look and feel 100 times better, employ procedural graphics and emojis as sprites.
3
+ Act as graphical effect engineer and add many more cool effect to the game play, make it explode with cool effects, particles etc., background effect ...
4
+ Add directly into the game handles, toggles etc. allowing to fine-tune the gameplay such as the speed, number of items, toleralnce, all key aspect allowing the user to find sweet spot for the game play, and store the values along with a tag such as level1 into the local store for re-use across gameplays