This commit is contained in:
Alexander Popov 2022-03-29 23:50:58 +03:00
parent 7f1140f997
commit 64d99d7476
Signed by: iiiypuk
GPG Key ID: 3F76816AEE08F908
7 changed files with 104 additions and 52 deletions

7
TODO.md Normal file
View File

@ -0,0 +1,7 @@
## Plan
- [ ] - fog (draw distance)
- [ ] - покачивание камеры
## Complete
- [ ] `...`
## Dropped
- [ ] `...`

View File

@ -1,19 +1,19 @@
var raycast = raycast || {}; var raycast = raycast || {};
window.requestAnimFrame = (function(){ window.requestAnimFrame = (function(){
return window.requestAnimationFrame || return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame || window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame || window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame || window.oRequestAnimationFrame ||
window.msRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback, element){ function(callback, element) {
window.setTimeout(callback, 1000 / 60); window.setTimeout(callback, 1000 / 60);
}; };
})(); })();
function start() { function start() {
document.onkeyup = raycast.keyhandler.onKeyup; document.onkeyup = raycast.keyHandler.onKeyup;
document.onkeydown = raycast.keyhandler.onKeydown; document.onkeydown = raycast.keyHandler.onKeydown;
var textureFiles = ["img/brick.png", "img/ground.png", "img/sky.png"]; var textureFiles = ["img/brick.png", "img/ground.png", "img/sky.png"];
raycast.texture.initiateLoad(textureFiles, raycast.engine.start); raycast.texture.initiateLoad(textureFiles, raycast.engine.start);
}; };

View File

@ -4,13 +4,15 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>JSRay</title> <title>JSRay</title>
<link rel="stylesheet" type="text/css" href="styles.css">
</head> </head>
<body bgcolor="999999"> <body>
<div id="canvasdiv"> <div class="container">
<canvas id="viewport" width="800" height="600"></canvas> <canvas id="canvas" width="600" height="400"></canvas>
</div> </div>
<script src="keyhandler.js"></script> <script src="worldMap.js"></script>
<script src="keyHandler.js"></script>
<script src="texture.js"></script> <script src="texture.js"></script>
<script src="raycast.js"></script> <script src="raycast.js"></script>
<script src="game.js"></script> <script src="game.js"></script>

View File

