rotate the camera horizontally and vertically three.js - javascript

I have the following code that makes my camera rotate vertically when i press a key (this works great):
var cameraOrginX = 0, cameraOrginY = 0, cameraOrginZ = 0;
var cameraEndX = 0, cameraEndY = -707, cameraEndZ = 707;
var angle = 1;
function onDocumentKeyDown(event){
var keyCode = event.which;
console.log(keyCode);
if(keyCode == 87 || keyCode == 83){
if (keyCode == 87) {
angle = 1;
console.log("forward " + angle);
}
else if (keyCode == 83) {
angle = -1;
console.log("backward " + angle);
}
}
if(keyCode == 68 || keyCode == 65){
if (keyCode == 68) {
angle = 1;
console.log("right " + angle);
}
else if (keyCode == 65) {
angle = -1;
console.log("left " + angle);
}
}
//rotate vertically
var radiansVert = angle * Math.PI / 180.0;
var radiansHori = angle * Math.PI / 180.0;
var cosTheta = Math.cos(radiansVert);
var sinTheta = Math.sin(radiansVert);
var aVert = cosTheta * (cameraEndY-cameraOrginY);
var bVert = sinTheta * (cameraEndZ-cameraOrginZ);
var cVert = sinTheta * (cameraEndY-cameraOrginY);
var dVert = cosTheta * (cameraEndZ-cameraOrginZ);
cameraEndY = aVert - bVert + cameraOrginY;
cameraEndZ = cVert + dVert + cameraOrginZ;
camera.position.x = cameraOrginX + cameraEndX;
camera.position.y = cameraOrginY + cameraEndY;
camera.position.z = cameraOrginZ + cameraEndZ;
//
}
But now i want to make my camera also rotate horizontally... i tried copy and pasting the code between the comments and changing the variable names so it would work on the x and y axis but that gave me some weird results what i was not really looking for ;) could someone give me a tip or point me in the right direction on how to do this? i am still learning and any help would be greatly appriciated :)
if there is more code needed to make my problem clear let me know i can also make a jsfiddle if you want!

Related

how to fix bugs in snake game?

