3D 1st Person Snake Game #2

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
5
down vote

favorite
1












This is an iterative review of this question: 3D 1st Person Snake Game #1
The next iteration can be found here: 3D 1st Person Snake Game #3
Here is a snippet of the code:






<html>
<style>
canvas
position:fixed;
left:0;
top:0;
width:99%;
height:99%;

*
padding:0px;
margin:0px

#score,#speed,#highscore,#maxspeed,#lag,#debug
position: fixed;
z-index: 100;
font-size:20px;
font-family:Verdana;
left:15px;
width: 100%;

#gameover
position:absolute;
z-index: 100;
font-size:60px;
font-family:Verdana;
margin: 0;
top: 50%;
left: 50%;
opacity:0;
transform: translate(-50%, -50%);

#maxspeed, #score, #josh, #speed, #highscore, #lag
display:block;

#maxspeed
width: 100%;
top:50px;
display:none;


#score
top: 10px;

#speed
top: 30px;


#highscore
top:30px;


#lag
top: 70px;

</style>
<div id="stats">
<div id="debug"></div>
<div id="score">Score: 0</div>
<div id="speed">Speed: 1</div>
<div id="highscore">Highscore: 1</div>
<div id="maxspeed">Highest Speed: 1</div>
<span id="lag">Lag: 0ms</span>
<div id="gameover" align="center">Game Over</div>
</div>
<div id="canvas"></div>
<p id="p"></p>
<p id="e"></p>
<script type="text/javascript" src="https://cdn.rawgit.com/alexgibson/shake.js/master/shake.js"></script>
<script src="https://threejs.org/build/three.min.js"></script>
<script>
//========================
// One times
//========================
const random = Math.random,
floor = function(a) return ~~a,
newGeometry = THREE.Geometry,
newBufferGeometry = THREE.BufferGeometry,
newMesh = THREE.Mesh,
newLineSegments = THREE.LineSegments,
newMeshBasicMaterial = THREE.MeshBasicMaterial,
newVector3 = THREE.Vector3,
newLineBasicMaterial = THREE.LineBasicMaterial,
newBoxGeometry = THREE.BoxGeometry,
newBoxBufferGeometry = THREE.BoxBufferGeometry,
arena = new THREE.Group(),
applegeometry = new THREE.SphereBufferGeometry( 0.5, 32, 32 ),
superapplematerial= new newMeshBasicMaterial(color:"gold"),
applematerial= new newMeshBasicMaterial(color:"limegreen"),
floormaterial = new newMeshBasicMaterial(color:"lightgrey"),
wallmaterial = new newMeshBasicMaterial( color: "grey" ),
linecube = new newBoxBufferGeometry( 1,1,1 ),
edges = new THREE.EdgesGeometry( linecube ),
geometry = new newBoxBufferGeometry( 1,1,1 ),
stringify = JSON.stringify


</script>
<script id="script">
(function(THREE,ArenaWidth, ArenaLength)
'use strict'
const arenaLines = new THREE.Group(),
arenaWall = new newGeometry(),
arenaFloor = new newGeometry(),
wall1 = new newBoxGeometry( ArenaWidth+1, 1, 1 )
.translate((ArenaWidth/2)-2,1,-2);
arenaWall.merge(wall1);
arenaWall.merge(wall1.translate(0,0, ArenaLength));
const wall2 = new newBoxGeometry( 1, 1, ArenaLength+1 ).translate(ArenaWidth-2,1,(ArenaLength/2)-2);
arenaWall.merge(wall2);
arenaWall.merge(wall2.translate(-ArenaWidth,0,0));
arenaFloor.merge(new newBoxGeometry( ArenaWidth+1, 1, ArenaLength+1 ).translate((ArenaWidth/2)-2,0,(ArenaLength/2)-2))
arenaWall.mergeVertices()
arenaFloor.mergeVertices()
// Get the meshs
window.arenaWallMesh = new newMesh(arenaWall, wallmaterial);
window.arenaFloorMesh = new newMesh(arenaFloor, floormaterial);

var speed = 100,
maxwidth = 40,
maxdepdth = 40,
size = 0.5,
score = 0,
maxheight = 0,
lagNum = 0,
highscoreNum,
showlag,
maxspeedNum,
showmaxspeed,
showhighscore

//========================
// Threejs
//========================

var scene = new THREE.Scene(),
camera= new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,60),
renderer = new THREE.WebGLRenderer(),
extrasLookup =
1:30,
2:50,
3:70,
4:90

//========================
// Reductions
//========================
const newScene = THREE.Scene

if(true /*localStorage.getItem("3dhighscore")==undefined*/)
highscoreNum=0
else
highscoreNum = localStorage.getItem("3dhighscore")

if(true /*localStorage.getItem("showlag")==undefined*/)
showlag=false
else
showlag = localStorage.getItem("showlag")

if(true /*localStorage.getItem("3dmaxspeed")==undefined*/)
maxspeedNum=100
else
maxspeedNum = localStorage.getItem("3dmaxspeed")

if(showmaxspeed==undefined)
showmaxspeed=false

if(showhighscore==undefined)
showhighscore=false


renderer.setSize( window.innerWidth, window.innerHeight );
document.getElementById("canvas").appendChild( renderer.domElement );

function animate()
requestAnimationFrame( animate )
renderer.render( scene, camera );

class Location
constructor(x,y,z)
return [x,y,z]



//========================
// Dom
//========================
const maxSpeedDom = document.getElementById("maxspeed"),
maxSpeedDomStyle = maxSpeedDom.style,
lagdom = document.getElementById("lag"),
lagdomstyle = lagdom.style,
highScoreDom = document.getElementById("highscore"),
highScoreDomStyle = highScoreDom.style,
scoredom = document.getElementById("score"),
speeddom = document.getElementById("speed"),
gameOverDom = document.getElementById("gameover"),
gameOverDomStyle = gameOverDom.style;
//========================
// Snake
//========================
class Snake
constructor()
this.segments = [
new Location(7,1,5),
new Location(6,1,5),
new Location(5,1,5)
];
this.direction = "forwards";
this.nextDirection = "forwards";
this.nextHead = new Location(8,1,5);

draw()
let snakeobject = new THREE.Group();
let j = this.segments.length
this.segments.forEach((item,index) =>
let i = index
let segmentColor=`rgb($255-(255/j,00,00)`
const cube = new newMesh(geometry, new newMeshBasicMaterial( color: segmentColor)),
x = item[0],
y = item[1],
z = item[2];
let pos = new newVector3(x,y,z)

const line = new newLineSegments(edges, new newLineBasicMaterial( color: segmentColor,linewidth:2 ));
cube.position.copy(pos);
line.position.copy(pos);
snakeobject.add(line,cube);
)
scene.add(snakeobject);

move()
this.segments.unshift(this.nextHead);
if(this.checkCollision())
this.segments.shift();
gameOver();
return;
;
var nextHeadPos = this.nextHead;
this.direction = this.nextDirection;
(directionSwitch[this.direction])(nextHeadPos)
if(stringify(this.segments[0]) === stringify(apple.pos))
speed=0.95*speed;
score++;
if(apple.type === "superapple")
speed = 1.10*speed;
score += 4;

apple.move();
else
this.segments.pop();
;

changeDirection(key)
switch(key)
case 39:
case 68:
case 37:
case 65:
keyLookup[key][this.direction]()
break;
case 192:
case 55:
case 56:
keyLookup[key]()
break;


checkCollision()


//========================
// Drawing
//========================
function drawStats()
var extras = 1;
if(score > highscoreNum)
highscoreNum = score;
//localStorage.setItem("3dhighscore", highscore);

if(speed < maxspeed)
maxspeedNum = speed;
//localStorage.setItem("3dmaxspeed", maxspeed);


scoredom.innerHTML=`Score: $score`;
speeddom.innerHTML=`Speed: $(((100/speed*100)`;

if(showhighscore)
extras++;
highscore.style.display = "block";
highscore.style.top = extrasLookup[extras]
highscore.innerHTML = `Highscore: $highscoreNum`;

else
highScoreDomStyle.display = "none";
;

if(showmaxspeed)
extras++;
maxspeed.style.display = "block";
maxspeed.style.top = extrasLookup[extras]
maxspeed.innerHTML = `Highest Speed: $0)/100)`;
else
maxspeed.style.display = "none";
;

if(showlag)
extras++;
lag.style.display = "block";
lag.style.top = extrasLookup[extras]
lag.innerHTML = `Lag: $lagNumms`;
else
lagdomstyle.display = "none";
;

function renderArena()
;


//========================
// Apple
//========================
class Apple
constructor()
this.pos = new Location(2,1,2)

move()

// Set the location to a random x and z.
var x = randomNumberBetween(0,ArenaWidth-4)
var z = randomNumberBetween(0,ArenaLength-4)
this.pos = new Location(x,1,z)
if(randomNumberBetween(1,11)===1&&score>15)
apple.type="superapple"
else
apple.type="apple"


draw()
var sphere

// Generate a new sphere.
if(this.type=="superapple")
sphere = new newMesh( applegeometry, superapplematerial );
else
sphere = new newMesh( applegeometry, applematerial );


// Get the data location.
var applepos=apple.pos

// Set the location of the visual apple to the data location.
sphere.position.set(applepos[0],applepos[1],applepos[2])
scene.add(sphere);


//========================
// Misc
//========================
function newGame(key)
if(key==82)

// Stop the game.
clearTimeout(gameLoop);
s=function();

// Start a new game.
var game = document.getElementById("canvas");
game.removeChild(game.childNodes[0]);
eval(document.getElementById("script").innerHTML);


gameOverDomStyle.opacity=0;
function gameOver()
s = function()
camera.position.copy(new newVector3((ArenaWidth/2)-2,Math.sqrt(
Math.pow(ArenaWidth/2,2)+Math.pow(ArenaLength/2,2)),(ArenaLength/2)-2));
camera.lookAt(new newVector3((ArenaWidth/2)-2,0,(ArenaLength/2)-2));
;
document.onkeydown=function(e)
newGame(e.keyCode);

//listen to shake event
var shakeEvent = new Shake(threshold: 15);
shakeEvent.start();
window.addEventListener('shake', function()
newGame(82)
, false);

//stop listening
function stopShake()
shakeEvent.stop();


//check if shake is supported or not.
if(!("ondevicemotion" in window))alert("Not Supported");
gameOverDomStyle.opacity = 1;


function randomNumberBetween(a,b)
return a+floor(random()*(b-a));

var apple = new Apple(),
snake = new Snake()
var directionSwitch=
"forwards":function(a)this.nextHead = new Location(a[0]+1, a[1], a[2]),
"backwards":function(a)this.nextHead = new Location(a[0]-1, a[1], a[2]),
"left":function(a)this.nextHead = new Location(a[0], a[1], a[2]-1),
"right":function(a)this.nextHead = new Location(a[0], a[1], a[2]+1)

