Skip to content

Instantly share code, notes, and snippets.

@andiogenes
Created May 25, 2018 04:01
Show Gist options
  • Save andiogenes/254210e82cf349cfaf73b628393a2c75 to your computer and use it in GitHub Desktop.
Save andiogenes/254210e82cf349cfaf73b628393a2c75 to your computer and use it in GitHub Desktop.
Haxe written Raycaster based on lodev's tutorials
package;
import js.Browser;
import js.html.CanvasElement;
import js.html.CanvasRenderingContext2D;
import js.html.KeyboardEvent;
import js.Lib;
/**
* @name ОНО РАБОТАЕТ
* @author Wookie
*/
class Main
{
var worldMap : Array<Array<Int>> = [
[1,1,1,1,1,1,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,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,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,0,0,0,0,0,0,1],
[1,0,0,0,0,0,2,2,2,2,2,0,0,0,0,3,0,3,0,3,0,0,0,1],
[1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,3,0,0,0,3,0,0,0,1],
[1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,2,2,0,2,2,0,0,0,0,3,0,3,0,3,0,0,0,1],
[1,0,0,0,0,0,0,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,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,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,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,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,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,4,0,4,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,4,0,0,0,0,5,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,4,0,4,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,4,0,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,4,4,4,4,4,4,4,4,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,1,1,1,1,1,1]
];
public function new()
{
// x and y start position
var posX : Float = 22;
var posY : Float = 12;
// initial direction vector
var dirX : Float = -1;
var dirY : Float = 0;
// the 2d raycaster version of camera plane
var planeX : Float = 0;
var planeY : Float = 0.66;
var time : Float = 0; // time of current frame
var oldTime : Float = 0; // time of previous frame
var frameTime : Float = 0; // вынес из игрового цикла сюда, т.к. доступ к клавишам из события
var screen : CanvasElement = Browser.document.createCanvasElement();
var w : Int = screen.width = 512;
var h : Int = screen.height = 384;
screen.style.backgroundColor = "#000";
Browser.document.head.title = screen.id = "Raycaster";
var ctx : CanvasRenderingContext2D = screen.getContext2d();
ctx.fillStyle = "#fff";
ctx.font = "12pt sans-serif";
Browser.document.body.appendChild(screen);
// javascript не переваривает while (true)
Browser.window.setInterval(function() {
ctx.clearRect(0, 0, w, h); // очистка экрана работает на заходе в функцию
for (x in 0 ... w)
{
// calculate ray position and direction
var cameraX : Float = 2 * x / w - 1;
var rayPosX : Float = posX;
var rayPosY : Float = posY;
var rayDirX : Float = dirX + planeX * cameraX;
var rayDirY : Float = dirY + planeY * cameraX;
// which box of the map we're in
var mapX : Int = Std.int(rayPosX);
var mapY : Int = Std.int(rayPosY);
// length of ray from current position to next x or y-side
var sideDistX : Float;
var sideDistY : Float;
// length of ray from one x or y-side to next x or y-side
var deltaDistX : Float = Math.sqrt(1 + (rayDirY * rayDirY) / (rayDirX * rayDirX));
var deltaDistY : Float = Math.sqrt(1 + (rayDirX * rayDirX) / (rayDirY * rayDirY));
var perpWallDist : Float;
// what direction to step in x or y-direction (either +1 or -1)
var stepX : Int;
var stepY : Int;
var hit : Int = 0; // was there a wall hit?
var side : Int = 0; // was a NS or a EW wall hit?
// calculate step and initial sideDist
if (rayDirX < 0)
{
stepX = -1;
sideDistX = (rayPosX - mapX) * deltaDistX;
}
else
{
stepX = 1;
sideDistX = (mapX + 1 - rayPosX) * deltaDistX;
}
if (rayDirY < 0)
{
stepY = -1;
sideDistY = (rayPosY - mapY) * deltaDistY;
}
else
{
stepY = 1;
sideDistY = (mapY + 1 - rayPosY) * deltaDistY;
}
// perform DDA
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) hit = 1;
}
// Calculate distance projected on camera direction (Euclidean distance will give fisheye effect!)
if (side == 0) perpWallDist = (mapX - rayPosX + (1 - stepX) / 2) / rayDirX;
else perpWallDist = (mapY - rayPosY + (1 - stepY) / 2) / rayDirY;
// Calculate height of line to draw on screen
var lineHeight : Int = Std.int(h / perpWallDist);
// calculate lowest and highest pixel to fill in current stripe
var drawStart : Int = Std.int(-lineHeight / 2 + h / 2);
if (drawStart < 0) drawStart = 0;
var drawEnd : Int = Std.int(lineHeight / 2 + h / 2);
if (drawEnd >= h) drawEnd = h - 1;
// choose wall color (сделал говнокодом)
var color : String;
switch(worldMap[mapX][mapY])
{
case 1:
if (side == 1) color = "#7f0000"; // red
else color = "#f00";
case 2:
if (side == 1) color = "#007f00"; // green
else color = "#00ff00";
case 3:
if (side == 1) color = "#00007f"; // blue
else color = "#0000ff";
case 4:
if (side == 1) color = "#7f7f7f"; // white
else color = "#fff";
default:
if (side == 1) color = "#7f7f00"; // yellow
else color = "#ffff00";
}
ctx.strokeStyle = color;
// draw the pixels of the stripe as vertical line
ctx.beginPath();
ctx.lineTo(x, drawStart);
ctx.lineTo(x, drawEnd);
ctx.stroke();
}
// timing for input and FPS counter
oldTime = time;
time = untyped __js__ ("Date.now()");
frameTime = (time - oldTime) / 1000; // frameTime is the time this frame has taken, in seconds
//ctx.fillText(Std.string(1 / frameTime), 5, 20); // FPS counter
// Тут была очистка
}, 0);
// Обработка клавиатуры
Browser.document.addEventListener("keydown", function(e : KeyboardEvent) {
/* LEFT = 37;
UP = 38;
RIGHT = 39;
DOWN = 40; */
if (e.keyCode == 37)
{
// LEFT
var oldDirX : Float = dirX;
dirX = dirX * Math.cos(frameTime * 3) - dirY * Math.sin(frameTime * 3);
dirY = oldDirX * Math.sin(frameTime * 3) + dirY * Math.cos(frameTime * 3);
var oldPlaneX : Float = planeX;
planeX = planeX * Math.cos(frameTime * 3) - planeY * Math.sin(frameTime * 3);
planeY = oldPlaneX * Math.sin(frameTime * 3) + planeY * Math.cos(frameTime * 3);
}
if (e.keyCode == 38)
{
// UP
if (worldMap[Std.int(posX + dirX * frameTime * 5)][Std.int(posY)] == 0) posX += dirX * frameTime * 5;
if (worldMap[Std.int(posX)][Std.int(posY + dirY * frameTime * 5)] == 0) posY += dirY * frameTime * 5;
}
if (e.keyCode == 39)
{
// RIGHT
var oldDirX : Float = dirX;
dirX = dirX * Math.cos(-frameTime * 3) - dirY * Math.sin(-frameTime * 3);
dirY = oldDirX * Math.sin(-frameTime * 3) + dirY * Math.cos(-frameTime * 3);
var oldPlaneX : Float = planeX;
planeX = planeX * Math.cos(-frameTime * 3) - planeY * Math.sin(-frameTime * 3);
planeY = oldPlaneX * Math.sin(-frameTime * 3) + planeY * Math.cos(-frameTime * 3);
}
if (e.keyCode == 40)
{
// DOWN
if (worldMap[Std.int(posX - dirX * frameTime * 5)][Std.int(posY)] == 0) posX -= dirX * frameTime * 5;
if (worldMap[Std.int(posX)][Std.int(posY - dirY * frameTime * 5)] == 0) posY -= dirY * frameTime * 5;
}
if (e.keyCode >= 49 && e.keyCode <= 57)
screen.style.width = w * 0.25 * (e.keyCode - 48) + "px";
}, false);
}
static function main()
{
new Main();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment