Skip to content

Commit 3af5eca

Browse files
Merge pull request #93 from Treevyy/music/things
added background music and dan speech
2 parents 3c8e2f5 + 832605d commit 3af5eca

File tree

10 files changed

+327
-207
lines changed

10 files changed

+327
-207
lines changed

client/public/audio/DecafDan.wav

185 KB
Binary file not shown.

client/src/App.tsx

Lines changed: 72 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1-
import React from 'react';
2-
import { BrowserRouter as Router, Routes, Route, useNavigate } from 'react-router-dom';
1+
import React, { useEffect, useRef } from 'react';
2+
import {
3+
BrowserRouter as Router,
4+
Routes,
5+
Route,
6+
useNavigate,
7+
useLocation,
8+
} from 'react-router-dom';
39
import IntroPage from './components/screens/IntroPage';
410
import { Login } from './components/screens/Login';
511
import GameMap from './components/screens/GameMap';
@@ -9,14 +15,41 @@ import Signup from './components/screens/Signup';
915
import Questions from './components/screens/Questions';
1016
import './styles/codezilla.css';
1117

18+
// 🔊 Persistent background music that plays on interaction
19+
const PersistentBackgroundMusic: React.FC = () => {
20+
const audioRef = useRef<HTMLAudioElement | null>(null);
21+
22+
useEffect(() => {
23+
if (!audioRef.current) {
24+
const audio = new Audio('/black.sabbath.mp3');
25+
audio.loop = true;
26+
audio.volume = 0.03;
27+
audioRef.current = audio;
28+
29+
const play = () => {
30+
audio.play().catch((err) =>
31+
console.warn('Autoplay blocked or error playing:', err)
32+
);
33+
};
34+
35+
document.addEventListener('click', play, { once: true });
36+
}
37+
38+
return () => {
39+
audioRef.current?.pause();
40+
};
41+
}, []);
42+
43+
return null;
44+
};
1245

1346
const LogoutButton: React.FC = () => {
1447
const navigate = useNavigate();
1548

1649
const handleLogout = () => {
17-
localStorage.clear();
18-
navigate('/login');
19-
};
50+
localStorage.clear();
51+
navigate('/login');
52+
};
2053

2154
return (
2255
<button className="logout-button" onClick={handleLogout}>
@@ -25,40 +58,45 @@ const LogoutButton: React.FC = () => {
2558
);
2659
};
2760

61+
const AppContent: React.FC = () => {
62+
const location = useLocation();
63+
const isGameActive =
64+
location.pathname.startsWith('/map') ||
65+
location.pathname.startsWith('/question');
66+
67+
return (
68+
<div className="app-wrapper">
69+
{/* Only load persistent music during gameplay */}
70+
{isGameActive && <PersistentBackgroundMusic />}
71+
72+
<img
73+
src="/codezilla_logo.png"
74+
alt="Codezilla Logo"
75+
className="logo-background"
76+
/>
77+
78+
<LogoutButton />
79+
80+
<Routes>
81+
<Route path="/" element={<IntroPage />} />
82+
<Route path="/login" element={<Login />} />
83+
<Route path="/map" element={<GameMap />} />
84+
<Route path="/gameover" element={<GameOver />} />
85+
<Route path="/signup" element={<Signup />} />
86+
<Route path="/victory" element={<Victory />} />
87+
<Route path="/question/:id" element={<Questions />} />
88+
</Routes>
89+
</div>
90+
);
91+
};
92+
2893
const App: React.FC = () => {
2994
return (
3095
<Router>
31-
<div className="app-wrapper">
32-
{/* Background Image
33-
<img
34-
src="/background/codezilla_bkgd.png"
35-
alt="Dark rainy cityscape"
36-
className="background-image"
37-
/> */}
38-
39-
40-
<img
41-
src="/codezilla_logo.png"
42-
alt="Codezilla Logo"
43-
className="logo-background"
44-
/>
45-
46-
{/* Logout Button */}
47-
<LogoutButton />
48-
49-
{/* Routes */}
50-
<Routes>
51-
<Route path="/" element={<IntroPage />} />
52-
<Route path="/login" element={<Login />} />
53-
<Route path="/map" element={<GameMap />} />
54-
<Route path="/gameover" element={<GameOver />} />
55-
<Route path="/signup" element={<Signup />} />
56-
<Route path="/victory" element={<Victory />} />
57-
<Route path="/question/:id" element={<Questions />} />
58-
</Routes>
59-
</div>
96+
<AppContent />
6097
</Router>
6198
);
6299
};
63100