for(var x in directionSwitch)
directionSwitch[x] = directionSwitch[x].bind(snake)

var right =
"right":function()this.nextDirection = "backwards",
"backwards":function()this.nextDirection = "left",
"forwards":function()this.nextDirection = "right",
"left":function()this.nextDirection = "forwards"

for(var x in right)
right[x] = right[x].bind(snake)

var left =
"right":function()snake.nextDirection = "forwards",
"forwards":function()snake.nextDirection = "left",
"left":function()snake.nextDirection = "backwards",
"backwards":function()snake.nextDirection = "right"

for(var x in left)
left[x] = left[x].bind(snake)

var keyLookup =
"39":right,
"68":right,
"37":left,
"65":left,
"192":function()showlag=!showlag,
"55":function()showhighscore=!showhighscore,
"56":function()showmaxspeed = !showmaxspeed

snake.draw();
apple.move();

var background = new THREE.Color( "white" ),
fog = new THREE.FogExp2( "random", 0.02625 );

let s = function()
// Start for lag detection.
var start = performance.now();

// Make a fresh scene.
scene = new newScene();

// Move the snake.
snake.move();

// Render various things onto the scene.
scene.add(arenaWallMesh,arenaFloorMesh)
snake.draw();
apple.draw();
drawStats();


// Get relevent snake parts.
let head = snake.segments[0];
let nextHead = snake.nextHead;

// Set camera position and target.
camera.position.set(head[0],head[1],head[2]);
camera.lookAt(new newVector3(nextHead[0],nextHead[1],nextHead[2]));

// Set background and fog.
scene.background = background;
scene.fog = fog;
let end = performance.now();
// Reschedule the next update
gameLoop = setTimeout(function()
requestAnimationFrame(s)
,speed)

// End for lag detection and calculation of lag.
lagNum = floor((end-start))

animate()
var gameLoop = setTimeout(function()
requestAnimationFrame(s)
,speed);
document.onkeydown = function(e)
snake.changeDirection(e.keyCode);

)(window.THREE, (((window.innerWidth/10)|0)*10-2*10)/10, (((window.innerHeight/10)|0)*10-2*10)/10)
</script>









share|improve this question





















  • Note: For the snippet, click "run", "Full page", purposely lose, and then click "r". Unfortunately the snippet makes the game small...
    – FreezePhoenix
    May 14 at 16:49







  • 2




    Oh maaan. It's so hard to play. Sorry, now got zero time to write an actual review! i.stack.imgur.com/gfiZi.png
    – Igor Soloydenko
    May 14 at 18:02
















up vote
5
down vote

favorite
1












This is an iterative review of this question: 3D 1st Person Snake Game #1
The next iteration can be found here: 3D 1st Person Snake Game #3
Here is a snippet of the code:






<html>
<style>
canvas
position:fixed;
left:0;
top:0;
width:99%;
height:99%;

*
padding:0px;
margin:0px

#score,#speed,#highscore,#maxspeed,#lag,#debug
position: fixed;
z-index: 100;
font-size:20px;
font-family:Verdana;
left:15px;
width: 100%;

#gameover
position:absolute;
z-index: 100;
font-size:60px;
font-family:Verdana;
margin: 0;
top: 50%;
left: 50%;
opacity:0;
transform: translate(-50%, -50%);

#maxspeed, #score, #josh, #speed, #highscore, #lag
display:block;

#maxspeed
width: 100%;
top:50px;
display:none;


#score
top: 10px;

#speed
top: 30px;


#highscore
top:30px;


#lag
top: 70px;

</style>
<div id="stats">
<div id="debug"></div>
<div id="score">Score: 0</div>
<div id="speed">Speed: 1</div>
<div id="highscore">Highscore: 1</div>
<div id="maxspeed">Highest Speed: 1</div>
<span id="lag">Lag: 0ms</span>
<div id="gameover" align="center">Game Over</div>
</div>
<div id="canvas"></div>
<p id="p"></p>
<p id="e"></p>
<script type="text/javascript" src="https://cdn.rawgit.com/alexgibson/shake.js/master/shake.js"></script>
<script src="https://threejs.org/build/three.min.js"></script>
<script>
//========================
// One times
//========================
const random = Math.random,
floor = function(a) return ~~a,
newGeometry = THREE.Geometry,
newBufferGeometry = THREE.BufferGeometry,
newMesh = THREE.Mesh,
newLineSegments = THREE.LineSegments,
newMeshBasicMaterial = THREE.MeshBasicMaterial,
newVector3 = THREE.Vector3,
newLineBasicMaterial = THREE.LineBasicMaterial,
newBoxGeometry = THREE.BoxGeometry,
newBoxBufferGeometry = THREE.BoxBufferGeometry,
arena = new THREE.Group(),
applegeometry = new THREE.SphereBufferGeometry( 0.5, 32, 32 ),
superapplematerial= new newMeshBasicMaterial(color:"gold"),
applematerial= new newMeshBasicMaterial(color:"limegreen"),
floormaterial = new newMeshBasicMaterial(color:"lightgrey"),
wallmaterial = new newMeshBasicMaterial( color: "grey" ),
linecube = new newBoxBufferGeometry( 1,1,1 ),
edges = new THREE.EdgesGeometry( linecube ),
geometry = new newBoxBufferGeometry( 1,1,1 ),
stringify = JSON.stringify


</script>
<script id="script">
(function(THREE,ArenaWidth, ArenaLength)
'use strict'
const arenaLines = new THREE.Group(),
arenaWall = new newGeometry(),
arenaFloor = new newGeometry(),
wall1 = new newBoxGeometry( ArenaWidth+1, 1, 1 )
.translate((ArenaWidth/2)-2,1,-2);
arenaWall.merge(wall1);
arenaWall.merge(wall1.translate(0,0, ArenaLength));
const wall2 = new newBoxGeometry( 1, 1, ArenaLength+1 ).translate(ArenaWidth-2,1,(ArenaLength/2)-2);
arenaWall.merge(wall2);
arenaWall.merge(wall2.translate(-ArenaWidth,0,0));
arenaFloor.merge(new newBoxGeometry( ArenaWidth+1, 1, ArenaLength+1 ).translate((ArenaWidth/2)-2,0,(ArenaLength/2)-2))
arenaWall.mergeVertices()
arenaFloor.mergeVertices()
// Get the meshs
window.arenaWallMesh = new newMesh(arenaWall, wallmaterial);
window.arenaFloorMesh = new newMesh(arenaFloor, floormaterial);

var speed = 100,
maxwidth = 40,
maxdepdth = 40,
size = 0.5,
score = 0,
maxheight = 0,
lagNum = 0,
highscoreNum,
showlag,
maxspeedNum,
showmaxspeed,
showhighscore

//========================
// Threejs
//========================

var scene = new THREE.Scene(),
camera= new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,60),
renderer = new THREE.WebGLRenderer(),
extrasLookup =
1:30,
2:50,
3:70,
4:90

//========================
// Reductions
//========================
const newScene = THREE.Scene

if(true /*localStorage.getItem("3dhighscore")==undefined*/)
highscoreNum=0
else
highscoreNum = localStorage.getItem("3dhighscore")

if(true /*localStorage.getItem("showlag")==undefined*/)
showlag=false
else
showlag = localStorage.getItem("showlag")

if(true /*localStorage.getItem("3dmaxspeed")==undefined*/)
maxspeedNum=100
else
maxspeedNum = localStorage.getItem("3dmaxspeed")

if(showmaxspeed==undefined)
showmaxspeed=false

if(showhighscore==undefined)
showhighscore=false


renderer.setSize( window.innerWidth, window.innerHeight );
document.getElementById("canvas").appendChild( renderer.domElement );

function animate()
requestAnimationFrame( animate )
renderer.render( scene, camera );

class Location
constructor(x,y,z)
return [x,y,z]



//========================
// Dom
//========================
const maxSpeedDom = document.getElementById("maxspeed"),
maxSpeedDomStyle = maxSpeedDom.style,
lagdom = document.getElementById("lag"),
lagdomstyle = lagdom.style,
highScoreDom = document.getElementById("highscore"),
highScoreDomStyle = highScoreDom.style,
scoredom = document.getElementById("score"),
speeddom = document.getElementById("speed"),
gameOverDom = document.getElementById("gameover"),
gameOverDomStyle = gameOverDom.style;
//========================
// Snake
//========================
class Snake
constructor()
this.segments = [
new Location(7,1,5),
new Location(6,1,5),
new Location(5,1,5)
];
this.direction = "forwards";
this.nextDirection = "forwards";
this.nextHead = new Location(8,1,5);

draw()
let snakeobject = new THREE.Group();
let j = this.segments.length
this.segments.forEach((item,index) =>
let i = index
let segmentColor=`rgb($255-(255/j,00,00)`
const cube = new newMesh(geometry, new newMeshBasicMaterial( color: segmentColor)),
x = item[0],
y = item[1],
z = item[2];
let pos = new newVector3(x,y,z)

const line = new newLineSegments(edges, new newLineBasicMaterial( color: segmentColor,linewidth:2 ));
cube.position.copy(pos);
line.position.copy(pos);
snakeobject.add(line,cube);
)
scene.add(snakeobject);

move()
this.segments.unshift(this.nextHead);
if(this.checkCollision())
this.segments.shift();
gameOver();
return;
;
var nextHeadPos = this.nextHead;
this.direction = this.nextDirection;
(directionSwitch[this.direction])(nextHeadPos)
if(stringify(this.segments[0]) === stringify(apple.pos))
speed=0.95*speed;
score++;
if(apple.type === "superapple")
speed = 1.10*speed;
score += 4;

apple.move();
else
this.segments.pop();
;

changeDirection(key)
switch(key)
case 39:
case 68:
case 37:
case 65:
keyLookup[key][this.direction]()
break;
case 192:
case 55:
case 56:
keyLookup[key]()
break;


checkCollision()


//========================
// Drawing
//========================
function drawStats()
var extras = 1;
if(score > highscoreNum)
highscoreNum = score;
//localStorage.setItem("3dhighscore", highscore);

if(speed < maxspeed)
maxspeedNum = speed;
//localStorage.setItem("3dmaxspeed", maxspeed);


scoredom.innerHTML=`Score: $score`;
speeddom.innerHTML=`Speed: $(((100/speed*100)`;

if(showhighscore)
extras++;
highscore.style.display = "block";
highscore.style.top = extrasLookup[extras]
highscore.innerHTML = `Highscore: $highscoreNum`;

else
highScoreDomStyle.display = "none";
;

if(showmaxspeed)
extras++;
maxspeed.style.display = "block";
maxspeed.style.top = extrasLookup[extras]
maxspeed.innerHTML = `Highest Speed: $0)/100)`;
else
maxspeed.style.display = "none";
;

