2016-12-09 22 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); 
関連する問題