64101
export default App;
102+
Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,31 @@
1-
// import { useEffect } from 'react';
1+
import { useEffect, useRef } from 'react';
22

3-
// const BackgroundMusic = () => {
4-
// useEffect(() => {
5-
// const audio = new Audio('/80s-loop-5.wav'); // or '/background-music.mp3'
6-
// audio.loop = true;
7-
// audio.volume = 0.5;
3+
interface Props {
4+
src: string;
5+
volume?: number;
6+
}
87

9-
// // Try autoplay inside a user interaction-friendly trigger
10-
// const playAudio = () => {
11-
// audio.play().catch((err) => {
12-
// console.warn('Autoplay blocked by browser:', err);
13-
// });
14-
// };
8+
const BackgroundMusic: React.FC<Props> = ({ src, volume = 0.03 }) => {
9+
const audioRef = useRef<HTMLAudioElement | null>(null);
1510

16-
// // Listen for first click
17-
// document.body.addEventListener('click', playAudio, { once: true });
11+
useEffect(() => {
12+
if (!audioRef.current) {
13+
audioRef.current = new Audio(src);
14+
audioRef.current.loop = true;
15+
audioRef.current.volume = volume;
16+
}
1817

19-
// return () => {
20-
// audio.pause();
21-
// };
22-
// }, []);
18+
const audio = audioRef.current;
19+
audio.play().catch((err) => {
20+
console.warn('⚠️ Autoplay blocked:', err);
21+
});
2322

24-
// return null;
25-
// };
23+
return () => {
24+
// Do not pause or destroy the audio here to preserve continuity
25+
};
26+
}, [src, volume]);
2627

27-
// export default BackgroundMusic;
28+
return null;
29+
};
30+
31+
export default BackgroundMusic;

client/src/components/screens/GameMap.tsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import React, { useState, useEffect } from 'react';
22
import { useNavigate } from 'react-router-dom';
33
import Minion from './Minions';
4-
import { useBodyClass } from '../../Utils/useBodyClass';
4+
import { useBodyClass } from '../../utils/useBodyClass';
55
import { preloadSounds } from '../../utils/preloadSounds';
6+
import BackgroundMusic from '../BackgroundMusic';
67
import "../../styles/codezilla.css";
78
import drDanImg from '../../../avatars/drdan2.png';
89
import flameImg from '../../assets/flame.png';
@@ -32,6 +33,12 @@ const GameMap: React.FC = () => {
3233
]);
3334
}, []);
3435

36+
const handleDanHover = () => {
37+
const audio = new Audio('/audio/DecafDan.wav');
38+
audio.volume = 0.3;
39+
audio.play().catch(err => console.warn('Autoplay blocked:', err));
40+
};
41+
3542
const minions = [
3643
{
3744
id: '1',
@@ -115,6 +122,8 @@ const GameMap: React.FC = () => {
115122

116123
return (
117124
<div className="game-map">
125+
<BackgroundMusic src="/black.sabbath.mp3" volume={0.03} />
126+
118127
<svg className="map-lines">
119128
{nodes.map((node, index) => {
120129
const nextNode = nodes[index + 1];
@@ -154,7 +163,12 @@ const GameMap: React.FC = () => {
154163

155164
<div className="dr-dan-wrapper">
156165
<div className="glow-circle"></div>
157-
<img src={drDanImg} alt="Dr. Dan" className="dr-dan-image" />
166+
<img
167+
src={drDanImg}
168+
alt="Dr. Dan"
169+
className="dr-dan-image hover:cursor-pointer"
170+
onMouseEnter={handleDanHover}
171+
/>
158172
</div>
159173

160174
{selectedAvatar && (

client/src/components/screens/IntroPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { useState, useEffect, useRef } from 'react';
22
import { useNavigate } from 'react-router-dom';
3-
import { useBodyClass } from '../../Utils/useBodyClass';
3+
import { useBodyClass } from '../../utils/useBodyClass';
44
import "../../styles/codezilla.css";
55

66
const IntroPage: React.FC = () => {

0 commit comments

Comments
 (0)