if(showlag)
extras++;
lag.style.display = "block";
lag.style.top = extrasLookup[extras]
lag.innerHTML = `Lag: $lagNumms`;
else
lagdomstyle.display = "none";
;

function renderArena()
;


//========================
// Apple
//========================
class Apple
constructor()
this.pos = new Location(2,1,2)

move()

// Set the location to a random x and z.
var x = randomNumberBetween(0,ArenaWidth-4)
var z = randomNumberBetween(0,ArenaLength-4)
this.pos = new Location(x,1,z)
if(randomNumberBetween(1,11)===1&&score>15)
apple.type="superapple"
else
apple.type="apple"


draw()
var sphere

// Generate a new sphere.
if(this.type=="superapple")
sphere = new newMesh( applegeometry, superapplematerial );
else
sphere = new newMesh( applegeometry, applematerial );


// Get the data location.
var applepos=apple.pos

// Set the location of the visual apple to the data location.
sphere.position.set(applepos[0],applepos[1],applepos[2])
scene.add(sphere);


//========================
// Misc
//========================
function newGame(key)
if(key==82)

// Stop the game.
clearTimeout(gameLoop);
s=function();

// Start a new game.
var game = document.getElementById("canvas");
game.removeChild(game.childNodes[0]);
eval(document.getElementById("script").innerHTML);


gameOverDomStyle.opacity=0;
function gameOver()
s = function()
camera.position.copy(new newVector3((ArenaWidth/2)-2,Math.sqrt(
Math.pow(ArenaWidth/2,2)+Math.pow(ArenaLength/2,2)),(ArenaLength/2)-2));
camera.lookAt(new newVector3((ArenaWidth/2)-2,0,(ArenaLength/2)-2));
;
document.onkeydown=function(e)
newGame(e.keyCode);

//listen to shake event
var shakeEvent = new Shake(threshold: 15);
shakeEvent.start();
window.addEventListener('shake', function()
newGame(82)
, false);

//stop listening
function stopShake()
shakeEvent.stop();


//check if shake is supported or not.
if(!("ondevicemotion" in window))alert("Not Supported");
gameOverDomStyle.opacity = 1;


function randomNumberBetween(a,b)
return a+floor(random()*(b-a));

var apple = new Apple(),
snake = new Snake()
var directionSwitch=
"forwards":function(a)this.nextHead = new Location(a[0]+1, a[1], a[2]),
"backwards":function(a)this.nextHead = new Location(a[0]-1, a[1], a[2]),
"left":function(a)this.nextHead = new Location(a[0], a[1], a[2]-1),
"right":function(a)this.nextHead = new Location(a[0], a[1], a[2]+1)

for(var x in directionSwitch)
directionSwitch[x] = directionSwitch[x].bind(snake)

var right =
"right":function()this.nextDirection = "backwards",
"backwards":function()this.nextDirection = "left",
"forwards":function()this.nextDirection = "right",
"left":function()this.nextDirection = "forwards"

for(var x in right)
right[x] = right[x].bind(snake)

var left =
"right":function()snake.nextDirection = "forwards",
"forwards":function()snake.nextDirection = "left",
"left":function()snake.nextDirection = "backwards",
"backwards":function()snake.nextDirection = "right"

for(var x in left)
left[x] = left[x].bind(snake)

var keyLookup =
"39":right,
"68":right,
"37":left,
"65":left,
"192":function()showlag=!showlag,
"55":function()showhighscore=!showhighscore,
"56":function()showmaxspeed = !showmaxspeed

snake.draw();
apple.move();

var background = new THREE.Color( "white" ),
fog = new THREE.FogExp2( "random", 0.02625 );

let s = function()
// Start for lag detection.
var start = performance.now();

// Make a fresh scene.
scene = new newScene();

// Move the snake.
snake.move();

// Render various things onto the scene.
scene.add(arenaWallMesh,arenaFloorMesh)
snake.draw();
apple.draw();
drawStats();


// Get relevent snake parts.
let head = snake.segments[0];
let nextHead = snake.nextHead;

// Set camera position and target.
camera.position.set(head[0],head[1],head[2]);
camera.lookAt(new newVector3(nextHead[0],nextHead[1],nextHead[2]));

// Set background and fog.
scene.background = background;
scene.fog = fog;
let end = performance.now();
// Reschedule the next update
gameLoop = setTimeout(function()
requestAnimationFrame(s)
,speed)

// End for lag detection and calculation of lag.
lagNum = floor((end-start))

animate()
var gameLoop = setTimeout(function()
requestAnimationFrame(s)
,speed);
document.onkeydown = function(e)
snake.changeDirection(e.keyCode);

)(window.THREE, (((window.innerWidth/10)|0)*10-2*10)/10, (((window.innerHeight/10)|0)*10-2*10)/10)
</script>









share|improve this question





















  • Note: For the snippet, click "run", "Full page", purposely lose, and then click "r". Unfortunately the snippet makes the game small...
    – FreezePhoenix
    May 14 at 16:49







  • 2




    Oh maaan. It's so hard to play. Sorry, now got zero time to write an actual review! i.stack.imgur.com/gfiZi.png
    – Igor Soloydenko
    May 14 at 18:02












up vote
5
down vote

favorite
1









up vote
5
down vote

favorite
1






1





This is an iterative review of this question: 3D 1st Person Snake Game #1
The next iteration can be found here: 3D 1st Person Snake Game #3
Here is a snippet of the code:






<html>
<style>
canvas
position:fixed;
left:0;
top:0;
width:99%;
height:99%;

*
padding:0px;
margin:0px

#score,#speed,#highscore,#maxspeed,#lag,#debug
position: fixed;
z-index: 100;
font-size:20px;
font-family:Verdana;
left:15px;
width: 100%;

#gameover
position:absolute;
z-index: 100;
font-size:60px;
font-family:Verdana;
margin: 0;
top: 50%;
left: 50%;
opacity:0;
transform: translate(-50%, -50%);

#maxspeed, #score, #josh, #speed, #highscore, #lag
display:block;

#maxspeed
width: 100%;
top:50px;
display:none;


#score
top: 10px;

#speed
top: 30px;


#highscore
top:30px;


#lag
top: 70px;

</style>
<div id="stats">
<div id="debug"></div>
<div id="score">Score: 0</div>
<div id="speed">Speed: 1</div>
<div id="highscore">Highscore: 1</div>
<div id="maxspeed">Highest Speed: 1</div>
<span id="lag">Lag: 0ms</span>
<div id="gameover" align="center">Game Over</div>
</div>
<div id="canvas"></div>
<p id="p"></p>
<p id="e"></p>
<script type="text/javascript" src="https://cdn.rawgit.com/alexgibson/shake.js/master/shake.js"></script>
<script src="https://threejs.org/build/three.min.js"></script>
<script>
//========================
// One times
//========================
const random = Math.random,
floor = function(a) return ~~a,
newGeometry = THREE.Geometry,
newBufferGeometry = THREE.BufferGeometry,
newMesh = THREE.Mesh,
newLineSegments = THREE.LineSegments,
newMeshBasicMaterial = THREE.MeshBasicMaterial,
newVector3 = THREE.Vector3,
newLineBasicMaterial = THREE.LineBasicMaterial,
newBoxGeometry = THREE.BoxGeometry,
newBoxBufferGeometry = THREE.BoxBufferGeometry,
arena = new THREE.Group(),
applegeometry = new THREE.SphereBufferGeometry( 0.5, 32, 32 ),
superapplematerial= new newMeshBasicMaterial(color:"gold"),
applematerial= new newMeshBasicMaterial(color:"limegreen"),
floormaterial = new newMeshBasicMaterial(color:"lightgrey"),
wallmaterial = new newMeshBasicMaterial( color: "grey" ),
linecube = new newBoxBufferGeometry( 1,1,1 ),
edges = new THREE.EdgesGeometry( linecube ),
geometry = new newBoxBufferGeometry( 1,1,1 ),
stringify = JSON.stringify


</script>
<script id="script">
(function(THREE,ArenaWidth, ArenaLength)
'use strict'
const arenaLines = new THREE.Group(),
arenaWall = new newGeometry(),
arenaFloor = new newGeometry(),
wall1 = new newBoxGeometry( ArenaWidth+1, 1, 1 )
.translate((ArenaWidth/2)-2,1,-2);
arenaWall.merge(wall1);
arenaWall.merge(wall1.translate(0,0, ArenaLength));
const wall2 = new newBoxGeometry( 1, 1, ArenaLength+1 ).translate(ArenaWidth-2,1,(ArenaLength/2)-2);
arenaWall.merge(wall2);
arenaWall.merge(wall2.translate(-ArenaWidth,0,0));
arenaFloor.merge(new newBoxGeometry( ArenaWidth+1, 1, ArenaLength+1 ).translate((ArenaWidth/2)-2,0,(ArenaLength/2)-2))
arenaWall.mergeVertices()
arenaFloor.mergeVertices()
// Get the meshs
window.arenaWallMesh = new newMesh(arenaWall, wallmaterial);
window.arenaFloorMesh = new newMesh(arenaFloor, floormaterial);

var speed = 100,
maxwidth = 40,
maxdepdth = 40,
size = 0.5,
score = 0,
maxheight = 0,
lagNum = 0,
highscoreNum,
showlag,
maxspeedNum,
showmaxspeed,
showhighscore

//========================
// Threejs
//========================

var scene = new THREE.Scene(),
camera= new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,60),
renderer = new THREE.WebGLRenderer(),
extrasLookup =
1:30,
2:50,
3:70,
4:90

//========================
// Reductions
//========================
const newScene = THREE.Scene

if(true /*localStorage.getItem("3dhighscore")==undefined*/)
highscoreNum=0
else
highscoreNum = localStorage.getItem("3dhighscore")

if(true /*localStorage.getItem("showlag")==undefined*/)
showlag=false
else
showlag = localStorage.getItem("showlag")

if(true /*localStorage.getItem("3dmaxspeed")==undefined*/)
maxspeedNum=100
else
maxspeedNum = localStorage.getItem("3dmaxspeed")

if(showmaxspeed==undefined)
showmaxspeed=false

if(showhighscore==undefined)
showhighscore=false


renderer.setSize( window.innerWidth, window.innerHeight );
document.getElementById("canvas").appendChild( renderer.domElement );

function animate()
requestAnimationFrame( animate )
renderer.render( scene, camera );

class Location
constructor(x,y,z)
return [x,y,z]



