feat: it speaks
This commit is contained in:
Binary file not shown.
Binary file not shown.
+32
-6
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import './page.css';
|
import './page.css';
|
||||||
|
|
||||||
import { Canvas } from "@react-three/fiber";
|
import { Canvas, useThree } from "@react-three/fiber";
|
||||||
import { BrightnessContrast, EffectComposer, HueSaturation, Noise, Pixelation, Vignette } from "@react-three/postprocessing";
|
import { BrightnessContrast, EffectComposer, HueSaturation, Noise, Pixelation, Vignette } from "@react-three/postprocessing";
|
||||||
import { Suspense, useEffect, useState } from "react";
|
import { Suspense, useEffect, useState } from "react";
|
||||||
|
|
||||||
@@ -14,34 +14,53 @@ import TheCreature from './scene-components/creature';
|
|||||||
import Player from './scene-components/player';
|
import Player from './scene-components/player';
|
||||||
import Hallway from './scene-components/hallway';
|
import Hallway from './scene-components/hallway';
|
||||||
|
|
||||||
|
import { AudioListener } from 'three';
|
||||||
|
|
||||||
function PostProcessing() {
|
function PostProcessing() {
|
||||||
const [getCaught, setCaught] = useState(fearState.wasCaught);
|
const [wasCaught, setWasCaught] = useState(fearState.wasCaught);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unsubscribe = fearState.subscribe(() => {
|
const unsubscribe = fearState.subscribe(() => {
|
||||||
setCaught(fearState.wasCaught);
|
setWasCaught(fearState.wasCaught);
|
||||||
});
|
});
|
||||||
return () => unsubscribe();
|
return () => unsubscribe();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (<EffectComposer>
|
return (<EffectComposer>
|
||||||
<Pixelation granularity={getCaught ? 18 : 12} />
|
<Pixelation granularity={wasCaught ? 18 : 12} />
|
||||||
<Vignette />
|
<Vignette />
|
||||||
<Noise opacity={getCaught ? 0.01 : 0.005} />
|
<Noise opacity={wasCaught ? 0.01 : 0.005} />
|
||||||
<BrightnessContrast
|
<BrightnessContrast
|
||||||
brightness={-0.01}
|
brightness={-0.01}
|
||||||
contrast={0.05}
|
contrast={0.05}
|
||||||
/>
|
/>
|
||||||
<HueSaturation saturation={getCaught ? 1 : 0} />
|
<HueSaturation saturation={wasCaught ? 1 : 0} />
|
||||||
</EffectComposer>)
|
</EffectComposer>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ListenerCreator() {
|
||||||
|
const { camera } = useThree();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const listener = new AudioListener();
|
||||||
|
camera.add(listener);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
camera.remove(listener);
|
||||||
|
};
|
||||||
|
}, [camera]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
export default function Fear() {
|
export default function Fear() {
|
||||||
const [isRustActive, setIsRustActive] = useState(fearState.isRustActive);
|
const [isRustActive, setIsRustActive] = useState(fearState.isRustActive);
|
||||||
|
const [wasCaught, setWasCaught] = useState(fearState.isRustActive);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unsubscribe = fearState.subscribe(() => {
|
const unsubscribe = fearState.subscribe(() => {
|
||||||
setIsRustActive(fearState.isRustActive);
|
setIsRustActive(fearState.isRustActive);
|
||||||
|
setWasCaught(fearState.wasCaught)
|
||||||
});
|
});
|
||||||
return () => unsubscribe();
|
return () => unsubscribe();
|
||||||
}, []);
|
}, []);
|
||||||
@@ -53,6 +72,8 @@ export default function Fear() {
|
|||||||
className='canvas'
|
className='canvas'
|
||||||
camera={{ position: [0, 3, -5], fov: 65, far: 100 }}
|
camera={{ position: [0, 3, -5], fov: 65, far: 100 }}
|
||||||
>
|
>
|
||||||
|
<ListenerCreator/>
|
||||||
|
|
||||||
<color attach="background" args={['#050505']} />
|
<color attach="background" args={['#050505']} />
|
||||||
|
|
||||||
<fogExp2 attach='fog' args={[0x050505, 0.035]} />
|
<fogExp2 attach='fog' args={[0x050505, 0.035]} />
|
||||||
@@ -67,6 +88,11 @@ export default function Fear() {
|
|||||||
url='fear/snd/ambience.mp3'
|
url='fear/snd/ambience.mp3'
|
||||||
volume={isRustActive ? 0 : 1}
|
volume={isRustActive ? 0 : 1}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{wasCaught ? <AmbientSound
|
||||||
|
url='fear/snd/glitch.mp3'
|
||||||
|
volume={1}
|
||||||
|
/> : null}
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</Canvas>
|
</Canvas>
|
||||||
</>)
|
</>)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useTexture } from "@react-three/drei";
|
import { useTexture, PositionalAudio } from "@react-three/drei";
|
||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
@@ -8,6 +8,7 @@ import { fearState } from "../state";
|
|||||||
export default function TheCreature() {
|
export default function TheCreature() {
|
||||||
const texture = useTexture('fear/img/creature.png');
|
const texture = useTexture('fear/img/creature.png');
|
||||||
const meshRef = useRef<THREE.Mesh>(null);
|
const meshRef = useRef<THREE.Mesh>(null);
|
||||||
|
const audioRef = useRef<THREE.PositionalAudio>(null);
|
||||||
const { camera } = useThree();
|
const { camera } = useThree();
|
||||||
|
|
||||||
const [hasTriggered, setHasTriggered] = useState(false);
|
const [hasTriggered, setHasTriggered] = useState(false);
|
||||||
@@ -17,6 +18,8 @@ export default function TheCreature() {
|
|||||||
const globalDistance = useRef<number>(32);
|
const globalDistance = useRef<number>(32);
|
||||||
const [currentLoop, setCurrentLoop] = useState(fearState.loopCount);
|
const [currentLoop, setCurrentLoop] = useState(fearState.loopCount);
|
||||||
|
|
||||||
|
const audioPlaying = useRef<boolean>(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unsubscribe = fearState.subscribe(() => {
|
const unsubscribe = fearState.subscribe(() => {
|
||||||
setCurrentLoop(fearState.loopCount);
|
setCurrentLoop(fearState.loopCount);
|
||||||
@@ -25,6 +28,11 @@ export default function TheCreature() {
|
|||||||
setIsSpawned(false);
|
setIsSpawned(false);
|
||||||
setHasTriggered(false);
|
setHasTriggered(false);
|
||||||
globalDistance.current = 32;
|
globalDistance.current = 32;
|
||||||
|
audioPlaying.current = false;
|
||||||
|
|
||||||
|
if (audioRef.current && audioRef.current.isPlaying) {
|
||||||
|
audioRef.current.stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return () => unsubscribe();
|
return () => unsubscribe();
|
||||||
@@ -41,12 +49,22 @@ export default function TheCreature() {
|
|||||||
globalDistance.current = 32;
|
globalDistance.current = 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasTriggered)
|
if (!hasTriggered) {
|
||||||
if (globalDistance.current < 40) setHasTriggered(true);
|
if (globalDistance.current < 40) {
|
||||||
|
setHasTriggered(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (hasTriggered) {
|
if (hasTriggered) {
|
||||||
globalDistance.current -= speed * delta;
|
globalDistance.current -= speed * delta;
|
||||||
|
|
||||||
|
if (audioRef.current && !audioPlaying.current) {
|
||||||
|
audioPlaying.current = true;
|
||||||
|
if (audioRef.current.context.state === 'suspended')
|
||||||
|
audioRef.current.context.resume();
|
||||||
|
audioRef.current.play();
|
||||||
|
}
|
||||||
|
|
||||||
const shakeIntensity = Math.max(0, 1 - (globalDistance.current / 32)) * 0.22;
|
const shakeIntensity = Math.max(0, 1 - (globalDistance.current / 32)) * 0.22;
|
||||||
camera.position.x += (Math.random() - 0.5) * shakeIntensity;
|
camera.position.x += (Math.random() - 0.5) * shakeIntensity;
|
||||||
camera.position.y += (Math.random() - 0.5) * shakeIntensity;
|
camera.position.y += (Math.random() - 0.5) * shakeIntensity;
|
||||||
@@ -80,6 +98,16 @@ export default function TheCreature() {
|
|||||||
depthWrite={false}
|
depthWrite={false}
|
||||||
side={THREE.DoubleSide}
|
side={THREE.DoubleSide}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{currentLoop >= 4 && (
|
||||||
|
<PositionalAudio
|
||||||
|
url="fear/snd/riser.mp3"
|
||||||
|
ref={audioRef}
|
||||||
|
distance={25}
|
||||||
|
loop={false}
|
||||||
|
autoplay={false}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</mesh>
|
</mesh>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { useEffect, useRef } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
import * as THREE from "three";
|
|
||||||
import { FEAR_SETTINGS, fearState } from "../state";
|
import { FEAR_SETTINGS, fearState } from "../state";
|
||||||
import { PointerLockControls } from "@react-three/drei";
|
import { PointerLockControls } from "@react-three/drei";
|
||||||
|
|
||||||
|
import * as THREE from "three";
|
||||||
|
|
||||||
const forward = new THREE.Vector3();
|
const forward = new THREE.Vector3();
|
||||||
const side = new THREE.Vector3();
|
const side = new THREE.Vector3();
|
||||||
const direction = new THREE.Vector3();
|
const direction = new THREE.Vector3();
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ export const FEAR_SETTINGS = {
|
|||||||
HALLWAY_WIDTH: 6,
|
HALLWAY_WIDTH: 6,
|
||||||
HALLWAY_HEIGHT: 5,
|
HALLWAY_HEIGHT: 5,
|
||||||
PLAYER_HEIGHT: 3,
|
PLAYER_HEIGHT: 3,
|
||||||
PLAYER_SPEED: 6,
|
PLAYER_SPEED: 4,
|
||||||
WALL_BUFFER: 0.6,
|
WALL_BUFFER: 0.6,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user