I have been making a snake game for a few days to improve my js skills.
And I released the first beta test of my mini-game. And you actually know that there are always a lot of bugs in beta tests. And I noticed them. First I notice that if the snake.x position < 0, then the snake appears from a different corner, but in front of one block, and not from the zero coordinate. This also applies to snake.y<0.
here is the code:
var canvas = document.getElementById("game");
var ctx = canvas.getContext("2d");
var box = 10;
//Snake
var snake = [];
var dir = "right";
var maxCell = 10;
var can = canvas.getBoundingClientRect();
var px = Math.floor(canvas.width / 2 / 10) * 10;
var py = Math.floor(canvas.height / 2 / 10) * 10;
//Apple
var ax = Math.floor((Math.random() * ~~(canvas.width / box)) / 10) * 10;
var ay = Math.floor((Math.random() * ~~(canvas.height / box)) / 10) * 10;
var loop = setInterval(() => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
Elems();
}, 1000 / 40);
document.addEventListener("keydown", function (e) {
if (e.keyCode === 37 && dir !== "right") {
dir = "left";
//console.log('left')
} else if (e.keyCode === 38 && dir !== "down") {
dir = "up";
//console.log('up')
} else if (e.keyCode === 39 && dir !== "left") {
dir = "right";
//console.log('right')
} else if (e.keyCode === 40 && dir !== "up") {
dir = "down";
//console.log('down')
}
});
function direction() {
if (dir == "right") {
px += box;
} else if (dir == "left") {
px -= box;
} else if (dir == "up") {
py -= box;
} else if (dir == "down") {
py += box;
}
}
//Closure )))
function Elems() {
function Apple() {
ctx.fillStyle = "green";
ctx.fillRect(ax, ay, box, box);
}
//! Spawn snake
function Snake() {
direction();
var head = {
x: px,
y: py,
};
snake.unshift(head);
//-------------BUG---------------
if (px >= canvas.width) {
px = 0;
}
if (px + box < 0) {
px = canvas.width;
}
if (py >= canvas.height) {
py = 0;
}
if (py + box < 0) {
py = canvas.height;
}
//-------------------------------
snake.forEach(function (elem, index) {
ctx.fillStyle = `red`;
ctx.fillRect(elem.x, elem.y, box, box);
});
if (head.x == ax && head.y == ay) {
maxCell += 1;
ax = Math.floor(Math.random() * ~~(canvas.width / box)) * 10;
ay = Math.floor(Math.random() * ~~(canvas.height / box)) * 10;
}
for (let i = 1; i < snake.length; i++) {
if (head.x === snake[i].x && head.y === snake[i].y) {
maxCell = 10;
px = Math.floor(canvas.width / 2 / 10) * 10;
py = Math.floor(canvas.height / 2 / 10) * 10;
clearInterval(loop);
alert("Game Over:(")
}
}
if (snake.length < maxCell) {
snake.push({ x: px, y: py });
}
snake.pop();
}
Snake();
Apple();
}
I tried changing the canvas dimensions and box value. But it didn't help x((((
You'd have to rearrange your code a good bit to get it working right.
The Snake function should not happen in a loop, the loop related stuff inside of Snake should be inside the Elems function instead. And the loop being set should happen last.
The following is a basic rework of your code with an added method, and I've included the grid that angel.bonev suggested so it works like a traditional snake game now and with the apple getting eaten to increase the snake size. The testForPointInArea method makes it such that the snake does not have to be exactly over the apple spot, but just overlapping.
Also the opposite direction restrictions in the keydown listener were removed;
&& dir !== "right" && dir !== "down" && dir !== "left" && dir !== "up"
If the snake is a small size or not big enough to bank corners,
then game over would not happen with the above backwards restrictions.
var canvas = document.getElementById("game");
var ctx = canvas.getContext("2d");
var box = 10;
//Snake body Array
var snake = [];
var dir = "right";
var maxCell = 2;
var can = canvas.getBoundingClientRect();
var grid = {
x: Math.floor(canvas.width / box),
y: Math.floor(canvas.height / box)
};
var px = Math.floor(grid.x / 2) * 10;
var py = Math.floor(grid.y / 2) * 10;
//Apple cords
var ax = Math.floor( Math.random() * grid.y ) * box;
var ay = Math.floor( Math.random() * grid.x ) * box;
var theSnake;
document.addEventListener("keydown", function(e) {
e.preventDefault();
if (e.keyCode === 37 ) {
dir = "left";
//console.log('left')
} else if (e.keyCode === 38 ) {
dir = "up";
//console.log('up')
} else if (e.keyCode === 39) {
dir = "right";
//console.log('right')
} else if (e.keyCode === 40 ) {
dir = "down";
//console.log('down')
}
});
function direction() {
if (dir == "right") {
px += 2;
} else if (dir == "left") {
px -= 2;
} else if (dir == "up") {
py -= 2;
} else if (dir == "down") {
py += 2;
}
}
function Apple() {
ctx.fillStyle = "green";
ctx.fillRect(ax, ay, box, box);
}
function testForPointInArea(p, left,top,right,bottom) {
return Boolean(!(p.x < left || p.x > right || p.y < top || p.y > bottom));
}
function Elems() {
direction();
theSnake.head.x = px; theSnake.head.y = py;
snake.unshift({x:theSnake.head.x, y:theSnake.head.y});
for (let i = 1; i < snake.length; i++) {
if (theSnake.head.x === snake[i].x && theSnake.head.y === snake[i].y) {
maxCell = 2;
px = Math.floor(grid.x / 2) * 10;
py = Math.floor(grid.y / 2) * 10;
snake = [];
//clearInterval(loop);
alert("Game Over :(");
return;
}
}
if (snake.length < maxCell) {
snake.push({ x: px, y: py });
}
if (px >= canvas.width) {
px = 0;
}
if (px + box < 0) {
px = canvas.width;
}
if (py >= canvas.height) {
py = 0;
}
if (py + box < 0) {
py = canvas.height;
}
theSnake.drawSnake();
Apple();
snake.pop();
if ( testForPointInArea(theSnake.head, ax - 3, ay - 3, ax + box + 3, ay + box + 3) ) {
maxCell += 1;
ax = Math.floor( Math.random() * grid.y ) * box;
ay = Math.floor( Math.random() * grid.x ) * box;
Apple();
}
}
//Snake Class
function Snake() {
this.head = {
x: px,
y: py,
};
this.drawSnake = function() {
snake.forEach(function (elem, index) {
ctx.fillStyle = "red";
ctx.fillRect(elem.x, elem.y, box, box);
});
};
}
theSnake = new Snake();
var loop = setInterval(() => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
Elems();
}, 1000 / 40);
<canvas id="game" width="150px" height="150px"> </canvas>

Why are my Raycaster Sprites blinking and how can I fix it?