//========================
// Dom
//========================
const maxSpeedDom = document.getElementById("maxspeed"),
maxSpeedDomStyle = maxSpeedDom.style,
lagdom = document.getElementById("lag"),
lagdomstyle = lagdom.style,
highScoreDom = document.getElementById("highscore"),
highScoreDomStyle = highScoreDom.style,
scoredom = document.getElementById("score"),
speeddom = document.getElementById("speed"),
gameOverDom = document.getElementById("gameover"),
gameOverDomStyle = gameOverDom.style;
//========================
// Snake
//========================
class Snake
constructor()
this.segments = [
new Location(7,1,5),
new Location(6,1,5),
new Location(5,1,5)
];
this.direction = "forwards";
this.nextDirection = "forwards";
this.nextHead = new Location(8,1,5);

draw()
let snakeobject = new THREE.Group();
let j = this.segments.length
this.segments.forEach((item,index) =>
let i = index
let segmentColor=`rgb($255-(255/j,00,00)`
const cube = new newMesh(geometry, new newMeshBasicMaterial( color: segmentColor)),
x = item[0],
y = item[1],
z = item[2];
let pos = new newVector3(x,y,z)

const line = new newLineSegments(edges, new newLineBasicMaterial( color: segmentColor,linewidth:2 ));
cube.position.copy(pos);
line.position.copy(pos);
snakeobject.add(line,cube);
)
scene.add(snakeobject);

move()
this.segments.unshift(this.nextHead);
if(this.checkCollision())
this.segments.shift();
gameOver();
return;
;
var nextHeadPos = this.nextHead;
this.direction = this.nextDirection;
(directionSwitch[this.direction])(nextHeadPos)
if(stringify(this.segments[0]) === stringify(apple.pos))
speed=0.95*speed;
score++;
if(apple.type === "superapple")
speed = 1.10*speed;
score += 4;

apple.move();
else
this.segments.pop();
;

changeDirection(key)
switch(key)
case 39:
case 68:
case 37:
case 65:
keyLookup[key][this.direction]()
break;
case 192:
case 55:
case 56:
keyLookup[key]()
break;


checkCollision()


//========================
// Drawing
//========================
function drawStats()
var extras = 1;
if(score > highscoreNum)
highscoreNum = score;
//localStorage.setItem("3dhighscore", highscore);

if(speed < maxspeed)
maxspeedNum = speed;
//localStorage.setItem("3dmaxspeed", maxspeed);


scoredom.innerHTML=`Score: $score`;
speeddom.innerHTML=`Speed: $(((100/speed*100)`;

if(showhighscore)
extras++;
highscore.style.display = "block";
highscore.style.top = extrasLookup[extras]
highscore.innerHTML = `Highscore: $highscoreNum`;

else
highScoreDomStyle.display = "none";
;

if(showmaxspeed)
extras++;
maxspeed.style.display = "block";
maxspeed.style.top = extrasLookup[extras]
maxspeed.innerHTML = `Highest Speed: $0)/100)`;
else
maxspeed.style.display = "none";
;

if(showlag)
extras++;
lag.style.display = "block";
lag.style.top = extrasLookup[extras]
lag.innerHTML = `Lag: $lagNumms`;
else
lagdomstyle.display = "none";
;

function renderArena()
;


//========================
// Apple
//========================
class Apple
constructor()
this.pos = new Location(2,1,2)

move()

// Set the location to a random x and z.
var x = randomNumberBetween(0,ArenaWidth-4)
var z = randomNumberBetween(0,ArenaLength-4)
this.pos = new Location(x,1,z)
if(randomNumberBetween(1,11)===1&&score>15)
apple.type="superapple"
else
apple.type="apple"


draw()
var sphere

// Generate a new sphere.
if(this.type=="superapple")
sphere = new newMesh( applegeometry, superapplematerial );
else
sphere = new newMesh( applegeometry, applematerial );


// Get the data location.
var applepos=apple.pos

// Set the location of the visual apple to the data location.
sphere.position.set(applepos[0],applepos[1],applepos[2])
scene.add(sphere);


//========================
// Misc
//========================
function newGame(key)
if(key==82)

// Stop the game.
clearTimeout(gameLoop);
s=function();

// Start a new game.
var game = document.getElementById("canvas");
game.removeChild(game.childNodes[0]);
eval(document.getElementById("script").innerHTML);


gameOverDomStyle.opacity=0;
function gameOver()
s = function()
camera.position.copy(new newVector3((ArenaWidth/2)-2,Math.sqrt(
Math.pow(ArenaWidth/2,2)+Math.pow(ArenaLength/2,2)),(ArenaLength/2)-2));
camera.lookAt(new newVector3((ArenaWidth/2)-2,0,(ArenaLength/2)-2));
;
document.onkeydown=function(e)
newGame(e.keyCode);

//listen to shake event
var shakeEvent = new Shake(threshold: 15);
shakeEvent.start();
window.addEventListener('shake', function()
newGame(82)
, false);

//stop listening
function stopShake()
shakeEvent.stop();


//check if shake is supported or not.
if(!("ondevicemotion" in window))alert("Not Supported");
gameOverDomStyle.opacity = 1;


function randomNumberBetween(a,b)
return a+floor(random()*(b-a));

var apple = new Apple(),
snake = new Snake()
var directionSwitch=
"forwards":function(a)this.nextHead = new Location(a[0]+1, a[1], a[2]),
"backwards":function(a)this.nextHead = new Location(a[0]-1, a[1], a[2]),
"left":function(a)this.nextHead = new Location(a[0], a[1], a[2]-1),
"right":function(a)this.nextHead = new Location(a[0], a[1], a[2]+1)

for(var x in directionSwitch)
directionSwitch[x] = directionSwitch[x].bind(snake)

var right =
"right":function()this.nextDirection = "backwards",
"backwards":function()this.nextDirection = "left",
"forwards":function()this.nextDirection = "right",
"left":function()this.nextDirection = "forwards"

for(var x in right)
right[x] = right[x].bind(snake)

var left =
"right":function()snake.nextDirection = "forwards",
"forwards":function()snake.nextDirection = "left",
"left":function()snake.nextDirection = "backwards",
"backwards":function()snake.nextDirection = "right"

for(var x in left)
left[x] = left[x].bind(snake)

var keyLookup =
"39":right,
"68":right,
"37":left,
"65":left,
"192":function()showlag=!showlag,
"55":function()showhighscore=!showhighscore,
"56":function()showmaxspeed = !showmaxspeed

snake.draw();
apple.move();

var background = new THREE.Color( "white" ),
fog = new THREE.FogExp2( "random", 0.02625 );

let s = function()
// Start for lag detection.
var start = performance.now();

// Make a fresh scene.
scene = new newScene();

// Move the snake.
snake.move();

// Render various things onto the scene.
scene.add(arenaWallMesh,arenaFloorMesh)
snake.draw();
apple.draw();
drawStats();


// Get relevent snake parts.
let head = snake.segments[0];
let nextHead = snake.nextHead;

// Set camera position and target.
camera.position.set(head[0],head[1],head[2]);
camera.lookAt(new newVector3(nextHead[0],nextHead[1],nextHead[2]));

// Set background and fog.
scene.background = background;
scene.fog = fog;
let end = performance.now();
// Reschedule the next update
gameLoop = setTimeout(function()
requestAnimationFrame(s)
,speed)

// End for lag detection and calculation of lag.
lagNum = floor((end-start))

animate()
var gameLoop = setTimeout(function()
requestAnimationFrame(s)
,speed);
document.onkeydown = function(e)
snake.changeDirection(e.keyCode);

)(window.THREE, (((window.innerWidth/10)|0)*10-2*10)/10, (((window.innerHeight/10)|0)*10-2*10)/10)
</script>









share|improve this question













This is an iterative review of this question: 3D 1st Person Snake Game #1
The next iteration can be found here: 3D 1st Person Snake Game #3
Here is a snippet of the code:






<html>
<style>
canvas
position:fixed;
left:0;
top:0;
width:99%;
height:99%;

*
padding:0px;
margin:0px

#score,#speed,#highscore,#maxspeed,#lag,#debug
position: fixed;
z-index: 100;
font-size:20px;
font-family:Verdana;
left:15px;
width: 100%;

#gameover
position:absolute;
z-index: 100;
font-size:60px;
font-family:Verdana;
margin: 0;
top: 50%;
left: 50%;
opacity:0;
transform: translate(-50%, -50%);

#maxspeed, #score, #josh, #speed, #highscore, #lag
display:block;

#maxspeed
width: 100%;
top:50px;
display:none;


#score
top: 10px;

#speed
top: 30px;


#highscore
top:30px;


#lag
top: 70px;

</style>
<div id="stats">
<div id="debug"></div>
<div id="score">Score: 0</div>
<div id="speed">Speed: 1</div>
<div id="highscore">Highscore: 1</div>
<div id="maxspeed">Highest Speed: 1</div>
<span id="lag">Lag: 0ms</span>
<div id="gameover" align="center">Game Over</div>
</div>
<div id="canvas"></div>
<p id="p"></p>
<p id="e"></p>
<script type="text/javascript" src="https://cdn.rawgit.com/alexgibson/shake.js/master/shake.js"></script>
<script src="https://threejs.org/build/three.min.js"></script>
<script>
//========================
// One times
//========================
const random = Math.random,
floor = function(a) return ~~a,
newGeometry = THREE.Geometry,
newBufferGeometry = THREE.BufferGeometry,
newMesh = THREE.Mesh,
newLineSegments = THREE.LineSegments,
newMeshBasicMaterial = THREE.MeshBasicMaterial,
newVector3 = THREE.Vector3,
newLineBasicMaterial = THREE.LineBasicMaterial,
newBoxGeometry = THREE.BoxGeometry,
newBoxBufferGeometry = THREE.BoxBufferGeometry,
arena = new THREE.Group(),
applegeometry = new THREE.SphereBufferGeometry( 0.5, 32, 32 ),
superapplematerial= new newMeshBasicMaterial(color:"gold"),
applematerial= new newMeshBasicMaterial(color:"limegreen"),
floormaterial = new newMeshBasicMaterial(color:"lightgrey"),
wallmaterial = new newMeshBasicMaterial( color: "grey" ),
linecube = new newBoxBufferGeometry( 1,1,1 ),
edges = new THREE.EdgesGeometry( linecube ),
geometry = new newBoxBufferGeometry( 1,1,1 ),
stringify = JSON.stringify


