Compare commits
10 Commits
hexTiling
...
e928eb3f01
| Author | SHA1 | Date | |
|---|---|---|---|
|
e928eb3f01
|
|||
|
94bf853589
|
|||
| b70bdfb955 | |||
| 6de586ba01 | |||
| d0446e680d | |||
| 852394c54c | |||
| 4717ec0877 | |||
| 9ac5c35c90 | |||
| 1fb8296bcd | |||
| 9187d8d9ef |
5
README.md
Normal file
5
README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Daedalus
|
||||
|
||||
3D Maze Web game made with Three.js library
|
||||
|
||||

|
||||
30
index.html
30
index.html
@@ -5,6 +5,15 @@
|
||||
<title>Daedalus</title>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
|
||||
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" id="favicon"/>
|
||||
<meta property="og:title" content="Daedalus"/>
|
||||
<meta property="og:type" content="game"/>
|
||||
<meta property="og:url" content="https://adrien.malingrey.fr/jeux/daedalus/"/>
|
||||
<meta property="og:image" content="https://adrien.malingrey.fr/jeux/daedalus/thumbnail.png"/>
|
||||
<meta property="og:image:width" content="250"/>
|
||||
<meta property="og:image:height" content="250"/>
|
||||
<meta property="og:description" content="Retrouvez la sortie"/>
|
||||
<meta property="og:locale" content="fr_FR"/>
|
||||
<meta property="og:site_name" content="adrien.malingrey.fr"/>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<!-- Import maps polyfill -->
|
||||
<!-- Remove this when import maps will be widely supported -->
|
||||
@@ -12,9 +21,8 @@
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"three": "https://cdn.jsdelivr.net/npm/three@0.161.0/build/three.module.min.js",
|
||||
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.161.0/examples/jsm/",
|
||||
"three-hex-tiling": "https://cdn.jsdelivr.net/npm/three-hex-tiling@0.1.1/dist/index.js"
|
||||
"three": "https://cdn.jsdelivr.net/npm/three@0.169.0/build/three.module.min.js",
|
||||
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.169.0/examples/jsm/"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -144,15 +152,23 @@
|
||||
</head>
|
||||
<body>
|
||||
<div id="loading">
|
||||
<table id="labyTable"></table>
|
||||
<div id="loadingMazeShadow">
|
||||
<table id="loadingMazeTable"></table>
|
||||
</div>
|
||||
<div id="loadingMessage">Construction du labyrinthe : <span id="progress">0</span>%</div>
|
||||
<div>
|
||||
Se déplacer : ↑←↓→, ZQSD ou clic<br/>
|
||||
Sauter : ESPACE<br/>
|
||||
Se déplacer : <table class="keysTable">
|
||||
<tr><td rowspan="2">←</td><td>↑</td><td rowspan="2">→</td></tr>
|
||||
<tr><td>↓</td></tr>
|
||||
</table>, <table class="keysTable">
|
||||
<tr><td rowspan="2">Q</td><td>Z</td><td rowspan="2">D</td></tr>
|
||||
<tr><td>S</td></tr>
|
||||
</table> ou clic<br/>
|
||||
Sauter : Espace<br/>
|
||||
Regarder : Souris
|
||||
</div>
|
||||
</div>
|
||||
<div id="container"></div>
|
||||
<div id="container" style="display: none"></div>
|
||||
<span id="message"></span>
|
||||
|
||||
<script type="module" src="./main.js"></script>
|
||||
|
||||
366
main.js
366
main.js
@@ -5,104 +5,11 @@ import { Water } from 'three/addons/objects/Water.js'
|
||||
import { PointerLockControls } from 'three/addons/controls/PointerLockControls.js'
|
||||
import { GUI } from 'three/addons/libs/lil-gui.module.min.js'
|
||||
import { OctreeHelper } from 'three/addons/helpers/OctreeHelper.js'
|
||||
import { CSM } from 'three/addons/csm/CSM.js';
|
||||
import Stats from 'three/addons/libs/stats.module.js'
|
||||
|
||||
import MazeMesh from './MazeMesh.js'
|
||||
|
||||
//import 'three-hex-tiling'
|
||||
|
||||
|
||||
// LOADING
|
||||
|
||||
const labyWidth = 23
|
||||
const labyHeight = 23
|
||||
|
||||
for(let y=0; y < labyHeight; y++) {
|
||||
let tr = document.createElement("tr")
|
||||
labyTable.appendChild(tr)
|
||||
for(let x=0; x < labyWidth; x++) {
|
||||
let td = document.createElement("td")
|
||||
tr.appendChild(td)
|
||||
}
|
||||
}
|
||||
|
||||
let walls
|
||||
|
||||
function dig(x, y) {
|
||||
walls[y][x] = false
|
||||
labyTable.children[y].children[x].className = "ground"
|
||||
}
|
||||
|
||||
const directions = [[0, 1], [0, -1], [1, 0], [-1, 0]]
|
||||
function* build(x, y) {
|
||||
for (let direction of Array.from(directions).sort(x => .5 - Math.random())) {
|
||||
let [dx, dy] = direction
|
||||
let x1 = x + dx
|
||||
let y1 = y + dy
|
||||
let x2 = x1 + dx
|
||||
let y2 = y1 + dy
|
||||
if (0 <= x2 && x2 < labyWidth && 0 <= y2 && y2 < labyHeight && walls[y2][x2]) {
|
||||
dig(x1, y1)
|
||||
yield x1, y1
|
||||
dig(x2, y2)
|
||||
yield x2, y2
|
||||
yield* build(x2, y2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function* endlessLaby() {
|
||||
while (true) {
|
||||
for (const tr of labyTable.children) {
|
||||
for (const td of tr.children) {
|
||||
td.className = "wall"
|
||||
}
|
||||
}
|
||||
|
||||
walls = Array(labyHeight).fill(true).map(row => Array(labyWidth).fill(true))
|
||||
|
||||
let x0 = Math.floor(labyWidth / 2)
|
||||
let y0 = Math.floor(labyHeight / 2)
|
||||
|
||||
dig(x0, y0)
|
||||
yield* build(x0, y0)
|
||||
}
|
||||
}
|
||||
|
||||
let labyIterator = endlessLaby()
|
||||
|
||||
let interval = window.setInterval(() => labyIterator.next(), 200)
|
||||
|
||||
|
||||
const loadMngr = new THREE.LoadingManager()
|
||||
const loader = new THREE.TextureLoader(loadMngr)
|
||||
loader.setPath("textures/")
|
||||
let t0
|
||||
loadMngr.onStart = function (url, itemsLoaded, itemsTotal) {
|
||||
progress.innerText = "0"
|
||||
t0 = Date.now()
|
||||
}
|
||||
loadMngr.onProgress = function (url, itemsLoaded, itemsTotal) {
|
||||
progress.innerText = Math.floor(100 * itemsLoaded / itemsTotal)
|
||||
}
|
||||
loadMngr.onError = function (url) {
|
||||
loadingMessage.innerHTML = `Erreur de chargement :<br/>${url}`
|
||||
}
|
||||
loadMngr.onLoad = function (url, itemsLoaded, itemsTotal) {
|
||||
loading.style.display = "none"
|
||||
window.clearInterval(interval)
|
||||
|
||||
renderer.setAnimationLoop(animate)
|
||||
|
||||
setInterval(() => {
|
||||
let x = Math.floor(8 + camera.position.x * 16 / mazeWidth)
|
||||
let y = Math.floor(8 + camera.position.z * 16 / mazeWidth)
|
||||
favicon.href = `favicon.php?x=${x}&y=${y}`
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
|
||||
// GAME
|
||||
|
||||
const playerHeight = 0.5
|
||||
const mazeWidth = 23
|
||||
@@ -118,21 +25,119 @@ const waves = {
|
||||
C: { direction: 60, steepness: 0.05, wavelength: 1.5 },
|
||||
}
|
||||
|
||||
const loadingMaze = {
|
||||
width: 23,
|
||||
height: 23
|
||||
}
|
||||
|
||||
const container = document.getElementById('container')
|
||||
|
||||
|
||||
// LOADING
|
||||
|
||||
for(let y=0; y < loadingMaze.height; y++) {
|
||||
let tr = document.createElement("tr")
|
||||
loadingMazeTable.appendChild(tr)
|
||||
for(let x=0; x < loadingMaze.width; x++) {
|
||||
let td = document.createElement("td")
|
||||
tr.appendChild(td)
|
||||
}
|
||||
}
|
||||
|
||||
let walls
|
||||
|
||||
function dig(x, y) {
|
||||
walls[y][x] = false
|
||||
loadingMazeTable.children[y].children[x].className = "ground"
|
||||
}
|
||||
|
||||
const directions = [[0, 1], [0, -1], [1, 0], [-1, 0]]
|
||||
function* build(x, y) {
|
||||
for (let direction of Array.from(directions).sort(x => .5 - Math.random())) {
|
||||
let [dx, dy] = direction
|
||||
let x1 = x + dx
|
||||
let y1 = y + dy
|
||||
let x2 = x1 + dx
|
||||
let y2 = y1 + dy
|
||||
if (0 <= x2 && x2 < loadingMaze.width && 0 <= y2 && y2 < loadingMaze.height && walls[y2][x2]) {
|
||||
dig(x1, y1)
|
||||
yield x1, y1
|
||||
dig(x2, y2)
|
||||
yield x2, y2
|
||||
yield* build(x2, y2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function* endlessLoadingMaze() {
|
||||
while (true) {
|
||||
for (const tr of loadingMazeTable.children) {
|
||||
for (const td of tr.children) {
|
||||
td.className = "wall"
|
||||
}
|
||||
}
|
||||
|
||||
walls = Array(loadingMaze.height).fill(true).map(row => Array(loadingMaze.width).fill(true))
|
||||
|
||||
let x0 = Math.floor(loadingMaze.width / 2)
|
||||
let y0 = Math.floor(loadingMaze.height / 2)
|
||||
|
||||
dig(x0, y0)
|
||||
yield* build(x0, y0)
|
||||
}
|
||||
}
|
||||
|
||||
let interval
|
||||
|
||||
const loadMngr = new THREE.LoadingManager()
|
||||
const loader = new THREE.TextureLoader(loadMngr)
|
||||
loader.setPath("textures/")
|
||||
|
||||
loadMngr.onStart = function (url, itemsLoaded, itemsTotal) {
|
||||
progress.innerText = "0"
|
||||
|
||||
let loadingMazeIterator = endlessLoadingMaze()
|
||||
interval = window.setInterval(() => loadingMazeIterator.next(), 200)
|
||||
}
|
||||
loadMngr.onProgress = function (url, itemsLoaded, itemsTotal) {
|
||||
progress.innerText = Math.floor(100 * itemsLoaded / itemsTotal)
|
||||
}
|
||||
loadMngr.onError = function (url) {
|
||||
loadingMessage.innerHTML = `Erreur de chargement :<br/>${url}`
|
||||
}
|
||||
loadMngr.onLoad = function (url, itemsLoaded, itemsTotal) {
|
||||
loading.style.display = "none"
|
||||
container.style.display = "block"
|
||||
window.clearInterval(interval)
|
||||
|
||||
renderer.setAnimationLoop(animate)
|
||||
|
||||
setInterval(() => {
|
||||
let x = Math.floor(8 + camera.position.x * 16 / mazeWidth)
|
||||
let y = Math.floor(8 + camera.position.z * 16 / mazeWidth)
|
||||
favicon.href = `favicon.php?x=${x}&y=${y}`
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
|
||||
// GAME
|
||||
|
||||
const ambiance = new Audio("snd/ambiance.mp3")
|
||||
ambiance.loop = true
|
||||
const piano = new Audio("snd/waves-and-tears.mp3")
|
||||
piano.loop = false
|
||||
|
||||
const container = document.getElementById('container')
|
||||
|
||||
const renderer = new THREE.WebGLRenderer({
|
||||
powerPreference: "high-performance",
|
||||
})
|
||||
renderer.setPixelRatio(window.devicePixelRatio)
|
||||
renderer.setSize(window.innerWidth, window.innerHeight)
|
||||
renderer.toneMapping = THREE.ACESFilmicToneMapping
|
||||
renderer.toneMappingExposure = 1.0
|
||||
renderer.shadowMap.enabled = true
|
||||
renderer.shadowMap.type = THREE.PCFSoftShadowMap
|
||||
renderer.physicallyCorrectLights = true
|
||||
renderer.outputColorSpace = THREE.SRGBColorSpace
|
||||
|
||||
container.appendChild(renderer.domElement)
|
||||
|
||||
@@ -165,15 +170,50 @@ const mazeCollisionner = new THREE.Group()
|
||||
const wallMaterial = new THREE.MeshStandardMaterial({
|
||||
map : loader.load('Poly-cobblestone-wall/color_map.webp'),
|
||||
normalMap : loader.load('Poly-cobblestone-wall/normal_map_opengl.webp'),
|
||||
aoMap : loader.load('Poly-cobblestone-wall/ao_map.webp'),
|
||||
aoMapIntensity : 1,
|
||||
roughnessMap : loader.load('Poly-cobblestone-wall/roughness_map.webp'),
|
||||
roughness : 1
|
||||
roughness : 1,
|
||||
metalness : 1
|
||||
})
|
||||
const sideGroundMaterial = new THREE.MeshStandardMaterial({
|
||||
map : wallMaterial.map.clone(),
|
||||
normalMap : wallMaterial.normalMap.clone(),
|
||||
normalScale : new THREE.Vector2(0.6, 0.6),
|
||||
aoMapIntensity : wallMaterial.aoMapIntensity,
|
||||
roughnessMap : wallMaterial.roughnessMap.clone(),
|
||||
roughness : wallMaterial.roughness,
|
||||
metalness : wallMaterial.metalness,
|
||||
})
|
||||
loader.load('Poly-cobblestone-wall/ao_map.jpg', (texture) => {
|
||||
wallMaterial.aoMap = texture
|
||||
wallMaterial.metalnessMap = texture
|
||||
wallMaterial.needsUpdate = true
|
||||
|
||||
const sidegroundTexture = texture.clone()
|
||||
sidegroundTexture.wrapS = sidegroundTexture.wrapT = THREE.RepeatWrapping
|
||||
sidegroundTexture.repeat.set(mazeWidth, 20)
|
||||
sidegroundTexture.rotation = Math.PI
|
||||
|
||||
sideGroundMaterial.map.wrapS = sideGroundMaterial.map.wrapT = THREE.RepeatWrapping
|
||||
sideGroundMaterial.map.repeat.set(mazeWidth, 20)
|
||||
sideGroundMaterial.map.rotation = Math.PI
|
||||
sideGroundMaterial.normalMap.wrapS = sideGroundMaterial.normalMap.wrapT = THREE.RepeatWrapping
|
||||
sideGroundMaterial.normalMap.repeat.set(mazeWidth, 20)
|
||||
sideGroundMaterial.normalMap.rotation = Math.PI
|
||||
sideGroundMaterial.aoMap = sidegroundTexture
|
||||
sideGroundMaterial.roughnessMap.wrapS = sideGroundMaterial.roughnessMap.wrapT = THREE.RepeatWrapping
|
||||
sideGroundMaterial.roughnessMap.repeat.set(mazeWidth, 20)
|
||||
sideGroundMaterial.roughnessMap.rotation = Math.PI
|
||||
sideGroundMaterial.metalnessMap = sidegroundTexture
|
||||
|
||||
sideGroundMaterial.needsUpdate = true
|
||||
})
|
||||
|
||||
const maze = new MazeMesh(mazeWidth, mazeWidth, 1, wallMaterial)
|
||||
maze.castShadow = true
|
||||
maze.receiveShadow = true
|
||||
maze.matrixAutoUpdate = false
|
||||
|
||||
scene.add(maze)
|
||||
|
||||
console.log(String(maze))
|
||||
@@ -204,9 +244,9 @@ function repeatGroundMaterial (texture) {
|
||||
const groundMaterial = new THREE.MeshStandardMaterial({
|
||||
map : loader.load('angled-blocks-vegetation/albedo.webp', repeatGroundMaterial),
|
||||
aoMap : loader.load('angled-blocks-vegetation/ao.webp', repeatGroundMaterial),
|
||||
metalnessMap: loader.load('angled-blocks-vegetation/metallic.webp', repeatGroundMaterial),
|
||||
metalnessMap: loader.load('angled-blocks-vegetation/ao-roughness-metalness.webp', repeatGroundMaterial),
|
||||
normalMap : loader.load('angled-blocks-vegetation/normal-dx.webp', repeatGroundMaterial),
|
||||
roughnessMap: loader.load('angled-blocks-vegetation/roughness.webp', repeatGroundMaterial),
|
||||
roughnessMap: loader.load('angled-blocks-vegetation/ao-roughness-metalness.webp', repeatGroundMaterial),
|
||||
/*hexTiling : {
|
||||
patchScale: 1,
|
||||
useContrastCorrectedBlending: true,
|
||||
@@ -215,27 +255,6 @@ const groundMaterial = new THREE.MeshStandardMaterial({
|
||||
}*/
|
||||
})
|
||||
|
||||
const sideGroundMaterial = new THREE.MeshStandardMaterial({
|
||||
map : wallMaterial.map.clone(),
|
||||
normalMap : wallMaterial.normalMap.clone(),
|
||||
normalScale : new THREE.Vector2(0.6, 0.6),
|
||||
aoMap : wallMaterial.aoMap.clone(),
|
||||
roughnessMap : wallMaterial.roughnessMap.clone(),
|
||||
roughness : 1,
|
||||
})
|
||||
sideGroundMaterial.map.wrapS = sideGroundMaterial.map.wrapT = THREE.RepeatWrapping
|
||||
sideGroundMaterial.map.repeat.set(mazeWidth, 20)
|
||||
sideGroundMaterial.map.rotation = Math.PI
|
||||
sideGroundMaterial.normalMap.wrapS = sideGroundMaterial.normalMap.wrapT = THREE.RepeatWrapping
|
||||
sideGroundMaterial.normalMap.repeat.set(mazeWidth, 20)
|
||||
sideGroundMaterial.normalMap.rotation = Math.PI
|
||||
sideGroundMaterial.aoMap.wrapS = sideGroundMaterial.aoMap.wrapT = THREE.RepeatWrapping
|
||||
sideGroundMaterial.aoMap.repeat.set(mazeWidth, 20)
|
||||
sideGroundMaterial.aoMap.rotation = Math.PI
|
||||
sideGroundMaterial.roughnessMap.wrapS = sideGroundMaterial.roughnessMap.wrapT = THREE.RepeatWrapping
|
||||
sideGroundMaterial.roughnessMap.repeat.set(mazeWidth, 20)
|
||||
sideGroundMaterial.roughnessMap.rotation = Math.PI
|
||||
|
||||
const ground = new THREE.Mesh(
|
||||
groundGeometry,
|
||||
[
|
||||
@@ -284,7 +303,6 @@ ocean.position.y = -0.2
|
||||
|
||||
ocean.material.transparent = true
|
||||
ocean.material.onBeforeCompile = function (shader) {
|
||||
|
||||
shader.uniforms.size = { value: 6 }
|
||||
|
||||
shader.uniforms.waveA = {
|
||||
@@ -313,7 +331,6 @@ ocean.material.onBeforeCompile = function (shader) {
|
||||
}
|
||||
shader.vertexShader = document.getElementById('vertexShader').textContent
|
||||
shader.fragmentShader = document.getElementById('fragmentShader').textContent
|
||||
|
||||
}
|
||||
|
||||
scene.add(ocean)
|
||||
@@ -321,12 +338,12 @@ const oceanOctree = new Octree().fromGraphNode(ocean)
|
||||
|
||||
// Lights
|
||||
|
||||
const sun = new THREE.Vector3()
|
||||
const sunPosition = new THREE.Vector3()
|
||||
|
||||
const ambientLight = new THREE.AmbientLight(0x404040, 5)
|
||||
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)
|
||||
scene.add(ambientLight)
|
||||
|
||||
const sunLight = new THREE.DirectionalLight(0xffffff, 1)
|
||||
const sunLight = new THREE.DirectionalLight(0xffffff, 3)
|
||||
sunLight.castShadow = true
|
||||
sunLight.shadow.camera.near = 0.1
|
||||
sunLight.shadow.camera.far = 1.4 * mazeWidth
|
||||
@@ -344,17 +361,15 @@ scene.add(sunLight)
|
||||
updateSun()
|
||||
|
||||
function updateSun() {
|
||||
|
||||
const phi = THREE.MathUtils.degToRad(90 - parameters.elevation)
|
||||
const theta = THREE.MathUtils.degToRad(parameters.azimuth)
|
||||
|
||||
sun.setFromSphericalCoords(1.4 * mazeWidth/2, phi, theta)
|
||||
ocean.material.uniforms['sunDirection'].value.copy(sun).normalize()
|
||||
sunPosition.setFromSphericalCoords(1.4 * mazeWidth/2, phi, theta)
|
||||
ocean.material.uniforms['sunDirection'].value.copy(sunPosition).normalize()
|
||||
|
||||
sunLight.position.copy(sun)
|
||||
|
||||
//ambientLight.intensity = 5 + 5 * Math.sin(Math.max(THREE.MathUtils.degToRad(parameters.elevation), 0))
|
||||
sunLight.position.copy(sunPosition)
|
||||
|
||||
ambientLight.intensity = 0.5 + 0.5 * Math.sin(Math.max(THREE.MathUtils.degToRad(parameters.elevation), 0))
|
||||
}
|
||||
|
||||
// Raft
|
||||
@@ -374,7 +389,7 @@ const raftMaterial = new THREE.MeshStandardMaterial({
|
||||
depthTest: true,
|
||||
depthWrite: true,
|
||||
displacementMap: loader.load("Poly-wood/displacement_map.webp", repeatRaftMaterial),
|
||||
displacementScale: -0.3,
|
||||
displacementScale: -0.32,
|
||||
displacementBias: 0.15,
|
||||
})
|
||||
const raft = new THREE.Mesh(raftGeometry, raftMaterial)
|
||||
@@ -389,30 +404,28 @@ const raftOctree = new Octree().fromGraphNode(raft)
|
||||
const stats = new Stats()
|
||||
|
||||
if (dev) {
|
||||
|
||||
container.appendChild(stats.dom)
|
||||
|
||||
const gui = new GUI()
|
||||
|
||||
const lightHelper = new THREE.DirectionalLightHelper(sunLight, .5)
|
||||
/*const lightHelper = new THREE.DirectionalLightHelper(sunLight, .5)
|
||||
lightHelper.position.copy(maze.start)
|
||||
lightHelper.visible = false
|
||||
lightHelper.visible = false*/
|
||||
|
||||
const octreeHelper = new OctreeHelper(mazeOctree)
|
||||
octreeHelper.visible = false
|
||||
scene.add(octreeHelper)
|
||||
const showHelper = gui.add({ helpers: false }, "helpers")
|
||||
showHelper.onChange(function (value) {
|
||||
|
||||
lightHelper.visible = value
|
||||
octreeHelper.visible = value
|
||||
|
||||
})
|
||||
|
||||
const cameraFolder = gui.addFolder("camera")
|
||||
cameraFolder.add(camera, "focus", 0, 200).onChange(() => camera.updateProjectionMatrix())
|
||||
cameraFolder.add(camera, "fov", 0, 200).onChange(() => camera.updateProjectionMatrix())
|
||||
cameraFolder.add(camera, "filmGauge", 0, 200).onChange(() => camera.updateProjectionMatrix())
|
||||
cameraFolder.close()
|
||||
|
||||
const raftFolder = gui.addFolder("Raft")
|
||||
const raftPositionFolder = raftFolder.addFolder("position")
|
||||
@@ -509,22 +522,31 @@ if (dev) {
|
||||
})
|
||||
waveCFolder.open()
|
||||
|
||||
const hexTilingFolder = gui.addFolder('Hex Tiling')
|
||||
if (wallMaterial?.hexTiling?.patchScale) {
|
||||
const wallMaterialFolder = hexTilingFolder.addFolder("wall")
|
||||
wallMaterialFolder.add(wallMaterial.hexTiling, "patchScale", 0, 10)
|
||||
wallMaterialFolder.add(wallMaterial.hexTiling, "useContrastCorrectedBlending")
|
||||
wallMaterialFolder.add(wallMaterial.hexTiling, "lookupSkipThreshold", 0, 1)
|
||||
wallMaterialFolder.add(wallMaterial.hexTiling, "textureSampleCoefficientExponent", 0, 64).name("SampleCoefExp")
|
||||
const wallMaterialFolder = gui.addFolder("wallMaterial")
|
||||
wallMaterialFolder.add(wallMaterial, "roughness").min(0).max(1)
|
||||
wallMaterialFolder.add(wallMaterial, "metalness").min(0).max(1)
|
||||
wallMaterialFolder.add(wallMaterial, "aoMapIntensity").min(-10).max(10)
|
||||
wallMaterialFolder.add(wallMaterial, "bumpScale").min(-10).max(10).onChange(() => wallMaterial.needsUpdate = true)
|
||||
wallMaterialFolder.close()
|
||||
|
||||
if (wallMaterial?.hexTiling) {
|
||||
const hexTilingFolder = gui.addFolder('Hex Tiling')
|
||||
if (wallMaterial?.hexTiling?.patchScale) {
|
||||
const wallMaterialFolder = hexTilingFolder.addFolder("wall")
|
||||
wallMaterialFolder.add(wallMaterial.hexTiling, "patchScale", 0, 10)
|
||||
wallMaterialFolder.add(wallMaterial.hexTiling, "useContrastCorrectedBlending")
|
||||
wallMaterialFolder.add(wallMaterial.hexTiling, "lookupSkipThreshold", 0, 1)
|
||||
wallMaterialFolder.add(wallMaterial.hexTiling, "textureSampleCoefficientExponent", 0, 64).name("SampleCoefExp")
|
||||
}
|
||||
if (groundMaterial?.hexTiling?.patchScale) {
|
||||
const groundMaterialFolder = hexTilingFolder.addFolder("ground")
|
||||
groundMaterialFolder.add(groundMaterial.hexTiling, "patchScale", 0, 10)
|
||||
groundMaterialFolder.add(groundMaterial.hexTiling, "useContrastCorrectedBlending")
|
||||
groundMaterialFolder.add(groundMaterial.hexTiling, "lookupSkipThreshold", 0, 1)
|
||||
groundMaterialFolder.add(groundMaterial.hexTiling, "textureSampleCoefficientExponent", 0, 64).name("SampleCoefExp")
|
||||
}
|
||||
hexTilingFolder.close()
|
||||
}
|
||||
if (groundMaterial?.hexTiling?.patchScale) {
|
||||
const groundMaterialFolder = hexTilingFolder.addFolder("ground")
|
||||
groundMaterialFolder.add(groundMaterial.hexTiling, "patchScale", 0, 10)
|
||||
groundMaterialFolder.add(groundMaterial.hexTiling, "useContrastCorrectedBlending")
|
||||
groundMaterialFolder.add(groundMaterial.hexTiling, "lookupSkipThreshold", 0, 1)
|
||||
groundMaterialFolder.add(groundMaterial.hexTiling, "textureSampleCoefficientExponent", 0, 64).name("SampleCoefExp")
|
||||
}
|
||||
hexTilingFolder.close()
|
||||
}
|
||||
|
||||
//
|
||||
@@ -553,15 +575,25 @@ let escaped = false
|
||||
const pointerLockControls = new PointerLockControls(camera, document.body)
|
||||
pointerLockControls.pointerSpeed = 0.7
|
||||
|
||||
const keys = [
|
||||
"ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight",
|
||||
"KeyW", "KeyS", "KeyA", "KeyD", "Space"
|
||||
]
|
||||
const keyStates = {}
|
||||
|
||||
document.addEventListener('keydown', (event) => {
|
||||
keyStates[event.code] = true
|
||||
if (keys.includes(event.code)) {
|
||||
event.preventDefault()
|
||||
keyStates[event.code] = true
|
||||
}
|
||||
})
|
||||
|
||||
document.addEventListener('keyup', (event) => {
|
||||
keyStates[event.code] = false
|
||||
if (event.code == 'Space') jumping = false
|
||||
if (keys.includes(event.code)) {
|
||||
event.preventDefault()
|
||||
keyStates[event.code] = false
|
||||
if (event.code == 'Space') jumping = false
|
||||
}
|
||||
})
|
||||
|
||||
let mouseButtonsStates = []
|
||||
@@ -588,10 +620,9 @@ pointerLockControls.addEventListener('unlock', function () {
|
||||
document.removeEventListener('mouseup', onMouseChange)
|
||||
})
|
||||
|
||||
scene.add(pointerLockControls.getObject())
|
||||
scene.add(pointerLockControls.object)
|
||||
|
||||
function playerCollisions() {
|
||||
|
||||
const playerOnMaze = mazeOctree.capsuleIntersect(playerCollider)
|
||||
const playerOnRaft = raftOctree.capsuleIntersect(playerCollider)
|
||||
const playerOnWater = oceanOctree.capsuleIntersect(playerCollider)
|
||||
@@ -619,11 +650,9 @@ function playerCollisions() {
|
||||
camera.position.y = ocean.position.y + waveInfo.position.y + 0.2
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function gameEnd() {
|
||||
|
||||
escaped = true
|
||||
message.innerHTML = '<h2>Libre !</h2><a href="">Rejouer</a>'
|
||||
message.className = "escaped"
|
||||
@@ -631,11 +660,9 @@ function gameEnd() {
|
||||
|
||||
document.exitPointerLock()
|
||||
//container.style.cursor = "default"
|
||||
|
||||
}
|
||||
|
||||
function updatePlayer(deltaTime) {
|
||||
|
||||
let damping = Math.exp(- 4 * deltaTime) - 1
|
||||
|
||||
if (!playerOnFloor) {
|
||||
@@ -651,32 +678,26 @@ function updatePlayer(deltaTime) {
|
||||
camera.position.copy(playerCollider.end)
|
||||
|
||||
playerCollisions()
|
||||
|
||||
}
|
||||
|
||||
function getForwardVector() {
|
||||
|
||||
camera.getWorldDirection(playerDirection)
|
||||
playerDirection.y = 0
|
||||
playerDirection.normalize()
|
||||
|
||||
return playerDirection
|
||||
|
||||
}
|
||||
|
||||
function getSideVector() {
|
||||
|
||||
camera.getWorldDirection(playerDirection)
|
||||
playerDirection.y = 0
|
||||
playerDirection.normalize()
|
||||
playerDirection.cross(camera.up)
|
||||
|
||||
return playerDirection
|
||||
|
||||
}
|
||||
|
||||
function controls(deltaTime) {
|
||||
|
||||
// gives a bit of air control
|
||||
const speedDelta = deltaTime * (playerOnFloor ? 100 : 20) / STEPS_PER_FRAME
|
||||
|
||||
@@ -701,7 +722,6 @@ function controls(deltaTime) {
|
||||
}
|
||||
|
||||
function getWaveInfo(x, z, time) {
|
||||
|
||||
const pos = new THREE.Vector3()
|
||||
const tangent = new THREE.Vector3(1, 0, 0)
|
||||
const binormal = new THREE.Vector3(0, 0, 1)
|
||||
@@ -732,11 +752,9 @@ function getWaveInfo(x, z, time) {
|
||||
const normal = binormal.cross(tangent).normalize()
|
||||
|
||||
return { position: pos, normal: normal }
|
||||
|
||||
}
|
||||
|
||||
function updateRaft(delta) {
|
||||
|
||||
const t = ocean.material.uniforms['time'].value
|
||||
|
||||
const waveInfo = getWaveInfo(raft.position.x, raft.position.z, t)
|
||||
@@ -745,22 +763,18 @@ function updateRaft(delta) {
|
||||
new THREE.Euler().setFromVector3(waveInfo.normal)
|
||||
)
|
||||
raft.quaternion.rotateTowards(quat, delta * 0.5)
|
||||
|
||||
}
|
||||
|
||||
window.addEventListener('resize', onWindowResize)
|
||||
|
||||
function onWindowResize() {
|
||||
|
||||
camera.aspect = window.innerWidth / window.innerHeight
|
||||
camera.updateProjectionMatrix()
|
||||
|
||||
renderer.setSize(window.innerWidth, window.innerHeight)
|
||||
|
||||
}
|
||||
|
||||
function animate() {
|
||||
|
||||
const delta = Math.min(0.05, clock.getDelta())
|
||||
const deltaTime = delta / STEPS_PER_FRAME
|
||||
|
||||
@@ -772,7 +786,6 @@ function animate() {
|
||||
// an object traversing another too quickly for detection.
|
||||
|
||||
for (let i = 0; i < STEPS_PER_FRAME; i++) {
|
||||
|
||||
controls(deltaTime)
|
||||
|
||||
updatePlayer(deltaTime)
|
||||
@@ -785,5 +798,4 @@ function animate() {
|
||||
renderer.render(scene, camera)
|
||||
|
||||
if (dev) stats.update()
|
||||
|
||||
}
|
||||
47
style.css
47
style.css
@@ -3,7 +3,7 @@ body {
|
||||
background-color: #041626;
|
||||
font-size: 1.3em;
|
||||
overscroll-behavior: none;
|
||||
cursor: wait;
|
||||
cursor: progress;
|
||||
}
|
||||
|
||||
#loading {
|
||||
@@ -12,27 +12,62 @@ body {
|
||||
font-size: 1.3em;
|
||||
top: 20vh;
|
||||
margin: auto;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
#loadingMessage {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
#labyTable {
|
||||
.keysTable {
|
||||
display: inline-table;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@keyframes perspective {
|
||||
from {
|
||||
transform: rotateX(0deg) perspective(0px);
|
||||
filter: drop-shadow(0px 00px 0px #0f2437);
|
||||
}
|
||||
to {
|
||||
transform: rotateX(40deg) perspective(150px);
|
||||
filter: drop-shadow(0px 10px 0px #0f2437);
|
||||
}
|
||||
}
|
||||
|
||||
#loadingMazeShadow {
|
||||
width: 230px;
|
||||
height: 230px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 20vh;
|
||||
margin-bottom: 5vh;
|
||||
border-collapse: collapse;
|
||||
animation: perspective 30s;
|
||||
transform: rotateX(40deg) perspective(150px);
|
||||
filter: drop-shadow(0px 10px 0px #0f2437);
|
||||
}
|
||||
|
||||
#labyTable td {
|
||||
@keyframes rotation {
|
||||
from {
|
||||
transform: rotateZ(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotateZ(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
#loadingMazeTable {
|
||||
border-collapse: collapse;
|
||||
animation: rotation 60s infinite;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#loadingMazeTable td {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
transition: background-color 1s;
|
||||
border: 0;
|
||||
border: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@@ -70,7 +105,7 @@ body {
|
||||
justify-content: center;
|
||||
z-index: 1;
|
||||
color: gray;
|
||||
font-family: Times, "Times New Roman", Georgia, serif;
|
||||
font-family: serif;
|
||||
}
|
||||
|
||||
#message a {
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 7.3 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.7 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.7 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 7.4 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.6 MiB |
Reference in New Issue
Block a user