xxxxxxxxxx
274
// Engineer: jWilliamDunn 2020
// First-person camera control w/ HUD
// Mouse: left/right : pan
// up/down : tilt
// click : activate pointerLock
// Keys: a/d : left/right
// w/s : forward/backward
// e/q : up/down
// space : jump <----------- extended behavior
// h : help
// update 20191014 tweaks for better behavior
// update 20200626 incorporate pointerLock and new roverCam API
// update 20200628 move pointerLock into roverCam and other improvements
// Ported to JS from github.com/jrc03c/queasycam/tree/master/examples/MazeRunner
class Block {
constructor(x, y, z, w, h, d) {
this.position = createVector(x, y, z);
this.dimensions = createVector(w, h, d);
this.fillColor = color(random(150, 200));
this.visited = false;
}
update() {
let playerLeft = player.position.x - player.dimensions.x / 2;
let playerRight = player.position.x + player.dimensions.x / 2;
let playerTop = player.position.y - player.dimensions.y / 2;
let playerBottom = player.position.y + player.dimensions.y / 2;
let playerFront = player.position.z - player.dimensions.z / 2;
let playerBack = player.position.z + player.dimensions.z / 2;
let boxLeft = this.position.x - this.dimensions.x / 2;
let boxRight = this.position.x + this.dimensions.x / 2;
let boxTop = this.position.y - this.dimensions.y / 2;
let boxBottom = this.position.y + this.dimensions.y / 2;
let boxFront = this.position.z - this.dimensions.z / 2;
let boxBack = this.position.z + this.dimensions.z / 2;
let boxLeftOverlap = playerRight - boxLeft;
let boxRightOverlap = boxRight - playerLeft;
let boxTopOverlap = playerBottom - boxTop;
let boxBottomOverlap = boxBottom - playerTop;
let boxFrontOverlap = playerBack - boxFront;
let boxBackOverlap = boxBack - playerFront;
if (((playerLeft > boxLeft && playerLeft < boxRight || (playerRight > boxLeft && playerRight < boxRight)) && ((playerTop > boxTop && playerTop < boxBottom) || (playerBottom > boxTop && playerBottom < boxBottom)) && ((playerFront > boxFront && playerFront < boxBack) || (playerBack > boxFront && playerBack < boxBack)))) {
let xOverlap = max(min(boxLeftOverlap, boxRightOverlap), 0);
let yOverlap = max(min(boxTopOverlap, boxBottomOverlap), 0);
let zOverlap = max(min(boxFrontOverlap, boxBackOverlap), 0);
if (xOverlap < yOverlap && xOverlap < zOverlap) {
if (boxLeftOverlap < boxRightOverlap) {
player.position.x = boxLeft - player.dimensions.x / 2;
} else {
player.position.x = boxRight + player.dimensions.x / 2;
}
} else if (yOverlap < xOverlap && yOverlap < zOverlap) {
if (boxTopOverlap < boxBottomOverlap) {
player.position.y = boxTop - player.dimensions.y / 2;
player.velocity.y = 0;
player.grounded = true;
} else {
player.position.y = boxBottom + player.dimensions.y / 2;
}
} else if (zOverlap < xOverlap && zOverlap < yOverlap) {
if (boxFrontOverlap < boxBackOverlap) {
player.position.z = boxFront - player.dimensions.x / 2;
} else {
player.position.z = boxBack + player.dimensions.x / 2;
}
}
}
// prevent player from falling out of the maze
if(player.position.x<0) player.position.x=0.01;
if(player.position.z<0) player.position.z=0.01;
if(player.position.x>55) player.position.x=54.99;
if(player.position.z>55) player.position.z=54.99;
if(player.position.y>55) maze.setPlayerAtStart(player);
}
display() {
push();
translate(this.position.x, this.position.y, this.position.z);
fill(this.fillColor);
box(this.dimensions.x, this.dimensions.y, this.dimensions.z);
pop();
}
pushDown() {
this.position.y += 5;
}
}
class Maze {
constructor(size) {
this.blocks = new Array(size);
for (let i = 0; i < size; i++) {
this.blocks[i] = new Array(size);
for (let j = 0; j < size; j++) {
let x = i * 5;
let y = 0;
let z = j * 5;
this.blocks[i][j] = new Block(x, y, z, 5, 5, 5);
}
}
this.start = this.blocks[1][1];
this.blocks[1][1].fillColor = color(63, 127, 63);
var m = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0],
[0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0],
[0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0],
[0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0],
[0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0],
[0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
];
for (let i = 1; i < size - 1; i++)
for (let j = 1; j < size - 1; j++)
if (m[i][j]) this.blocks[i][j].pushDown();
else this.blocks[i][j].fillColor = color(127);
this.blocks[3][3].fillColor = color(127, 63, 63);
}
update() {
for (let i = 0; i < this.blocks.length; i++) {
for (let j = 0; j < this.blocks[i].length; j++) {
this.blocks[i][j].update();
}
}
}
display() {
for (let i = 0; i < this.blocks.length; i++) {
for (let j = 0; j < this.blocks[i].length; j++) {
this.blocks[i][j].display();
}
}
}
setPlayerAtStart(player) {
player.reset();
player.position = p5.Vector.add(this.start.position, createVector(0, -15, 0));
}
}
class Player extends RoverCam {
constructor() {
super();
this.dimensions = createVector(1, 3, 1); // min elevation = 0.2
this.velocity = createVector(0, 0, 0);
this.gravity = createVector(0, 0.03, 0);
this.grounded = false;
this.speed = 0.04;
this.sensitivity = 0.02;
}
update() {
// ffd8 - add SHIFT for running!
this.speed = 0.04;
this.sensitivity = 0.02;
if (keyIsDown(16)) {
this.sensitivity = 0.04;
this.speed = 0.06;
}
if (keyIsPressed && key == 'e') {
this.grounded = false;
return;
}
this.velocity.add(this.gravity);
this.position.add(this.velocity);
if (this.grounded && keyIsDown(32)) { // space
this.grounded = false;
this.velocity.y = -1.5;
this.position.y -= 0.2;
}
}
}
var player, maze, f, help = false;
function preload() {
f = loadFont('inconsolata.otf');
}
function setup() {
createCanvas(windowWidth, windowHeight, WEBGL);
strokeWeight(0.04);
textFont(f);
textSize(10);
player = new Player();
player.usePointerLock();
maze = new Maze(12);
maze.setPlayerAtStart(player);
frameRate(60);
strokeWeight(2);
}
function keyPressed() {
if (key == 'h') help = !help;
// ffd8 - respawn with DELETE or BACKSPACE
if (keyCode == 8 || keyCode == 46) {
maze.setPlayerAtStart(player);
}
}
function windowResized() {
resizeCanvas(window.innerWidth, window.innerHeight, WEBGL);
}
function draw() {
background(0, 0, 51);
maze.update();
maze.display();
player.update();
//drawAxes();
if (help || frameCount < 400) { // Heads Up Display extension by jWilliam
push(); // this affects the frame rate
camera(0, 0, (height / 2.0) / tan(PI * 30.0 / 180.0), 0, 0, 0, 0, 1, 0);
ortho(-width / 2, width / 2, -height / 2, height / 2, 0, 1000);
fill(0, 0, 0, 200);
noStroke();
translate(-380, -380, 0);
scale(2);
rect(0, 0, 140, 85);
fill(127);
text('mouse: left/right : pan', 10, 10);
text(' up/down : tilt', 10, 20);
text(' click : ptrlock', 10, 30);
text(' keys: a/d : left/right', 10, 40);
text(' w/s : fwd/bkwd', 10, 50);
text(' e/q : up/down', 10, 60);
text(' space : jump', 10, 70);
text(' h : help', 10, 80);
pop();
}
}
function drawAxes(){
push();
noStroke();
fill(127,0,0); // X red
translate(75,0.5,0.5);
box(150,1,1);
pop();
push();
noStroke();
fill(0,127,0); // Y green
translate(0.5,75,0.5);
box(1,150,1);
pop();
push();
noStroke();
fill(0,0,127); // Z blue
translate(0.5,0.5,75);
box(1,1,150);
pop();
}