</script>
<script id="script">
(function(THREE,ArenaWidth, ArenaLength)
'use strict'
const arenaLines = new THREE.Group(),
arenaWall = new newGeometry(),
arenaFloor = new newGeometry(),
wall1 = new newBoxGeometry( ArenaWidth+1, 1, 1 )
.translate((ArenaWidth/2)-2,1,-2);
arenaWall.merge(wall1);
arenaWall.merge(wall1.translate(0,0, ArenaLength));
const wall2 = new newBoxGeometry( 1, 1, ArenaLength+1 ).translate(ArenaWidth-2,1,(ArenaLength/2)-2);
arenaWall.merge(wall2);
arenaWall.merge(wall2.translate(-ArenaWidth,0,0));
arenaFloor.merge(new newBoxGeometry( ArenaWidth+1, 1, ArenaLength+1 ).translate((ArenaWidth/2)-2,0,(ArenaLength/2)-2))
arenaWall.mergeVertices()
arenaFloor.mergeVertices()
// Get the meshs
window.arenaWallMesh = new newMesh(arenaWall, wallmaterial);
window.arenaFloorMesh = new newMesh(arenaFloor, floormaterial);

var speed = 100,
maxwidth = 40,
maxdepdth = 40,
size = 0.5,
score = 0,
maxheight = 0,
lagNum = 0,
highscoreNum,
showlag,
maxspeedNum,
showmaxspeed,
showhighscore

//========================
// Threejs
//========================

var scene = new THREE.Scene(),
camera= new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,60),
renderer = new THREE.WebGLRenderer(),
extrasLookup =
1:30,
2:50,
3:70,
4:90

//========================
// Reductions
//========================
const newScene = THREE.Scene

if(true /*localStorage.getItem("3dhighscore")==undefined*/)
highscoreNum=0
else
highscoreNum = localStorage.getItem("3dhighscore")

if(true /*localStorage.getItem("showlag")==undefined*/)
showlag=false
else
showlag = localStorage.getItem("showlag")

if(true /*localStorage.getItem("3dmaxspeed")==undefined*/)
maxspeedNum=100
else
maxspeedNum = localStorage.getItem("3dmaxspeed")

if(showmaxspeed==undefined)
showmaxspeed=false

if(showhighscore==undefined)
showhighscore=false


renderer.setSize( window.innerWidth, window.innerHeight );
document.getElementById("canvas").appendChild( renderer.domElement );

function animate()
requestAnimationFrame( animate )
renderer.render( scene, camera );

class Location
constructor(x,y,z)
return [x,y,z]



//========================
// Dom
//========================
const maxSpeedDom = document.getElementById("maxspeed"),
maxSpeedDomStyle = maxSpeedDom.style,
lagdom = document.getElementById("lag"),
lagdomstyle = lagdom.style,
highScoreDom = document.getElementById("highscore"),
highScoreDomStyle = highScoreDom.style,
scoredom = document.getElementById("score"),
speeddom = document.getElementById("speed"),
gameOverDom = document.getElementById("gameover"),
gameOverDomStyle = gameOverDom.style;
//========================
// Snake
//========================
class Snake
constructor()
this.segments = [
new Location(7,1,5),
new Location(6,1,5),
new Location(5,1,5)
];
this.direction = "forwards";
this.nextDirection = "forwards";
this.nextHead = new Location(8,1,5);

draw()
let snakeobject = new THREE.Group();
let j = this.segments.length
this.segments.forEach((item,index) =>
let i = index
let segmentColor=`rgb($255-(255/j,00,00)`
const cube = new newMesh(geometry, new newMeshBasicMaterial( color: segmentColor)),
x = item[0],
y = item[1],
z = item[2];
let pos = new newVector3(x,y,z)

const line = new newLineSegments(edges, new newLineBasicMaterial( color: segmentColor,linewidth:2 ));
cube.position.copy(pos);
line.position.copy(pos);
snakeobject.add(line,cube);
)
scene.add(snakeobject);

move()
this.segments.unshift(this.nextHead);
if(this.checkCollision())
this.segments.shift();
gameOver();
return;
;
var nextHeadPos = this.nextHead;
this.direction = this.nextDirection;
(directionSwitch[this.direction])(nextHeadPos)
if(stringify(this.segments[0]) === stringify(apple.pos))
speed=0.95*speed;
score++;
if(apple.type === "superapple")
speed = 1.10*speed;
score += 4;

apple.move();
else
this.segments.pop();
;

changeDirection(key)
switch(key)
case 39:
case 68:
case 37:
case 65:
keyLookup[key][this.direction]()
break;
case 192:
case 55:
case 56:
keyLookup[key]()
break;


checkCollision()


//========================
// Drawing
//========================
function drawStats()
var extras = 1;
if(score > highscoreNum)
highscoreNum = score;
//localStorage.setItem("3dhighscore", highscore);

if(speed < maxspeed)
maxspeedNum = speed;
//localStorage.setItem("3dmaxspeed", maxspeed);


scoredom.innerHTML=`Score: $score`;
speeddom.innerHTML=`Speed: $(((100/speed*100)`;

if(showhighscore)
extras++;
highscore.style.display = "block";
highscore.style.top = extrasLookup[extras]
highscore.innerHTML = `Highscore: $highscoreNum`;

else
highScoreDomStyle.display = "none";
;

if(showmaxspeed)
extras++;
maxspeed.style.display = "block";
maxspeed.style.top = extrasLookup[extras]
maxspeed.innerHTML = `Highest Speed: $0)/100)`;
else
maxspeed.style.display = "none";
;

if(showlag)
extras++;
lag.style.display = "block";
lag.style.top = extrasLookup[extras]
lag.innerHTML = `Lag: $lagNumms`;
else
lagdomstyle.display = "none";
;

function renderArena()
;


//========================
// Apple
//========================
class Apple
constructor()
this.pos = new Location(2,1,2)

move()

// Set the location to a random x and z.
var x = randomNumberBetween(0,ArenaWidth-4)
var z = randomNumberBetween(0,ArenaLength-4)
this.pos = new Location(x,1,z)
if(randomNumberBetween(1,11)===1&&score>15)
apple.type="superapple"
else
apple.type="apple"


draw()
var sphere

// Generate a new sphere.
if(this.type=="superapple")
sphere = new newMesh( applegeometry, superapplematerial );
else
sphere = new newMesh( applegeometry, applematerial );


// Get the data location.
var applepos=apple.pos

// Set the location of the visual apple to the data location.
sphere.position.set(applepos[0],applepos[1],applepos[2])
scene.add(sphere);


//========================
// Misc
//========================
function newGame(key)
if(key==82)

// Stop the game.
clearTimeout(gameLoop);
s=function();

// Start a new game.
var game = document.getElementById("canvas");
game.removeChild(game.childNodes[0]);
eval(document.getElementById("script").innerHTML);


gameOverDomStyle.opacity=0;
function gameOver()
s = function()
camera.position.copy(new newVector3((ArenaWidth/2)-2,Math.sqrt(
Math.pow(ArenaWidth/2,2)+Math.pow(ArenaLength/2,2)),(ArenaLength/2)-2));
camera.lookAt(new newVector3((ArenaWidth/2)-2,0,(ArenaLength/2)-2));
;
document.onkeydown=function(e)
newGame(e.keyCode);

//listen to shake event
var shakeEvent = new Shake(threshold: 15);
shakeEvent.start();
window.addEventListener('shake', function()
newGame(82)
, false);

//stop listening
function stopShake()
shakeEvent.stop();


//check if shake is supported or not.
if(!("ondevicemotion" in window))alert("Not Supported");
gameOverDomStyle.opacity = 1;


function randomNumberBetween(a,b)
return a+floor(random()*(b-a));

var apple = new Apple(),
snake = new Snake()
var directionSwitch=
"forwards":function(a)this.nextHead = new Location(a[0]+1, a[1], a[2]),
"backwards":function(a)this.nextHead = new Location(a[0]-1, a[1], a[2]),
"left":function(a)this.nextHead = new Location(a[0], a[1], a[2]-1),
"right":function(a)this.nextHead = new Location(a[0], a[1], a[2]+1)

for(var x in directionSwitch)
directionSwitch[x] = directionSwitch[x].bind(snake)

var right =
"right":function()this.nextDirection = "backwards",
"backwards":function()this.nextDirection = "left",
"forwards":function()this.nextDirection = "right",
"left":function()this.nextDirection = "forwards"

for(var x in right)
right[x] = right[x].bind(snake)

var left =
"right":function()snake.nextDirection = "forwards",
"forwards":function()snake.nextDirection = "left",
"left":function()snake.nextDirection = "backwards",
"backwards":function()snake.nextDirection = "right"

for(var x in left)
left[x] = left[x].bind(snake)

var keyLookup =
"39":right,
"68":right,
"37":left,
"65":left,
"192":function()showlag=!showlag,
"55":function()showhighscore=!showhighscore,
"56":function()showmaxspeed = !showmaxspeed

snake.draw();
apple.move();

var background = new THREE.Color( "white" ),
fog = new THREE.FogExp2( "random", 0.02625 );

let s = function()
// Start for lag detection.
var start = performance.now();

// Make a fresh scene.
scene = new newScene();

// Move the snake.
snake.move();

// Render various things onto the scene.
scene.add(arenaWallMesh,arenaFloorMesh)
snake.draw();
apple.draw();
drawStats();


// Get relevent snake parts.
let head = snake.segments[0];
let nextHead = snake.nextHead;

// Set camera position and target.
camera.position.set(head[0],head[1],head[2]);
camera.lookAt(new newVector3(nextHead[0],nextHead[1],nextHead[2]));

// Set background and fog.
scene.background = background;
scene.fog = fog;
let end = performance.now();
// Reschedule the next update
gameLoop = setTimeout(function()
requestAnimationFrame(s)
,speed)

// End for lag detection and calculation of lag.
lagNum = floor((end-start))

animate()
var gameLoop = setTimeout(function()
requestAnimationFrame(s)
,speed);
document.onkeydown = function(e)
snake.changeDirection(e.keyCode);

)(window.THREE, (((window.innerWidth/10)|0)*10-2*10)/10, (((window.innerHeight/10)|0)*10-2*10)/10)
</script>








<html>
<style>
canvas
position:fixed;
left:0;
top:0;
width:99%;
height:99%;

*
padding:0px;
margin:0px

#score,#speed,#highscore,#maxspeed,#lag,#debug
position: fixed;
z-index: 100;
font-size:20px;
font-family:Verdana;
left:15px;
width: 100%;

#gameover
position:absolute;
z-index: 100;
font-size:60px;
font-family:Verdana;
margin: 0;
top: 50%;
left: 50%;
opacity:0;
transform: translate(-50%, -50%);

#maxspeed, #score, #josh, #speed, #highscore, #lag
display:block;

#maxspeed
width: 100%;
top:50px;
display:none;


#score
top: 10px;

#speed
top: 30px;


#highscore
top:30px;


#lag
top: 70px;