@ -1,16 +1,22 @@
var raycast = raycast || {}; var raycast = raycast || {};
raycast.keyhandler = (function () { raycast.keyHandler = (function() {
var codes = { var codes = {
// forward
up: 38, up: 38,
w: 87, w: 87,
// backward
down: 40, down: 40,
s: 83,
// turn left
left: 37, left: 37,
a: 65, a: 65,
// turn right
right: 39, right: 39,
d: 68, d: 68,
// special
space: 32, space: 32,
ctrl: 17, ctrl: 17, // change filtering type
esc: 27 esc: 27
}; };

View File

@ -1,13 +1,10 @@
// http://lodev.org/cgtutor/raycasting.html
var raycast = raycast || {}; var raycast = raycast || {};
raycast.engine = (function () { raycast.engine = (function() {
var canvas = document.getElementById("viewport"); var canvas = document.getElementById("canvas");
var g = canvas.getContext("2d"); var g = canvas.getContext("2d");
var filtering = false; var filtering = false;
var mapWidth = 24, let texHeight = 64, // mapWidth = 24, mapHeight = 24
mapHeight = 24,
texHeight = 64,
texWidth = 64; texWidth = 64;
var texture; var texture;
@ -24,24 +21,14 @@ raycast.engine = (function () {
} }
} }
} }
/* /*
texture[0] = raycast.texture.load("ground"); texture[0] = raycast.texture.load("...");
texture[1] = raycast.texture.load("brick"); texture[1] = raycast.texture.load("brick");
texture[2] = raycast.texture.load("sky"); texture[2] = raycast.texture.load("ground");
texture[3] = raycast.texture.load("sky");
*/ */
var worldMap = [
[1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,1],
[1,0,0,1,0,0,1,0,0,1],
[1,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,1],
[1,0,0,1,0,0,1,0,0,1],
[1,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,1],
[1,1,1,1,1,1,1,1,1,1]
];
var posX = 2, posY = 2, var posX = 2, posY = 2,
dirX = -1, dirY = 0, dirX = -1, dirY = 0,
@ -54,7 +41,6 @@ raycast.engine = (function () {
h = canvas.height; h = canvas.height;
function verLine(arr, x, yStart, yEnd, color){ function verLine(arr, x, yStart, yEnd, color){
//console.log(x, yStart, yEnd);
for (var y = yStart | 0; y < yEnd | 0; y++) { for (var y = yStart | 0; y < yEnd | 0; y++) {
var i = 4 * (w * y) + 4 * x; var i = 4 * (w * y) + 4 * x;
arr[i + 0] = color[0]; arr[i + 0] = color[0];
@ -67,20 +53,21 @@ raycast.engine = (function () {
imagedata = g.getImageData(0,0,w,h); imagedata = g.getImageData(0,0,w,h);
var buffer = imagedata.data; var buffer = imagedata.data;
var keys = raycast.keyhandler; var keys = raycast.keyHandler;
function input() { function input() {
if (keys.isKeydown("up")) { // player move forward
if (keys.isKeydown("up") || keys.isKeydown("w")) {
if(worldMap[(posX + dirX * moveSpeed) | 0][posY | 0] == 0) posX += dirX * moveSpeed; if(worldMap[(posX + dirX * moveSpeed) | 0][posY | 0] == 0) posX += dirX * moveSpeed;
if(worldMap[posX | 0][(posY + dirY * moveSpeed) | 0] == 0) posY += dirY * moveSpeed; if(worldMap[posX | 0][(posY + dirY * moveSpeed) | 0] == 0) posY += dirY * moveSpeed;
} }
//move backwards if no wall behind you // player move backwards if no wall behind you
if (keys.isKeydown("down")) { if (keys.isKeydown("down") || keys.isKeydown("s")) {
if(worldMap[(posX - dirX * moveSpeed) | 0][posY | 0] == 0) posX -= dirX * moveSpeed; if(worldMap[(posX - dirX * moveSpeed) | 0][posY | 0] == 0) posX -= dirX * moveSpeed;
if(worldMap[posX | 0][(posY - dirY * moveSpeed) | 0] == 0) posY -= dirY * moveSpeed; if(worldMap[posX | 0][(posY - dirY * moveSpeed) | 0] == 0) posY -= dirY * moveSpeed;
} }
if (keys.isKeydown("right")) { if (keys.isKeydown("right") || keys.isKeydown("d")) {
//both camera direction and camera plane must be rotated // both camera direction and camera plane must be rotated
var oldDirX = dirX; var oldDirX = dirX;
dirX = dirX * Math.cos(-rotSpeed) - dirY * Math.sin(-rotSpeed); dirX = dirX * Math.cos(-rotSpeed) - dirY * Math.sin(-rotSpeed);
dirY = oldDirX * Math.sin(-rotSpeed) + dirY * Math.cos(-rotSpeed); dirY = oldDirX * Math.sin(-rotSpeed) + dirY * Math.cos(-rotSpeed);
@ -88,8 +75,8 @@ raycast.engine = (function () {
planeX = planeX * Math.cos(-rotSpeed) - planeY * Math.sin(-rotSpeed); planeX = planeX * Math.cos(-rotSpeed) - planeY * Math.sin(-rotSpeed);
planeY = oldPlaneX * Math.sin(-rotSpeed) + planeY * Math.cos(-rotSpeed); planeY = oldPlaneX * Math.sin(-rotSpeed) + planeY * Math.cos(-rotSpeed);
} }
if (keys.isKeydown("left")) { if (keys.isKeydown("left") || keys.isKeydown("a")) {
//both camera direction and camera plane must be rotated // both camera direction and camera plane must be rotated
var oldDirX = dirX; var oldDirX = dirX;
dirX = dirX * Math.cos(rotSpeed) - dirY * Math.sin(rotSpeed); dirX = dirX * Math.cos(rotSpeed) - dirY * Math.sin(rotSpeed);
dirY = oldDirX * Math.sin(rotSpeed) + dirY * Math.cos(rotSpeed); dirY = oldDirX * Math.sin(rotSpeed) + dirY * Math.cos(rotSpeed);
@ -97,7 +84,7 @@ raycast.engine = (function () {
planeX = planeX * Math.cos(rotSpeed) - planeY * Math.sin(rotSpeed); planeX = planeX * Math.cos(rotSpeed) - planeY * Math.sin(rotSpeed);
planeY = oldPlaneX * Math.sin(rotSpeed) + planeY * Math.cos(rotSpeed); planeY = oldPlaneX * Math.sin(rotSpeed) + planeY * Math.cos(rotSpeed);
} }
if (keys.isKeypress("d")) if (keys.isKeypress("ctrl"))
filtering = !filtering; filtering = !filtering;
} }
@ -158,10 +145,10 @@ raycast.engine = (function () {
else else
perpWallDist = Math.abs((mapY - rayPosY + (1 - stepY) / 2) / rayDirY); perpWallDist = Math.abs((mapY - rayPosY + (1 - stepY) / 2) / rayDirY);
//Calculate height of line to draw on screen // calculate height of line to draw on screen
var lineHeight = Math.abs((h / perpWallDist) | 0); var lineHeight = Math.abs((h / perpWallDist) | 0);
//calculate lowest and highest pixel to fill in current stripe // calculate lowest and highest pixel to fill in current stripe
var drawStart = ((h - lineHeight) / 2) | 0; var drawStart = ((h - lineHeight) / 2) | 0;
if(drawStart < 0) if(drawStart < 0)
drawStart = 0; drawStart = 0;
@ -247,7 +234,7 @@ raycast.engine = (function () {
var ceilTex = texture[2]; var ceilTex = texture[2];
var floorTex = texture[1]; var floorTex = texture[1];
//draw the floor from drawEnd to the bottom of the screen // draw the floor from drawEnd to the bottom of the screen
for(var y = drawEnd; y < h; y++) for(var y = drawEnd; y < h; y++)
{ {
currentDist = h / (2.0 * y - h); //you could make a small lookup table for this instead currentDist = h / (2.0 * y - h); //you could make a small lookup table for this instead
@ -286,7 +273,7 @@ raycast.engine = (function () {
color = floorTex[texWidth * (floorTexY|0) + (floorTexX|0)]; color = floorTex[texWidth * (floorTexY|0) + (floorTexX|0)];
} }
//floor // floor
i = 4 * (w * y) + 4 * x; i = 4 * (w * y) + 4 * x;
buffer[i+0] = (color[0])/2; buffer[i+0] = (color[0])/2;
@ -308,7 +295,7 @@ raycast.engine = (function () {
color = ceilTex[texWidth * (floorTexY|0) + (floorTexX|0)]; color = ceilTex[texWidth * (floorTexY|0) + (floorTexX|0)];
} }
//ceiling (symmetrical!) // ceiling (symmetrical!)
i = 4 * (w * (h - y - 1)) + 4 * x; i = 4 * (w * (h - y - 1)) + 4 * x;
buffer[i+0] = color[0]/2; buffer[i+0] = color[0]/2;
@ -327,8 +314,8 @@ raycast.engine = (function () {
rotSpeed = frameTime * 3.0; //the constant value is in radians/second rotSpeed = frameTime * 3.0; //the constant value is in radians/second
g.putImageData(imagedata, 0, 0); g.putImageData(imagedata, 0, 0);
g.font = "bold 30pt Monospace"; g.font = "14pt Monospace";
g.fillText(""+((1000 / (time - oldTime))|0), 0, 30); g.fillText("FPS: " + ((1000 / (time - oldTime)) | 0), 5, 20);
}; };
function tick() { function tick() {
@ -337,7 +324,6 @@ raycast.engine = (function () {
keys.tick(); keys.tick();
window.requestAnimFrame(tick); window.requestAnimFrame(tick);
//window.setTimeout(tick, 1);
}; };
function start() { function start() {

20
src/styles.css Normal file
View File

@ -0,0 +1,20 @@
* { margin: 0; padding: 0; outline: 0; }
html, body {
height: 100%;
}
body {
background-color: #444;
}
.container {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
canvas {
border: 2px solid #000;
}

31
src/worldMap.js Normal file
View File

@ -0,0 +1,31 @@
/*let worldMap = [
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,1,1,1,0,0,0,0,0,0,0,0,1,0,0,1],
[1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1],
[1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1],
[1,0,0,1,0,1,0,0,0,0,0,0,0,0,1,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,1,1,1,0,1,0,0,0,0,0,0,0,0,1,1,1,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1],
[1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1],
[1,1,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,1],
[1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,0,1],
[1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,1,0,1,0,0,0,0,0,0,0,0,1,0,1,1],
[1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
];*/
let worldMap = [
[1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,1,1,1,0,0,1,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,1],
[1,1,1,1,1,1,1,1,1,1,1,1]
];