Skip to main content
Code Review

Return to Question

Notice removed Draw attention by Nasser Al-Shawwa
Bounty Ended with Sᴀᴍ Onᴇᴌᴀ's answer chosen by Nasser Al-Shawwa
Tweeted twitter.com/StackCodeReview/status/1032326868287070208
update tags
Link
Clarify what I'm looking for
Source Link

Here's my attempt at an Arkanoid/Breakout clone using JavaScript with ThreeJS. Let me haveThe feedback I'm looking for is more on the code side; the game itself is a work in progress. You can take it! for a spin by running the code snippet below.

(function() {
 "use strict";
 letconst paddleStates = {
 MOVING_LEFT : 0,
 MOVING_RIGHT : 1,
 STATIONARY : 2
 };
 function createMeshAtPosition(meshProperties, position) {
 let mesh = new THREE.Mesh(meshProperties.geometry, meshProperties.material);
 mesh.position.copy(position);
 return mesh;
 }
 function createFullScreenRenderer(elementId, settings) {
 let renderer = new THREE.WebGLRenderer({
 canvas: document.getElementById(elementId)
 });
 renderer.setPixelRatio(window.devicePixelRatio);
 renderer.setSize(window.innerWidth, window.innerHeight);
 renderer.setClearColor(settings.backgroundColor);
 return renderer;
 }
 function createCamera() {
 let camera = new THREE.PerspectiveCamera(
 90,
 window.innerWidth / window.innerHeight,
 0.1,
 3000);
 camera.position.set(0.0, 10.0, 0.0);
 camera.lookAt(0.0, 0.0, -10.0);
 return camera;
 }
 function makeResizeCallback(camera, renderer) {
 return function() {
 camera.aspect = window.innerWidth / window.innerHeight;
 camera.updateProjectionMatrix();
 renderer.setSize(window.innerWidth, window.innerHeight);
 };
 }
 function makeKeyDownCallback(paddle, speed) {
 return function(event) {
 if (paddle.state ===== paddleStates.STATIONARY) {
 if (event.key ===== "ArrowLeft") {
 paddle.velocity.x = -speed;
 paddle.state = paddleStates.MOVING_LEFT;
 } else if (event.key ===== "ArrowRight") {
 paddle.velocity.x = speed;
 paddle.state = paddleStates.MOVING_RIGHT;
 }
 }
 };
 }
 function makeKeyUpCallback(paddle) {
 return function(event) {
 if (paddle.state ===== paddleStates.MOVING_LEFT && event.key ===== "ArrowLeft") {
 paddle.velocity.x = 0.0;
 paddle.state = paddleStates.STATIONARY;
 } else if (paddle.state ===== paddleStates.MOVING_RIGHT && event.key ===== "ArrowRight") {
 paddle.velocity.x = 0.0;
 paddle.state = paddleStates.STATIONARY;
 }
 };
 }
 function updatePosition(gameObject) {
 gameObject.mesh.position.add(gameObject.velocity);
 }
 function resolveBallBlockCollision(ball, blockMesh, blockProperties, callback) {
 if ((ball.mesh.position.z + ball.radius > blockMesh.position.z - blockProperties.height / 2 &&
 (ball.mesh.position.z < blockMesh.position.z)) &&
 (ball.mesh.position.x > blockMesh.position.x - blockProperties.width / 2) &&
 (ball.mesh.position.x < blockMesh.position.x + blockProperties.width / 2) &&
 (ball.velocity.z > 0.0)) 
 {
 ball.velocity.z *= -1.0;
 callback();
 return true;
 }
 if ((ball.mesh.position.z - ball.radius < blockMesh.position.z + blockProperties.height / 2 &&
 (ball.mesh.position.z > blockMesh.position.z)) &&
 (ball.mesh.position.x > blockMesh.position.x - blockProperties.width / 2) &&
 (ball.mesh.position.x < blockMesh.position.x + blockProperties.width / 2) &&
 (ball.velocity.z < 0.0)) 
 {
 ball.velocity.z *= -1.0;
 callback();
 return true;
 }
 if ((ball.mesh.position.x + ball.radius > blockMesh.position.x - blockProperties.width / 2 &&
 (ball.mesh.position.x < blockMesh.position.x)) &&
 (ball.mesh.position.z > blockMesh.position.z - blockProperties.height / 2) &&
 (ball.mesh.position.z < blockMesh.position.z + blockProperties.height / 2) &&
 (ball.velocity.x > 0.0)) 
 {
 ball.velocity.x *= -1.0;
 callback();
 return true;
 }
 if ((ball.mesh.position.x - ball.radius < blockMesh.position.x + blockProperties.width / 2 &&
 (ball.mesh.position.x > blockMesh.position.x)) &&
 (ball.mesh.position.z > blockMesh.position.z - blockProperties.height / 2) &&
 (ball.mesh.position.z < blockMesh.position.z + blockProperties.height / 2) &&
 (ball.velocity.x < 0.0)) 
 {
 ball.velocity.x *= -1.0;
 callback();
 return true;
 }
 return false;
 }
 function main() {
 // Hard-coded "settings"
 let settings = {
 backgroundColor : 0x008888,
 paddleSpeed : 0.3,
 ballSpeed: 0.2
 };
 let paddle = {
 width : 4,
 height : 1,
 depth : 1,
 color : 0xffffff,
 velocity : new THREE.Vector3(0.0, 0.0, 0.0),
 state : paddleStates.STATIONARY,
 startPosition : new THREE.Vector3(0.0, 0.0, -4.0)
 };
 let ball = {
 radius : 0.5,
 color : 0xffff00,
 velocity : new THREE.Vector3(settings.ballSpeed, 0.0, -settings.ballSpeed),
 startPosition : new THREE.Vector3(0.0, 0.0, -9.0),
 segments : {
 width : 16,
 height : 16
 }
 };
 const levelBounds = {
 top : -35.0,
 right : 17.0,
 left : -17.0,
 bottom : 0.0
 };
 const bricks = {
 rows : 11,
 columns : 11,
 distanceFromEdges : 1.0,
 distanceFromTop : 13.0,
 spacing : 0.2,
 color : 0xff00ff,
 depth : 1.0
 };
 const lights = [
 new THREE.AmbientLight(0xffffff, 0.5), 
 new THREE.PointLight(0xffffff, 0.5)
 ];
 // Game
 let renderer = createFullScreenRenderer("game-window", settings);
 let scene = new THREE.Scene();
 let camera = createCamera();
 scene.add(camera);
 paddle.mesh = createMeshAtPosition({
 geometry : new THREE.BoxGeometry(paddle.width, paddle.depth, paddle.height),
 material : new THREE.MeshLambertMaterial({ color : paddle.color })
 }, paddle.startPosition);
 scene.add(paddle.mesh);
 ball.mesh = createMeshAtPosition({
 geometry : new THREE.SphereGeometry(ball.radius, ball.segments.width, ball.segments.height),
 material : new THREE.MeshLambertMaterial({ color: ball.color })
 }, ball.startPosition);
 scene.add(ball.mesh);
 lights.forEach(light => scene.add(light));
 const levelWidth = levelBounds.right - levelBounds.left;
 const brick = {
 width : (levelWidth - 2 * bricks.distanceFromEdges + bricks.spacing * (1 - bricks.columns)) / bricks.columns,
 height : (bricks.distanceFromTop - bricks.distanceFromEdges) / bricks.rows,
 depth : bricks.depth
 };
 let visibleBricks = [];
 for (let row = 0; row < bricks.rows; row += 1) {
 for (let column = 0; column < bricks.columns; column += 1) {
 let position = new THREE.Vector3(
 levelBounds.left + bricks.distanceFromEdges + column * (brick.width + bricks.spacing) + 0.5 * brick.width,
 0.0,
 levelBounds.top + bricks.distanceFromEdges + row * (brick.height + bricks.spacing) + 0.5 * brick.height);
 let mesh = createMeshAtPosition({
 geometry : new THREE.BoxGeometry(brick.width, brick.depth, brick.height),
 material : new THREE.MeshLambertMaterial({ color : bricks.color })
 }, position);
 let name = `${row},${column}`;
 mesh.name = name;
 scene.add(mesh);
 visibleBricks.push({
 position : position,
 name : name
 });
 }
 } 
 requestAnimationFrame(render);
 function render() {
 // update paddle position
 // ball-level collision
 if ((ball.mesh.position.z - ball.radius < levelBounds.top && ball.velocity.z < 0.0) ||
 (ball.mesh.position.z + ball.radius > levelBounds.bottom && ball.velocity.z > 0.0)) 
 {
 ball.velocity.z *= -1.0;
 }
 if ((ball.mesh.position.x + ball.radius > levelBounds.right && ball.velocity.x > 0.0) ||
 (ball.mesh.position.x - ball.radius < levelBounds.left && ball.velocity.x < 0.0))
 {
 ball.velocity.x *= -1.0;
 }
 resolveBallBlockCollision(ball, paddle.mesh, paddle, function() {});
 // ball-brick collision
 for (let i = 0; i < visibleBricks.length; i += 1) {
 let visibleBrick = visibleBricks[i];
 let isCollided = resolveBallBlockCollision(ball, visibleBrick, brick, function() {
 let selectedObject = scene.getObjectByName(visibleBrick.name);
 scene.remove(selectedObject);
 visibleBricks.splice(i, 1);
 });
 if (isCollided) {
 break;
 }
 }
 updatePosition(paddle);
 updatePosition(ball);
 renderer.render(scene, camera);
 requestAnimationFrame(render);
 }
 window.addEventListener("resize", makeResizeCallback(camera, renderer), false);
 window.addEventListener("keydown", makeKeyDownCallback(paddle, settings.paddleSpeed), false);
 window.addEventListener("keyup", makeKeyUpCallback(paddle), false);
 }
 window.addEventListener("load", main, false);
})();
<!DOCTYPE html>
<html>
 <head>
 <title>Arkanoid</title>
 <style>
 body {
 padding: 0px;
 margin: 0px;
 overflow: hidden;
 }
 </style>
 </head>
 <body>
 <canvas id="game-window"></canvas>
 <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/95/three.js"></script>
 </body>