</style>
<div id="stats">
<div id="debug"></div>
<div id="score">Score: 0</div>
<div id="speed">Speed: 1</div>
<div id="highscore">Highscore: 1</div>
<div id="maxspeed">Highest Speed: 1</div>
<span id="lag">Lag: 0ms</span>
<div id="gameover" align="center">Game Over</div>
</div>
<div id="canvas"></div>
<p id="p"></p>
<p id="e"></p>
<script type="text/javascript" src="https://cdn.rawgit.com/alexgibson/shake.js/master/shake.js"></script>
<script src="https://threejs.org/build/three.min.js"></script>
<script>
//========================
// One times
//========================
const random = Math.random,
floor = function(a) return ~~a,
newGeometry = THREE.Geometry,
newBufferGeometry = THREE.BufferGeometry,
newMesh = THREE.Mesh,
newLineSegments = THREE.LineSegments,
newMeshBasicMaterial = THREE.MeshBasicMaterial,
newVector3 = THREE.Vector3,
newLineBasicMaterial = THREE.LineBasicMaterial,
newBoxGeometry = THREE.BoxGeometry,
newBoxBufferGeometry = THREE.BoxBufferGeometry,
arena = new THREE.Group(),
applegeometry = new THREE.SphereBufferGeometry( 0.5, 32, 32 ),
superapplematerial= new newMeshBasicMaterial(color:"gold"),
applematerial= new newMeshBasicMaterial(color:"limegreen"),
floormaterial = new newMeshBasicMaterial(color:"lightgrey"),
wallmaterial = new newMeshBasicMaterial( color: "grey" ),
linecube = new newBoxBufferGeometry( 1,1,1 ),
edges = new THREE.EdgesGeometry( linecube ),
geometry = new newBoxBufferGeometry( 1,1,1 ),
stringify = JSON.stringify


</script>
<script id="script">
(function(THREE,ArenaWidth, ArenaLength)
'use strict'
const arenaLines = new THREE.Group(),
arenaWall = new newGeometry(),
arenaFloor = new newGeometry(),
wall1 = new newBoxGeometry( ArenaWidth+1, 1, 1 )
.translate((ArenaWidth/2)-2,1,-2);
arenaWall.merge(wall1);
arenaWall.merge(wall1.translate(0,0, ArenaLength));
const wall2 = new newBoxGeometry( 1, 1, ArenaLength+1 ).translate(ArenaWidth-2,1,(ArenaLength/2)-2);
arenaWall.merge(wall2);
arenaWall.merge(wall2.translate(-ArenaWidth,0,0));
arenaFloor.merge(new newBoxGeometry( ArenaWidth+1, 1, ArenaLength+1 ).translate((ArenaWidth/2)-2,0,(ArenaLength/2)-2))
arenaWall.mergeVertices()
arenaFloor.mergeVertices()
// Get the meshs
window.arenaWallMesh = new newMesh(arenaWall, wallmaterial);
window.arenaFloorMesh = new newMesh(arenaFloor, floormaterial);

var speed = 100,
maxwidth = 40,
maxdepdth = 40,
size = 0.5,
score = 0,
maxheight = 0,
lagNum = 0,
highscoreNum,
showlag,
maxspeedNum,
showmaxspeed,
showhighscore

//========================
// Threejs
//========================

var scene = new THREE.Scene(),
camera= new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,60),
renderer = new THREE.WebGLRenderer(),
extrasLookup =
1:30,
2:50,
3:70,
4:90

//========================
// Reductions
//========================
const newScene = THREE.Scene

if(true /*localStorage.getItem("3dhighscore")==undefined*/)
highscoreNum=0
else
highscoreNum = localStorage.getItem("3dhighscore")

if(true /*localStorage.getItem("showlag")==undefined*/)
showlag=false
else
showlag = localStorage.getItem("showlag")

if(true /*localStorage.getItem("3dmaxspeed")==undefined*/)
maxspeedNum=100
else
maxspeedNum = localStorage.getItem("3dmaxspeed")

if(showmaxspeed==undefined)
showmaxspeed=false

if(showhighscore==undefined)
showhighscore=false


renderer.setSize( window.innerWidth, window.innerHeight );
document.getElementById("canvas").appendChild( renderer.domElement );

function animate()
requestAnimationFrame( animate )
renderer.render( scene, camera );

class Location
constructor(x,y,z)
return [x,y,z]



//========================
// Dom
//========================
const maxSpeedDom = document.getElementById("maxspeed"),
maxSpeedDomStyle = maxSpeedDom.style,
lagdom = document.getElementById("lag"),
lagdomstyle = lagdom.style,
highScoreDom = document.getElementById("highscore"),
highScoreDomStyle = highScoreDom.style,
scoredom = document.getElementById("score"),
speeddom = document.getElementById("speed"),
gameOverDom = document.getElementById("gameover"),
gameOverDomStyle = gameOverDom.style;
//========================
// Snake
//========================
class Snake
constructor()
this.segments = [
new Location(7,1,5),
new Location(6,1,5),
new Location(5,1,5)
];
this.direction = "forwards";
this.nextDirection = "forwards";
this.nextHead = new Location(8,1,5);

draw()
let snakeobject = new THREE.Group();
let j = this.segments.length
this.segments.forEach((item,index) =>
let i = index
let segmentColor=`rgb($255-(255/j,00,00)`
const cube = new newMesh(geometry, new newMeshBasicMaterial( color: segmentColor)),
x = item[0],
y = item[1],
z = item[2];
let pos = new newVector3(x,y,z)

const line = new newLineSegments(edges, new newLineBasicMaterial( color: segmentColor,linewidth:2 ));
cube.position.copy(pos);
line.position.copy(pos);
snakeobject.add(line,cube);
)
scene.add(snakeobject);

move()
this.segments.unshift(this.nextHead);
if(this.checkCollision())
this.segments.shift();
gameOver();
return;
;
var nextHeadPos = this.nextHead;
this.direction = this.nextDirection;
(directionSwitch[this.direction])(nextHeadPos)
if(stringify(this.segments[0]) === stringify(apple.pos))
speed=0.95*speed;
score++;
if(apple.type === "superapple")
speed = 1.10*speed;
score += 4;

apple.move();
else
this.segments.pop();
;

changeDirection(key)
switch(key)
case 39:
case 68:
case 37:
case 65:
keyLookup[key][this.direction]()
break;
case 192:
case 55:
case 56:
keyLookup[key]()
break;


checkCollision()


//========================
// Drawing
//========================
function drawStats()
var extras = 1;
if(score > highscoreNum)
highscoreNum = score;
//localStorage.setItem("3dhighscore", highscore);

if(speed < maxspeed)
maxspeedNum = speed;
//localStorage.setItem("3dmaxspeed", maxspeed);


scoredom.innerHTML=`Score: $score`;
speeddom.innerHTML=`Speed: $(((100/speed*100)`;

if(showhighscore)
extras++;
highscore.style.display = "block";
highscore.style.top = extrasLookup[extras]
highscore.innerHTML = `Highscore: $highscoreNum`;

else
highScoreDomStyle.display = "none";
;

if(showmaxspeed)
extras++;
maxspeed.style.display = "block";
maxspeed.style.top = extrasLookup[extras]
maxspeed.innerHTML = `Highest Speed: $0)/100)`;
else
maxspeed.style.display = "none";
;

if(showlag)
extras++;
lag.style.display = "block";
lag.style.top = extrasLookup[extras]
lag.innerHTML = `Lag: $lagNumms`;
else
lagdomstyle.display = "none";
;

function renderArena()
;


//========================
// Apple
//========================
class Apple
constructor()
this.pos = new Location(2,1,2)

move()

// Set the location to a random x and z.
var x = randomNumberBetween(0,ArenaWidth-4)
var z = randomNumberBetween(0,ArenaLength-4)
this.pos = new Location(x,1,z)
if(randomNumberBetween(1,11)===1&&score>15)
apple.type="superapple"
else
apple.type="apple"


draw()
var sphere

// Generate a new sphere.
if(this.type=="superapple")
sphere = new newMesh( applegeometry, superapplematerial );
else
sphere = new newMesh( applegeometry, applematerial );


// Get the data location.
var applepos=apple.pos

// Set the location of the visual apple to the data location.
sphere.position.set(applepos[0],applepos[1],applepos[2])
scene.add(sphere);


//========================
// Misc
//========================
function newGame(key)
if(key==82)

// Stop the game.
clearTimeout(gameLoop);
s=function();

// Start a new game.
var game = document.getElementById("canvas");
game.removeChild(game.childNodes[0]);
eval(document.getElementById("script").innerHTML);


gameOverDomStyle.opacity=0;
function gameOver()
s = function()
camera.position.copy(new newVector3((ArenaWidth/2)-2,Math.sqrt(
Math.pow(ArenaWidth/2,2)+Math.pow(ArenaLength/2,2)),(ArenaLength/2)-2));
camera.lookAt(new newVector3((ArenaWidth/2)-2,0,(ArenaLength/2)-2));
;
document.onkeydown=function(e)
newGame(e.keyCode);

//listen to shake event
var shakeEvent = new Shake(threshold: 15);
shakeEvent.start();
window.addEventListener('shake', function()
newGame(82)
, false);

//stop listening
function stopShake()
shakeEvent.stop();


//check if shake is supported or not.
if(!("ondevicemotion" in window))alert("Not Supported");
gameOverDomStyle.opacity = 1;


function randomNumberBetween(a,b)
return a+floor(random()*(b-a));

var apple = new Apple(),
snake = new Snake()
var directionSwitch=
"forwards":function(a)this.nextHead = new Location(a[0]+1, a[1], a[2]),
"backwards":function(a)this.nextHead = new Location(a[0]-1, a[1], a[2]),
"left":function(a)this.nextHead = new Location(a[0], a[1], a[2]-1),
"right":function(a)this.nextHead = new Location(a[0], a[1], a[2]+1)

for(var x in directionSwitch)
directionSwitch[x] = directionSwitch[x].bind(snake)

var right =
"right":function()this.nextDirection = "backwards",
"backwards":function()this.nextDirection = "left",
"forwards":function()this.nextDirection = "right",
"left":function()this.nextDirection = "forwards"

for(var x in right)
right[x] = right[x].bind(snake)

var left =
"right":function()snake.nextDirection = "forwards",
"forwards":function()snake.nextDirection = "left",
"left":function()snake.nextDirection = "backwards",
"backwards":function()snake.nextDirection = "right"

for(var x in left)
left[x] = left[x].bind(snake)

var keyLookup =
"39":right,
"68":right,
"37":left,
"65":left,
"192":function()showlag=!showlag,
"55":function()showhighscore=!showhighscore,
"56":function()showmaxspeed = !showmaxspeed

snake.draw();
apple.move();

var background = new THREE.Color( "white" ),
fog = new THREE.FogExp2( "random", 0.02625 );

let s = function()
// Start for lag detection.
var start = performance.now();

// Make a fresh scene.
scene = new newScene();

// Move the snake.
snake.move();

// Render various things onto the scene.
scene.add(arenaWallMesh,arenaFloorMesh)
snake.draw();
apple.draw();
drawStats();


// Get relevent snake parts.
let head = snake.segments[0];
let nextHead = snake.nextHead;

// Set camera position and target.
camera.position.set(head[0],head[1],head[2]);
camera.lookAt(new newVector3(nextHead[0],nextHead[1],nextHead[2]));

