Click on the floor to start building cubes, click on the faces of cubes to build out from each face. Delete a cube with right-click. Have fun, don't expect the best FPS :) ~ Known oddities in Firefox and Edge.
A Pen by Miguel Maldonado on CodePen.
Click on the floor to start building cubes, click on the faces of cubes to build out from each face. Delete a cube with right-click. Have fun, don't expect the best FPS :) ~ Known oddities in Firefox and Edge.
A Pen by Miguel Maldonado on CodePen.
div.controls | |
p #[strong Add cube]: Left mouse click #[br] #[strong Delete cube]: Right mouse click #[br] #[strong Rotate]: Left and right arrow keys #[br] #[strong Ascend / Descend]: Up and down arrow keys | |
div.container | |
div.floor#floor | |
//FLOOR TILES | |
- var i = 11; | |
- for (var x=0; x<=i; x++) { | |
- for (var y=0; y<=i; y++) { | |
div(class="f x" + x + " y" + y)(data-x = x*50)(data-y = y*50) | |
- } | |
- } |
(function() { | |
var c = document.getElementById('cursor'); | |
var f = document.getElementById('floor'); | |
f.addEventListener('mousedown', clickHandle, false); | |
window.addEventListener('keydown', keysdown, false); | |
window.addEventListener('keyup', keysup, false); | |
//DISABLE RIGHT CLICK MENUS | |
window.addEventListener('contextmenu', function(e) { | |
e.preventDefault(); | |
}, false); | |
function clickHandle(e) { | |
var sel = e.target; | |
var pCube = sel.parentElement; | |
//CLICK ON FLOOR TILE | |
if (e.buttons === 1) { | |
addCube(); | |
} | |
if (e.buttons === 2) { | |
deleteCube(); | |
} | |
function addCube() { | |
if (sel.classList.contains("f")) { | |
var sx = sel.dataset.x; | |
var sy = sel.dataset.y; | |
var sz = 0; | |
var newCube = { | |
obj: createCube(sx, sy, sz), | |
x: sx, | |
y: sy, | |
z: sz | |
}; | |
} | |
//CLICK ON 'UP' WALL | |
if (sel.classList.contains("u")) { | |
var sx = pCube.dataset.x; | |
var sy = pCube.dataset.y; | |
var sz = parseInt(pCube.dataset.z, 10) + 50; | |
addNewCube(sx, sy, sz); | |
} | |
//CLICK ON 'NORTH' WALL | |
if (sel.classList.contains("n")) { | |
var sx = pCube.dataset.x; | |
var sy = parseInt(pCube.dataset.y, 10) - 50; | |
var sz = pCube.dataset.z; | |
addNewCube(sx, sy, sz); | |
} | |
//CLICK ON 'SOUTH' WALL | |
if (sel.classList.contains("s")) { | |
var sx = pCube.dataset.x; | |
var sy = parseInt(pCube.dataset.y, 10) + 50; | |
var sz = pCube.dataset.z; | |
addNewCube(sx, sy, sz); | |
} | |
//CLICK ON 'EAST' WALL | |
if (sel.classList.contains("e")) { | |
var sx = parseInt(pCube.dataset.x, 10) + 50; | |
var sy = pCube.dataset.y; | |
var sz = pCube.dataset.z; | |
addNewCube(sx, sy, sz); | |
} | |
//CLICK ON 'WEST' WALL | |
if (sel.classList.contains("w")) { | |
var sx = parseInt(pCube.dataset.x, 10) - 50; | |
var sy = pCube.dataset.y; | |
var sz = pCube.dataset.z; | |
addNewCube(sx, sy, sz); | |
} | |
function addNewCube(sx, sy, sz) { | |
var newCube = { | |
obj: createCube(sx, sy, sz), | |
x: sx, | |
y: sy, | |
z: sz | |
}; | |
} | |
} | |
function deleteCube() { | |
if (pCube.parentNode === f) { | |
//remove the cube DOM element | |
pCube.parentNode.removeChild(pCube); | |
} | |
} | |
} | |
//Create a cube, add to DOM, return cube element | |
function createCube(x, y, z) { | |
var docFragment = document.createDocumentFragment(); | |
var cube = document.createElement('div'); | |
cube.setAttribute('class', 'cube'); | |
var w = [], | |
i = 0; | |
var sides = ['d', 'n', 'e', 'w', 's', 'u']; | |
while (i < 6) { | |
w[i] = document.createElement('div'); | |
w[i].setAttribute('class', 'w' + (i + 1) + ' ' + sides[i]); | |
cube.appendChild(w[i]); | |
i++; | |
} | |
cube.dataset.x = x; | |
cube.dataset.y = y; | |
cube.dataset.z = z; | |
f.appendChild(cube); | |
cube.style.left = x + 'px'; | |
cube.style.top = y + 'px'; | |
cube.style.transform = 'translateZ(' + z + 'px)'; | |
return cube; | |
} | |
var floor = { | |
rotateZ: 0, | |
translateZ: 0 | |
}; | |
var keyManager = { | |
leftArrow: false, | |
rightArrow: false, | |
upArrow: false, | |
downArrow: false | |
} | |
function keysdown(e) { | |
if (e.which === 37) { | |
keyManager.leftArrow = true; | |
} | |
if (e.which === 39) { | |
keyManager.rightArrow = true; | |
} | |
if (e.which === 38) { | |
keyManager.upArrow = true; | |
} | |
if (e.which === 40) { | |
keyManager.downArrow = true; | |
} | |
} | |
function keysup(e) { | |
keyManager.leftArrow = false; | |
keyManager.rightArrow = false; | |
keyManager.upArrow = false; | |
keyManager.downArrow = false; | |
} | |
function render() { | |
requestAnimationFrame(render); | |
if (keyManager.leftArrow) { | |
floor.rotateZ--; | |
f.style.transform = 'rotateX(70deg) rotateZ(' + floor.rotateZ + 'deg) translateZ(' + floor.translateZ + 'px)'; | |
} | |
if (keyManager.rightArrow) { | |
floor.rotateZ++; | |
f.style.transform = 'rotateX(70deg) rotateZ(' + floor.rotateZ + 'deg) translateZ(' + floor.translateZ + 'px)'; | |
} | |
if (keyManager.upArrow) { | |
floor.translateZ -= 3; | |
f.style.transform = 'rotateX(70deg) rotateZ(' + floor.rotateZ + 'deg) translateZ(' + floor.translateZ + 'px)'; | |
} | |
if (keyManager.downArrow) { | |
floor.translateZ += 3; | |
f.style.transform = 'rotateX(70deg) rotateZ(' + floor.rotateZ + 'deg) translateZ(' + floor.translateZ + 'px)'; | |
} | |
}; | |
render(); | |
})(); |
html, | |
body { | |
margin: 0; | |
padding: 0; | |
height: 100%; | |
overflow: hidden; | |
background: linear-gradient(to bottom, rgba(31, 113, 168, 1) 0%, rgba(88, 186, 232, 1) 100%); | |
} | |
.controls{ | |
font-family:sans-serif; | |
line-height:1.5; | |
position:absolute; | |
bottom:2em; | |
left:2em; | |
font-size:0.9em; | |
color:white; | |
background:rgba(0,0,0,0.5); | |
padding:1em; | |
z-index:1; | |
strong{ | |
color:yellow; | |
} | |
p{ | |
margin:0; | |
} | |
} | |
.container { | |
perspective: 800px; | |
height: 100%; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
} | |
.floor { | |
width: 600px; | |
height: 600px; | |
transform: rotateX(70deg); | |
transform-style: preserve-3d; | |
} | |
@for $x from 0 through 11 { | |
@for $y from 0 through 11 { | |
.x#{$x}.y#{$y} { | |
left: $x * 50px; | |
top: $y * 50px; | |
} | |
} | |
} | |
.f { | |
width: 50px; | |
height: 50px; | |
background: #2f3658; | |
position: absolute; | |
&:hover { | |
background: orange; | |
} | |
} | |
.w { | |
width: 50px; | |
height: 50px; | |
position: absolute; | |
box-shadow: inset 0px 0px 24px rgba(0, 0, 0, 0.53); | |
background: white; | |
&:hover { | |
box-shadow: inset 0 0 0px 4px orange; | |
} | |
} | |
.cube { | |
position: absolute; | |
transform-style: preserve-3d; | |
.w1 { | |
@extend .w; | |
} | |
.w2 { | |
@extend .w; | |
background: darken(white, 60%); | |
transform: rotateX(90deg)translateY(25px)translateZ(25px); | |
} | |
.w3 { | |
@extend .w; | |
background: darken(white, 25%); | |
transform: rotateX(90deg)rotateY(90deg)translateY(25px)translateZ(25px); | |
} | |
.w4 { | |
@extend .w; | |
background: darken(white, 40%); | |
transform: rotateX(90deg)rotateY(90deg)translateY(25px)translateZ(-25px); | |
} | |
.w5 { | |
@extend .w; | |
background: darken(white, 15%); | |
transform: rotateX(90deg)translateY(25px)translateZ(-25px); | |
} | |
.w6 { | |
@extend .w; | |
transform: translateZ(50px); | |
} | |
} | |
.c1 { | |
top: 0; | |
left: 0; | |
} | |
.c2 { | |
top: 0; | |
left: 100px; | |
} |