</html>

Here's my attempt at an Arkanoid/Breakout clone using JavaScript with ThreeJS. Let me have it!

(function() {
 "use strict";
 let paddleStates = {
 MOVING_LEFT : 0,
 MOVING_RIGHT : 1,
 STATIONARY : 2
 };
 function createMeshAtPosition(meshProperties, position) {
 let mesh = new THREE.Mesh(meshProperties.geometry, meshProperties.material);
 mesh.position.copy(position);
 return mesh;
 }
 function createFullScreenRenderer(elementId, settings) {
 let renderer = new THREE.WebGLRenderer({
 canvas: document.getElementById(elementId)
 });
 renderer.setPixelRatio(window.devicePixelRatio);
 renderer.setSize(window.innerWidth, window.innerHeight);
 renderer.setClearColor(settings.backgroundColor);
 return renderer;
 }
 function createCamera() {
 let camera = new THREE.PerspectiveCamera(
 90,
 window.innerWidth / window.innerHeight,
 0.1,
 3000);
 camera.position.set(0.0, 10.0, 0.0);
 camera.lookAt(0.0, 0.0, -10.0);
 return camera;
 }
 function makeResizeCallback(camera, renderer) {
 return function() {
 camera.aspect = window.innerWidth / window.innerHeight;
 camera.updateProjectionMatrix();
 renderer.setSize(window.innerWidth, window.innerHeight);
 };
 }
 function makeKeyDownCallback(paddle, speed) {
 return function(event) {
 if (paddle.state == paddleStates.STATIONARY) {
 if (event.key == "ArrowLeft") {
 paddle.velocity.x = -speed;
 paddle.state = paddleStates.MOVING_LEFT;
 } else if (event.key == "ArrowRight") {
 paddle.velocity.x = speed;
 paddle.state = paddleStates.MOVING_RIGHT;
 }
 }
 };
 }
 function makeKeyUpCallback(paddle) {
 return function(event) {
 if (paddle.state == paddleStates.MOVING_LEFT && event.key == "ArrowLeft") {
 paddle.velocity.x = 0.0;
 paddle.state = paddleStates.STATIONARY;
 } else if (paddle.state == paddleStates.MOVING_RIGHT && event.key == "ArrowRight") {
 paddle.velocity.x = 0.0;
 paddle.state = paddleStates.STATIONARY;
 }
 };
 }
 function updatePosition(gameObject) {
 gameObject.mesh.position.add(gameObject.velocity);
 }
 function resolveBallBlockCollision(ball, blockMesh, blockProperties, callback) {
 if ((ball.mesh.position.z + ball.radius > blockMesh.position.z - blockProperties.height / 2 &&
 (ball.mesh.position.z < blockMesh.position.z)) &&
 (ball.mesh.position.x > blockMesh.position.x - blockProperties.width / 2) &&
 (ball.mesh.position.x < blockMesh.position.x + blockProperties.width / 2) &&
 (ball.velocity.z > 0.0)) 
 {
 ball.velocity.z *= -1.0;
 callback();
 return true;
 }
 if ((ball.mesh.position.z - ball.radius < blockMesh.position.z + blockProperties.height / 2 &&
 (ball.mesh.position.z > blockMesh.position.z)) &&
 (ball.mesh.position.x > blockMesh.position.x - blockProperties.width / 2) &&
 (ball.mesh.position.x < blockMesh.position.x + blockProperties.width / 2) &&
 (ball.velocity.z < 0.0)) 
 {
 ball.velocity.z *= -1.0;
 callback();
 return true;
 }
 if ((ball.mesh.position.x + ball.radius > blockMesh.position.x - blockProperties.width / 2 &&
 (ball.mesh.position.x < blockMesh.position.x)) &&
 (ball.mesh.position.z > blockMesh.position.z - blockProperties.height / 2) &&
 (ball.mesh.position.z < blockMesh.position.z + blockProperties.height / 2) &&
 (ball.velocity.x > 0.0)) 
 {
 ball.velocity.x *= -1.0;
 callback();
 return true;
 }
 if ((ball.mesh.position.x - ball.radius < blockMesh.position.x + blockProperties.width / 2 &&
 (ball.mesh.position.x > blockMesh.position.x)) &&
 (ball.mesh.position.z > blockMesh.position.z - blockProperties.height / 2) &&
 (ball.mesh.position.z < blockMesh.position.z + blockProperties.height / 2) &&
 (ball.velocity.x < 0.0)) 
 {
 ball.velocity.x *= -1.0;
 callback();
 return true;
 }
 return false;
 }
 function main() {
 // Hard-coded "settings"
 let settings = {
 backgroundColor : 0x008888,
 paddleSpeed : 0.3,
 ballSpeed: 0.2
 };
 let paddle = {
 width : 4,
 height : 1,
 depth : 1,
 color : 0xffffff,
 velocity : new THREE.Vector3(0.0, 0.0, 0.0),
 state : paddleStates.STATIONARY,
 startPosition : new THREE.Vector3(0.0, 0.0, -4.0)
 };
 let ball = {
 radius : 0.5,
 color : 0xffff00,
 velocity : new THREE.Vector3(settings.ballSpeed, 0.0, -settings.ballSpeed),
 startPosition : new THREE.Vector3(0.0, 0.0, -9.0),
 segments : {
 width : 16,
 height : 16
 }
 };
 const levelBounds = {
 top : -35.0,
 right : 17.0,
 left : -17.0,
 bottom : 0.0
 };
 const bricks = {
 rows : 11,
 columns : 11,
 distanceFromEdges : 1.0,
 distanceFromTop : 13.0,
 spacing : 0.2,
 color : 0xff00ff,
 depth : 1.0
 };
 const lights = [
 new THREE.AmbientLight(0xffffff, 0.5), 
 new THREE.PointLight(0xffffff, 0.5)
 ];
 // Game
 let renderer = createFullScreenRenderer("game-window", settings);
 let scene = new THREE.Scene();
 let camera = createCamera();
 scene.add(camera);
 paddle.mesh = createMeshAtPosition({
 geometry : new THREE.BoxGeometry(paddle.width, paddle.depth, paddle.height),
 material : new THREE.MeshLambertMaterial({ color : paddle.color })
 }, paddle.startPosition);
 scene.add(paddle.mesh);
 ball.mesh = createMeshAtPosition({
 geometry : new THREE.SphereGeometry(ball.radius, ball.segments.width, ball.segments.height),
 material : new THREE.MeshLambertMaterial({ color: ball.color })
 }, ball.startPosition);
 scene.add(ball.mesh);
 lights.forEach(light => scene.add(light));
 const levelWidth = levelBounds.right - levelBounds.left;
 const brick = {
 width : (levelWidth - 2 * bricks.distanceFromEdges + bricks.spacing * (1 - bricks.columns)) / bricks.columns,
 height : (bricks.distanceFromTop - bricks.distanceFromEdges) / bricks.rows,
 depth : bricks.depth
 };
 let visibleBricks = [];
 for (let row = 0; row < bricks.rows; row += 1) {
 for (let column = 0; column < bricks.columns; column += 1) {
 let position = new THREE.Vector3(
 levelBounds.left + bricks.distanceFromEdges + column * (brick.width + bricks.spacing) + 0.5 * brick.width,
 0.0,
 levelBounds.top + bricks.distanceFromEdges + row * (brick.height + bricks.spacing) + 0.5 * brick.height);
 let mesh = createMeshAtPosition({
 geometry : new THREE.BoxGeometry(brick.width, brick.depth, brick.height),
 material : new THREE.MeshLambertMaterial({ color : bricks.color })
 }, position);
 let name = `${row},${column}`;
 mesh.name = name;
 scene.add(mesh);
 visibleBricks.push({
 position : position,
 name : name
 });
 }
 } 
 requestAnimationFrame(render);
 function render() {
 // update paddle position
 // ball-level collision
 if ((ball.mesh.position.z - ball.radius < levelBounds.top && ball.velocity.z < 0.0) ||
 (ball.mesh.position.z + ball.radius > levelBounds.bottom && ball.velocity.z > 0.0)) 
 {
 ball.velocity.z *= -1.0;
 }
 if ((ball.mesh.position.x + ball.radius > levelBounds.right && ball.velocity.x > 0.0) ||
 (ball.mesh.position.x - ball.radius < levelBounds.left && ball.velocity.x < 0.0))
 {
 ball.velocity.x *= -1.0;
 }
 resolveBallBlockCollision(ball, paddle.mesh, paddle, function() {});
 // ball-brick collision
 for (let i = 0; i < visibleBricks.length; i += 1) {
 let visibleBrick = visibleBricks[i];
 let isCollided = resolveBallBlockCollision(ball, visibleBrick, brick, function() {
 let selectedObject = scene.getObjectByName(visibleBrick.name);
 scene.remove(selectedObject);
 visibleBricks.splice(i, 1);
 });
 if (isCollided) {
 break;
 }
 }
 updatePosition(paddle);
 updatePosition(ball);
 renderer.render(scene, camera);
 requestAnimationFrame(render);
 }
 window.addEventListener("resize", makeResizeCallback(camera, renderer), false);
 window.addEventListener("keydown", makeKeyDownCallback(paddle, settings.paddleSpeed), false);
 window.addEventListener("keyup", makeKeyUpCallback(paddle), false);
 }
 window.addEventListener("load", main, false);
})();
<!DOCTYPE html>
<html>
 <head>
 <title>Arkanoid</title>
 <style>
 body {
 padding: 0px;
 margin: 0px;
 overflow: hidden;
 }
 </style>
 </head>
 <body>
 <canvas id="game-window"></canvas>
 <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/95/three.js"></script>
 </body>