My raycaster's sprites keep blinking, and I think it has to do with ZBuffer.
Using this for reference: https://lodev.org/cgtutor/index.html
I have done plenty of research and can't find any JS raycasters that answer my problem. By sprites, I mean billboarded images, and when you move they blink like an atari game that is being pushed to its limits.
Here is the project on JSFiddle: https://jsfiddle.net/Vakore/bsvx1m26/
Here is where I am using ZBuffer:
for (var stripe = drawStartX; stripe < drawEndX; stripe++) {
var texX =
floor((256 * (stripe - (-spriteWidth / 2 + spriteScreenX)) * texWidth) / spriteWidth) / 256;
// the conditions in the if are:
// 1) it's in front of camera plane so you don't see things behind you
// 2) it's on the screen (left)
// 3) it's on the screen (right)
// 4) ZBuffer, with perpendicular distance
var ruffer = 0;
if (sprite[i][2] == "barrel") {
ruffer = 576 - 64;
}
if (sprite[i][2] == "pillar") {
ruffer = 576;
}
if (sprite[i][2] == "greenlight") {
ruffer = 576 + 64;
}
if (
transformY > 0 &&
stripe > 0 &&
stripe < w &&
transformY < ZBuffer[stripe]
) {
can.drawImage(
document.getElementById(sprite[i][2]),
texX + ruffer, 0, 1, texHeight, stripe, drawStartY, 1, drawEndY - drawStartY
);
}
}
ZBuffer was declared and assigned an array value earlier in the code.
var keys = {
"a": false,
"s": false,
"d": false,
"A": false,
"S": false,
"D": false,
"W": false,
"Z": false,
"X": false,
"C": false,
"ENTER": false
};
document.addEventListener("keydown", function(e) {
e.preventDefault();
if (e.keyCode === 16)
keys["SHIFT"] = true;
if (e.keyCode === 37)
keys["a"] = true;
if (e.keyCode === 39)
keys["d"] = true;
if (e.keyCode === 65)
keys["A"] = true;
if (e.keyCode === 68)
keys["D"] = true;
if (e.keyCode === 83)
keys["S"] = true;
if (e.keyCode === 87)
keys["W"] = true;
if (e.keyCode === 40)
keys["S"] = true;
if (e.keyCode === 38)
keys["W"] = true;
if (e.keyCode === 67)
keys["C"] = true;
if (e.keyCode === 88)
keys["X"] = true;
if (e.keyCode === 90)
keys["Z"] = true;
if (e.keyCode === 13)
keys["ENTER"] = true;
})
document.addEventListener("keyup", function(e) {
e.preventDefault();
if (e.keyCode === 16)
keys["SHIFT"] = false;
if (e.keyCode === 37)
keys["a"] = false;
if (e.keyCode === 39)
keys["d"] = false;
if (e.keyCode === 65)
keys["A"] = false;
if (e.keyCode === 68)
keys["D"] = false;
if (e.keyCode === 83)
keys["S"] = false;
if (e.keyCode === 87)
keys["W"] = false;
if (e.keyCode === 40)
keys["S"] = false;
if (e.keyCode === 38)
keys["W"] = false;
if (e.keyCode === 67)
keys["C"] = false;
if (e.keyCode === 88)
keys["X"] = false;
if (e.keyCode === 90)
keys["Z"] = false;
})
/*
Basic functions(ease of access)
*/
var canvas = document.getElementById("canva");
var can = canvas.getContext("2d");
canvas.requestPointerLock = canvas.requestPointerLock || canvas.mozRequestPointerLock;
document.exitPointerLock = document.exitPointerLock || document.mozExitPointerLock;
canvas.onclick = function() {
canvas.requestPointerLock();
clicked = true;
};
var mouseX = 0;
var mouseMove = function(e) {
mouseX += e.movementX;
};
var rect = function(x, y, w, h) {
can.fillRect(x, y, w, h);
};
var arc = function(x, y, r, start, stop) {
can.beginPath();
can.arc(x, y, r, start, stop);
can.fill();
};
var circle = function(x, y, r) {
arc(x, y, r, 0, 360);
};
var fill = function(r, g, b, a) {
if (a === undefined) {
a = 1;
}
can.fillStyle = "rgb(" + r + "," + g + "," + b + "," + a + ")";
};
var font = function(siz) {
can.font = siz;
};
var textAlign = function(ali) {
can.textAlign = ali;
};
var text = function(txt, x, y, w, h) {
can.fillText(txt, x, y, w, h);
};
var quad = function(x1, y1, x2, y2, x3, y3, x4, y4) {
can.beginPath();
can.moveTo(x1, y1);
can.lineTo(x2, y2);
can.lineTo(x3, y3);
can.lineTo(x4, y4);
can.closePath();
can.fill();
};
var random = function(min, max) {
return round(Math.random() * (max - min)) + min;
};
var translate = function(x, y) {
can.save();
can.translate(x, y);
};
var scale = function(w, h) {
can.scale(w, h);
}
var trestore = function() {
can.restore();
};
var floor = function(num) {
return Math.floor(num);
};
var sqrt = function(num) {
return Math.sqrt(num);
};
var abs = function(num) {
return Math.abs(num);
};
var color = function(r, g, b, a) {
return [r, g, b, a];
};
var dist = function() {
return true;
};
var cos = function(num) {
return Math.cos(num);
}
var sin = function(num) {
return Math.sin(num);
}
var dist = function(x1, y1, x2, y2) {
dx = x1 - x2;
dy = y1 - y2;
return Math.sqrt(dx * dx + dy * dy);
};
//Begin the raycaster
var scaler = 3; //This reduces the resolution so that it can display large rooms without lagging
var w = 640 / scaler;
var h = 480 / scaler;
var texWidth = 64;
var texHeight = 64;
var rotSpeed = 0.1;
var moveSpeed = 0.1;
var worldMap = [
"1111111111111111111111111111111111111111",
"1001000001234567800000000000000000000001",
"1001000000000000000000000000000000000001",
"1000000000000000000000000000000000000001",
"1001000000000000000000000000000000000001",
"1001000000000000000000000000222200000001",
"1001000000000000000000000000200200000001",
"1111000000000000000000000000200200000001",
"1000000000000000000000000033300333000001",
"8008000000000000000000000000000000000001",
"8000800000000000000000000033300333000001",
"8000080000000000000000000000300300000001",
"8000008000000000000000000000333300000001",
"8888888000000000000000000000000000000001",
"1000000000000000000000000000000000000001",
"1000000000000000000000000000000000000001",
"1000000000000000000000000000000000000001",
"1000000000000000000000000000000000000001",
"1000000000000000000000000000000000000001",
"1666006660000000000000000000000000000001",
"1000000060000000000000000000000000000001",
"1000000060000000000000000000000000000001",
"1000000060000000000000000000000000000001",
"1000000060000000000000000000000000000001",
"1666666660000000000000000000000000000001",
"1000000000000000000000000000000000000001",
"1000000000000000000000000000000000000001",
"1000000000000000000000000000000000000001",
"1000000040444444444444400000000000000001",
"1000000040000000000000400000000000000001",
"1000000040000000000000400000000000000001",
"1000000040000000000000400000000000000001",
"1000000044444444444444400000000000000001",
"1000000000000000000000000000000000000001",
"1000000000000007775777000000000000000001",
"1000000000000007000007000000000000000001",
"1000000000000005000005000000000000000001",
"1000000000000007000007000000000000000001",
"1000000000000000000007000000000000000001",
"1111111111111117775777111111111111111111",
];
try {
var ZBuffer = [];
var sprite = [
[5, 5, "barrel", 0], //Y and X are reversed
[6.5, 2.5, "pillar", 1],
[6.5, 1.5, "pillar", 1.5],
[8, 6, "greenlight", 2],
];
var posX = 2,
posY = 2,
dirX = -1,
dirY = 0,
planeX = 0,
planeY = 0.66; //The 2d raycaster version of the camera plane
} catch (e) {
alert(e);
}
var castRays = function() {
for (var x = 0; x < w; x++) {
var cameraX = 2 * x / (w) - 1; //x-coordinate in camera space
var rayDirX = dirX + planeX * cameraX;
var rayDirY = dirY + planeY * cameraX;
//which box of the map we're in
var mapX = floor(posX);
var mapY = floor(posY);
//length of ray from current position to next x or y-side
var sideDistX;
var sideDistY;
//length of ray from one x or y-side to next x or y-side
var deltaDistX = sqrt(1 + (rayDirY * rayDirY) / (rayDirX * rayDirX));
var deltaDistY = sqrt(1 + (rayDirX * rayDirX) / (rayDirY * rayDirY));
var perpWallDist = 0;
//what direction to step in x or y-direction (either +1 or -1)
var stepX = 0;
var stepY = 0;
var hit = 0; //was there a wall hit?
var side = 0; //was a NS or a EW wall hit?
//calculate step and initial sideDist
if (rayDirX < 0) {
stepX = -1;
sideDistX = (posX - mapX) * deltaDistX;
} else {
stepX = 1;
sideDistX = (mapX + 1.0 - posX) * deltaDistX;
}
if (rayDirY < 0) {
stepY = -1;
sideDistY = (posY - mapY) * deltaDistY;
} else {
stepY = 1;
sideDistY = (mapY + 1.0 - posY) * deltaDistY;
}
while (hit == 0) {
//jump to next map square, OR in x-direction, OR in y-direction
if (sideDistX < sideDistY) {
sideDistX += deltaDistX;
mapX += stepX;
side = 0;
} else {
sideDistY += deltaDistY;
mapY += stepY;
side = 1;
}
//Check if ray has hit a wall
if (worldMap[mapX][mapY] == 0) {}
if (worldMap[mapX][mapY] != 0) {
hit = 1;
}
} //end of while loop
//Calculate distance of perpendicular ray (Euclidean distance will give fisheye effect!)
if (side == 0) {
perpWallDist = (mapX - posX + (1 - stepX) / 2) / rayDirX;
} else {
perpWallDist = (mapY - posY + (1 - stepY) / 2) / rayDirY;
}
//Calculate height of line to draw on screen
var lineHeight = abs(floor(h / perpWallDist));
//calculate lowest and highest pixel to fill in current stripe
var drawStart = -lineHeight / 2 + h / 2;
//if(drawStart < 0) {drawStart = 0;}
var drawEnd = lineHeight / 2 + h / 2;
//if(drawEnd >= h) {drawEnd = h - 1;}
//texturing calculations
//var texNum = worldMap[mapX][mapY] - 1; //1 subtracted from it so that texture 0 can be used!
//calculate value of wallX
var wallX = 0; //where exactly the wall was hit
if (side == 0) {
wallX = posY + perpWallDist * rayDirY;
} else {
wallX = posX + perpWallDist * rayDirX;
}
wallX -= floor((wallX));
//x coordinate on the texture
var texX = floor(wallX * (texWidth));
if (side == 0 && rayDirX > 0) {
texX = texWidth - texX - 1;
}
if (side == 1 && rayDirY < 0) {
texX = texWidth - texX - 1;
}
//Untextured variant
/*var currentColor = color(255, 255, 255);
if (worldMap[mapX][mapY] == "1") {currentColor = color(150, 150, 150);}
if (worldMap[mapX][mapY] == "2") {currentColor = color(255, 255, 255);}
if (worldMap[mapX][mapY] == "3") {currentColor = color(255,0,0);}
if (worldMap[mapX][mapY] == "4") {currentColor = color(0,0,255);}
if (worldMap[mapX][mapY] == "5") {currentColor = color(0,255,0);}
if (worldMap[mapX][mapY] == "6") {currentColor = color(255,0,255);}
if (worldMap[mapX][mapY]=="7") {currentColor = color(0,255,255);}
if (side === 1) {currentColor = [currentColor[0] - 40, currentColor[1] - 40, currentColor[2] - 40];}
//if (dist(mapX, mapY, px, pz) > 10) {continue;}
fill(currentColor[0],currentColor[1],currentColor[2]);
rect(x, drawStart, 1, drawEnd - drawStart);*/
var currentImg = "bluestone";
if (worldMap[mapX][mapY] == "1") {
currentImg = "bluestone";
}
if (worldMap[mapX][mapY] == "2") {
currentImg = "greystone";
}
if (worldMap[mapX][mapY] == "3") {
currentImg = "wood";
}
if (worldMap[mapX][mapY] == "4") {
currentImg = "colorstone";
}
if (worldMap[mapX][mapY] == "5") {
currentImg = "eagle";
}
if (worldMap[mapX][mapY] == "6") {
currentImg = "mossy";
}
if (worldMap[mapX][mapY] == "7") {
currentImg = "redbrick";
}
if (worldMap[mapX][mapY] == "8") {
currentImg = "purplestone";
}
//if (worldMap[mapX][mapY] =="a") {currentImg = "barrel";}
//if (dist(mapX, mapY, posX, posY) > 20) {continue;}
can.drawImage(document.getElementById(currentImg), texX + ((worldMap[mapX][mapY] - 1) * 64), 0, 1, texHeight, x, drawStart, 1, drawEnd - drawStart);
//fill(255, 0, 0);rect(x, drawStart, 1, drawEnd - drawStart);
if (side === 1) {
fill(0, 0, 0, 0.3);
rect(x, drawStart, 1, drawEnd - drawStart);
}
//Set the ZBuffer
ZBuffer[x] = perpWallDist;
//FLOOR CASTING(not using till figure out how to do without lag)
var floorXWall = 0,
floorYWall = 0;
if (side == 0 && rayDirX > 0) {
floorXWall = mapX;
floorYWall = mapY + wallX;
} else if (side == 0 && rayDirX < 0) {
floorXWall = mapX + 1.0;
floorYWall = mapY + wallX;
} else if (side == 1 && rayDirY > 0) {
floorXWall = mapX + wallX;
floorYWall = mapY;
} else {
floorXWall = mapX + wallX;
floorYWall = mapY + 1.0;
}
var distWall, distPlayer, currentDist;
distWall = perpWallDist;
distPlayer = 0.0;
for (var y = drawEnd + 1; y < h; y++) {
//if (dist(mapX, mapY, posX, posY) > 5) {continue;}
currentDist = h / (2.0 * y - h); //you could make a small lookup table for this instead
var weight = (currentDist - distPlayer) / (distWall - distPlayer);
var currentFloorX = weight * floorXWall + (1.0 - weight) * posX;
var currentFloorY = weight * floorYWall + (1.0 - weight) * posY;
var floorTexX, floorTexY;
floorTexX = floor(currentFloorX * texWidth) % texWidth;
floorTexY = floor(currentFloorY * texHeight) % texHeight;
//OPTIMIZE FOR LESS LAG!!!!!!!!!! (search
//FLOOR
//can.drawImage(document.getElementById("greystone"), floorTexX, floorTexY, texWidth, texHeight, x, y, texWidth, texHeight);
//CEILING
//can.drawImage(document.getElementById("wood"), floorTexX, floorTexY, texWidth, 1, x, h - y, texWidth, 1);
} //End of the 'y' loop
} //end the loop
//SPRITE CASTING
//Sort sprites
sprite.sort(function(a, b) {
return b[3] - a[3];
}); //Sort the depth of each sprite
//Draw sprites
for (var i = 0; i < sprite.length; i++) {
var spriteX = sprite[i][0] - posX;
var spriteY = sprite[i][1] - posY;
sprite[i][3] = abs((posX - sprite[i][0]) - (posY - sprite[i][1]));
var invDet = 1.0 / (planeX * dirY - dirX * planeY);
var transformX = invDet * (dirY * spriteX - dirX * spriteY);
var transformY = invDet * (-planeY * spriteX + planeX * spriteY); //this is actually the depth inside the screen, that what Z is in 3D(Thanks lodev.org for explanation!)
var spriteScreenX = floor((w / 2) * (1 + transformX / transformY));
//calculate height of the sprite on screen
var spriteHeight = abs(floor(h / (transformY))); //using "transformY" instead of the real distance prevents fisheye
//calculate lowest and highest pixel to fill in current stripe
var drawStartY = -spriteHeight / 2 + h / 2;
//if (drawStartY < 0) {drawStartY = 0;} Don't need THIS
var drawEndY = spriteHeight / 2 + h / 2;
//if (drawEndY >= h) {drawEndY = h - 1;} Or THIS
//calculate width of the sprite
var spriteWidth = abs(floor(h / (transformY)));
var drawStartX = -spriteWidth / 2 + spriteScreenX;
//if (drawStartX < 0) {drawStartX = 0;} Nor this
var drawEndX = spriteWidth / 2 + spriteScreenX;
//if (drawEndX >= w) {drawEndX = w - 1;} Nor dis
//loop through every vertical stripe of the sprite on screen
for (var stripe = drawStartX; stripe < drawEndX; stripe++) {
var texX = floor(256 * (stripe - (-spriteWidth / 2 + spriteScreenX)) * texWidth / spriteWidth) / 256;
//the conditions in the if are:
//1) it's in front of camera plane so you don't see things behind you
//2) it's on the screen (left)
//3) it's on the screen (right)
//4) ZBuffer, with perpendicular distance
var ruffer = 0;
if (sprite[i][2] == "barrel") {
ruffer = 576 - 64;
}
if (sprite[i][2] == "pillar") {
ruffer = 576;
}
if (sprite[i][2] == "greenlight") {
ruffer = 576 + 64;
}
if (transformY > 0 && stripe > 0 && stripe < w && transformY < ZBuffer[stripe]) {
can.drawImage(document.getElementById(sprite[i][2]), texX + ruffer, 0, 1, texHeight, stripe, drawStartY, 1, drawEndY - drawStartY);
}
}
} //End of 'i' loop
//Bottom of dat
if (keys["W"]) {
if (worldMap[floor(posX + dirX * moveSpeed)][floor(posY)] == false) {
posX += dirX * moveSpeed
};
if (worldMap[floor(posX)][floor(posY + dirY * moveSpeed)] == false) {
posY += dirY * moveSpeed
};
}
//move backwards if no wall behind you
if (keys["S"]) {
if (worldMap[floor(posX - dirX * moveSpeed)][floor(posY)] == false) {
posX -= dirX * moveSpeed;
}
if (worldMap[floor(posX)][floor(posY - dirY * moveSpeed)] == false) {
posY -= dirY * moveSpeed;
}
}
if (keys["D"]) {
if (worldMap[floor(posX + planeX * moveSpeed)][floor(posY)] == false) {
posX += planeX * moveSpeed
};
if (worldMap[floor(posX)][floor(posY + planeY * moveSpeed)] == false) {
posY += planeY * moveSpeed
};
}
if (keys["A"]) {
if (worldMap[floor(posX - planeX * moveSpeed)][floor(posY)] == false) {
posX -= planeX * moveSpeed;
}
if (worldMap[floor(posX)][floor(posY - planeY * moveSpeed)] == false) {
posY -= planeY * moveSpeed;
}
}
//rotate to the right
mouseX = -mouseX / 75;
var oldDirX = dirX;
dirX = dirX * cos(mouseX) - dirY * sin(mouseX);
dirY = oldDirX * sin(mouseX) + dirY * cos(mouseX);
var oldPlaneX = planeX;
planeX = planeX * cos(mouseX) - planeY * sin(mouseX);
planeY = oldPlaneX * sin(mouseX) + planeY * cos(mouseX);
mouseX = 0;
if (keys["d"]) {
//both camera direction and camera plane must be rotated
var oldDirX = dirX;
dirX = dirX * cos(-rotSpeed) - dirY * sin(-rotSpeed);
dirY = oldDirX * sin(-rotSpeed) + dirY * cos(-rotSpeed);
var oldPlaneX = planeX;
planeX = planeX * cos(-rotSpeed) - planeY * sin(-rotSpeed);
planeY = oldPlaneX * sin(-rotSpeed) + planeY * cos(-rotSpeed);
}
//rotate to the left
if (keys["a"]) {
//both camera direction and camera plane must be rotated
var oldDirX = dirX;
dirX = dirX * cos(rotSpeed) - dirY * sin(rotSpeed);
dirY = oldDirX * sin(rotSpeed) + dirY * cos(rotSpeed);
var oldPlaneX = planeX;
planeX = planeX * cos(rotSpeed) - planeY * sin(rotSpeed);
planeY = oldPlaneX * sin(rotSpeed) + planeY * cos(rotSpeed);
}
};
var run = function() {
try {
if (document.pointerLockElement === canvas || document.mozPointerLockElement === canvas) {
document.addEventListener("mousemove", mouseMove, false);
} else {
document.removeEventListener("mousemove", mouseMove, false);
} //Mouse stuff
translate(0, 0);
scale(scaler, scaler);
fill(40, 40, 40);
rect(0, 0, w, h / 2);
fill(80, 80, 80);
rect(0, h / 2, w, h / 2);
if (keys["C"]) {
rotSpeed = 0.04;
} else {
rotSpeed = 0.1;
}
/*if (keys["W"]) {fill(255, 0, 0);}
if (keys["A"]) {fill(0, 255, 0);}
if (keys["S"]) {fill(0, 0, 255);}
if (keys["D"]) {fill(255, 0, 255);}
if (keys["X"]) {fill(255, 255, 0);}
if (keys["Z"]) {fill(0, 255, 255);}*/
castRays();
trestore();
requestAnimationFrame(run);
} catch (e) {
alert(e);
}
};
run();
<html>
<title>Jailbreak</title>
<div class="center">
<canvas width="640" height="480" id="canva"></canvas>
<br>
<img id="barrel" src="https://lodev.org/cgtutor/images/wolftexturesobj.gif">
<img id="pillar" src="https://lodev.org/cgtutor/images/wolftexturesobj.gif">
<img id="greenlight" src="https://lodev.org/cgtutor/images/wolftexturesobj.gif">
<img id="bluestone" src="https://lodev.org/cgtutor/images/wolftexturesobj.gif">
<img id="greystone" src="https://lodev.org/cgtutor/images/wolftexturesobj.gif">
<img id="wood" src="https://lodev.org/cgtutor/images/wolftexturesobj.gif">
<img id="colorstone" src="https://lodev.org/cgtutor/images/wolftexturesobj.gif">
<img id="eagle" src="https://lodev.org/cgtutor/images/wolftexturesobj.gif">
<img id="mossy" src="https://lodev.org/cgtutor/images/wolftexturesobj.gif">
<img id="redbrick" src="https://lodev.org/cgtutor/images/wolftexturesobj.gif">
<img id="purplestone" src="https://lodev.org/cgtutor/images/wolftexturesobj.gif">
</div>
</html>
UPDATE: I tried changing
if (
transformY > 0 &&
stripe > 0 &&
stripe < w &&
transformY < ZBuffer[stripe]//Pay attention to this line
) {
to:
if (
transformY > 0 &&
stripe > 0 &&
stripe < w &&
transformY > ZBuffer[stripe]//Now look
) {
Which basically reverses the check to see if it is behind a wall. Surprisingly, the blinking continues.
The answer was pretty simple. It was because stripe is not an even value, and if you were to have an array like this: var thisArray = [1, 2, 3, 4]; and you were to try and grab var money = thisArray[1.5]; the value undefined would be returned.
So I changed this:
if (
transformY > 0 &&
stripe > 0 &&
stripe < w &&
transformY < ZBuffer[stripe]
) {
To this:
if (
transformY > 0 &&
stripe > 0 &&
stripe < w &&
transformY < ZBuffer[Math.round(stripe)]
) {
Math.floor also works, since it also returns an integer value.

Javascript device compass data always starts at ~90 degrees

I'm using code from here and here to determine which way the phone is facing when looking through the camera.
After initialization, the code seems very fluid and consistent. The problem is that it seems no matter which way my device is pointing when I load the code, that becomes 90 degrees (actually 89.7ish). This is an obvious issue because now I can't simply say dir < 45 && dir > 315 = "south".
Is this due to my specific hardware/software? (Pixel XL, Chrome mobile) or am I doing something wrong in the code?
update: I experience the same behavior with complex compasses like this one from ArcGIS and this Marine Compass demo.
Here is the full code:
function compassHeading(alpha, beta, gamma) {
// Convert degrees to radians
var alphaRad = alpha * (Math.PI / 180);
var betaRad = beta * (Math.PI / 180);
var gammaRad = gamma * (Math.PI / 180);
// Calculate equation components
var cA = Math.cos(alphaRad);
var sA = Math.sin(alphaRad);
var cB = Math.cos(betaRad);
var sB = Math.sin(betaRad);
var cG = Math.cos(gammaRad);
var sG = Math.sin(gammaRad);
// Calculate A, B, C rotation components
var rA = - cA * sG - sA * sB * cG;
var rB = - sA * sG + cA * sB * cG;
var rC = - cB * cG;
// Calculate compass heading
var compassHeading = Math.atan(rA / rB);
// Convert from half unit circle to whole unit circle
if(rB < 0) {
compassHeading += Math.PI;
}else if(rA < 0) {
compassHeading += 2 * Math.PI;
}
// Convert radians to degrees
compassHeading *= 180 / Math.PI;
return compassHeading;
}
document.addEventListener("DOMContentLoaded", function(event) {
if (window.DeviceOrientationEvent) {
window.addEventListener('deviceorientation', function(eventData) {
let tiltLR = eventData.gamma;
let tiltFB = eventData.beta;
let dir = eventData.alpha;
deviceOrientationHandler(tiltLR, tiltFB, dir);
}, false);
}
function deviceOrientationHandler(tiltLR, tiltFB, dir) {
document.getElementById("tiltLR").innerHTML = 'tiltLR: ' + Math.ceil(tiltLR);
document.getElementById("tiltFB").innerHTML = 'tiltFB: ' + Math.ceil(tiltFB);
let heading = compassHeading(dir, tiltFB, tiltLR);
if (heading >= 0 && heading < 90) {
document.getElementById("direction").innerHTML = 'direction: S (' + heading + ')';
} else if (heading >= 90 && heading < 180) {
document.getElementById("direction").innerHTML = 'direction: W (' + heading + ')';
} else if (heading >= 180 && heading < 270) {
document.getElementById("direction").innerHTML = 'direction: N (' + heading + ')';
} else if (heading >= 270 && heading <= 360) {
document.getElementById("direction").innerHTML = 'direction: E (' + heading + ')';
} else {
document.getElementById("direction").innerHTML = 'direction: ? (' + heading + ')';
}
}
});

Three.js rotating a cube around a sphere

i'm trying to rotate a cube around a sphere, when i press the spacebar, the cube starts rotating around the sphere just fine, but it goes a lot quicker than i wanted, i wrote a function which would calculate the rotation using "angle" as a parameter. a full rotation would require the angle to go from 0 to 359 (or 1 to 360), but somehow the cube rotates around the sphere completely when the angle increases by just 7 degrees.
code: (im excluding the initialization of the cube and sphere meshes, just the functions)
var rotationAngle = 0;
function rotate(angle)
{
if(angle == 0)
{
keu.position.x = whiteBall.position.x + 1;
keu.position.z = whiteBall.position.z;
} else if(angle > 0 && angle < 90)
{
keu.position.x = whiteBall.position.x + Math.cos(angle);
keu.position.z = whiteBall.position.z - Math.sin(angle);
} else if(angle == 90)
{
keu.position.x = whiteBall.position.x;
keu.position.z = whiteBall.position.z - 1;
} else if(angle > 90 && angle < 180)
{
angle -= 90;
keu.position.x = whiteBall.position.x - Math.sin(angle);
keu.position.z = whiteBall.position.z - Math.cos(angle);
} else if(angle == 180)
{
keu.position.x = whiteBall.position.x - 1;
keu.position.z = whiteBall.position.z;
} else if(angle > 180 && angle < 270)
{
angle -= 180;
keu.position.x = whiteBall.position.x - Math.cos(angle);
keu.position.z = whiteBall.position.z + Math.sin(angle);
} else if(angle == 270)
{
keu.position.x = whiteBall.position.x;
keu.position.z = whiteBall.position.z + 1;
}else if(angle > 270 && angle < 360)
{
angle -= 270;
keu.position.x = whiteBall.position.x + Math.sin(angle);
keu.position.z = whiteBall.position.z + Math.cos(angle);
}
console.log(angle);
}
in the code above "whiteball is the sphere, and "keu" is the cube.
in my render function i have to following code to increase the angle and apply the rotation:
if(isKeyPressed)
{
if(rotationAngle < 360)
{
rotationAngle += 1;
}
if(rotationAngle == 360)
rotationAngle = 0;
}
rotate(rotationAngle);
i have no idea why an increase of just 7 degrees would cause the cube to make a full rotation around the sphere, any code snippets / advice would be appreciated.
Treat x position of the cube as Math.sin(counter) and y position as Math.cos(counter) where counter is some number being incremented in some requestAnimationFrame loop and if spacebar is down then increment the counter and if up then stop incrementing it. You can also modify the distance from your central point around which you move the cube by multiplying Math.sin(counter) by that distance (in pixels). You surely know range of sin is from -1 to 1.
So the code would look something like:
let isMoving = false;
document.body.addEventListener('keydown', event => {
if (event.key === 'Space') {
isMoving = true;
}
});
document.body.addEventListener('keyup', event => {
if (event.key === 'Space') {
isMoving = false;
}
});
const X = ...; //your central point, X coordinate of the sphere
const Y = ...// your central point, Y coordinate of the sphere
const distance = 100;
const speed = ...; // how fast do you want your cube to move around the sphere
let counter = 0;
let wholeCircle = false; // will be set to true after first round and stop further movement of the cube
function render() {
if (isMoving) {
counter += speed;
}
cube.position.x = X + distance * Math.sin(counter);
cube.position.y = Y + distance * Math.cos(counter);
}
render();
This is not a code to copy and paste, you needto adjust it to your situation and variable names. It is just to give you an idea on how to do this kind of movement. I didn't use the wholeCircle, you can surely figure it out.

How can I get my JS car to move?

I'm trying to get this car to move with the arrow keys and rotate as well. The car loaded onto the canvas, but its not moving with the keys. I think I've put in everything I need, or I'm wrong. Or, there just some minor mistakes. Anyways, please help a noob like me :D!
<!doctype html>
<html lang="en">
<head>
<title>Ball</title>
<script src="http://code.jquery.com/jquery-git2.js"></script>
</head>
<body>
<center>
<canvas id="gameCanvas" width="500" height="500" style="border:5px solid green"></canvas>
<script src="js/Game.js"></script>
</center>
</body>
</html>
JS:
//Set context for canvas
var context = $('#gameCanvas')[0].getContext('2d');
//Dimensions For Canvas
var width = $('#gameCanvas').width();
var height = $('#gameCanvas').height();
//Image for Car
var car = new Image();
car.src = "http://thumb1.shutterstock.com/thumb_small/338038/192139124/stock-vector-illustration-of-a-red-sports-car-top-view-192139124.jpg";
//Car Variables and position
var x = 80;
var y = 80;
var vx = 0;
var vy = 0;
var angle = 0;
var mod = 0;
//Draws car during motion
var moveInterval = setInterval(function () {
draw();
}, 30);
//Clears Canvas
function draw()
{
context.clearRect(0, 0, gameCanvas.width, gameCanvas.height);
// Change direction and velocity of car
x += (vx * mod) * Math.cos(Math.PI / 180 * angle);
y += (vy * mod) * Math.sin(Math.PI / 180 * angle);
context.save();
context.translate(x, y);
context.rotate(Math.PI / 180 * angle);
context.drawImage(car, -(car.width / 2), -(car.height / 2));
context.restore();
}
//Codes for keyboard keys
$('#gameCanvas').keydown(function(event) {
code = event.keyCode;
if (code == 37) vx = -10.0; // left key pressed
if (code == 39) vx = 10.0; // rightkey pressed
if (code == 38) vy = -2.0; // up key pressed
if (code == 40) vy = 2.0; // down key pressed
});
$('#gameCanvas').up(function(event) {
code = event.keyCode;
if (code == 37) vx = 0.0; // leftkey not pressed
if (code == 39) vx = 0.0; // rightkey not pressed
if (code == 38) vy = 0.0; // upkey not pressed
if (code == 40) vy = 0.0; // downkey not pressed
});
update();
Maybe something like this:
//Set context for canvas
var context = $('#gameCanvas')[0].getContext('2d');
//Dimensions For Canvas
var width = $('#gameCanvas').width();
var height = $('#gameCanvas').height();
//Image for Car
var car = new Image();
car.src = "http://thumb1.shutterstock.com/thumb_small/338038/192139124/stock-vector-illustration-of-a-red-sports-car-top-view-192139124.jpg";
//Car Variables and position
var x = 80;
var y = 80;
var vx = 0;
var vy = 0;
var angle = 0;
var mod = 0;
draw();
function draw()
{
context.clearRect(0, 0, gameCanvas.width, gameCanvas.height);
x += (vx * mod) * Math.cos(Math.PI / 180 * angle);
y += (vy * mod) * Math.sin(Math.PI / 180 * angle);
console.log(vx);
console.log(vy);
context.translate(vx, vy);
context.rotate(Math.PI / 180 * angle);
context.drawImage(car, x, y);
}
$(document).keydown(function(event) {
code = event.keyCode;
if (code == 37) { vx = -10.0; } // left key pressed
if (code == 39){ vx = 10.0;} // rightkey pressed
if (code == 38){ vy = -2.0;} // up key pressed
if (code == 40){ vy = 2.0; } // down key pressed
draw();
});

Categories