【问题标题】:Javscript optimization with for loops and intervals使用 for 循环和间隔进行 Javascript 优化
【发布时间】:2021-05-05 19:57:05
【问题描述】:

我正在用java脚本(一个光线投射器)制作一个游戏,它真的很慢,因为有很多嵌套的for循环和间隔,有很大的数组,有没有办法优化它,如果有,会吗当我开始做更大的数学来计算线-线交点时仍然很慢,我只是不认为我以最好的方式这样做。

<!DOCTYPE html>
<html>

<head>
  <title>Page Title</title>
</head>

<body>

  <canvas width="500px" height="500px" id="c"></canvas>
</body>
<script>
  c = document.getElementById("c");
  w = c.width;
  h = c.height;
  ctx = c.getContext("2d");
  var tilesize = 50;
  var walls = [];


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


  var map = [
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ],
    [1, 0, 0, 0, 0, 0, 0, 0, 0, 1, ],
    [1, 0, 1, 1, 0, 0, 0, 0, 0, 1, ],
    [1, 0, 1, 1, 0, 0, 0, 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, 0, 0, 0, 1, 0, 0, 1, ],
    [1, 0, 0, 0, 0, 0, 1, 0, 0, 1, ],
    [1, 0, 0, 0, 0, 0, 1, 0, 0, 1, ],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ]
  ]





  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;
    }

  }

  var gameloop = setInterval(function() {
    ctx.clearRect(0, 0, w, h);

    //move
    rotstep = player.rotSpeed * player.rotDir
    movestep = player.speed * player.dir;
    player.rot += 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++) {
        if (map[y][x] == 1) {
          var wallSeg = {
            coordX: x * tilesize,
            coordY: y * tilesize,
            sizeX: tilesize,
            sizeY: 0,
          }
          var wallSeg2 = {
            coordX: x * tilesize,
            coordY: y * tilesize,
            sizeX: 0,
            sizeY: tilesize,
          }
          var wallSeg3 = {
            coordX: x * tilesize,
            coordY: (y * tilesize) + tilesize,
            sizeX: tilesize,
            sizeY: 0,
          }
          var wallSeg4 = {
            coordX: (x * tilesize) + tilesize,
            coordY: y * tilesize,
            sizeX: 0,
            sizeY: tilesize,
          }
          walls.push(wallSeg)
          walls.push(wallSeg2)
          walls.push(wallSeg3)
          walls.push(wallSeg4)

        }
      }
    }
    for (i = 0; i < walls.length; i++) {
      var currentwall = walls[i]
      ctx.strokeStyle = "black"
      ctx.beginPath()
      ctx.moveTo(currentwall.coordX, currentwall.coordY);
      ctx.lineTo((currentwall.coordX) + currentwall.sizeX, (currentwall.coordY) + currentwall.sizeY);
      ctx.stroke();
    }
    //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();
    //marker
    ctx.beginPath();
    ctx.moveTo(player.x, player.y)
    ctx.lineTo(markerX, markerY)
    ctx.strokeStyle = "Blue"
    ctx.stroke();

  }, 1000 / 30)

  document.addEventListener("keydown", function(event) {
    keydown(event);
  })
  document.addEventListener("keyup", function(event) {
    keyup(event);
  })
</script>

</html>

【问题讨论】:

  • WebWorkers 可能是一个很好的用例。生成进程以在主进程处理 UI 时进行计算和报告结果。先看看example
  • 这里是一个相关项目:github.com/ercang/raytracer-js
  • 你需要在每个游戏循环中做所有walls 的事情吗,你不能一开始就做一次吗?此外,您似乎一直在每个游戏循环都附加到 walls 数组而没有清除它,使其变得越来越大。

标签: javascript html performance optimization canvas


【解决方案1】:

我想出了一种方法,而不是渲染每个单独的线段,只需为每个线段渲染一个正方形,我不需要渲染线段,我只需要变量,并且只在开始时初始化墙壁。

<!DOCTYPE html>
<html>
    <head>
        <title>Page Title</title>
    </head>
    <body>

    <canvas width="500px" height="500px" id="c"></canvas>   
    </body>
    <script>
        
        c = document.getElementById("c");
        w = c.width;
        h = c.height;
        ctx = c.getContext("2d");
        var tilesize = 50;
    var walls = [];
    rayangle = 35;


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


        var map = [
            [1,1,1,1,1,1,1,1,1,1,],
            [1,0,0,0,0,0,0,0,0,1,],
            [1,0,1,1,0,0,0,0,0,1,],
            [1,0,1,1,0,0,0,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,0,0,0,1,0,0,1,],
            [1,0,0,0,0,0,1,0,0,1,],
            [1,0,0,0,0,0,1,0,0,1,],
            [1,1,1,1,1,1,1,1,1,1,]
            ]
            

      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);

                    if(map[y][x] == 1){
                      var wallSeg = {
                        coordX : x * tilesize,
                        coordY : y * tilesize,
                        sizeX : tilesize,
                        sizeY : 0,
                      }
                      var wallSeg2 = {
                        coordX : x * tilesize,
                        coordY : y * tilesize,
                        sizeX : 0,
                        sizeY : tilesize,
                      }
                      var wallSeg3 = {
                        coordX : x * tilesize,
                        coordY : (y * tilesize)+tilesize,
                        sizeX : tilesize,
                        sizeY : 0,
                      }
                      var wallSeg4 = {
                        coordX : (x * tilesize) + tilesize,
                        coordY : y * tilesize,
                        sizeX : 0,
                        sizeY : tilesize,
                      }
                      walls.push(wallSeg)
                      walls.push(wallSeg2)
                      walls.push(wallSeg3)
                      walls.push(wallSeg4)

                    }
                    }    
                }
        

            

            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;
                }

            }
        
            var gameloop = setInterval(function(){
                ctx.clearRect(0,0,w,h);

                //move
        rotstep = player.rotSpeed * player.rotDir
                movestep = player.speed * player.dir;
        player.rot += 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     
                //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();
        //marker
        ctx.beginPath();
        ctx.moveTo(player.x,player.y)
        ctx.lineTo(markerX,markerY)
        ctx.strokeStyle = "Blue"
        ctx.stroke();

            },1000/30)

            document.addEventListener("keydown",function(event){
                keydown(event);
            })
      document.addEventListener("keyup",function(event){
                keyup(event);
            })

    </script>
</html>

【讨论】:

    猜你喜欢
    • 2012-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-23
    • 1970-01-01
    • 2020-06-14
    • 2021-10-11
    • 2021-06-22
    相关资源
    最近更新 更多