</html>

Here's my attempt at an Arkanoid/Breakout clone using JavaScript with ThreeJS. The feedback I'm looking for is more on the code side; the game itself is a work in progress. You can take it for a spin by running the code snippet below.

(function() {
 "use strict";
 const paddleStates = {
 MOVING_LEFT : 0,
 MOVING_RIGHT : 1,
 STATIONARY : 2
 };
 function createMeshAtPosition(meshProperties, position) {
 let mesh = new THREE.Mesh(meshProperties.geometry, meshProperties.material);
 mesh.position.copy(position);
 return mesh;
 }
 function createFullScreenRenderer(elementId, settings) {
 let renderer = new THREE.WebGLRenderer({
 canvas: document.getElementById(elementId)
 });
 renderer.setPixelRatio(window.devicePixelRatio);
 renderer.setSize(window.innerWidth, window.innerHeight);
 renderer.setClearColor(settings.backgroundColor);
 return renderer;
 }
 function createCamera() {
 let camera = new THREE.PerspectiveCamera(
 90,
 window.innerWidth / window.innerHeight,
 0.1,
 3000);
 camera.position.set(0.0, 10.0, 0.0);
 camera.lookAt(0.0, 0.0, -10.0);
 return camera;
 }
 function makeResizeCallback(camera, renderer) {
 return function() {
 camera.aspect = window.innerWidth / window.innerHeight;
 camera.updateProjectionMatrix();
 renderer.setSize(window.innerWidth, window.innerHeight);
 };
 }
 function makeKeyDownCallback(paddle, speed) {
 return function(event) {
 if (paddle.state === paddleStates.STATIONARY) {
 if (event.key === "ArrowLeft") {
 paddle.velocity.x = -speed;
 paddle.state = paddleStates.MOVING_LEFT;
 } else if (event.key === "ArrowRight") {
 paddle.velocity.x = speed;
 paddle.state = paddleStates.MOVING_RIGHT;
 }
 }
 };
 }
 function makeKeyUpCallback(paddle) {
 return function(event) {
 if (paddle.state === paddleStates.MOVING_LEFT && event.key === "ArrowLeft") {
 paddle.velocity.x = 0.0;
 paddle.state = paddleStates.STATIONARY;
 } else if (paddle.state === paddleStates.MOVING_RIGHT && event.key === "ArrowRight") {
 paddle.velocity.x = 0.0;
 paddle.state = paddleStates.STATIONARY;
 }
 };
 }
 function updatePosition(gameObject) {
 gameObject.mesh.position.add(gameObject.velocity);
 }
 function resolveBallBlockCollision(ball, blockMesh, blockProperties, callback) {
 if ((ball.mesh.position.z + ball.radius > blockMesh.position.z - blockProperties.height / 2 &&
 (ball.mesh.position.z < blockMesh.position.z)) &&
 (ball.mesh.position.x > blockMesh.position.x - blockProperties.width / 2) &&
 (ball.mesh.position.x < blockMesh.position.x + blockProperties.width / 2) &&
 (ball.velocity.z > 0.0)) 
 {
 ball.velocity.z *= -1.0;
 callback();
 return true;
 }
 if ((ball.mesh.position.z - ball.radius < blockMesh.position.z + blockProperties.height / 2 &&
 (ball.mesh.position.z > blockMesh.position.z)) &&
 (ball.mesh.position.x > blockMesh.position.x - blockProperties.width / 2) &&
 (ball.mesh.position.x < blockMesh.position.x + blockProperties.width / 2) &&
 (ball.velocity.z < 0.0)) 
 {
 ball.velocity.z *= -1.0;
 callback();
 return true;
 }
 if ((ball.mesh.position.x + ball.radius > blockMesh.position.x - blockProperties.width / 2 &&
 (ball.mesh.position.x < blockMesh.position.x)) &&
 (ball.mesh.position.z > blockMesh.position.z - blockProperties.height / 2) &&
 (ball.mesh.position.z < blockMesh.position.z + blockProperties.height / 2) &&
 (ball.velocity.x > 0.0)) 
 {
 ball.velocity.x *= -1.0;
 callback();
 return true;
 }
 if ((ball.mesh.position.x - ball.radius < blockMesh.position.x + blockProperties.width / 2 &&
 (ball.mesh.position.x > blockMesh.position.x)) &&
 (ball.mesh.position.z > blockMesh.position.z - blockProperties.height / 2) &&
 (ball.mesh.position.z < blockMesh.position.z + blockProperties.height / 2) &&
 (ball.velocity.x < 0.0)) 
 {
 ball.velocity.x *= -1.0;
 callback();
 return true;
 }
 return false;
 }
 function main() {
 // Hard-coded "settings"
 let settings = {
 backgroundColor : 0x008888,
 paddleSpeed : 0.3,
 ballSpeed: 0.2
 };
 let paddle = {
 width : 4,
 height : 1,
 depth : 1,
 color : 0xffffff,
 velocity : new THREE.Vector3(0.0, 0.0, 0.0),
 state : paddleStates.STATIONARY,
 startPosition : new THREE.Vector3(0.0, 0.0, -4.0)
 };
 let ball = {
 radius : 0.5,
 color : 0xffff00,
 velocity : new THREE.Vector3(settings.ballSpeed, 0.0, -settings.ballSpeed),
 startPosition : new THREE.Vector3(0.0, 0.0, -9.0),
 segments : {
 width : 16,
 height : 16
 }
 };
 const levelBounds = {
 top : -35.0,
 right : 17.0,
 left : -17.0,
 bottom : 0.0
 };
 const bricks = {
 rows : 11,
 columns : 11,
 distanceFromEdges : 1.0,
 distanceFromTop : 13.0,
 spacing : 0.2,
 color : 0xff00ff,
 depth : 1.0
 };
 const lights = [
 new THREE.AmbientLight(0xffffff, 0.5), 
 new THREE.PointLight(0xffffff, 0.5)
 ];
 // Game
 let renderer = createFullScreenRenderer("game-window", settings);
 let scene = new THREE.Scene();
 let camera = createCamera();
 scene.add(camera);
 paddle.mesh = createMeshAtPosition({
 geometry : new THREE.BoxGeometry(paddle.width, paddle.depth, paddle.height),
 material : new THREE.MeshLambertMaterial({ color : paddle.color })
 }, paddle.startPosition);
 scene.add(paddle.mesh);
 ball.mesh = createMeshAtPosition({
 geometry : new THREE.SphereGeometry(ball.radius, ball.segments.width, ball.segments.height),
 material : new THREE.MeshLambertMaterial({ color: ball.color })
 }, ball.startPosition);
 scene.add(ball.mesh);
 lights.forEach(light => scene.add(light));
 const levelWidth = levelBounds.right - levelBounds.left;
 const brick = {
 width : (levelWidth - 2 * bricks.distanceFromEdges + bricks.spacing * (1 - bricks.columns)) / bricks.columns,
 height : (bricks.distanceFromTop - bricks.distanceFromEdges) / bricks.rows,
 depth : bricks.depth
 };
 let visibleBricks = [];
 for (let row = 0; row < bricks.rows; row += 1) {
 for (let column = 0; column < bricks.columns; column += 1) {
 let position = new THREE.Vector3(
 levelBounds.left + bricks.distanceFromEdges + column * (brick.width + bricks.spacing) + 0.5 * brick.width,
 0.0,
 levelBounds.top + bricks.distanceFromEdges + row * (brick.height + bricks.spacing) + 0.5 * brick.height);
 let mesh = createMeshAtPosition({
 geometry : new THREE.BoxGeometry(brick.width, brick.depth, brick.height),
 material : new THREE.MeshLambertMaterial({ color : bricks.color })
 }, position);
 let name = `${row},${column}`;
 mesh.name = name;
 scene.add(mesh);
 visibleBricks.push({
 position : position,
 name : name
 });
 }
 } 
 requestAnimationFrame(render);
 function render() {
 // update paddle position
 // ball-level collision
 if ((ball.mesh.position.z - ball.radius < levelBounds.top && ball.velocity.z < 0.0) ||
 (ball.mesh.position.z + ball.radius > levelBounds.bottom && ball.velocity.z > 0.0)) 
 {
 ball.velocity.z *= -1.0;
 }
 if ((ball.mesh.position.x + ball.radius > levelBounds.right && ball.velocity.x > 0.0) ||
 (ball.mesh.position.x - ball.radius < levelBounds.left && ball.velocity.x < 0.0))
 {
 ball.velocity.x *= -1.0;
 }
 resolveBallBlockCollision(ball, paddle.mesh, paddle, function() {});
 // ball-brick collision
 for (let i = 0; i < visibleBricks.length; i += 1) {
 let visibleBrick = visibleBricks[i];
 let isCollided = resolveBallBlockCollision(ball, visibleBrick, brick, function() {
 let selectedObject = scene.getObjectByName(visibleBrick.name);
 scene.remove(selectedObject);
 visibleBricks.splice(i, 1);
 });
 if (isCollided) {
 break;
 }
 }
 updatePosition(paddle);
 updatePosition(ball);
 renderer.render(scene, camera);
 requestAnimationFrame(render);
 }
 window.addEventListener("resize", makeResizeCallback(camera, renderer), false);
 window.addEventListener("keydown", makeKeyDownCallback(paddle, settings.paddleSpeed), false);
 window.addEventListener("keyup", makeKeyUpCallback(paddle), false);
 }
 window.addEventListener("load", main, false);
})();
<!DOCTYPE html>
<html>
 <head>
 <title>Arkanoid</title>
 <style>
 body {
 padding: 0px;
 margin: 0px;
 overflow: hidden;
 }
 </style>
 </head>
 <body>
 <canvas id="game-window"></canvas>
 <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/95/three.js"></script>
 </body>
