Add README, assets, UI enhancements, and audio support
- Introduce ReadMe.md describing the Ultimatch Memory Match project. - Add background image and sound files (background.mp3, flip.mp3, match.mp3). - Update index.html to include a full‑screen background div and rename the game title. - Refactor board dimensions to a 7 × 4 grid (BOARD_WIDTH = 7, BOARD_HEIGHT = 4) and expand SVG icon set to 14 cards. - Pre‑load and play background, flip, and match audio cues; start background music on first move and stop on win. - Adjust win‑condition logic to use new board size. - Enhance styling: fixed background image, dark translucent header overlay, glowing title and stats, and refined card layout.
This commit is contained in:
parent
36828b276e
commit
5c184a6ab1
|
|
@ -0,0 +1,28 @@
|
|||
# Ultimatch Memory Match – Project Overview
|
||||
|
||||
## Purpose
|
||||
This project implements a simple **memory‑match (concentration) game** that uses SVG graphics as cards.
|
||||
The HTML page creates the game layout, the CSS styles the visual appearance (including a dark translucent header overlay and glowing text), and the JavaScript provides the core game logic—starting with a **Fisher‑Yates shuffle** to randomize the cards.
|
||||
|
||||
## File Summary
|
||||
|
||||
| File | Role |
|
||||
|------|------|
|
||||
| **`index.html`** | Sets up the page structure: a background image, a header with the game title and live stats (moves & timer), and a `<section id="board">` where the SVG cards will be rendered. It also loads `style.css` and `script.js`. |
|
||||
| **`style.css`** | Provides a clean reset, centers the layout, adds a full‑screen background image, and styles the header with a dark translucent overlay, large glowing title, and highlighted stats. |
|
||||
| **`script.js`** | Contains the JavaScript foundation for the game. The only function shown is `shuffle(array)`, which implements an **in‑place Fisher‑Yates shuffle** to randomize the order of the card data before they are placed on the board. Additional game logic (card creation, click handling, move counting, timer, win detection, etc.) would be built on top of this utility. |
|
||||
|
||||
## How It Works
|
||||
1. **Page Load** – `index.html` loads the stylesheet and script.
|
||||
2. **Styling** – `style.css` ensures the game looks polished, with a full‑screen background and a readable, glowing header.
|
||||
3. **Game Setup** – In `script.js`, the card data array is shuffled using `shuffle()`. The shuffled array is then used to generate SVG card elements inside the `#board` section (implementation not shown).
|
||||
4. **Gameplay** – Players click cards to reveal SVGs, trying to find matching pairs. Moves and elapsed time are displayed in the header’s stats area.
|
||||
|
||||
## Extending the Project
|
||||
- Add SVG assets and a function to render them as clickable cards.
|
||||
- Implement click handling, match checking, move counting, and a timer.
|
||||
- Provide a reset/restart button and optional difficulty levels.
|
||||
|
||||
---
|
||||
|
||||
*This README snippet gives a concise overview of the current codebase and its intended use for a memory‑match game.*
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 3.3 MiB |
|
|
@ -6,8 +6,9 @@
|
|||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="background"></div>
|
||||
<header>
|
||||
<h1>SVG Memory Match</h1>
|
||||
<h1>Ultimatch Memory Match</h1>
|
||||
<div class="stats">
|
||||
<span id="moves">Moves: 0</span>
|
||||
<span id="timer">Time: 0s</span>
|
||||
|
|
@ -20,4 +21,4 @@
|
|||
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
36
script.js
36
script.js
|
|
@ -1,17 +1,24 @@
|
|||
// Configuration
|
||||
const BOARD_SIZE = 4; // 4x4 grid → 16 cards (8 pairs)
|
||||
const BOARD_HEIGHT = 4;
|
||||
const BOARD_WIDTH = 7;
|
||||
const FLIP_DELAY = 800; // ms before non‑matching cards flip back
|
||||
|
||||
// SVG icons – eight distinct graphics (you can replace these with your own)
|
||||
// SVG icons – fourteen distinct graphics (you can replace these with your own)
|
||||
const SVG_ICONS = [
|
||||
`<svg viewBox="0 0 64 64" fill="#ff9800"><polygon points="32,4 39,24 60,24 42,38 48,58 32,46 16,58 22,38 4,24 25,24"/></svg>`,
|
||||
`<svg viewBox="0 0 64 64"><line x1="8" y1="8" x2="56" y2="56" stroke="#ff5722" stroke-width="8"/></svg>`,
|
||||
`<svg viewBox="0 0 64 64" fill="#795548"><polygon points="32,4 39,24 60,24 42,38 48,58 32,46 16,58 22,38 4,24 25,24"/></svg>`,
|
||||
`<svg viewBox="0 0 64 64"><line x1="8" y1="56" x2="56" y2="8" stroke="#e91e63" stroke-width="8"/></svg>`,
|
||||
`<svg viewBox="0 0 64 64" fill="#4caf50"><circle cx="32" cy="32" r="28"/></svg>`,
|
||||
`<svg viewBox="0 0 64 64" fill="#2196F3"><rect x="12" y="12" width="40" height="40"/></svg>`,
|
||||
`<svg viewBox="0 0 64 64" fill="#e91e63"><path d="M32 4 L39 24 H60 L42 38 L48 58 L32 46 L16 58 L22 38 L4 24 H25z"/></svg>`,
|
||||
`<svg viewBox="0 0 64 64" fill="#9c27b0"><ellipse cx="32" cy="32" rx="28" ry="14"/></svg>`,
|
||||
`<svg viewBox="0 0 64 64" fill="#ff5722"><line x1="8" y1="8" x2="56" y2="56" stroke-width="8"/></svg>`,
|
||||
`<svg viewBox="0 0 64 64" fill="#03a9f4"><polygon points="32,8 40,24 58,24 44,36 50,54 32,44 14,54 20,36 6,24 24,24"/></svg>`,
|
||||
`<svg viewBox="0 0 64 64" fill="#8bc34a"><polygon points="32,4 39,24 60,24 42,38 48,58 32,46 16,58 22,38 4,24 25,24"/></svg>`
|
||||
`<svg viewBox="0 0 64 64" fill="#8bc34a"><polygon points="32,4 39,24 60,24 42,38 48,58 32,46 16,58 22,38 4,24 25,24"/></svg>`,
|
||||
`<svg viewBox="0 0 64 64" fill="#607d8b"><polygon points="16,32 48,32 32,48"/></svg>`,
|
||||
`<svg viewBox="0 0 64 64" fill="#ff9800"><circle cx="32" cy="32" r="12"/></svg>`,
|
||||
`<svg viewBox="0 0 64 64" fill="#4caf50"><rect x="20" y="20" width="24" height="24"/></svg>`,
|
||||
`<svg viewBox="0 0 64 64" fill="#2196F3"><path d="M16,32 Q32,4 48,32 T80,32"/></svg>`
|
||||
];
|
||||
|
||||
// Game state variables
|
||||
|
|
@ -87,6 +94,17 @@ function createCard(svgMarkup, id) {
|
|||
return card;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Pre‑load background music */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
const bgMusic = new Audio('./background.mp3');
|
||||
bgMusic.preload = 'auto'; // ensure the file is loaded early
|
||||
bgMusic.loop = true; // optional – keep playing while the game runs
|
||||
const flip = new Audio('./flip.mp3');
|
||||
flip.preload = 'auto';
|
||||
const match = new Audio('./match.mp3');
|
||||
match.preload = 'auto';
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Click handling */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
|
@ -94,9 +112,13 @@ function onCardClick(event) {
|
|||
if (lockBoard) return;
|
||||
const card = event.currentTarget;
|
||||
if (card.classList.contains('flipped')) return; // ignore already revealed cards
|
||||
flip.play();
|
||||
|
||||
// Start timer on the very first flip
|
||||
if (moves === 0 && seconds === 0) startTimer();
|
||||
if (moves === 0 && seconds === 0) {
|
||||
startTimer();
|
||||
bgMusic.play(); // ← play pre‑loaded audio
|
||||
}
|
||||
|
||||
card.classList.add('flipped');
|
||||
|
||||
|
|
@ -115,12 +137,14 @@ function onCardClick(event) {
|
|||
// Keep both cards flipped
|
||||
matched += 2;
|
||||
firstCard = null;
|
||||
match.play();
|
||||
// Check for win condition
|
||||
if (matched === BOARD_SIZE * BOARD_SIZE) {
|
||||
if (matched === BOARD_HEIGHT * BOARD_WIDTH) {
|
||||
stopTimer();
|
||||
setTimeout(() => {
|
||||
alert(`Congratulations! You completed the game in ${moves} moves and ${seconds} seconds.`);
|
||||
}, 300);
|
||||
bgMusic.stop();
|
||||
}
|
||||
} else {
|
||||
// Not a match – flip back after a short delay
|
||||
|
|
|
|||
59
style.css
59
style.css
|
|
@ -1,10 +1,59 @@
|
|||
/* Basic reset */
|
||||
* { box-sizing: border-box; margin:0; padding:0; }
|
||||
body { font-family: Arial, sans-serif; background:#fafafa; display:flex; flex-direction:column; align-items:center; }
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background:#fafafa;
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
align-items:center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.background {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
background-image: url('./background.png');
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
header { text-align:center; margin:20px; }
|
||||
.stats { margin-top:8px; font-size:0.9rem; }
|
||||
header {
|
||||
text-align:center;
|
||||
margin:20px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
/* NEW: add a dark translucent overlay behind the text */
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
padding: 15px 30px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
/* NEW: style the main heading */
|
||||
header h1 {
|
||||
font-size: 2.5rem;
|
||||
color: #fff;
|
||||
text-shadow:
|
||||
0 0 8px rgba(255,255,255,0.8), /* soft outer glow */
|
||||
0 0 12px rgba(255,255,255,0.6),
|
||||
2px 2px 4px rgba(0,0,0,0.7); /* subtle inner shadow */
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* NEW: give the stats a slight glow as well */
|
||||
header .stats span {
|
||||
color: #fff;
|
||||
text-shadow: 0 0 4px rgba(255,255,255,0.7);
|
||||
}
|
||||
.stats {
|
||||
margin-top:8px;
|
||||
font-size:0.9rem;
|
||||
}
|
||||
|
||||
/* Board */
|
||||
.board {
|
||||
|
|
@ -34,7 +83,9 @@ header { text-align:center; margin:20px; }
|
|||
inset: 0;
|
||||
backface-visibility: hidden;
|
||||
border-radius: 8px;
|
||||
display:flex; align-items:center; justify-content:center;
|
||||
display:flex;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
}
|
||||
.card-back {
|
||||
background:#2196F3;
|
||||
|
|
|
|||
Loading…
Reference in New Issue