2016-12-09 3 views
0

Я создаю начало механизма качания лучей, используя HTML Canvas, и я быстро столкнулся с проблемой эффекта рыбий глаз. Есть много сайтов, которые говорят вам просто умножить длину луча на косинус его угла от игрока, чтобы исправить его.Почему моя коррекция рыбий глаз для двигателя для литья лучей вызывает вогнутые стены?

distance * Math.cos(angle) 

Однако исправление работает только на оси y моей карты. На оси x это приводит к тому, что стены в основном выполняют противоположную функцию рыбий глаз. Любые идеи, почему это может произойти?

Вот мой код:

var c = document.getElementById('canvas'); 
 
var ctx = c.getContext('2d'); 
 

 
c.height = window.innerHeight; 
 
c.width = window.innerWidth; 
 

 
//Setup up map 
 
var map = []; 
 
for(var i = 0;i < 20;i++) 
 
{ 
 
    map[i] = []; 
 
} 
 
map[0] = [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]; 
 
map[1] = [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]; 
 
map[2] = [2, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 2]; 
 
map[3] = [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]; 
 
map[4] = [2, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 2]; 
 
map[5] = [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]; 
 
map[6] = [2, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 2]; 
 
map[7] = [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]; 
 
map[8] = [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]; 
 
map[9] = [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]; 
 
map[10] = [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]; 
 
map[11] = [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]; 
 
map[12] = [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]; 
 
map[13] = [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]; 
 
map[14] = [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]; 
 
map[15] = [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]; 
 
map[16] = [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]; 
 
map[17] = [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]; 
 
map[18] = [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]; 
 
map[19] = [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]; 
 

 
var character = { 
 
    x: c.width/2, 
 
    y: (c.height/2) + 100, 
 
    r: 25, 
 
    angle: 0 
 
}; 
 

 
//Define all rays 
 
var rays = []; 
 
for(var i = 0;i < 300;i++) 
 
{ 
 
    rays[i] = { 
 
     x: 0, 
 
     y: 0, 
 
     travelling: false, 
 
     hit: false, 
 
     type: 0 
 
    }; 
 
} 
 

 
//GET INPUT 
 
var turningLeft = false, 
 
    turningRight = false, 
 
    movingUp = false, 
 
    movingDown = false; 
 

 
window.addEventListener('keydown', handleKeyDown, true); 
 
window.addEventListener('keyup', handleKeyUp, true); 
 
function handleKeyDown(e) 
 
{ 
 
    switch(e.keyCode) 
 
    { 
 
     case 87: movingUp = true; 
 
      break; 
 
     case 83: movingDown = true; 
 
      break; 
 
     case 65: turningLeft = true; 
 
      break; 
 
     case 68: turningRight = true; 
 
      break; 
 
    } 
 
} 
 
function handleKeyUp(e) 
 
{ 
 
    switch(e.keyCode) 
 
    { 
 
     case 87: movingUp = false; 
 
      break; 
 
     case 83: movingDown = false; 
 
      break; 
 
     case 65: turningLeft = false; 
 
      break; 
 
     case 68: turningRight = false; 
 
      break; 
 
    } 
 
} 
 

 
function gameLoop() 
 
{ 
 
    update(); 
 
    render(); 
 
    
 
    window.requestAnimationFrame(gameLoop); 
 
} 
 

 
function update() 
 