</html>
Notice added Draw attention by Nasser Al-Shawwa
Bounty Started worth 100 reputation by Nasser Al-Shawwa
Refactor into code snippet
Source Link
<!DOCTYPE html>
<html>
 <head>
 <title>Arkanoid</title>
 <style>
 body {
 padding: 0px;
 margin: 0px;
 overflow: hidden;
 }
 </style>
 </head>
 <body>
 <canvas id="game-window"></canvas>
 <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/95/three.js"></script>
 <script>
 (function() {
 "use strict";
 
 let paddleStates = {
 MOVING_LEFT : 0,
 MOVING_RIGHT : 1,
 STATIONARY : 2
 };
 function createMeshAtPosition(meshProperties, position) {
 let mesh = new THREE.Mesh(meshProperties.geometry, meshProperties.material);
 mesh.position.copy(position);
 return mesh;
 }
 function createFullScreenRenderer(elementId, settings) {
 let renderer = new THREE.WebGLRenderer({
 canvas: document.getElementById(elementId)
 });
 renderer.setPixelRatio(window.devicePixelRatio);
 renderer.setSize(window.innerWidth, window.innerHeight);
 renderer.setClearColor(settings.backgroundColor);
 return renderer;
 }
 function createCamera() {
 let camera = new THREE.PerspectiveCamera(
 90,
 window.innerWidth / window.innerHeight,
 0.1,
 3000);
 camera.position.set(0.0, 10.0, 0.0);
 camera.lookAt(0.0, 0.0, -10.0);
 return camera;
 }
 function makeResizeCallback(camera, renderer) {
 return function() {
 camera.aspect = window.innerWidth / window.innerHeight;
 camera.updateProjectionMatrix();
 renderer.setSize(window.innerWidth, window.innerHeight);
 };
 }
 function makeKeyDownCallback(paddle, speed) {
 return function(event) {
 if (paddle.state == paddleStates.STATIONARY) {
 if (event.key == "ArrowLeft") {
 paddle.velocity.x = -speed;
 paddle.state = paddleStates.MOVING_LEFT;
 } else if (event.key == "ArrowRight") {
 paddle.velocity.x = speed;
 paddle.state = paddleStates.MOVING_RIGHT;
 }
 }
 };
 }
 function makeKeyUpCallback(paddle) {
 return function(event) {
 if (paddle.state == paddleStates.MOVING_LEFT && event.key == "ArrowLeft") {
 paddle.velocity.x = 0.0;
 paddle.state = paddleStates.STATIONARY;
 } else if (paddle.state == paddleStates.MOVING_RIGHT && event.key == "ArrowRight") {
 paddle.velocity.x = 0.0;
 paddle.state = paddleStates.STATIONARY;
 }
 };
 }
 function updatePosition(gameObject) {
 gameObject.mesh.position.add(gameObject.velocity);
 }
 function resolveBallBlockCollision(ball, blockMesh, blockProperties, callback) {
 if ((ball.mesh.position.z + ball.radius > blockMesh.position.z - blockProperties.height / 2 &&
 (ball.mesh.position.z < blockMesh.position.z)) &&
 (ball.mesh.position.x > blockMesh.position.x - blockProperties.width / 2) &&
 (ball.mesh.position.x < blockMesh.position.x + blockProperties.width / 2) &&
 (ball.velocity.z > 0.0)) 
 {
 ball.velocity.z *= -1.0;
 callback();
 return true;
 }
 if ((ball.mesh.position.z - ball.radius < blockMesh.position.z + blockProperties.height / 2 &&
 (ball.mesh.position.z > blockMesh.position.z)) &&
 (ball.mesh.position.x > blockMesh.position.x - blockProperties.width / 2) &&
 (ball.mesh.position.x < blockMesh.position.x + blockProperties.width / 2) &&
 (ball.velocity.z < 0.0)) 
 {
 ball.velocity.z *= -1.0;
 callback();
 return true;
 }
 if ((ball.mesh.position.x + ball.radius > blockMesh.position.x - blockProperties.width / 2 &&
 (ball.mesh.position.x < blockMesh.position.x)) &&
 (ball.mesh.position.z > blockMesh.position.z - blockProperties.height / 2) &&
 (ball.mesh.position.z < blockMesh.position.z + blockProperties.height / 2) &&
 (ball.velocity.x > 0.0)) 
 {
 ball.velocity.x *= -1.0;
 callback();
 return true;
 }
 if ((ball.mesh.position.x - ball.radius < blockMesh.position.x + blockProperties.width / 2 &&
 (ball.mesh.position.x > blockMesh.position.x)) &&
 (ball.mesh.position.z > blockMesh.position.z - blockProperties.height / 2) &&
 (ball.mesh.position.z < blockMesh.position.z + blockProperties.height / 2) &&
 (ball.velocity.x < 0.0)) 
 {
 ball.velocity.x *= -1.0;
 callback();
 return true;
 }
 return false;
 }
 function main() {
 // Hard-coded "settings"
 let settings = {
 backgroundColor : 0x008888,
 paddleSpeed : 0.3,
 ballSpeed: 0.2
 };
 let paddle = {
 width : 4,
 height : 1,
 depth : 1,
 color : 0xffffff,
 velocity : new THREE.Vector3(0.0, 0.0, 0.0),
 state : paddleStates.STATIONARY,
 startPosition : new THREE.Vector3(0.0, 0.0, -4.0)
 };
 let ball = {
 radius : 0.5,
 color : 0xffff00,
 velocity : new THREE.Vector3(settings.ballSpeed, 0.0, -settings.ballSpeed),
 startPosition : new THREE.Vector3(0.0, 0.0, -9.0),
 segments : {
 width : 16,
 height : 16
 }
 };
 const levelBounds = {
 top : -35.0,
 right : 17.0,
 left : -17.0,
 bottom : 0.0
 };
 const bricks = {
 rows : 11,
 columns : 11,
 distanceFromEdges : 1.0,
 distanceFromTop : 13.0,
 spacing : 0.2,
 color : 0xff00ff,
 depth : 1.0
 };
 
 const lights = [
 new THREE.AmbientLight(0xffffff, 0.5), 
 new THREE.PointLight(0xffffff, 0.5)
 ];
 // Game
 let renderer = createFullScreenRenderer("game-window", settings);
 
 let scene = new THREE.Scene();
 let camera = createCamera();
 scene.add(camera);
 
 paddle.mesh = createMeshAtPosition({
 geometry : new THREE.BoxGeometry(paddle.width, paddle.depth, paddle.height),
 material : new THREE.MeshLambertMaterial({ color : paddle.color })
 }, paddle.startPosition);
 scene.add(paddle.mesh);
 ball.mesh = createMeshAtPosition({
 geometry : new THREE.SphereGeometry(ball.radius, ball.segments.width, ball.segments.height),
 material : new THREE.MeshLambertMaterial({ color: ball.color })
 }, ball.startPosition);
 scene.add(ball.mesh);
 lights.forEach(light => scene.add(light));
 const levelWidth = levelBounds.right - levelBounds.left;
 const brick = {
 width : (levelWidth - 2 * bricks.distanceFromEdges + bricks.spacing * (1 - bricks.columns)) / bricks.columns,
 height : (bricks.distanceFromTop - bricks.distanceFromEdges) / bricks.rows,
 depth : bricks.depth
 };
 
 let visibleBricks = [];
 for (let row = 0; row < bricks.rows; row += 1) {
 for (let column = 0; column < bricks.columns; column += 1) {
 let position = new THREE.Vector3(
 levelBounds.left + bricks.distanceFromEdges + column * (brick.width + bricks.spacing) + 0.5 * brick.width,
 0.0,
 levelBounds.top + bricks.distanceFromEdges + row * (brick.height + bricks.spacing) + 0.5 * brick.height);
 let mesh = createMeshAtPosition({
 geometry : new THREE.BoxGeometry(brick.width, brick.depth, brick.height),
 material : new THREE.MeshLambertMaterial({ color : bricks.color })
 }, position);
 let name = `${row},${column}`;
 mesh.name = name;
 scene.add(mesh);
 visibleBricks.push({
 position : position,
 name : name
 });
 }
 } 
 requestAnimationFrame(render);
 function render() {
 // update paddle position
 // ball-level collision
 if ((ball.mesh.position.z - ball.radius < levelBounds.top && ball.velocity.z < 0.0) ||
 (ball.mesh.position.z + ball.radius > levelBounds.bottom && ball.velocity.z > 0.0)) 
 {
 ball.velocity.z *= -1.0;
 }
 if ((ball.mesh.position.x + ball.radius > levelBounds.right && ball.velocity.x > 0.0) ||
 (ball.mesh.position.x - ball.radius < levelBounds.left && ball.velocity.x < 0.0))
 {
 ball.velocity.x *= -1.0;
 }
 resolveBallBlockCollision(ball, paddle.mesh, paddle, function() {});
 // ball-brick collision
 for (let i = 0; i < visibleBricks.length; i += 1) {
 let visibleBrick = visibleBricks[i];
 let isCollided = resolveBallBlockCollision(ball, visibleBrick, brick, function() {
 let selectedObject = scene.getObjectByName(visibleBrick.name);
 scene.remove(selectedObject);
 visibleBricks.splice(i, 1);
 });
 if (isCollided) {
 break;
 }
 }
 updatePosition(paddle);
 updatePosition(ball);
 renderer.render(scene, camera);
 requestAnimationFrame(render);
 }
 
 window.addEventListener("resize", makeResizeCallback(camera, renderer), false);
 window.addEventListener("keydown", makeKeyDownCallback(paddle, settings.paddleSpeed), false);
 window.addEventListener("keyup", makeKeyUpCallback(paddle), false);
 }
 window.addEventListener("load", main, false);
 })();
 </script>
 </body>
