I'm using Javascript and A-frame. I want to be able to get a random block from the list of blocks and I want it to move down by 1. I can't seem to get any of the blocks to appear randomly on the load current. Below is the code I created to make my tetris board but it's currently giving me slight issues.
I am getting the error
"message": "Uncaught SyntaxError: Unexpected end of input",
I'm not sure what that means?
var zigZag = document.querySelector("#zigZag");
var fork = document.querySelector("#fork");
var box = document.querySelector("#box");
var line = document.querySelector("#line");
var plane = document.querySelector("#plane");
//timer
// let hour = 0;
// let minute = 0;
// let second = 0;
// let millisecond = 0;
// let cron;
var newBlock, blocks, element, blocksOnPlane, planeBlock;
// Describe this function...
newBlock = [];
blocks = [zigZag, fork, line, box];
blocksOnPlane = [];
document.addEventListener("load", start);
function start() {
while (true) {
new Promise((res) => setTimeout(() => res(chooseBlock()), 10));
console.log(newBlock.length);
for (var element_index in newBlock) {
element = newBlock[element_index];
moveBlock(element);
plane.detectCollisionsWith(newBlock[element_index], function (
collidedObject
) {
newBlock = collidedObject;
newBlock.object3D.position.y = 0;
blocksOnPlane.unshift(planeBlock);
newBlock.shift();
});
// for (var element_index in blocksOnPlane) {
// element = blocksOnPlane[element_index];
// newBlock.detectCollisionsWith(planeBlock, function (collidedObject) {
// element.setY(element.getY() + 0)
// planeBlock = collidedObject;
// blocksOnPlane.unshift(planeBlock);
// newBlock.shift();
// })
// }
}
}
}
document.addEventListener("keydown", function (event) {
if (event.keyCode === 37) {
element.object3D.position.x += -1;
}
//top
else if (event.keyCode === 38) {
element.object3D.position.x += 1;
}
//right
else if (event.keyCode === 39) {
element.object3D.position.x += 1;
}
//bottom
else if (event.keyCode === 40) {
element.object3D.position.x += -1;
}
});
function moveBlock(element) {
document.createTimer("timer1", 1 * 1000, function () {
element.object3D.position.y += -1;
});
}
function listsGetRandomItem(list, remove) {
var x = Math.floor(Math.random() * list.length);
if (remove) {
return list.splice(x, 1)[0];
} else {
return list[x];
}
}
// Describe this function...
function chooseBlock() {
var tetrisBlock = document.clone(listsGetRandomItem(blocks, false));
tetrisBlock.visible = true;
tetrisBlock.object3D.position.x = 0;
tetrisBlock.object3D.position.y = 7.5;
tetrisBlock.object3D.position.z = -14;
newBlock.unshift(tetrisBlock);
}
<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<!DOCTYPE html>
<button type="button" name="start">start</button>
<button type="button" name="pause">pause</button>
<button type="button" name="reset">reset</button>
<a-scene>
<a-entity
id="zigZag"
collide-with-player=""
hatch-type-shape=""
data-hatch-type="hatch-type-empty"
data-icon-type="rectangle"
physics-scale-fix=""
hatch-physics=""
shadow="cast: false; receive: false"
hatch-cursor-event-detection="enableCursorDetection: true"
position="-4.0825353394644335 5.15966087923683 -17.160361366799766"
color="#d5b949"
class="clickable"
<!--
visible="true"
--
>
><a-box
id="line6"
collide-with-player=""
hatch-type-shape=""
geometry="primitive: box"
data-hatch-type="hatch-type-shape"
data-icon-type="box"
physics-scale-fix=""
hatch-physics=""
shadow=""
hatch-cursor-event-detection="enableCursorDetection: true"
position="5.039535339464433 3.3480091207631695 3.1603613667997656"
color="#f1eaa3"
material="color: #f1eaa3"
class="clickable"
scale="2 1 1"
rotation="0 0 89.99999999999999"
child-test="true"
></a-box
><a-box
id="line5"
collide-with-player=""
hatch-type-shape=""
geometry="primitive: box"
data-hatch-type="hatch-type-shape"
data-icon-type="box"
physics-scale-fix=""
hatch-physics=""
shadow=""
hatch-cursor-event-detection="enableCursorDetection: true"
position="4.137505339464433 4.44454912076317 3.1603613667997656"
color="#f1eaa3"
material="color: #f1eaa3"
class="clickable"
scale="2 1 1"
rotation="0 0 89.99999999999999"
child-test="true"
></a-box
><a-box
id="line4"
collide-with-player=""
hatch-type-shape=""
geometry="primitive: box"
data-hatch-type="hatch-type-shape"
data-icon-type="box"
physics-scale-fix=""
hatch-physics=""
shadow=""
hatch-cursor-event-detection="enableCursorDetection: true"
position="4.636015339464434 3.91959912076317 3.1603613667997656"
color="#f1eaa3"
material="color: #f1eaa3"
class="clickable"
scale="2 1 1"
rotation="0 0 0"
child-test="true"
></a-box
></a-entity>
<a-entity
id="fork"
collide-with-player=""
hatch-type-shape=""
data-hatch-type="hatch-type-empty"
data-icon-type="rectangle"
physics-scale-fix=""
hatch-physics=""
shadow="cast: false; receive: false"
hatch-cursor-event-detection="enableCursorDetection: true"
position="1.158747821160648 5.997102835551197 -14.335538215901849"
color="#617ec2"
class="clickable"
rotation="0 0 0"
scale="1 1 1"
visible="true"
><a-box
id="line3"
collide-with-player=""
hatch-type-shape=""
geometry="primitive: box"
data-hatch-type="hatch-type-shape"
data-icon-type="box"
physics-scale-fix=""
hatch-physics=""
shadow=""
hatch-cursor-event-detection="enableCursorDetection: true"
position="-1.158747821160648 1.502897164448803 0.33553821590184896"
color="#a3eaf1"
material="color: #a3eaf1"
class="clickable"
scale="3 1.0000000000000002 1"
rotation="0 0 89.99999999999999"
child-test="true"
></a-box
><a-box
id="line2"
collide-with-player=""
hatch-type-shape=""
geometry="primitive: box"
data-hatch-type="hatch-type-shape"
data-icon-type="box"
physics-scale-fix=""
hatch-physics=""
shadow=""
hatch-cursor-event-detection="enableCursorDetection: true"
position="-0.60527 1.44434 0.33554"
color="#a3edf1"
material="color: #a3edf1"
class="clickable"
scale="2 1 1"
rotation="0 0 0"
child-test="true"
></a-box
></a-entity>
<a-box
hatch-type-shape=""
data-icon-type="box"
id="box"
shadow=""
displayname="Box"
position="0 9.09 -14"
rotation="0 0 0"
color="#4CC3D9"
side="front"
hatch-physics=""
data-hatch-type="hatch-type-shape"
material="color: #4CC3D9; side: front"
geometry="primitive: box"
physics-scale-fix=""
hatch-cursor-event-detection="enableCursorDetection: true"
collide-with-player=""
class="clickable"
scale="2 2 1"
child-test="true"
visible="true"
></a-box>
<a-box
id="line"
collide-with-player=""
hatch-type-shape=""
geometry="primitive: box"
data-hatch-type="hatch-type-shape"
data-icon-type="box"
physics-scale-fix=""
hatch-physics=""
shadow=""
hatch-cursor-event-detection="enableCursorDetection: true"
position="0 7.5 -14"
color="#a3f1af"
material="color: #a3f1af"
class="clickable"
scale="4 1 1"
visible="true"
></a-box>
<a-entity
id="Ground"
ground="dressing: none; groundSize: 100; ground: flat; groundTexture: none; grid: 1x1; groundColor: #333343; flatShading: true; gridColor: #B5B5B5"
data-hatch-type="hatch-type-ground"
data-is-droppable="false"
data-icon-type="terrain"
data-is-expandable="false"
position="0 0 0"
color="#62E9F7"
visible="true"
><a-entity
class="environment"
position=""
visible=""
light=""
data-not-selectable="true"
data-hide-model="true"
data-icon-type="light-hemisphere"
></a-entity
><a-entity
class="environment"
position=""
light=""
data-hide-model="true"
visible="true"
data-icon-type="light-directional"
></a-entity
><a-entity
rotation=""
visible=""
data-not-selectable="true"
class="environmentGround environment"
scale=""
shadow=""
></a-entity
><a-entity
data-not-selectable="true"
visible=""
class="environmentDressing environment"
></a-entity
></a-entity>
<a-plane
id="plane"
collide-with-player=""
hatch-type-shape=""
geometry="primitive: plane"
data-hatch-type="hatch-type-shape"
data-icon-type="plane"
physics-scale-fix=""
hatch-physics=""
shadow=""
hatch-cursor-event-detection=""
position="-0.38406 0 -16.5359"
color="#975c26"
material="color: #975c26; shader: flat; side: back"
rotation="90 0 0"
scale="17.9 12.9 1"
visible="true"
></a-plane>
</a-scene>
Not sure where did you get document.clone(element)
as the document
object doesn't seem to have a cloning utility.
There is a element.cloneNode() method which works fine - we can use it within a custom component, which will also handle the entity lifecycle:
<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<script>
// register new component
AFRAME.registerComponent("foo", {
// on init
init: function() {
// grab the button, and the entity
const btn = document.querySelector("button")
const tmplate = document.getElementById("template")
// when clicked
btn.addEventListener("click", evt => {
// clone the node
const new_element = tmplate.cloneNode(true);
// make it smaller, and move it a bit
new_element.setAttribute("scale", "0.2 0.2 0.2")
new_element.setAttribute("position", {
x: Math.random() * 6 - 3,
y: 0.5,
z: -1
})
// append it to the scene
this.el.appendChild(new_element)
})
}
})
</script>
<button style="z-index: 9999; position: fixed;">COPY</button>
<a-scene foo>
<a-entity id="template">
<a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"></a-box>
<a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"></a-sphere>
<a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
<a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
</a-entity>
<a-sky color="#ECECEC"></a-sky>
</a-scene>
You can move it down with interval timeouts, or a tick / throttledTick handler. This could be done within a system, which would manage created entities (moving down, collisions).
A simple "moving down" version could look like this:
<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<script>
//register system
AFRAME.registerSystem("foo", {
init: function() {
// array of all registered elements
this.elements = [];
// set up the throttled version
this.tick = AFRAME.utils.throttleTick(this.tick, 250, this);
},
register: function(el) {
// push new element to the registered array
this.elements.push(el)
},
tick: function() {
// loop through all of the elements, and move them down
for (el of this.elements) {
const pos = el.object3D.position // this is more efficient than getAttribute("position")
pos.y = (pos.y < 0) ? 2 : pos.y - 0.1; // use setAttribute() if you want getAttribute() to work
}
}
})
// register new component
AFRAME.registerComponent("foo", {
// on init
init: function() {
// move it a bit, and make it visible
this.el.setAttribute("position", {
x: Math.random() * 6 - 3,
y: 0.5,
z: -2
})
this.el.setAttribute("visible", "true")
// register the element in the system
this.system.register(this.el)
}
})
AFRAME.registerComponent("inserter", {
init: function() {
// grab the button, and the entity
const btn = document.querySelector("button")
const tmplate = document.getElementById("template")
// when clicked
btn.addEventListener("click", evt => {
// clone the node
const new_element = tmplate.cloneNode(true);
new_element.setAttribute("foo", "")
// append it to the scene
this.el.appendChild(new_element)
})
}
})
</script>
<button style="z-index: 9999; position: fixed;">NEW</button>
<a-scene inserter>
<a-entity id="template" visible="false" scale="0.2 0.2 0.2">
<a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"></a-box>
<a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"></a-sphere>
<a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
<a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
</a-entity>
<a-sky color="#ECECEC"></a-sky>
</a-scene>
Sooner or later You'll probably run into performance issues (once there are several nodes) and it would be best to dive into mesh instancing (or at least check the performance guidelines)