// Set background and fog.
scene.background = background;
scene.fog = fog;
let end = performance.now();
// Reschedule the next update
gameLoop = setTimeout(function()
requestAnimationFrame(s)
,speed)

// End for lag detection and calculation of lag.
lagNum = floor((end-start))

animate()
var gameLoop = setTimeout(function()
requestAnimationFrame(s)
,speed);
document.onkeydown = function(e)
snake.changeDirection(e.keyCode);

)(window.THREE, (((window.innerWidth/10)|0)*10-2*10)/10, (((window.innerHeight/10)|0)*10-2*10)/10)
</script>





<html>
<style>
canvas
position:fixed;
left:0;
top:0;
width:99%;
height:99%;

*
padding:0px;
margin:0px

#score,#speed,#highscore,#maxspeed,#lag,#debug
position: fixed;
z-index: 100;
font-size:20px;
font-family:Verdana;
left:15px;
width: 100%;

#gameover
position:absolute;
z-index: 100;
font-size:60px;
font-family:Verdana;
margin: 0;
top: 50%;
left: 50%;
opacity:0;
transform: translate(-50%, -50%);

#maxspeed, #score, #josh, #speed, #highscore, #lag
display:block;

#maxspeed
width: 100%;
top:50px;
display:none;


#score
top: 10px;

#speed
top: 30px;


#highscore
top:30px;


#lag
top: 70px;

</style>
<div id="stats">
<div id="debug"></div>
<div id="score">Score: 0</div>
<div id="speed">Speed: 1</div>
<div id="highscore">Highscore: 1</div>
<div id="maxspeed">Highest Speed: 1</div>
<span id="lag">Lag: 0ms</span>
<div id="gameover" align="center">Game Over</div>
</div>
<div id="canvas"></div>
<p id="p"></p>
<p id="e"></p>
<script type="text/javascript" src="https://cdn.rawgit.com/alexgibson/shake.js/master/shake.js"></script>
<script src="https://threejs.org/build/three.min.js"></script>
<script>
//========================
// One times
//========================
const random = Math.random,
floor = function(a) return ~~a,
newGeometry = THREE.Geometry,
newBufferGeometry = THREE.BufferGeometry,
newMesh = THREE.Mesh,
newLineSegments = THREE.LineSegments,
newMeshBasicMaterial = THREE.MeshBasicMaterial,
newVector3 = THREE.Vector3,
newLineBasicMaterial = THREE.LineBasicMaterial,
newBoxGeometry = THREE.BoxGeometry,
newBoxBufferGeometry = THREE.BoxBufferGeometry,
arena = new THREE.Group(),
applegeometry = new THREE.SphereBufferGeometry( 0.5, 32, 32 ),
superapplematerial= new newMeshBasicMaterial(color:"gold"),
applematerial= new newMeshBasicMaterial(color:"limegreen"),
floormaterial = new newMeshBasicMaterial(color:"lightgrey"),
wallmaterial = new newMeshBasicMaterial( color: "grey" ),
linecube = new newBoxBufferGeometry( 1,1,1 ),
edges = new THREE.EdgesGeometry( linecube ),
geometry = new newBoxBufferGeometry( 1,1,1 ),
stringify = JSON.stringify


</script>
<script id="script">
(function(THREE,ArenaWidth, ArenaLength)
'use strict'
const arenaLines = new THREE.Group(),
arenaWall = new newGeometry(),
arenaFloor = new newGeometry(),
wall1 = new newBoxGeometry( ArenaWidth+1, 1, 1 )
.translate((ArenaWidth/2)-2,1,-2);
arenaWall.merge(wall1);
arenaWall.merge(wall1.translate(0,0, ArenaLength));
const wall2 = new newBoxGeometry( 1, 1, ArenaLength+1 ).translate(ArenaWidth-2,1,(ArenaLength/2)-2);
arenaWall.merge(wall2);
arenaWall.merge(wall2.translate(-ArenaWidth,0,0));
arenaFloor.merge(new newBoxGeometry( ArenaWidth+1, 1, ArenaLength+1 ).translate((ArenaWidth/2)-2,0,(ArenaLength/2)-2))
arenaWall.mergeVertices()
arenaFloor.mergeVertices()
// Get the meshs
window.arenaWallMesh = new newMesh(arenaWall, wallmaterial);
window.arenaFloorMesh = new newMesh(arenaFloor, floormaterial);

var speed = 100,
maxwidth = 40,
maxdepdth = 40,
size = 0.5,
score = 0,
maxheight = 0,
lagNum = 0,
highscoreNum,
showlag,
maxspeedNum,
showmaxspeed,
showhighscore

//========================
// Threejs
//========================

var scene = new THREE.Scene(),
camera= new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,60),
renderer = new THREE.WebGLRenderer(),
extrasLookup =
1:30,
2:50,
3:70,
4:90

//========================
// Reductions
//========================
const newScene = THREE.Scene

if(true /*localStorage.getItem("3dhighscore")==undefined*/)
highscoreNum=0
else
highscoreNum = localStorage.getItem("3dhighscore")

if(true /*localStorage.getItem("showlag")==undefined*/)
showlag=false
else
showlag = localStorage.getItem("showlag")

if(true /*localStorage.getItem("3dmaxspeed")==undefined*/)
maxspeedNum=100
else
maxspeedNum = localStorage.getItem("3dmaxspeed")

if(showmaxspeed==undefined)
showmaxspeed=false

if(showhighscore==undefined)
showhighscore=false


renderer.setSize( window.innerWidth, window.innerHeight );
document.getElementById("canvas").appendChild( renderer.domElement );

function animate()
requestAnimationFrame( animate )
renderer.render( scene, camera );

class Location
constructor(x,y,z)
return [x,y,z]



//========================
// Dom
//========================
const maxSpeedDom = document.getElementById("maxspeed"),
maxSpeedDomStyle = maxSpeedDom.style,
lagdom = document.getElementById("lag"),
lagdomstyle = lagdom.style,
highScoreDom = document.getElementById("highscore"),
highScoreDomStyle = highScoreDom.style,
scoredom = document.getElementById("score"),
speeddom = document.getElementById("speed"),
gameOverDom = document.getElementById("gameover"),
gameOverDomStyle = gameOverDom.style;
//========================
// Snake
//========================
class Snake
constructor()
this.segments = [
new Location(7,1,5),
new Location(6,1,5),
new Location(5,1,5)
];
this.direction = "forwards";
this.nextDirection = "forwards";
this.nextHead = new Location(8,1,5);

draw()
let snakeobject = new THREE.Group();
let j = this.segments.length
this.segments.forEach((item,index) =>
let i = index
let segmentColor=`rgb($255-(255/j,00,00)`
const cube = new newMesh(geometry, new newMeshBasicMaterial( color: segmentColor)),
x = item[0],
y = item[1],
z = item[2];
let pos = new newVector3(x,y,z)

const line = new newLineSegments(edges, new newLineBasicMaterial( color: segmentColor,linewidth:2 ));
cube.position.copy(pos);
line.position.copy(pos);
snakeobject.add(line,cube);
)
scene.add(snakeobject);

move()
this.segments.unshift(this.nextHead);
if(this.checkCollision())
this.segments.shift();
gameOver();
return;
;
var nextHeadPos = this.nextHead;
this.direction = this.nextDirection;
(directionSwitch[this.direction])(nextHeadPos)
if(stringify(this.segments[0]) === stringify(apple.pos))
speed=0.95*speed;
score++;
if(apple.type === "superapple")
speed = 1.10*speed;
score += 4;

apple.move();
else
this.segments.pop();
;

changeDirection(key)
switch(key)
case 39:
case 68:
case 37:
case 65:
keyLookup[key][this.direction]()
break;
case 192:
case 55:
case 56:
keyLookup[key]()
break;


checkCollision()


//========================
// Drawing
//========================
function drawStats()
var extras = 1;
if(score > highscoreNum)
highscoreNum = score;
//localStorage.setItem("3dhighscore", highscore);

if(speed < maxspeed)
maxspeedNum = speed;
//localStorage.setItem("3dmaxspeed", maxspeed);


scoredom.innerHTML=`Score: $score`;
speeddom.innerHTML=`Speed: $(((100/speed*100)`;

if(showhighscore)
extras++;
highscore.style.display = "block";
highscore.style.top = extrasLookup[extras]
highscore.innerHTML = `Highscore: $highscoreNum`;

else
highScoreDomStyle.display = "none";
;

if(showmaxspeed)
extras++;
maxspeed.style.display = "block";
maxspeed.style.top = extrasLookup[extras]
maxspeed.innerHTML = `Highest Speed: $0)/100)`;
else
maxspeed.style.display = "none";
;

if(showlag)
extras++;
lag.style.display = "block";
lag.style.top = extrasLookup[extras]
lag.innerHTML = `Lag: $lagNumms`;
else
lagdomstyle.display = "none";
;

function renderArena()
;


//========================
// Apple
//========================
class Apple
constructor()
this.pos = new Location(2,1,2)

move()

// Set the location to a random x and z.
var x = randomNumberBetween(0,ArenaWidth-4)
var z = randomNumberBetween(0,ArenaLength-4)
this.pos = new Location(x,1,z)
if(randomNumberBetween(1,11)===1&&score>15)
apple.type="superapple"
else
apple.type="apple"


draw()
var sphere

// Generate a new sphere.
if(this.type=="superapple")
sphere = new newMesh( applegeometry, superapplematerial );
else
sphere = new newMesh( applegeometry, applematerial );


// Get the data location.
var applepos=apple.pos

// Set the location of the visual apple to the data location.
sphere.position.set(applepos[0],applepos[1],applepos[2])
scene.add(sphere);


//========================
// Misc
//========================
function newGame(key)
if(key==82)

// Stop the game.
clearTimeout(gameLoop);
s=function();

// Start a new game.
var game = document.getElementById("canvas");
game.removeChild(game.childNodes[0]);
eval(document.getElementById("script").innerHTML);


gameOverDomStyle.opacity=0;
function gameOver()
s = function()
camera.position.copy(new newVector3((ArenaWidth/2)-2,Math.sqrt(
Math.pow(ArenaWidth/2,2)+Math.pow(ArenaLength/2,2)),(ArenaLength/2)-2));
camera.lookAt(new newVector3((ArenaWidth/2)-2,0,(ArenaLength/2)-2));
;
document.onkeydown=function(e)
newGame(e.keyCode);

//listen to shake event
var shakeEvent = new Shake(threshold: 15);
shakeEvent.start();
window.addEventListener('shake', function()
newGame(82)
, false);

//stop listening
function stopShake()
shakeEvent.stop();


//check if shake is supported or not.
if(!("ondevicemotion" in window))alert("Not Supported");
gameOverDomStyle.opacity = 1;


function randomNumberBetween(a,b)
return a+floor(random()*(b-a));