</html>

(function() {
 "use strict";
 let paddleStates = {
 MOVING_LEFT : 0,
 MOVING_RIGHT : 1,
 STATIONARY : 2
 };
 function createMeshAtPosition(meshProperties, position) {
 let mesh = new THREE.Mesh(meshProperties.geometry, meshProperties.material);
 mesh.position.copy(position);
 return mesh;
 }
 function createFullScreenRenderer(elementId, settings) {
 let renderer = new THREE.WebGLRenderer({
 canvas: document.getElementById(elementId)
 });
 renderer.setPixelRatio(window.devicePixelRatio);
 renderer.setSize(window.innerWidth, window.innerHeight);
 renderer.setClearColor(settings.backgroundColor);
 return renderer;
 }
 function createCamera() {
 let camera = new THREE.PerspectiveCamera(
 90,
 window.innerWidth / window.innerHeight,
 0.1,
 3000);
 camera.position.set(0.0, 10.0, 0.0);
 camera.lookAt(0.0, 0.0, -10.0);
 return camera;
 }
 function makeResizeCallback(camera, renderer) {
 return function() {
 camera.aspect = window.innerWidth / window.innerHeight;
 camera.updateProjectionMatrix();
 renderer.setSize(window.innerWidth, window.innerHeight);
 };
 }
 function makeKeyDownCallback(paddle, speed) {
 return function(event) {
 if (paddle.state == paddleStates.STATIONARY) {
 if (event.key == "ArrowLeft") {
 paddle.velocity.x = -speed;
 paddle.state = paddleStates.MOVING_LEFT;
 } else if (event.key == "ArrowRight") {
 paddle.velocity.x = speed;
 paddle.state = paddleStates.MOVING_RIGHT;
 }
 }
 };
 }
 function makeKeyUpCallback(paddle) {
 return function(event) {
 if (paddle.state == paddleStates.MOVING_LEFT && event.key == "ArrowLeft") {
 paddle.velocity.x = 0.0;
 paddle.state = paddleStates.STATIONARY;
 } else if (paddle.state == paddleStates.MOVING_RIGHT && event.key == "ArrowRight") {
 paddle.velocity.x = 0.0;
 paddle.state = paddleStates.STATIONARY;
 }
 };
 }
 function updatePosition(gameObject) {
 gameObject.mesh.position.add(gameObject.velocity);
 }
 function resolveBallBlockCollision(ball, blockMesh, blockProperties, callback) {
 if ((ball.mesh.position.z + ball.radius > blockMesh.position.z - blockProperties.height / 2 &&
 (ball.mesh.position.z < blockMesh.position.z)) &&
 (ball.mesh.position.x > blockMesh.position.x - blockProperties.width / 2) &&
 (ball.mesh.position.x < blockMesh.position.x + blockProperties.width / 2) &&
 (ball.velocity.z > 0.0)) 
 {
 ball.velocity.z *= -1.0;
 callback();
 return true;
 }
 if ((ball.mesh.position.z - ball.radius < blockMesh.position.z + blockProperties.height / 2 &&
 (ball.mesh.position.z > blockMesh.position.z)) &&
 (ball.mesh.position.x > blockMesh.position.x - blockProperties.width / 2) &&
 (ball.mesh.position.x < blockMesh.position.x + blockProperties.width / 2) &&
 (ball.velocity.z < 0.0)) 
 {
 ball.velocity.z *= -1.0;
 callback();
 return true;
 }
 if ((ball.mesh.position.x + ball.radius > blockMesh.position.x - blockProperties.width / 2 &&
 (ball.mesh.position.x < blockMesh.position.x)) &&
 (ball.mesh.position.z > blockMesh.position.z - blockProperties.height / 2) &&
 (ball.mesh.position.z < blockMesh.position.z + blockProperties.height / 2) &&
 (ball.velocity.x > 0.0)) 
 {
 ball.velocity.x *= -1.0;
 callback();
 return true;
 }
 if ((ball.mesh.position.x - ball.radius < blockMesh.position.x + blockProperties.width / 2 &&
 (ball.mesh.position.x > blockMesh.position.x)) &&
 (ball.mesh.position.z > blockMesh.position.z - blockProperties.height / 2) &&
 (ball.mesh.position.z < blockMesh.position.z + blockProperties.height / 2) &&
 (ball.velocity.x < 0.0)) 
 {
 ball.velocity.x *= -1.0;
 callback();
 return true;
 }
 return false;
 }
 function main() {
 // Hard-coded "settings"
 let settings = {
 backgroundColor : 0x008888,
 paddleSpeed : 0.3,
 ballSpeed: 0.2
 };
 let paddle = {
 width : 4,
 height : 1,
 depth : 1,
 color : 0xffffff,
 velocity : new THREE.Vector3(0.0, 0.0, 0.0),
 state : paddleStates.STATIONARY,
 startPosition : new THREE.Vector3(0.0, 0.0, -4.0)
 };
 let ball = {
 radius : 0.5,
 color : 0xffff00,
 velocity : new THREE.Vector3(settings.ballSpeed, 0.0, -settings.ballSpeed),
 startPosition : new THREE.Vector3(0.0, 0.0, -9.0),
 segments : {
 width : 16,
 height : 16
 }
 };
 const levelBounds = {
 top : -35.0,
 right : 17.0,
 left : -17.0,
 bottom : 0.0
 };
 const bricks = {
 rows : 11,
 columns : 11,
 distanceFromEdges : 1.0,
 distanceFromTop : 13.0,
 spacing : 0.2,
 color : 0xff00ff,
 depth : 1.0
 };
 const lights = [
 new THREE.AmbientLight(0xffffff, 0.5), 
 new THREE.PointLight(0xffffff, 0.5)
 ];
 // Game
 let renderer = createFullScreenRenderer("game-window", settings);
 let scene = new THREE.Scene();
 let camera = createCamera();
 scene.add(camera);
 paddle.mesh = createMeshAtPosition({
 geometry : new THREE.BoxGeometry(paddle.width, paddle.depth, paddle.height),
 material : new THREE.MeshLambertMaterial({ color : paddle.color })
 }, paddle.startPosition);
 scene.add(paddle.mesh);
 ball.mesh = createMeshAtPosition({
 geometry : new THREE.SphereGeometry(ball.radius, ball.segments.width, ball.segments.height),
 material : new THREE.MeshLambertMaterial({ color: ball.color })
 }, ball.startPosition);
 scene.add(ball.mesh);
 lights.forEach(light => scene.add(light));
 const levelWidth = levelBounds.right - levelBounds.left;
 const brick = {
 width : (levelWidth - 2 * bricks.distanceFromEdges + bricks.spacing * (1 - bricks.columns)) / bricks.columns,
 height : (bricks.distanceFromTop - bricks.distanceFromEdges) / bricks.rows,
 depth : bricks.depth
 };
 let visibleBricks = [];
 for (let row = 0; row < bricks.rows; row += 1) {
 for (let column = 0; column < bricks.columns; column += 1) {
 let position = new THREE.Vector3(
 levelBounds.left + bricks.distanceFromEdges + column * (brick.width + bricks.spacing) + 0.5 * brick.width,
 0.0,
 levelBounds.top + bricks.distanceFromEdges + row * (brick.height + bricks.spacing) + 0.5 * brick.height);
 let mesh = createMeshAtPosition({
 geometry : new THREE.BoxGeometry(brick.width, brick.depth, brick.height),
 material : new THREE.MeshLambertMaterial({ color : bricks.color })
 }, position);
 let name = `${row},${column}`;
 mesh.name = name;
 scene.add(mesh);
 visibleBricks.push({
 position : position,
 name : name
 });
 }
 } 
 requestAnimationFrame(render);
 function render() {
 // update paddle position
 // ball-level collision
 if ((ball.mesh.position.z - ball.radius < levelBounds.top && ball.velocity.z < 0.0) ||
 (ball.mesh.position.z + ball.radius > levelBounds.bottom && ball.velocity.z > 0.0)) 
 {
 ball.velocity.z *= -1.0;
 }
 if ((ball.mesh.position.x + ball.radius > levelBounds.right && ball.velocity.x > 0.0) ||
 (ball.mesh.position.x - ball.radius < levelBounds.left && ball.velocity.x < 0.0))
 {
 ball.velocity.x *= -1.0;
 }
 resolveBallBlockCollision(ball, paddle.mesh, paddle, function() {});
 // ball-brick collision
 for (let i = 0; i < visibleBricks.length; i += 1) {
 let visibleBrick = visibleBricks[i];
 let isCollided = resolveBallBlockCollision(ball, visibleBrick, brick, function() {
 let selectedObject = scene.getObjectByName(visibleBrick.name);
 scene.remove(selectedObject);
 visibleBricks.splice(i, 1);
 });
 if (isCollided) {
 break;
 }
 }
 updatePosition(paddle);
 updatePosition(ball);
 renderer.render(scene, camera);
 requestAnimationFrame(render);
 }
 window.addEventListener("resize", makeResizeCallback(camera, renderer), false);
 window.addEventListener("keydown", makeKeyDownCallback(paddle, settings.paddleSpeed), false);
 window.addEventListener("keyup", makeKeyUpCallback(paddle), false);
 }
 window.addEventListener("load", main, false);
})();
<!DOCTYPE html>
<html>
 <head>
 <title>Arkanoid</title>
 <style>
 body {
 padding: 0px;
 margin: 0px;
 overflow: hidden;
 }
 </style>
 </head>
 <body>
 <canvas id="game-window"></canvas>
 <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/95/three.js"></script>
 </body>
