Last active
December 9, 2023 02:45
-
-
Save primaryobjects/8fb9214ade94704a46057c4b8ba542e9 to your computer and use it in GitHub Desktop.
Creating a random 3D maze with WebGL and three.js along with ChatGPT4 on Bing https://3D-Maze.primaryobjects.repl.co
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>3D Maze with GPT4</title> | |
<link rel="stylesheet" href="style.css"> | |
<script src="https://code.jquery.com/jquery-3.6.4.slim.min.js" integrity="sha256-a2yjHM4jnF9f54xUQakjZGaqYs/V1CYvWpoqZzC2/Bw=" crossorigin="anonymous"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.8.1/gl-matrix-min.js"></script> | |
<script src="script.js"></script> | |
</head> | |
<body> | |
<canvas id="canvas" width="100%" height="100%"></canvas> | |
<div id="controls"> | |
<button id="up-arrow">Up</button> | |
<br> | |
<button id="left-arrow">Left</button> | |
<button id="right-arrow">Right</button> | |
<br> | |
<button id="down-arrow">Down</button> | |
</div> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//create a scene | |
const scene = new THREE.Scene(); | |
//create a camera | |
const camera = new THREE.PerspectiveCamera( | |
90, | |
window.innerWidth / window.innerHeight, | |
0.1, | |
500 | |
); | |
camera.position.z = 5; | |
//create the first object | |
const geometry = new THREE.BoxGeometry(1, 1, 1); | |
var material = new THREE.MeshBasicMaterial({ | |
color: 0xfffff, | |
wireframe: false, | |
}); | |
var cube = new THREE.Mesh(geometry, material); | |
//add the first object to scene | |
scene.add(cube); | |
//create the second object | |
const geometry2 = new THREE.BoxGeometry(1, 1, 1); | |
var material2 = new THREE.MeshBasicMaterial({ | |
color: 'red', | |
wireframe: false, | |
}); | |
var cube2 = new THREE.Mesh(geometry2, material2); | |
cube2.position.x = 2; | |
//add the second object to scene | |
scene.add(cube2); | |
//create the maze | |
const mazeGeometry = new THREE.BoxGeometry(0.5, 0.5, 0.5); | |
// Load texture for maze blocks | |
const loader = new THREE.TextureLoader(); | |
const textures = [ | |
loader.load('block1.jpg'), | |
loader.load('block2.jpg'), | |
loader.load('block3.jpg') | |
]; | |
// Maze generation using depth-first search algorithm | |
const mazeSize = 10; | |
let maze = new Array(mazeSize); | |
for (let i = 0; i < mazeSize; i++) { | |
maze[i] = new Array(mazeSize).fill(1); | |
} | |
let stack = []; | |
let visitedCells = 1; | |
let totalCells = ((mazeSize - 1) / 2) ** 2; | |
let currentCell = [1,1]; | |
while (visitedCells < totalCells) { | |
let possibleDirections = []; | |
if (currentCell[0] + 2 < mazeSize - 1 && maze[currentCell[0] + 2][currentCell[1]] === 1) { | |
possibleDirections.push('S'); | |
} | |
if (currentCell[0] - 2 > 0 && maze[currentCell[0] - 2][currentCell[1]] === 1) { | |
possibleDirections.push('N'); | |
} | |
if (currentCell[1] + 2 < mazeSize - 1 && maze[currentCell[0]][currentCell[1] + 2] === 1) { | |
possibleDirections.push('E'); | |
} | |
if (currentCell[1] - 2 > 0 && maze[currentCell[0]][currentCell[1] - 2] === 1) { | |
possibleDirections.push('W'); | |
} | |
if (possibleDirections.length > 0) { | |
let direction = possibleDirections[Math.floor(Math.random() * possibleDirections.length)]; | |
switch(direction) { | |
case 'N': | |
maze[currentCell[0] - 2][currentCell[1]] = 0; | |
maze[currentCell[0] - 1][currentCell[1]] = 0; | |
currentCell[0] -= 2; | |
break; | |
case 'S': | |
maze[currentCell[0] + 2][currentCell[1]] = 0; | |
maze[currentCell[0] + 1][currentCell[1]] = 0; | |
currentCell[0] += 2; | |
break; | |
case 'W': | |
maze[currentCell[0]][currentCell[1] - 2] = 0; | |
maze[currentCell[0]][currentCell[1] - 1] = 0; | |
currentCell[1] -= 2; | |
break; | |
case 'E': | |
maze[currentCell[0]][currentCell[1] + 2] = 0; | |
maze[currentCell[0]][currentCell[1] + 1] = 0; | |
currentCell[1] += 2; | |
break; | |
} | |
visitedCells++; | |
stack.push(currentCell.slice()); | |
} else { | |
if (stack.length < 1) { | |
break; | |
} | |
else { | |
currentCell = stack.pop(); | |
} | |
} | |
} | |
/*maze = [ | |
[1,1,1,1,1], | |
[1,0,0,0,1], | |
[1,0,1,0,1], | |
[1,0,0,0,1], | |
[1,1,1,1,1] | |
];*/ | |
const mazeBlocks = []; | |
for (let i = 0; i < maze.length; i++) { | |
for (let j = 0; j < maze[i].length; j++) { | |
if (maze[i][j] === 1) { | |
const r = Math.floor(Math.random() * 3); | |
const mazeMaterial = new THREE.MeshBasicMaterial({ | |
map: textures[r], | |
}); | |
const block = new THREE.Mesh(mazeGeometry, mazeMaterial); | |
block.position.set(i - 2.5 , j - 2.5 , -2); | |
mazeBlocks.push(block); | |
scene.add(block); | |
} | |
} | |
} | |
//create renderer | |
const renderer = new THREE.WebGLRenderer({ antialias: true }); | |
renderer.setSize(window.innerWidth, window.innerHeight); | |
renderer.render(scene, camera); | |
// Create an object to keep track of which keys are pressed | |
const keysPressed = { | |
ArrowLeft: false, | |
ArrowRight: false, | |
ArrowUp: false, | |
ArrowDown: false | |
}; | |
//animation loop | |
const animate = () => { | |
requestAnimationFrame(animate); | |
cube.rotation.y += 0.01; | |
cube.rotation.x += 0.02; | |
cube2.rotation.y += 0.01; | |
cube2.rotation.x += 0.02; | |
// Move the maze blocks | |
for (let block of mazeBlocks) { | |
block.position.z += 0.01; | |
if (block.position.z > 5) { | |
block.position.z = -5; | |
} | |
} | |
// Update camera position based on keys pressed | |
if (keysPressed.ArrowLeft) { | |
camera.position.x -= 0.1; | |
} | |
if (keysPressed.ArrowRight) { | |
camera.position.x += 0.1; | |
} | |
if (keysPressed.ArrowUp) { | |
camera.position.y += 0.1; | |
} | |
if (keysPressed.ArrowDown) { | |
camera.position.y -= 0.1; | |
} | |
renderer.render(scene, camera); | |
}; | |
animate(); | |
$(function() { | |
$('body').append(renderer.domElement); | |
// Add event listeners for keydown and keyup events | |
document.addEventListener('keydown', (event) => { | |
if (event.key in keysPressed) { | |
keysPressed[event.key] = true; | |
} | |
}); | |
document.addEventListener('keyup', (event) => { | |
if (event.key in keysPressed) { | |
keysPressed[event.key] = false; | |
} | |
}); | |
window.addEventListener("keydown", function(e) { | |
if(["Space","ArrowUp","ArrowDown","ArrowLeft","ArrowRight"].indexOf(e.code) > -1) { | |
e.preventDefault(); | |
} | |
}, false); | |
const leftArrow = document.getElementById('left-arrow'); | |
const rightArrow = document.getElementById('right-arrow'); | |
const upArrow = document.getElementById('up-arrow'); | |
const downArrow = document.getElementById('down-arrow'); | |
leftArrow.addEventListener('touchstart', () => { | |
keysPressed.ArrowLeft = true; | |
}); | |
leftArrow.addEventListener('touchend', () => { | |
keysPressed.ArrowLeft = false; | |
}); | |
leftArrow.addEventListener('mousedown', () => { | |
keysPressed.ArrowLeft = true; | |
}); | |
leftArrow.addEventListener('mouseup', () => { | |
keysPressed.ArrowLeft = false; | |
}); | |
rightArrow.addEventListener('touchstart', () => { | |
keysPressed.ArrowRight = true; | |
}); | |
rightArrow.addEventListener('touchend', () => { | |
keysPressed.ArrowRight = false; | |
}); | |
rightArrow.addEventListener('mousedown', () => { | |
keysPressed.ArrowRight = true; | |
}); | |
rightArrow.addEventListener('mouseup', () => { | |
keysPressed.ArrowRight = false; | |
}); | |
upArrow.addEventListener('touchstart', () => { | |
keysPressed.ArrowUp = true; | |
}); | |
upArrow.addEventListener('touchend', () => { | |
keysPressed.ArrowUp = false; | |
}); | |
upArrow.addEventListener('mousedown', () => { | |
keysPressed.ArrowUp = true; | |
}); | |
upArrow.addEventListener('mouseup', () => { | |
keysPressed.ArrowUp = false; | |
}); | |
downArrow.addEventListener('touchstart', () => { | |
keysPressed.ArrowDown = true; | |
}); | |
downArrow.addEventListener('touchend', () => { | |
keysPressed.ArrowDown = false; | |
}); | |
downArrow.addEventListener('mousedown', () => { | |
keysPressed.ArrowDown = true; | |
}); | |
downArrow.addEventListener('mouseup', () => { | |
keysPressed.ArrowDown = false; | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
overflow: hidden; | |
position: relative; | |
-webkit-touch-callout: none; /* iOS Safari */ | |
-webkit-user-select: none; /* Safari */ | |
-khtml-user-select: none; /* Konqueror HTML */ | |
-moz-user-select: none; /* Old versions of Firefox */ | |
-ms-user-select: none; /* Internet Explorer/Edge */ | |
user-select: none; /* Non-prefixed version, currently supported by Chrome, Opera and Firefox */ | |
} | |
#controls { | |
position: absolute; | |
bottom: 15%; | |
left: 15%; | |
z-index: 1; | |
} | |
button { | |
width: 150px; | |
height: 150px; | |
background-color: rgba(255, 255, 255, 0.1); /* change the color and opacity as desired */ | |
color: white; | |
font-size: 30px; | |
} | |
#up-arrow, #down-arrow { | |
margin-left: 70px; | |
} | |
#container { | |
position: relative; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment