var scene = new THREE.Scene();
// =============================================================================================
// =============================================================================================
// AUDIO
// =============================================================================================
// =============================================================================================
const SPEED1 = "/uploads/duarte/swingx1.mp3";
const SPEED2 = "/uploads/duarte/swingx1.25.mp3";
const SPEED3 = "/uploads/duarte/swingx1.5.mp3";
const HONK = "/uploads/duarte/car-honk.mp3";
const SPEEDUP = "/uploads/duarte/speed-up.mp3";
var speed1 = new Audio(SPEED1);
var speed2 = new Audio(SPEED2);
var speed3 = new Audio(SPEED3);
var honk = new Audio(HONK);
var speedUp = new Audio(SPEEDUP);
speed1.volume = 0.1;
speed2.volume = 0.1;
speed3.volume = 0.1;
honk.volume = 0.1;
speedUp.volume = 0.1;
// =============================================================================================
// =============================================================================================
// VARIABLES
// =============================================================================================
// =============================================================================================
const distance = 500;
var score1 = 0;
var hscore1 = 0;
var score2 = 0;
var hscore2 = 0;
const positionWidth = 42;
const columns = 17;
const boardWidth = positionWidth*columns;
const stepTime = 50; // Miliseconds it takes for the player to take a step forward, backward, left or right
let lanes;
let currentLane;
let currentColumn;
let password = "753";
let previousTimestamp;
let startMoving;
let moves;
let stepStartTimestamp;
// Player settings
const zoom = 2;
var player;
const playerSize = 15;
const initialDirLightPositionX = -100;
const initialDirLightPositionY = -100;
var d = 500;
const laneTypes = ['car', 'forest'];
const vechicleColors = [0xFFFFFF, 0x000000, 0xFF0000, 0xFFFF00, 0x0000FF, 0x9400D3, 0xFFA500];
const laneSpeeds = [2, 3, 5, 6, 7];
const bushHeights = [15,25,35];
const rocksHeights = [5,7,12];
var host;
var playerJoined= false;
var playerLeft = false;
var lockControls = false;
var clock;
// Manages Sound Speed UPs
var onSpeedUp1 = true;
var onSpeedUp2 = true;
// =============================================================================================
// =============================================================================================
// CAMERA
// =============================================================================================
// =============================================================================================
const camera = new THREE.OrthographicCamera( window.innerWidth/-2, window.innerWidth/2, window.innerHeight / 2, window.innerHeight / -2, 0.1, 10000 );
camera.rotation.x = 50*Math.PI/180;
camera.rotation.y = 20*Math.PI/180;
camera.rotation.z = 10*Math.PI/180;
const initialCameraPositionY = -Math.tan(camera.rotation.x)*distance;
const initialCameraPositionX = Math.tan(camera.rotation.y) * Math.sqrt(distance**2 + initialCameraPositionY**2);
camera.position.y = initialCameraPositionY;
camera.position.x = initialCameraPositionX;
camera.position.z = distance;
const generateLanes = () => [-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9].map((index) => {
const lane = new Lane(index);
lane.mesh.position.y = index*positionWidth*zoom;
scene.add( lane.mesh );
return lane;
}).filter((lane) => lane.index >= 0);
const addLane = () => {
const index = lanes.length;
const lane = new Lane(index);
lane.mesh.position.y = index*positionWidth*zoom;
scene.add(lane.mesh);
lanes.push(lane);
}
const initaliseValues = () => {
player = new Player();
scene.add( player );
hemiLight = new THREE.HemisphereLight(0xffffff, 0xffffff, 0.6);
scene.add(hemiLight);
dirLight = new THREE.DirectionalLight(0xffffff, 0.6);
dirLight.position.set(initialDirLightPositionX, initialDirLightPositionY, 200);
dirLight.target = player;
scene.add(dirLight);
backLight = new THREE.DirectionalLight(0x000000, .4);
backLight.position.set(200, 200, 50);
scene.add(backLight);
lanes = generateLanes()
currentLane = 0;
currentColumn = Math.floor(columns/2);
previousTimestamp = null;
startMoving = false;
moves = [];
stepStartTimestamp;
player.position.x = 0;
player.position.y = 0;
camera.position.y = initialCameraPositionY;
camera.position.x = initialCameraPositionX;
dirLight.position.x = initialDirLightPositionX;
dirLight.position.y = initialDirLightPositionY;
requestAnimationFrame( animate );
updateHtml();
speed1.play();
}
function loadResources() {
AB.socketStart ( );
AB.removeSplash();
if (playerJoined) {
initaliseValues();
} else {
waitingForPlayers();
}
}
AB.socketUserlist = function(e) {
console.log(e);
if (e.length % 2 === 0 && !playerJoined && host === undefined) {
// Join game
host = Math.floor(Math.random() * 999999999);
console.log(host);
playerJoined = true;
initaliseValues();
AB.removeSplash();
clock = new Clock();
clock.start();
socketOut("triggerJoin", true, false);
console.log("Join game");
} else if (e.length % 2 === 1 && !playerJoined && host === undefined) {
// Create game
host = AB.socket.id;
console.log("Create game");
}
switch(e.length) {
default:
if (void 0 !== host) {
socketOut("start", false, true);
}
}
AB.msg("<p>Current number of players = " + e.length + "\n</p>", 2);
}
window.onbeforeunload = function() {
socketOut("playerLeft", false, true);
}
AB.socketIn = function(element) {
console.log("TRIGGER SOCKET IN ", element.name, element.data);
if (element.name === "playerLeft" && element.data.host === host && playerJoined) {
lockControls = true;
playerLeft = true;
AB.socket.destroy();
endGame();
resetPlayer();
} else if (element.name === "update" && element.data.host === host && playerJoined) {
score2 = element.data.score2;
hscore2 = element.data.hscore2;
updateHtml();
} else if (element.name === "triggerJoin" && element.data.joined === true && !playerJoined) {
playerJoined = true;
clock = element.data.clock;
host = element.data.host;
initaliseValues();
AB.removeSplash();
} else if (element.name === "clockUpdate" && element.data.host === host && playerJoined) {
clock = element.data.clock;
AB.msg("<p>Time left: "+ clock.currTime +" seconds</p>", 5);
} else if (element.name === "endGame" && element.data.host === host && playerJoined) {
score2 = element.data.score2;
hscore2 = element.data.hscore2;
lockControls = true;
AB.socket.destroy();
endGame();
resetPlayer();
}
};
function updateHtml() {
AB.msg(`<h3> Welcome to our game!</h3>`, 1);
AB.msg(`<p>Player 1 Score: `+ score1+` | Highest: ` + hscore1 + ` </p>`, 3);
AB.msg(`<p>Player 2 Score: `+ score2 +` | Highest: ` + hscore2 + ` </p>`, 4);
}
const renderer = new THREE.WebGLRenderer({
alpha: true,
antialias: true
});
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
// =============================================================================================
// =============================================================================================
// SOCKETS
// =============================================================================================
// =============================================================================================
function socketOut(_name, _joined, _closed) {
AB.socketOut({
name: _name,
data : {
joined: _joined,
closed: _closed,
host: host,
clock: clock,
score2: score1,
hscore2: hscore1,
}
});
}
// =============================================================================================
// =============================================================================================
// CLOCK
// =============================================================================================
// =============================================================================================
class Clock {
constructor () {
this.currTime = 60
}
start() {
var clock = this;
function _time() {
clock.currTime--;
if (clock.currTime < 0) {
socketOut("endGame", false, false);
lockControls = true;
AB.socket.destroy();
endGame();
resetPlayer();
return;
}
AB.msg("<p>Time left: "+ clock.currTime +" seconds</p>", 5);
socketOut("clockUpdate", false, false);
}
setInterval(_time, 1000);
}
}
// =============================================================================================
// =============================================================================================
// PLAYER
// =============================================================================================
// =============================================================================================
function Player() {
const player = new THREE.Group();
const body = new THREE.Mesh(
new THREE.BoxBufferGeometry( (playerSize - 1)*zoom, (playerSize - 1)*zoom, (playerSize - 1)*zoom ),
new THREE.MeshPhongMaterial( { color: 0xF0B8A0 } )
);
body.position.z = 10*zoom;
body.position.z += 15;
player.add(body);
const hair = new THREE.Mesh(
new THREE.BoxBufferGeometry( (playerSize - 0.8)*zoom , (playerSize - 0.8)*zoom, 2*zoom ),
new THREE.MeshLambertMaterial( { color: 0x000000 } )
);
hair.position.z = 21*zoom;
hair.position.z += 6;
player.add(hair);
const pants = new THREE.Mesh(
new THREE.BoxBufferGeometry( playerSize*zoom , playerSize*zoom, 20*zoom ),
new THREE.MeshLambertMaterial( { color: 0x435F9A } )
);
pants.position.z = 10*zoom / 2;
player.add(pants);
return player;
}
// =============================================================================================
// =============================================================================================
// CAR
// =============================================================================================
// =============================================================================================
function Wheel() {
const wheel = new THREE.Mesh(
new THREE.BoxBufferGeometry( 12*zoom, 33*zoom, 12*zoom ),
new THREE.MeshLambertMaterial( { color: 0x333333 } )
);
wheel.position.z = 6*zoom;
return wheel;
}
function Car() {
const car = new THREE.Group();
const carFrontTexture = new Texture(40,80,[{x: 0, y: 10, w: 30, h: 60 }]);
const carBackTexture = new Texture(40,80,[{x: 10, y: 10, w: 30, h: 60 }]);
const carRightSideTexture = new Texture(110,40,[{x: 10, y: 0, w: 50, h: 30 }, {x: 70, y: 0, w: 30, h: 30 }]);
const carLeftSideTexture = new Texture(110,40,[{x: 10, y: 10, w: 50, h: 30 }, {x: 70, y: 10, w: 30, h: 30 }]);
const color = vechicleColors[Math.floor(Math.random() * vechicleColors.length)];
const main = new THREE.Mesh(
new THREE.BoxBufferGeometry( 60*zoom, 30*zoom, 15*zoom ),
new THREE.MeshPhongMaterial( { color} )
);
main.position.z = 12*zoom;
car.add(main)
const cabin = new THREE.Mesh(
new THREE.BoxBufferGeometry( 33*zoom, 24*zoom, 12*zoom ),
[
new THREE.MeshPhongMaterial( { color: 0xcccccc, map: carBackTexture } ),
new THREE.MeshPhongMaterial( { color: 0xcccccc, map: carFrontTexture } ),
new THREE.MeshPhongMaterial( { color: 0xcccccc, map: carRightSideTexture } ),
new THREE.MeshPhongMaterial( { color: 0xcccccc, map: carLeftSideTexture } ),
new THREE.MeshPhongMaterial( { color: 0xcccccc, } ), // top
new THREE.MeshPhongMaterial( { color: 0xcccccc, } ) // bottom
]
);
cabin.position.x = 6*zoom;
cabin.position.z = 25.5*zoom;
car.add( cabin );
const frontWheel = new Wheel();
frontWheel.position.x = -18*zoom;
car.add( frontWheel );
const backWheel = new Wheel();
backWheel.position.x = 18*zoom;
car.add( backWheel );
return car;
}
// =============================================================================================
// =============================================================================================
// BUSH
// =============================================================================================
// =============================================================================================
function Bush() {
const bush = new THREE.Group();
height = bushHeights[Math.floor(Math.random()*bushHeights.length)];
const leaf = new THREE.Mesh(
new THREE.BoxBufferGeometry( 30*zoom, 30*zoom, height*zoom ),
new THREE.MeshLambertMaterial( { color: 0x37AE0F, } )
);
leaf.position.z = (height/2)*zoom;
bush.add(leaf);
return bush;
}
// =============================================================================================
// =============================================================================================
// ROCK
// =============================================================================================
// =============================================================================================
function Rock() {
const rocks = new THREE.Group();
height = rocksHeights[Math.floor(Math.random()*bushHeights.length)];
const rock = new THREE.Mesh(
new THREE.BoxBufferGeometry( 12*zoom, 12*zoom, height*zoom ),
new THREE.MeshLambertMaterial( { color: 0x666a6c, } )
);
rock.position.z = (height/2)*zoom;
rocks.add(rock);
return rocks;
}
// =============================================================================================
// =============================================================================================
// ROAD
// =============================================================================================
// =============================================================================================
function Road() {
const road = new THREE.Group();
const createSection = color => new THREE.Mesh(
new THREE.PlaneBufferGeometry( boardWidth*zoom, positionWidth*zoom ),
new THREE.MeshPhongMaterial( { color } )
);
const middle = createSection(0x454A59);
road.add(middle);
const left = createSection(0x393D49);
left.position.x = - boardWidth*zoom;
road.add(left);
const right = createSection(0x393D49);
right.position.x = boardWidth*zoom;
road.add(right);
return road;
}
// =============================================================================================
// =============================================================================================
// GRASS
// =============================================================================================
// =============================================================================================
function Grass() {
const grass = new THREE.Group();
const createSection = color => new THREE.Mesh(
new THREE.BoxBufferGeometry( boardWidth*zoom, positionWidth*zoom, 3*zoom ),
new THREE.MeshPhongMaterial( { color } )
);
const middle = createSection(0xbaf455);
middle.receiveShadow = true;
grass.add(middle);
const left = createSection(0x99C846);
left.position.x = - boardWidth*zoom;
grass.add(left);
const right = createSection(0x99C846);
right.position.x = boardWidth*zoom;
grass.add(right);
grass.position.z = 1.5*zoom;
return grass;
}
// =============================================================================================
// =============================================================================================
// LANE
// =============================================================================================
// =============================================================================================
function Lane(index) {
this.index = index;
this.type = index <= 0 ? 'field' : laneTypes[Math.floor(Math.random()*laneTypes.length)];
this.hasHit = false;
switch(this.type) {
case 'field': {
this.type = 'field';
this.mesh = new Grass();
break;
}
case 'forest': {
this.mesh = new Grass();
this.occupiedPositions = new Set();
this.threes = [1,2,3,4].map(() => {
var obstacle;
if (Math.random() > 0.7) {
obstacle = new Bush();
} else {
obstacle = new Rock();
}
let position;
do {
position = Math.floor(Math.random()*columns);
}while(this.occupiedPositions.has(position))
this.occupiedPositions.add(position);
obstacle.position.x = (position*positionWidth+positionWidth/2)*zoom-boardWidth*zoom/2;
this.mesh.add( obstacle );
return obstacle;
})
break;
}
case 'car' : {
this.mesh = new Road();
this.direction = Math.random() >= 0.5;
const occupiedPositions = new Set();
this.vechicles = [1,2,3].map(() => {
const vechicle = new Car();
let position;
do {
position = Math.floor(Math.random()*columns/2);
} while(occupiedPositions.has(position))
occupiedPositions.add(position);
vechicle.position.x = (position*positionWidth*2+positionWidth/2)*zoom-boardWidth*zoom/2;
if(!this.direction) vechicle.rotation.z = Math.PI;
this.mesh.add( vechicle );
return vechicle;
})
this.speed = laneSpeeds[Math.floor(Math.random()*laneSpeeds.length)];
if (score1 >= 29) {
this.speed *= 1.7;
} else if (score1 >= 9) {
this.speed *= 1.3;
}
break;
}
}
}
// =============================================================================================
// =============================================================================================
// TEXTURE
// =============================================================================================
// =============================================================================================
function Texture(width, height, rects) {
const canvas = document.createElement( "canvas" );
canvas.width = width;canvas.height = height;
const context = canvas.getContext( "2d" );
context.fillStyle = "#ffffff";
context.fillRect( 0, 0, width, height );
context.fillStyle = "rgba(0,0,0,0.6)";
rects.forEach(rect => {
context.fillRect(rect.x, rect.y, rect.w, rect.h);
});
return new THREE.CanvasTexture(canvas);
}
window.addEventListener("keyup", event => {
if (lockControls) return;
if (event.keyCode == '38' || event.keyCode == '87' ) {
// up arrow OR W
move('forward');
}
else if (event.keyCode == '40' || event.keyCode == '83' ) {
// down arrow OR S
move('backward');
}
else if (event.keyCode == '37' || event.keyCode == '65' ) {
// left arrow OR A
move('left');
}
else if (event.keyCode == '39' || event.keyCode == '68' ) {
// right arrow OR D
move('right');
}
});
function move(direction) {
const finalPositions = moves.reduce((position,move) => {
if(move === 'forward') return {lane: position.lane+1, column: position.column};
if(move === 'backward') return {lane: position.lane-1, column: position.column};
if(move === 'left') return {lane: position.lane, column: position.column-1};
if(move === 'right') return {lane: position.lane, column: position.column+1};
}, {lane: currentLane, column: currentColumn})
if (direction === 'forward') {
if(lanes[finalPositions.lane+1].type === 'forest' && lanes[finalPositions.lane+1].occupiedPositions.has(finalPositions.column)) return;
if(!stepStartTimestamp) {
startMoving = true;
}
addLane();
}
else if (direction === 'backward') {
if(finalPositions.lane === 0) return;
if(lanes[finalPositions.lane-1].type === 'forest' && lanes[finalPositions.lane-1].occupiedPositions.has(finalPositions.column)) return;
if(!stepStartTimestamp) {
startMoving = true;
}
}
else if (direction === 'left') {
if(finalPositions.column === 0) return;
if(lanes[finalPositions.lane].type === 'forest' && lanes[finalPositions.lane].occupiedPositions.has(finalPositions.column-1)) return;
if(!stepStartTimestamp) startMoving = true;
}
else if (direction === 'right') {
if(finalPositions.column === columns - 1 ) return;
if(lanes[finalPositions.lane].type === 'forest' && lanes[finalPositions.lane].occupiedPositions.has(finalPositions.column+1)) return;
if(!stepStartTimestamp) startMoving = true;
}
moves.push(direction);
}
function animate(timestamp) {
requestAnimationFrame( animate );
if(!previousTimestamp) previousTimestamp = timestamp;
const delta = timestamp - previousTimestamp;
previousTimestamp = timestamp;
// Animate cars and trucks moving on the lane
lanes.forEach(lane => {
if(lane.type === 'car') {
const aBitBeforeTheBeginingOfLane = -boardWidth*zoom/2 - positionWidth*2*zoom;
const aBitAfterTheEndOFLane = boardWidth*zoom/2 + positionWidth*2*zoom;
lane.vechicles.forEach(vechicle => {
if(lane.direction) {
vechicle.position.x = vechicle.position.x < aBitBeforeTheBeginingOfLane ? aBitAfterTheEndOFLane : vechicle.position.x -= lane.speed/16*delta;
}else{
vechicle.position.x = vechicle.position.x > aBitAfterTheEndOFLane ? aBitBeforeTheBeginingOfLane : vechicle.position.x += lane.speed/16*delta;
}
});
}
});
if(startMoving) {
stepStartTimestamp = timestamp;
startMoving = false;
}
if(stepStartTimestamp) {
const moveDeltaTime = timestamp - stepStartTimestamp;
const moveDeltaDistance = Math.min(moveDeltaTime/stepTime,1)*positionWidth*zoom;
switch(moves[0]) {
case 'forward': {
const positionY = currentLane*positionWidth*zoom + moveDeltaDistance;
camera.position.y = initialCameraPositionY + positionY;
dirLight.position.y = initialDirLightPositionY + positionY;
player.position.y = positionY;
break;
}
case 'backward': {
positionY = currentLane*positionWidth*zoom - moveDeltaDistance
camera.position.y = initialCameraPositionY + positionY;
dirLight.position.y = initialDirLightPositionY + positionY;
player.position.y = positionY;
break;
}
case 'left': {
const positionX = (currentColumn*positionWidth+positionWidth/2)*zoom -boardWidth*zoom/2 - moveDeltaDistance;
camera.position.x = initialCameraPositionX + positionX;
dirLight.position.x = initialDirLightPositionX + positionX;
player.position.x = positionX; // initial player position is 0
break;
}
case 'right': {
const positionX = (currentColumn*positionWidth+positionWidth/2)*zoom -boardWidth*zoom/2 + moveDeltaDistance;
camera.position.x = initialCameraPositionX + positionX;
dirLight.position.x = initialDirLightPositionX + positionX;
player.position.x = positionX;
break;
}
}
// Once a step has ended
if(moveDeltaTime > stepTime) {
switch(moves[0]) {
case 'forward': {
if (lanes[currentLane].type === 'car') {
score1++;
// console.log("FOWARDs in car lane");
}
currentLane++;
break;
}
case 'backward': {
currentLane--;
if (lanes[currentLane].type === 'car') {
score1--;
// console.log("backwards in car lane");
}
break;
}
case 'left': {
currentColumn--;
break;
}
case 'right': {
currentColumn++;
break;
}
}
if (hscore1 < score1) hscore1 = score1;
if (score1 > 9 ) {
// AB.socket.destroy();
// endGame();
}
if (score1 >= 30 && onSpeedUp1) {
speed2.pause();
speedUp.play();
onSpeedUp2 = false;
speed3.play();
} else if (score1 >= 10 && onSpeedUp1) {
speed1.pause();
speedUp.play();
speed2.play();
onSpeedUp1 = false;
}
socketOut("update", false, false);
updateHtml();
moves.shift();
// If more steps are to be taken then restart counter otherwise stop stepping
stepStartTimestamp = moves.length === 0 ? null : timestamp;
}
}
// Hit test for lanes
if(lanes[currentLane].type === 'car') {
const playerMinX = player.position.x - playerSize*zoom/2;
const playerMaxX = player.position.x + playerSize*zoom/2;
const vechicleLength = { car: 60, truck: 105}[lanes[currentLane].type];
lanes[currentLane].vechicles.forEach(vechicle => {
const carMinX = vechicle.position.x - vechicleLength*zoom/2;
const carMaxX = vechicle.position.x + vechicleLength*zoom/2;
if(playerMaxX > carMinX && playerMinX < carMaxX) {
if (hscore1 < score1) hscore1 = score1;
speed1.pause();
speed2.pause();
speed3.pause();
honk.play();
onSpeedUp1 = true;
onSpeedUp2 = true;
score1 = 0;
resetPlayer();
socketOut("update", false, false);
}
});
}
renderer.render( scene, camera );
}
function resetPlayer() {
currentLane = 0;
currentColumn = Math.floor(columns/2);
previousTimestamp = null;
startMoving = false;
moves = [];
stepStartTimestamp;
player.position.x = 0;
player.position.y = 0;
camera.position.y = initialCameraPositionY;
camera.position.x = initialCameraPositionX;
dirLight.position.x = initialDirLightPositionX;
dirLight.position.y = initialDirLightPositionY;
updateHtml();
speed1.play();
}
// =============================================================================================
// =============================================================================================
// WAITING FOR PLAYERS
// =============================================================================================
// =============================================================================================
function endGame() {
speed1.pause();
speed2.pause();
speed3.pause();
AB.removeSplash();
AB.newSplash();
var txt;
var other = "";
if (playerLeft) {
// Other player left
txt = "Other Player has left.<br><br><span style='color: rgb(0, 255, 0);'>You Won!</span>";
} else if (hscore1 > hscore2) {
// You Win
txt = "<span style='color: rgb(0, 255, 0);'>You Won!</span>";
other = `Your opponent's highscore was: `+ hscore2 +` <br>`;
} else if (hscore2 > hscore1) {
// Other Player Wins
txt = "<span style='color: rgb(255, 0, 0);'>You Lost!</span>";
other = `Your opponent's highscore was: `+ hscore2 +` <br>`;
} else {
// Draw
txt = "It's a draw!";
other = `Your opponent's highscore was: `+ hscore2 +` <br>`;
}
AB.splashHtml ( `
<h1> GAME OVER... </h1>
<h3>` + txt +`<br></h3>
Your highest score was: ` + hscore1 + `<br>
`+ other +`<br>
<button onclick='location.reload();' class=ab-largenormbutton >Play Again</button>` );
}
// =============================================================================================
// =============================================================================================
// WAITING FOR PLAYERS
// =============================================================================================
// =============================================================================================
function waitingForPlayers() {
AB.removeSplash();
AB.newSplash();
AB.splashHtml ( `
<h1> Waiting for opponent, please wait... </h1>
<img src="/uploads/wuk/loading-buffering.gif">
` );
}
// =============================================================================================
// =============================================================================================
// WELCOME
// =============================================================================================
// =============================================================================================
function welcome() {
var pwd = jQuery("input#p").val();
pwd = pwd.trim();
if ( pwd != password )
{
$("#errordiv").html( "<font color=red> <B> LEAVE NOW!! </b></font> " );
return;
}
AB.removeSplash();
AB.newSplash();
AB.splashHtml ( `
<h1 style="font-family:cooper"> RUN RUN RUN! </h1>
Run as far as you can in 60 seconds and beat your opponent's highscore to win! <br>
Avoid all the cars! If you get hit you will start again. <br>
<br>
<b>Controls:</b> <br>
Arrow Up/W - Move Up <br>
Arrow Left/A - Move Left <br>
Arrow Down/S - Move Down <br>
Arrow Right/D - Move Right <br>
<br>
<b>GOOD LUCK! <br>
<p>
<button onclick='loadResources();' class=ab-largenormbutton >Search for match</button>
<p>
<div id=errordiv name=errordiv> </div> ` );
}
function splashPass() {
AB.removeSplash();
AB.newSplash();
AB.splashHtml ( `
<input style='width:25vw;' maxlength='2000' NAME="p" id="p" VALUE='' >
<button onclick='welcome();' class=ab-largenormbutton >Start</button>
<p>
<div id=errordiv name=errordiv> </div> ` );
}
splashPass();