</html>

<!DOCTYPE html>
<html>
 <head>
 <title>Arkanoid</title>
 <style>
 body {
 padding: 0px;
 margin: 0px;
 overflow: hidden;
 }
 </style>
 </head>
 <body>
 <canvas id="game-window"></canvas>
 <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/95/three.js"></script>
 <script>
 (function() {
 "use strict";
 
 let paddleStates = {
 MOVING_LEFT : 0,
 MOVING_RIGHT : 1,
 STATIONARY : 2
 };
 function createMeshAtPosition(meshProperties, position) {
 let mesh = new THREE.Mesh(meshProperties.geometry, meshProperties.material);
 mesh.position.copy(position);
 return mesh;
 }
 function createFullScreenRenderer(elementId, settings) {
 let renderer = new THREE.WebGLRenderer({
 canvas: document.getElementById(elementId)
 });
 renderer.setPixelRatio(window.devicePixelRatio);
 renderer.setSize(window.innerWidth, window.innerHeight);
 renderer.setClearColor(settings.backgroundColor);
 return renderer;
 }
 function createCamera() {
 let camera = new THREE.PerspectiveCamera(
 90,
 window.innerWidth / window.innerHeight,
 0.1,
 3000);
 camera.position.set(0.0, 10.0, 0.0);
 camera.lookAt(0.0, 0.0, -10.0);
 return camera;
 }
 function makeResizeCallback(camera, renderer) {
 return function() {
 camera.aspect = window.innerWidth / window.innerHeight;
 camera.updateProjectionMatrix();
 renderer.setSize(window.innerWidth, window.innerHeight);
 };
 }
 function makeKeyDownCallback(paddle, speed) {
 return function(event) {
 if (paddle.state == paddleStates.STATIONARY) {
 if (event.key == "ArrowLeft") {
 paddle.velocity.x = -speed;
 paddle.state = paddleStates.MOVING_LEFT;
 } else if (event.key == "ArrowRight") {
 paddle.velocity.x = speed;
 paddle.state = paddleStates.MOVING_RIGHT;
 }
 }
 };
 }
 function makeKeyUpCallback(paddle) {
 return function(event) {
 if (paddle.state == paddleStates.MOVING_LEFT && event.key == "ArrowLeft") {
 paddle.velocity.x = 0.0;
 paddle.state = paddleStates.STATIONARY;
 } else if (paddle.state == paddleStates.MOVING_RIGHT && event.key == "ArrowRight") {
 paddle.velocity.x = 0.0;
 paddle.state = paddleStates.STATIONARY;
 }
 };
 }
 function updatePosition(gameObject) {
 gameObject.mesh.position.add(gameObject.velocity);
 }
 function resolveBallBlockCollision(ball, blockMesh, blockProperties, callback) {
 if ((ball.mesh.position.z + ball.radius > blockMesh.position.z - blockProperties.height / 2 &&
 (ball.mesh.position.z < blockMesh.position.z)) &&
 (ball.mesh.position.x > blockMesh.position.x - blockProperties.width / 2) &&
 (ball.mesh.position.x < blockMesh.position.x + blockProperties.width / 2) &&
 (ball.velocity.z > 0.0)) 
 {
 ball.velocity.z *= -1.0;
 callback();
 return true;
 }
 if ((ball.mesh.position.z - ball.radius < blockMesh.position.z + blockProperties.height / 2 &&
 (ball.mesh.position.z > blockMesh.position.z)) &&
 (ball.mesh.position.x > blockMesh.position.x - blockProperties.width / 2) &&
 (ball.mesh.position.x < blockMesh.position.x + blockProperties.width / 2) &&
 (ball.velocity.z < 0.0)) 
 {
 ball.velocity.z *= -1.0;
 callback();
 return true;
 }
 if ((ball.mesh.position.x + ball.radius > blockMesh.position.x - blockProperties.width / 2 &&
 (ball.mesh.position.x < blockMesh.position.x)) &&
 (ball.mesh.position.z > blockMesh.position.z - blockProperties.height / 2) &&
 (ball.mesh.position.z < blockMesh.position.z + blockProperties.height / 2) &&
 (ball.velocity.x > 0.0)) 
 {
 ball.velocity.x *= -1.0;
 callback();
 return true;
 }
 if ((ball.mesh.position.x - ball.radius < blockMesh.position.x + blockProperties.width / 2 &&
 (ball.mesh.position.x > blockMesh.position.x)) &&
 (ball.mesh.position.z > blockMesh.position.z - blockProperties.height / 2) &&
 (ball.mesh.position.z < blockMesh.position.z + blockProperties.height / 2) &&
 (ball.velocity.x < 0.0)) 
 {
 ball.velocity.x *= -1.0;
 callback();
 return true;
 }
 return false;
 }
 function main() {
 // Hard-coded "settings"
 let settings = {
 backgroundColor : 0x008888,
 paddleSpeed : 0.3,
 ballSpeed: 0.2
 };
 let paddle = {
 width : 4,
 height : 1,
 depth : 1,
 color : 0xffffff,
 velocity : new THREE.Vector3(0.0, 0.0, 0.0),
 state : paddleStates.STATIONARY,
 startPosition : new THREE.Vector3(0.0, 0.0, -4.0)
 };
 let ball = {
 radius : 0.5,
 color : 0xffff00,
 velocity : new THREE.Vector3(settings.ballSpeed, 0.0, -settings.ballSpeed),
 startPosition : new THREE.Vector3(0.0, 0.0, -9.0),
 segments : {
 width : 16,
 height : 16
 }
 };
 const levelBounds = {
 top : -35.0,
 right : 17.0,
 left : -17.0,
 bottom : 0.0
 };
 const bricks = {
 rows : 11,
 columns : 11,
 distanceFromEdges : 1.0,
 distanceFromTop : 13.0,
 spacing : 0.2,
 color : 0xff00ff,
 depth : 1.0
 };
 
 const lights = [
 new THREE.AmbientLight(0xffffff, 0.5), 
 new THREE.PointLight(0xffffff, 0.5)
 ];
 // Game
 let renderer = createFullScreenRenderer("game-window", settings);
 
 let scene = new THREE.Scene();
 let camera = createCamera();
 scene.add(camera);
 
 paddle.mesh = createMeshAtPosition({
 geometry : new THREE.BoxGeometry(paddle.width, paddle.depth, paddle.height),
 material : new THREE.MeshLambertMaterial({ color : paddle.color })
 }, paddle.startPosition);
 scene.add(paddle.mesh);
 ball.mesh = createMeshAtPosition({
 geometry : new THREE.SphereGeometry(ball.radius, ball.segments.width, ball.segments.height),
 material : new THREE.MeshLambertMaterial({ color: ball.color })
 }, ball.startPosition);
 scene.add(ball.mesh);
 lights.forEach(light => scene.add(light));
 const levelWidth = levelBounds.right - levelBounds.left;
 const brick = {
 width : (levelWidth - 2 * bricks.distanceFromEdges + bricks.spacing * (1 - bricks.columns)) / bricks.columns,
 height : (bricks.distanceFromTop - bricks.distanceFromEdges) / bricks.rows,
 depth : bricks.depth
 };
 
 let visibleBricks = [];
 for (let row = 0; row < bricks.rows; row += 1) {
 for (let column = 0; column < bricks.columns; column += 1) {
 let position = new THREE.Vector3(
 levelBounds.left + bricks.distanceFromEdges + column * (brick.width + bricks.spacing) + 0.5 * brick.width,
 0.0,
 levelBounds.top + bricks.distanceFromEdges + row * (brick.height + bricks.spacing) + 0.5 * brick.height);
 let mesh = createMeshAtPosition({
 geometry : new THREE.BoxGeometry(brick.width, brick.depth, brick.height),
 material : new THREE.MeshLambertMaterial({ color : bricks.color })
 }, position);
 let name = `${row},${column}`;
 mesh.name = name;
 scene.add(mesh);
 visibleBricks.push({
 position : position,
 name : name
 });
 }
 } 
 requestAnimationFrame(render);
 function render() {
 // update paddle position
 // ball-level collision
 if ((ball.mesh.position.z - ball.radius < levelBounds.top && ball.velocity.z < 0.0) ||
 (ball.mesh.position.z + ball.radius > levelBounds.bottom && ball.velocity.z > 0.0)) 
 {
 ball.velocity.z *= -1.0;
 }
 if ((ball.mesh.position.x + ball.radius > levelBounds.right && ball.velocity.x > 0.0) ||
 (ball.mesh.position.x - ball.radius < levelBounds.left && ball.velocity.x < 0.0))
 {
 ball.velocity.x *= -1.0;
 }
 resolveBallBlockCollision(ball, paddle.mesh, paddle, function() {});
 // ball-brick collision
 for (let i = 0; i < visibleBricks.length; i += 1) {
 let visibleBrick = visibleBricks[i];
 let isCollided = resolveBallBlockCollision(ball, visibleBrick, brick, function() {
 let selectedObject = scene.getObjectByName(visibleBrick.name);
 scene.remove(selectedObject);
 visibleBricks.splice(i, 1);
 });
 if (isCollided) {
 break;
 }
 }
 updatePosition(paddle);
 updatePosition(ball);
 renderer.render(scene, camera);
 requestAnimationFrame(render);
 }
 
 window.addEventListener("resize", makeResizeCallback(camera, renderer), false);
 window.addEventListener("keydown", makeKeyDownCallback(paddle, settings.paddleSpeed), false);
 window.addEventListener("keyup", makeKeyUpCallback(paddle), false);
 }
 window.addEventListener("load", main, false);
 })();
 </script>
 </body>
