Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/C2DH/zoomland
Browse files Browse the repository at this point in the history
  • Loading branch information
donsiamese committed Aug 9, 2023
2 parents bcabe22 + 49efc41 commit b82384d
Show file tree
Hide file tree
Showing 14 changed files with 162 additions and 16 deletions.
2 changes: 2 additions & 0 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { isMobile } from 'react-device-detect'
import SideMenu from './components/SideMenu'
import ZoomlandIntro from './components/ZoomlandIntro'
import SkipIntro from './components/SkipIntro'
import GameControls from './components/GameControls'

const Map = React.lazy(() => import('./pages/Map'))
const Chapters = React.lazy(() => import('./pages/Chapters'))
Expand Down Expand Up @@ -40,6 +41,7 @@ function App() {

<Vignette></Vignette>
<SkipIntro />
<GameControls />
<World isMobile={isMobile} width={window.innerWidth} height={window.innerHeight} />
<AppRoutes>
<Route path="/about" element={<About />} />
Expand Down
17 changes: 17 additions & 0 deletions src/components/GameControls.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.GameControls {
position: fixed;
z-index: var(--z-index-game-controls);
background: var(--dark-blue-alpha);
border-radius: var(--small-border-radius);

width: 50%;
top: 150px;
left: 50%;
margin-left: -25%;
color: var(--pale-yellow);
}

.GameControls button {
border: 0 none;
color: var(--pale-yellow);
}
36 changes: 36 additions & 0 deletions src/components/GameControls.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { useSpring, a } from '@react-spring/web'
import { MenuClosed, useMenuStore } from '../store'
import './GameControls.css'
import { useEffect } from 'react'

const GameControls = () => {
const [gameControlsStatus, setGameControlsStatus] = useMenuStore((state) => [
state.gameControlsStatus,
state.setGameControlsStatus,
])

const [style, api] = useSpring(() => ({
opacity: 0,
}))

const hide = () => {
setGameControlsStatus(MenuClosed)
}

useEffect(() => {
api.start({
opacity: gameControlsStatus === MenuClosed ? 0 : 1,
})
}, [gameControlsStatus])

return (
<a.div style={style} className="GameControls p-5">
GameControls
<button className="btn btn-link btn-lg" onClick={hide}>
Got it!
</button>
</a.div>
)
}

export default GameControls
7 changes: 6 additions & 1 deletion src/components/IcescreamTruck.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { useGLTF } from '@react-three/drei'
import { RigidBody } from '@react-three/rapier'
import { useEffect } from 'react'
import { useQueueStore } from '../store/preload'

const IcescreamTruck = (props, transparent = true, geometryPosition = [0, 0, 0]) => {
const { nodes, materials } = useGLTF('../assets/models/IcescreamTruck.glb')

const addToLoaded = useQueueStore((state) => state.addToLoaded)
useEffect(() => {
addToLoaded('IcescreamTruck')
}, [])
return (
<RigidBody colliders={'hull'} type={'fixed'}>
<mesh position={geometryPosition}>
Expand Down
9 changes: 9 additions & 0 deletions src/components/Landscape.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,18 @@ Command: npx [email protected] public/models/Landscape.gltf

import { useGLTF } from '@react-three/drei'
import { RigidBody, CuboidCollider } from '@react-three/rapier'
import { useQueueStore } from '../store/preload'
import { useEffect } from 'react'

const Landscape = ({ debug = false, ...props }) => {
const { nodes, materials } = useGLTF('../assets/models/Landscape.glb')
const addToLoaded = useQueueStore((state) => state.addToLoaded)

useEffect(() => {
console.debug('[Landscape] loaded')
addToLoaded('Landscape')
}, [])

return (
<>
{/* {debug && <Debug />*/}
Expand Down
42 changes: 35 additions & 7 deletions src/components/Player.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
useWorldStore,
} from '../store'
import { updateCamera } from '../utils/camera'
import { useQueueStore } from '../store/preload'

const JumpForce = 0.7
const Speed = 0.4
Expand All @@ -27,6 +28,7 @@ let internalDebounceTimer = null

const Player = ({ isMobile = false, scale = 0.6 }) => {
const rigidbody = useRef()
const platformRef = useRef()
const isOnFloor = useRef(true)
const character = useRef()
// joystick
Expand All @@ -41,10 +43,6 @@ const Player = ({ isMobile = false, scale = 0.6 }) => {
state.isCollectingQuest,
state.isCollectingChapter,
])
const [doneCollectingQuest, doneCollectingChapter] = usePlayerStore((state) => [
state.doneCollectingQuest,
state.doneCollectingChapter,
])
const [initialPlayerPosition, initialPlayerAngle] = usePlayerStore((state) => [
state.initialPlayerPosition,
state.initialPlayerAngle,
Expand Down Expand Up @@ -80,10 +78,21 @@ const Player = ({ isMobile = false, scale = 0.6 }) => {
// Connect to the store on mount, disconnect on unmount, catch state-changes in a reference
useEffect(() => {
if (isMobile) {
useWorldStore.subscribe((state) => (joystickRef.current = state.joystick))
return useWorldStore.subscribe((state) => (joystickRef.current = state.joystick))
}
// link radius
useWorldStore.subscribe((state) => (cameraOffsetRef.current = state.cameraOffset))
return useWorldStore.subscribe((state) => (cameraOffsetRef.current = state.cameraOffset))
}, [])

useEffect(() => {
console.debug('[Player] @useEffect - useQueueStore.subscribe')
return useQueueStore.subscribe((state) => {
console.debug(
'[Player] @useEffect - useQueueStore.subscribe',
state.loaded,
state.isLoadingComplete,
)
})
}, [])

const movePlayerWithJoystick = (state, delta, shouldStayStill) => {
Expand Down Expand Up @@ -226,6 +235,21 @@ const Player = ({ isMobile = false, scale = 0.6 }) => {

return (
<>
<RigidBody
ref={platformRef}
type="fixed"
colliders={'cuboid'}
position={[
initialPlayerPosition[0],
initialPlayerPosition[1] + 0.5,
initialPlayerPosition[2],
]}
>
<mesh>
<boxGeometry args={[5, 0.5, 5]} />
<meshStandardMaterial depthWrite={false} color={'red'} />
</mesh>
</RigidBody>
<RigidBody
ref={rigidbody}
restitution={0}
Expand All @@ -234,7 +258,11 @@ const Player = ({ isMobile = false, scale = 0.6 }) => {
mass={2.2}
enabledTranslations={[true, true, true]}
enabledRotations={[false, false, false]}
position={initialPlayerPosition}
position={[
initialPlayerPosition[0],
initialPlayerPosition[1] + 2,
initialPlayerPosition[2],
]}
onCollisionEnter={() => {
isOnFloor.current = true
}}
Expand Down
15 changes: 11 additions & 4 deletions src/components/Quest.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,21 @@ import { useSprings, animated, to as interpolate } from '@react-spring/web'
import { Button, Col, Container, Row } from 'react-bootstrap'
import DialogueCard from './DialogueCard'

const to = (i) => ({
const to = (i, delay = 0) => ({
x: 0,
y: i * 200,
opacity: 0,
delay: delay,
})
const from = (i) => ({ x: 0, y: i * -200, opacity: 0 })

const Quest = ({ quest, withChapter = false, onComplete, onCompleteLabel = 'Done' }) => {
const Quest = ({
quest,
initialDelay = 100,
withChapter = false,
onComplete,
onCompleteLabel = 'Done',
}) => {
const [sentenceIndex, setSentenceIndex] = useState(-1)
const [sentences, setSentences] = useState([])

Expand Down Expand Up @@ -62,7 +69,7 @@ const Quest = ({ quest, withChapter = false, onComplete, onCompleteLabel = 'Done
}, [quest, withChapter])

const [props, api] = useSprings(sentences.length, (i) => ({
to: to(i),
to: to(i, i === 0 ? initialDelay : 0),
from: from(i),
}))

Expand All @@ -71,7 +78,7 @@ const Quest = ({ quest, withChapter = false, onComplete, onCompleteLabel = 'Done
if (i < sentenceIndex) {
return from(sentenceIndex - i)
} else if (i === sentenceIndex) {
return { x: 0, y: 0, opacity: 1 }
return { x: 0, y: 0, opacity: 1, delay: i === 0 ? initialDelay : 0 }
} else {
return to(sentenceIndex + i)
}
Expand Down
13 changes: 11 additions & 2 deletions src/components/SideMenu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
const SideMenu = () => {
const { pathname } = useLocation()
const [menuStatus, set] = useMenuStore((state) => [state.menuStatus, state.setMenuStatus])
const setGameControlsStatus = useMenuStore((state) => state.setGameControlsStatus)
const saveInitialPropsToPlayerStore = useWorldStore(
(state) => state.saveInitialPropsToPlayerStore,
)
Expand Down Expand Up @@ -94,7 +95,7 @@ const SideMenu = () => {
</Nav.Item>
<Nav.Item className="mb-3">
<button className="btn btn-link" onClick={saveInitialPropsToPlayerStore}>
save
Save
</button>
</Nav.Item>
<Nav.Item>
Expand All @@ -104,7 +105,15 @@ const SideMenu = () => {
<Link to="/chapters">Chapters</Link>
</Nav.Item>
<Nav.Item>
<Link to="/game_controls">Game Controls</Link>
<button
className="btn btn-link"
onClick={() => {
setGameControlsStatus(MenuOpen)
set(MenuClosed)
}}
>
Game Controls
</button>
</Nav.Item>
<Nav.Item>
<Link to="/about">About</Link>
Expand Down
1 change: 1 addition & 0 deletions src/components/SkipIntro.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const SkipIntro = () => {
<a.div style={style} className="SkipIntro">
{scene === Start ? (
<Quest
initialDelay={20000}
quest={IntroQuest}
onComplete={onIntroQuestComplete}
onCompleteLabel="Let's get to the harbour!"
Expand Down
2 changes: 1 addition & 1 deletion src/components/World.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ const World = ({
scale={[2.5, 2.5, 2]}
position={[16.45, 9.8, -50.67]}
/>
<Player isMobile={isMobile} debug={debug} position={[94.88, 0.26, -14.2]}></Player>
<Player isMobile={isMobile} debug={debug}></Player>

<Boundaries />
<Sensor position={[-60.51, 26.97, -48.47]} />
Expand Down
1 change: 1 addition & 0 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
--z-index-toggle-sounds: 7;
--z-index-side-menu: 8;
--z-index-skip-intro: 9;
--z-index-game-controls: 10;
--spacer: 1.5em;
--spacer-half: 0.75em;
--spacer-double: 3em;
Expand Down
4 changes: 3 additions & 1 deletion src/main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { Gameplay, Start, usePlayerStore } from './store/index.js'
const setIntroTimeout = () => {
if (scene !== Gameplay) {
usePlayerStore.setState({ scene: Start })
} else {
usePlayerStore.setState({ scene: Gameplay })
}
document.getElementById('loading').classList.add('hide')
}
Expand All @@ -23,7 +25,7 @@ ReactDOM.createRoot(document.getElementById('root')).render(
// get current scene from zustand non reactive fresh state
const scene = usePlayerStore.getState().scene
// set fresh state to start scene
usePlayerStore.setState({ isCollectingChapter: false, isCollectingQuest: false })
usePlayerStore.setState({ isCollectingChapter: false, scene: Start, isCollectingQuest: false })

if (scene !== Gameplay) {
setTimeout(setIntroTimeout, 6000)
Expand Down
3 changes: 3 additions & 0 deletions src/store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export const Gameplay = 'gameplay'
export const OpenSea = 'opensea'
export const Start = 'start'
export const Baloon = 'baloon'

export const usePlayerStore = create(
persist(
(set, get) => ({
Expand Down Expand Up @@ -203,4 +204,6 @@ export const MenuOpen = 'open'
export const useMenuStore = create((set) => ({
menuStatus: MenuClosed,
setMenuStatus: (menuStatus) => set({ menuStatus }),
gameControlsStatus: MenuClosed,
setGameControlsStatus: (gameControlsStatus) => set({ gameControlsStatus }),
}))
26 changes: 26 additions & 0 deletions src/store/preload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { create } from 'zustand'

const Expected = ['Landscape', 'IcescreamTruck']

export const useQueueStore = create((set, get) => ({
loaded: [],
isLoadingComplete: false,
addToLoaded: (key) => {
// if key is in loaded already, ignore
const loaded = get().loaded
if (loaded.includes(key)) return
const isLoadingComplete = loaded.length + 1 === Expected.length
console.debug(
'[useQueueStore] addToLoaded:',
key,
'isLoadingComplete',
isLoadingComplete,
'time',
new Date().getTime(),
)
return set({
loaded: [...loaded, key],
isLoadingComplete: loaded.length + 1 === Expected.length,
})
},
}))

0 comments on commit b82384d

Please sign in to comment.