4

我正在使用画布在 javscript 中构建 raycastin 引擎,我构建了 raycaster 及其完全工作,除了一个问题,有鱼眼效果,我尝试进行更正

var d = (Math.sqrt( Math.pow((rays[i].x - rays[i].newX),2 )+Math.pow((rays[i].y - rays[i].newY),2 )))

// my attempted corection
var correctedDis = d * Math.cos((rays[i].rayAngle - player.rot)) 

但它不会产生任何结果:

当我运行它时的光线投射器

我仔细检查了数学,我没有发现任何问题,但我可能仍然做错了,因为我在七年级并且还没有学到很多关于三角学的知识,(只参加了可汗学院的课程)所以有人可以让我知道是否有更好或更简单的方法来做到这一点,提前谢谢你。

(我也认为我可能做错了阴影,如果有人能帮忙的话。)

编辑:我忘了包括你可以使用 WASD 键来控制演示,并且图像被翻转,但这将是一个简单的修复。 如果您需要,我的完整代码:

const scale = (num, in_min, in_max, out_min, out_max) => {
  return (num - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

tex_stone = document.getElementById("stone")
c3 = document.getElementById("c3");
c = document.getElementById("c");
w = c.width;
h = c.height;
ctx = c.getContext("2d");
fctx = c3.getContext("2d")
var tilesize = 30;
var walls = [];
var rays = [];
rayangle = 0.5;
lowrayangle = -0.5;

var player = {
  x: 80,
  y: 80,
  size: 10,
  speed: 1.3,
  dir: 0,
  rot: 0,
  rotSpeed: 0.05,
  rotDir: 0,
}

map = [];



for (y = 0; y < map.length; y++) {
  for (x = 0; x < map[y].length; x++) {

    ctx.fillStyle = ["white", "black"][map[y][x]];
    ctx.fillRect(x * tilesize, y * tilesize, tilesize, tilesize);


  }
}





function keydown(event) {
  switch (event.keyCode) {
    case 87:
      player.dir = 1;
      break;
    case 83:
      player.dir = -1;
      break;
    case 68:
      player.rotDir = -1;
      break;
    case 65:
      player.rotDir = 1;
      break;
  }

}

function keyup(event) {
  switch (event.keyCode) {
    case 87:
      player.dir = 0;
      break;
    case 83:
      player.dir = 0;
      break;
    case 68:
      player.rotDir = 0;
      break;
    case 65:
      player.rotDir = 0;
      break;
  }

}

window.requestAnimationFrame(update)

function update() {
  if (player.rot == 6.28319) {
    player.rot = 0;
  }
  var map = [
    [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, 1],
    [1, 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, 1],
    [1, 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, 1],
    [1, 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, 1],
    [1, 0, 0, 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, 1, 1],

  ]

  fctx.clearRect(0, 0, w, h)

  ctx.clearRect(0, 0, w, h);
  rays = [];
  //move


  rotstep = player.rotSpeed * player.rotDir
  movestep = player.speed * player.dir;
  player.rot += rotstep;
  rayangle += rotstep;
  lowrayangle += rotstep;
  newY = player.y - Math.cos(player.rot) * movestep;
  newX = player.x - Math.sin(player.rot) * movestep;

  leftbY = (player.y - 10) - Math.cos(player.rot) * movestep;
  leftbX = (player.x - 10) - Math.sin(player.rot) * movestep;
  rightbY = (player.y + 10) - Math.cos(player.rot) * movestep;
  rightbX = (player.x + 10) - Math.sin(player.rot) * movestep;



  //borders 
  var leftcol = Math.floor((leftbX) / tilesize)
  var leftrow = Math.floor((leftbY) / tilesize)
  var rightcol = Math.floor((rightbX) / tilesize)
  var rightrow = Math.floor((rightbY) / tilesize)
  if (map[rightcol][rightrow] == 0 && map[leftcol][leftrow] == 0) {
    player.y = newY;
    player.x = newX;
  }

  //map
  for (y = 0; y < map.length; y++) {
    for (x = 0; x < map[y].length; x++) {

      ctx.fillStyle = ["white", "black"][map[y][x]];
      ctx.fillRect(x * tilesize, y * tilesize, tilesize, tilesize);

    }
  }



  //rays  

  for (i = lowrayangle; i < rayangle; i += 0.01) {

    var detail = 0.5;
    var rayLn = 1000;
    var memX;
    var memY;
    for (j = 0; j < rayLn; j += detail) {
      var lY = player.y - Math.cos(i) * j;
      var lX = player.x - Math.sin(i) * j;

      memX = lX;
      memY = lY;

      lX = lX - (lX % tilesize);
      lY = lY - (lY % tilesize);

      if (map[lY / tilesize][lX / tilesize] == 1) {
        break;
      }
    }

    var ray = {
      rayAngle: i,
      newY: memY,
      newX: memX,
      x: player.x,
      y: player.y
    }
    rays.push(ray)
  }

  for (i = 0; i < rays.length; i++) {
    if (rays[i].rayAngle == 6.28319) {
      rays[i].rayAngle = 0;
    }
  }
  for (i = 0; i < rays.length; i++) {
    ctx.beginPath();
    ctx.moveTo(rays[i].x, rays[i].y)
    ctx.lineTo(rays[i].newX, rays[i].newY)
    ctx.stroke();

    var d = (Math.sqrt(Math.pow((rays[i].x - rays[i].newX), 2) + Math.pow((rays[i].y - rays[i].newY), 2)))

    // my attempted corection
    var correctedD = d * Math.cos((rays[i].rayAngle - player.rot))

    var rayW = w / rays.length
    var light = scale(correctedD, 0, 700, 255, 0)
    var threeDRayHeight = scale(correctedD, 0, 700, h, 10)
    fctx.fillStyle = 'rgb(' + light + ',' + light + ',' + light + ')';
    fctx.fillRect(i * rayW, 200 - threeDRayHeight * 0.5, rayW + 1, threeDRayHeight)
    fctx.fillStyle = "blue"
    fctx.fillRect(i * rayW, (200 - threeDRayHeight * 0.5) + threeDRayHeight, rayW + 1, 1000)
    fctx.fillStyle = "red"
    fctx.fillRect(i * rayW, (200 - threeDRayHeight * 0.5) - 1000, rayW + 1, 1000)


  }
  //player
  markerY = player.y - Math.cos(player.rot) * 30;
  markerX = player.x - Math.sin(player.rot) * 30;
  ctx.fillStyle = "red";
  ctx.beginPath();
  ctx.ellipse(player.x, player.y, player.size, player.size, player.rot * (Math.PI / 180), 0, 2 * Math.PI);
  ctx.fill();

  window.requestAnimationFrame(update)
}

document.addEventListener("keydown", function(event) {
  keydown(event);
})
document.addEventListener("keyup", function(event) {
  keyup(event);
})
#c3 {
  background-color: black;
}
<img src="https://i.pinimg.com/originals/16/e1/6b/16e16b80294d07b81cfafaefdf1d2909.jpg" width=4 00px; style="display: none;" id="stone">
<canvas width="600px" height="450px" id="c3"></canvas>
<canvas width="600px" height="450px" id="c"></canvas>

4

0 回答 0