</html>

(function() {
 "use strict";
 let paddleStates = {
 MOVING_LEFT : 0,
 MOVING_RIGHT : 1,
 STATIONARY : 2
 };
 function createMeshAtPosition(meshProperties, position) {
 let mesh = new THREE.Mesh(meshProperties.geometry, meshProperties.material);
 mesh.position.copy(position);
 return mesh;
 }
 function createFullScreenRenderer(elementId, settings) {
 let renderer = new THREE.WebGLRenderer({
 canvas: document.getElementById(elementId)
 });
 renderer.setPixelRatio(window.devicePixelRatio);
 renderer.setSize(window.innerWidth, window.innerHeight);
 renderer.setClearColor(settings.backgroundColor);
 return renderer;
 }
 function createCamera() {
 let camera = new THREE.PerspectiveCamera(
 90,
 window.innerWidth / window.innerHeight,
 0.1,
 3000);
 camera.position.set(0.0, 10.0, 0.0);
 camera.lookAt(0.0, 0.0, -10.0);
 return camera;
 }
 function makeResizeCallback(camera, renderer) {
 return function() {
 camera.aspect = window.innerWidth / window.innerHeight;
 camera.updateProjectionMatrix();
 renderer.setSize(window.innerWidth, window.innerHeight);
 };
 }
 function makeKeyDownCallback(paddle, speed) {
 return function(event) {
 if (paddle.state == paddleStates.STATIONARY) {
 if (event.key == "ArrowLeft") {
 paddle.velocity.x = -speed;
 paddle.state = paddleStates.MOVING_LEFT;
 } else if (event.key == "ArrowRight") {
 paddle.velocity.x = speed;
 paddle.state = paddleStates.MOVING_RIGHT;
 }
 }
 };
 }
 function makeKeyUpCallback(paddle) {
 return function(event) {
 if (paddle.state == paddleStates.MOVING_LEFT && event.key == "ArrowLeft") {
 paddle.velocity.x = 0.0;
 paddle.state = paddleStates.STATIONARY;
 } else if (paddle.state == paddleStates.MOVING_RIGHT && event.key == "ArrowRight") {
 paddle.velocity.x = 0.0;
 paddle.state = paddleStates.STATIONARY;
 }
 };
 }
 function updatePosition(gameObject) {
 gameObject.mesh.position.add(gameObject.velocity);
 }
 function resolveBallBlockCollision(ball, blockMesh, blockProperties, callback) {
 if ((ball.mesh.position.z + ball.radius > blockMesh.position.z - blockProperties.height / 2 &&
 (ball.mesh.position.z < blockMesh.position.z)) &&
 (ball.mesh.position.x > blockMesh.position.x - blockProperties.width / 2) &&
 (ball.mesh.position.x < blockMesh.position.x + blockProperties.width / 2) &&
 (ball.velocity.z > 0.0)) 
 {
 ball.velocity.z *= -1.0;
 callback();
 return true;
 }
 if ((ball.mesh.position.z - ball.radius < blockMesh.position.z + blockProperties.height / 2 &&
 (ball.mesh.position.z > blockMesh.position.z)) &&
 (ball.mesh.position.x > blockMesh.position.x - blockProperties.width / 2) &&
 (ball.mesh.position.x < blockMesh.position.x + blockProperties.width / 2) &&
 (ball.velocity.z < 0.0)) 
 {
 ball.velocity.z *= -1.0;
 callback();
 return true;
 }
 if ((ball.mesh.position.x + ball.radius > blockMesh.position.x - blockProperties.width / 2 &&
 (ball.mesh.position.x < blockMesh.position.x)) &&
 (ball.mesh.position.z > blockMesh.position.z - blockProperties.height / 2) &&
 (ball.mesh.position.z < blockMesh.position.z + blockProperties.height / 2) &&
 (ball.velocity.x > 0.0)) 
 {
 ball.velocity.x *= -1.0;
 callback();
 return true;
 }
 if ((ball.mesh.position.x - ball.radius < blockMesh.position.x + blockProperties.width / 2 &&
 (ball.mesh.position.x > blockMesh.position.x)) &&
 (ball.mesh.position.z > blockMesh.position.z - blockProperties.height / 2) &&
 (ball.mesh.position.z < blockMesh.position.z + blockProperties.height / 2) &&
 (ball.velocity.x < 0.0)) 
 {
 ball.velocity.x *= -1.0;
 callback();
 return true;
 }
 return false;
 }
 function main() {
 // Hard-coded "settings"
 let settings = {
 backgroundColor : 0x008888,
 paddleSpeed : 0.3,
 ballSpeed: 0.2
 };
 let paddle = {
 width : 4,
 height : 1,
 depth : 1,
 color : 0xffffff,
 velocity : new THREE.Vector3(0.0, 0.0, 0.0),
 state : paddleStates.STATIONARY,
 startPosition : new THREE.Vector3(0.0, 0.0, -4.0)
 };
 let ball = {
 radius : 0.5,
 color : 0xffff00,
 velocity : new THREE.Vector3(settings.ballSpeed, 0.0, -settings.ballSpeed),
 startPosition : new THREE.Vector3(0.0, 0.0, -9.0),
 segments : {
 width : 16,
 height : 16
 }
 };
 const levelBounds = {
 top : -35.0,
 right : 17.0,
 left : -17.0,
 bottom : 0.0
 };
 const bricks = {
 rows : 11,
 columns : 11,
 distanceFromEdges : 1.0,
 distanceFromTop : 13.0,
 spacing : 0.2,
 color : 0xff00ff,
 depth : 1.0
 };
 const lights = [
 new THREE.AmbientLight(0xffffff, 0.5), 
 new THREE.PointLight(0xffffff, 0.5)
 ];
 // Game
 let renderer = createFullScreenRenderer("game-window", settings);
 let scene = new THREE.Scene();
 let camera = createCamera();
 scene.add(camera);
 paddle.mesh = createMeshAtPosition({
 geometry : new THREE.BoxGeometry(paddle.width, paddle.depth, paddle.height),
 material : new THREE.MeshLambertMaterial({ color : paddle.color })
 }, paddle.startPosition);
 scene.add(paddle.mesh);
 ball.mesh = createMeshAtPosition({
 geometry : new THREE.SphereGeometry(ball.radius, ball.segments.width, ball.segments.height),
 material : new THREE.MeshLambertMaterial({ color: ball.color })
 }, ball.startPosition);
 scene.add(ball.mesh);
 lights.forEach(light => scene.add(light));
 const levelWidth = levelBounds.right - levelBounds.left;
 const brick = {
 width : (levelWidth - 2 * bricks.distanceFromEdges + bricks.spacing * (1 - bricks.columns)) / bricks.columns,
 height : (bricks.distanceFromTop - bricks.distanceFromEdges) / bricks.rows,
 depth : bricks.depth
 };
 let visibleBricks = [];
 for (let row = 0; row < bricks.rows; row += 1) {
 for (let column = 0; column < bricks.columns; column += 1) {
 let position = new THREE.Vector3(
 levelBounds.left + bricks.distanceFromEdges + column * (brick.width + bricks.spacing) + 0.5 * brick.width,
 0.0,
 levelBounds.top + bricks.distanceFromEdges + row * (brick.height + bricks.spacing) + 0.5 * brick.height);
 let mesh = createMeshAtPosition({
 geometry : new THREE.BoxGeometry(brick.width, brick.depth, brick.height),
 material : new THREE.MeshLambertMaterial({ color : bricks.color })
 }, position);
 let name = `${row},${column}`;
 mesh.name = name;
 scene.add(mesh);
 visibleBricks.push({
 position : position,
 name : name
 });
 }
 } 
 requestAnimationFrame(render);
 function render() {
 // update paddle position
 // ball-level collision
 if ((ball.mesh.position.z - ball.radius < levelBounds.top && ball.velocity.z < 0.0) ||
 (ball.mesh.position.z + ball.radius > levelBounds.bottom && ball.velocity.z > 0.0)) 
 {
 ball.velocity.z *= -1.0;
 }
 if ((ball.mesh.position.x + ball.radius > levelBounds.right && ball.velocity.x > 0.0) ||
 (ball.mesh.position.x - ball.radius < levelBounds.left && ball.velocity.x < 0.0))
 {
 ball.velocity.x *= -1.0;
 }
 resolveBallBlockCollision(ball, paddle.mesh, paddle, function() {});
 // ball-brick collision
 for (let i = 0; i < visibleBricks.length; i += 1) {
 let visibleBrick = visibleBricks[i];
 let isCollided = resolveBallBlockCollision(ball, visibleBrick, brick, function() {
 let selectedObject = scene.getObjectByName(visibleBrick.name);
 scene.remove(selectedObject);
 visibleBricks.splice(i, 1);
 });
 if (isCollided) {
 break;
 }
 }
 updatePosition(paddle);
 updatePosition(ball);
 renderer.render(scene, camera);
 requestAnimationFrame(render);
 }
 window.addEventListener("resize", makeResizeCallback(camera, renderer), false);
 window.addEventListener("keydown", makeKeyDownCallback(paddle, settings.paddleSpeed), false);
 window.addEventListener("keyup", makeKeyUpCallback(paddle), false);
 }
 window.addEventListener("load", main, false);
})();
<!DOCTYPE html>
<html>
 <head>
 <title>Arkanoid</title>
 <style>
 body {
 padding: 0px;
 margin: 0px;
 overflow: hidden;
 }
 </style>
 </head>
 <body>
 <canvas id="game-window"></canvas>
 <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/95/three.js"></script>
 </body>
</html>

Source Link
Loading
lang-js

AltStyle によって変換されたページ (->オリジナル) /