{ 
 
     
 
    //Allow movement 
 
    if(movingUp) 
 
    { 
 
     if(!detectCharacterCollision(character.x + Math.cos(character.angle) * 2, character.y)) 
 
     { 
 
      character.x += Math.cos(character.angle) * 2; 
 
     } 
 
     if(!detectCharacterCollision(character.x, character.y + Math.sin(character.angle) * 2)) 
 
     { 
 
      character.y += Math.sin(character.angle) * 2; 
 
     } 
 
    } 
 
    if(movingDown) 
 
    { 
 
     character.x -= Math.cos(character.angle); 
 
     character.y -= Math.sin(character.angle); 
 
    } 
 
    if(turningLeft) 
 
    { 
 
     character.angle -= Math.PI/180; 
 
    } 
 
    if(turningRight) 
 
    { 
 
     character.angle += Math.PI/180; 
 
    } 
 
     
 
    //Cast ray 
 
    for(var i = 0;i < rays.length;i++) 
 
    { 
 
     rays[i] = { 
 
      x: character.x, 
 
      y: character.y, 
 
      travelling: true, 
 
      hit: false, 
 
      type: 0 
 
     }; 
 
     
 
     //Until the ray hits a wall 
 
     while(rays[i].travelling) 
 
     { 
 
      //Detect if ray has hit a wall 
 
      var collision = detectRayCollision(rays[i].x, rays[i].y); 
 
      //Collision has the type of wall which was collided with (0 for no wall) 
 
      if(collision == 1) 
 
      { 
 
       rays[i].travelling = false; 
 
       rays[i].hit = true; 
 
       rays[i].type = 1; 
 
      } 
 
      else if(collision == 2) 
 
      { 
 
       rays[i].travelling = false; 
 
       rays[i].hit = true; 
 
       rays[i].type = 2; 
 
      } 
 
      else 
 
      { 
 
       //If nothing was hit, move ray is appropriate direction from player 
 
       var angle = (i * ((Math.PI/2)/rays.length)) - (Math.PI/4); 
 
       
 
       rays[i].x += Math.cos(character.angle + angle); 
 
       rays[i].y += Math.sin(character.angle + angle); 
 
      } 
 
     } 
 
    } 
 
} 
 

 
function detectRayCollision(x, y) 
 
{ 
 
    return map[Math.trunc(y/(c.height/20))][Math.trunc(x/(c.width/20))]; 
 
} 
 

 
function detectCharacterCollision(x, y) 
 
{ 
 
    if(map[Math.trunc(y/(c.height/20))][Math.trunc(x/(c.width/20))] == 0) 
 
    { 
 
     return false; 
 
    } 
 
    else 
 
    { 
 
     return true; 
 
    } 
 
} 
 

 
function getTime() 
 
{ 
 
    var date = new Date(); 
 
    return date.getTime(); 
 
} 
 

 
function render() 
 
{ 
 
    ctx.clearRect(0, 0, c.width, c.height); 
 
    
 
    //Skybox 
 
    ctx.beginPath(); 
 
    ctx.rect(0, 0, c.width, c.height/2); 
 
    ctx.fillStyle = 'rgb(135,206,250)'; 
 
    ctx.fill(); 
 
    ctx.closePath(); 
 
    
 
    //Floor 
 
    ctx.beginPath(); 
 
    ctx.rect(0, c.height/2, c.width, c.height/2); 
 
    ctx.fillStyle = 'black'; 
 
    ctx.fill(); 
 
    ctx.closePath(); 
 
    
 
    for(var i = 0;i < rays.length;i++) 
 
    { 
 
     var dx = rays[i].x - character.x; 
 
     var dy = rays[i].y - character.y; 
 
     var angle = Math.atan2(dy, dx); 
 
     var distance = Math.sqrt((dy * dy) + (dx * dx)); 
 
     var z = distance * Math.cos(angle); 
 
     
 
     ctx.beginPath(); 
 
     
 
     //Set color (or texture) for wall 
 
     if(rays[i].type == 1) 
 
     { 
 
      ctx.fillStyle = 'grey'; 
 
     } 
 
     else if(rays[i].type == 2) 
 
     { 
 
      ctx.fillStyle = 'orange'; 
 
     } 
 
     
 
     ctx.fillRect(i * (c.width/rays.length), (c.height/2) - ((c.height/(z/100))/2), c.width/rays.length + 1, c.height/(z/100)); 
 
     
 
     ctx.closePath(); 
 
    } 
 
} 
 

 
window.requestAnimationFrame(gameLoop);

ответ

0

Я ответил на мой собственный вопрос. Я не учитывал направление, в котором сейчас находится игрок. Поэтому в моем коде строка для коррекции рыбий глаз должна быть:

var z = distance * Math.cos(angle - character.angle);