var apple = new Apple(),
snake = new Snake()
var directionSwitch=
"forwards":function(a)this.nextHead = new Location(a[0]+1, a[1], a[2]),
"backwards":function(a)this.nextHead = new Location(a[0]-1, a[1], a[2]),
"left":function(a)this.nextHead = new Location(a[0], a[1], a[2]-1),
"right":function(a)this.nextHead = new Location(a[0], a[1], a[2]+1)

for(var x in directionSwitch)
directionSwitch[x] = directionSwitch[x].bind(snake)

var right =
"right":function()this.nextDirection = "backwards",
"backwards":function()this.nextDirection = "left",
"forwards":function()this.nextDirection = "right",
"left":function()this.nextDirection = "forwards"

for(var x in right)
right[x] = right[x].bind(snake)

var left =
"right":function()snake.nextDirection = "forwards",
"forwards":function()snake.nextDirection = "left",
"left":function()snake.nextDirection = "backwards",
"backwards":function()snake.nextDirection = "right"

for(var x in left)
left[x] = left[x].bind(snake)

var keyLookup =
"39":right,
"68":right,
"37":left,
"65":left,
"192":function()showlag=!showlag,
"55":function()showhighscore=!showhighscore,
"56":function()showmaxspeed = !showmaxspeed

snake.draw();
apple.move();

var background = new THREE.Color( "white" ),
fog = new THREE.FogExp2( "random", 0.02625 );

let s = function()
// Start for lag detection.
var start = performance.now();

// Make a fresh scene.
scene = new newScene();

// Move the snake.
snake.move();

// Render various things onto the scene.
scene.add(arenaWallMesh,arenaFloorMesh)
snake.draw();
apple.draw();
drawStats();


// Get relevent snake parts.
let head = snake.segments[0];
let nextHead = snake.nextHead;

// Set camera position and target.
camera.position.set(head[0],head[1],head[2]);
camera.lookAt(new newVector3(nextHead[0],nextHead[1],nextHead[2]));

// Set background and fog.
scene.background = background;
scene.fog = fog;
let end = performance.now();
// Reschedule the next update
gameLoop = setTimeout(function()
requestAnimationFrame(s)
,speed)

// End for lag detection and calculation of lag.
lagNum = floor((end-start))

animate()
var gameLoop = setTimeout(function()
requestAnimationFrame(s)
,speed);
document.onkeydown = function(e)
snake.changeDirection(e.keyCode);

)(window.THREE, (((window.innerWidth/10)|0)*10-2*10)/10, (((window.innerHeight/10)|0)*10-2*10)/10)
</script>








share|improve this question












share|improve this question




share|improve this question








edited May 21 at 12:02
























asked May 14 at 16:29









FreezePhoenix

310218




310218











  • Note: For the snippet, click "run", "Full page", purposely lose, and then click "r". Unfortunately the snippet makes the game small...
    – FreezePhoenix
    May 14 at 16:49







  • 2




    Oh maaan. It's so hard to play. Sorry, now got zero time to write an actual review! i.stack.imgur.com/gfiZi.png
    – Igor Soloydenko
    May 14 at 18:02
















  • Note: For the snippet, click "run", "Full page", purposely lose, and then click "r". Unfortunately the snippet makes the game small...
    – FreezePhoenix
    May 14 at 16:49







  • 2




    Oh maaan. It's so hard to play. Sorry, now got zero time to write an actual review! i.stack.imgur.com/gfiZi.png
    – Igor Soloydenko
    May 14 at 18:02















Note: For the snippet, click "run", "Full page", purposely lose, and then click "r". Unfortunately the snippet makes the game small...
– FreezePhoenix
May 14 at 16:49





Note: For the snippet, click "run", "Full page", purposely lose, and then click "r". Unfortunately the snippet makes the game small...
– FreezePhoenix
May 14 at 16:49





2




2




Oh maaan. It's so hard to play. Sorry, now got zero time to write an actual review! i.stack.imgur.com/gfiZi.png
– Igor Soloydenko
May 14 at 18:02




Oh maaan. It's so hard to play. Sorry, now got zero time to write an actual review! i.stack.imgur.com/gfiZi.png
– Igor Soloydenko
May 14 at 18:02










1 Answer
1






active

oldest

votes

















up vote
3
down vote



accepted










Feedback



I like how the DOM elements are stored in constants at the beginning of the code. It seems that a lot of the feedback from previous answers has been incorporated, except a few things like resetting the game without using eval(), and other es-6 features like classes. The CSS styles look succinct and appear to be sufficient.



Suggestions/Comments



  • In the function checkCollision() it might be fitting to use Array.prototype.some() instead of assigning the value of a boolean inside the callback of a forEach(). Also, that loop call comes after the check for a wall collision - if there is a wall collision, the function could immediately return true instead of also looping through the segments.


  • As was mentioned by samurai8 in the answer to your previous review there are still places where var is used instead of let



  • Blindman's answer on the first game mentioned using semi-colons - it appears most lines have them but some still don't.

  • The HTML snippet doesn't have a <body> tag - apparently it still works and perhaps you have one in other environments but it feels weird not to have one.


  • The event listener for shake could be simplified: Use Function.prototype.bind() to create a partially applied function:




    window.addEventListener('shake', function()
    newGame(82)
    , false);



    Can be simplified to:



    window.addEventListener('shake', newGame.bind(null,82), false);






share|improve this answer





















    Your Answer




    StackExchange.ifUsing("editor", function ()
    return StackExchange.using("mathjaxEditing", function ()
    StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
    StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
    );
    );
    , "mathjax-editing");

    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "196"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    convertImagesToLinks: false,
    noModals: false,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );








     

    draft saved


    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f194377%2f3d-1st-person-snake-game-2%23new-answer', 'question_page');

    );

    Post as a guest






























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    3
    down vote



    accepted










    Feedback



    I like how the DOM elements are stored in constants at the beginning of the code. It seems that a lot of the feedback from previous answers has been incorporated, except a few things like resetting the game without using eval(), and other es-6 features like classes. The CSS styles look succinct and appear to be sufficient.



    Suggestions/Comments



    • In the function checkCollision() it might be fitting to use Array.prototype.some() instead of assigning the value of a boolean inside the callback of a forEach(). Also, that loop call comes after the check for a wall collision - if there is a wall collision, the function could immediately return true instead of also looping through the segments.


    • As was mentioned by samurai8 in the answer to your previous review there are still places where var is used instead of let



    • Blindman's answer on the first game mentioned using semi-colons - it appears most lines have them but some still don't.

    • The HTML snippet doesn't have a <body> tag - apparently it still works and perhaps you have one in other environments but it feels weird not to have one.


    • The event listener for shake could be simplified: Use Function.prototype.bind() to create a partially applied function:




      window.addEventListener('shake', function()
      newGame(82)
      , false);



      Can be simplified to:



      window.addEventListener('shake', newGame.bind(null,82), false);






    share|improve this answer

























      up vote
      3
      down vote



      accepted










      Feedback



      I like how the DOM elements are stored in constants at the beginning of the code. It seems that a lot of the feedback from previous answers has been incorporated, except a few things like resetting the game without using eval(), and other es-6 features like classes. The CSS styles look succinct and appear to be sufficient.



      Suggestions/Comments



      • In the function checkCollision() it might be fitting to use Array.prototype.some() instead of assigning the value of a boolean inside the callback of a forEach(). Also, that loop call comes after the check for a wall collision - if there is a wall collision, the function could immediately return true instead of also looping through the segments.


      • As was mentioned by samurai8 in the answer to your previous review there are still places where var is used instead of let



      • Blindman's answer on the first game mentioned using semi-colons - it appears most lines have them but some still don't.

      • The HTML snippet doesn't have a <body> tag - apparently it still works and perhaps you have one in other environments but it feels weird not to have one.


      • The event listener for shake could be simplified: Use Function.prototype.bind() to create a partially applied function:




        window.addEventListener('shake', function()
        newGame(82)
        , false);



        Can be simplified to:



        window.addEventListener('shake', newGame.bind(null,82), false);






      share|improve this answer























        up vote
        3
        down vote



        accepted







        up vote
        3
        down vote



        accepted






        Feedback



        I like how the DOM elements are stored in constants at the beginning of the code. It seems that a lot of the feedback from previous answers has been incorporated, except a few things like resetting the game without using eval(), and other es-6 features like classes. The CSS styles look succinct and appear to be sufficient.



        Suggestions/Comments



        • In the function checkCollision() it might be fitting to use Array.prototype.some() instead of assigning the value of a boolean inside the callback of a forEach(). Also, that loop call comes after the check for a wall collision - if there is a wall collision, the function could immediately return true instead of also looping through the segments.


        • As was mentioned by samurai8 in the answer to your previous review there are still places where var is used instead of let



        • Blindman's answer on the first game mentioned using semi-colons - it appears most lines have them but some still don't.

        • The HTML snippet doesn't have a <body> tag - apparently it still works and perhaps you have one in other environments but it feels weird not to have one.


        • The event listener for shake could be simplified: Use Function.prototype.bind() to create a partially applied function:




          window.addEventListener('shake', function()
          newGame(82)
          , false);



          Can be simplified to:



          window.addEventListener('shake', newGame.bind(null,82), false);






        share|improve this answer













        Feedback



        I like how the DOM elements are stored in constants at the beginning of the code. It seems that a lot of the feedback from previous answers has been incorporated, except a few things like resetting the game without using eval(), and other es-6 features like classes. The CSS styles look succinct and appear to be sufficient.



        Suggestions/Comments



        • In the function checkCollision() it might be fitting to use Array.prototype.some() instead of assigning the value of a boolean inside the callback of a forEach(). Also, that loop call comes after the check for a wall collision - if there is a wall collision, the function could immediately return true instead of also looping through the segments.


        • As was mentioned by samurai8 in the answer to your previous review there are still places where var is used instead of let



        • Blindman's answer on the first game mentioned using semi-colons - it appears most lines have them but some still don't.

        • The HTML snippet doesn't have a <body> tag - apparently it still works and perhaps you have one in other environments but it feels weird not to have one.


        • The event listener for shake could be simplified: Use Function.prototype.bind() to create a partially applied function:




          window.addEventListener('shake', function()
          newGame(82)
          , false);



          Can be simplified to:



          window.addEventListener('shake', newGame.bind(null,82), false);







        share|improve this answer













        share|improve this answer



        share|improve this answer











        answered May 14 at 18:47









        Sam Onela

        5,77461543




        5,77461543






















             

            draft saved


            draft discarded


























             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f194377%2f3d-1st-person-snake-game-2%23new-answer', 'question_page');

            );

            Post as a guest













































































            Popular posts from this blog

            Chat program with C++ and SFML

            Function to Return a JSON Like Objects Using VBA Collections and Arrays

            Will my employers contract hold up in court?