html 获取一个像素时ImageData不同

cbeh67ev  于 2023-04-18  发布在  其他
关注(0)|答案(1)|浏览(109)

我正在用html canvas制作一个2d光线模拟器,每次光线移动时我都会创建一个1像素的ImageData,所以当我制作它时,它只在开始时创建一个,它停止正常工作。顶部是旧版本的工作,底部是新版本的不工作。我希望它能做同样的事情,但在新版本中,碰撞被搞砸了。

const canvas = document.getElementById("canvas");
        const ctx = canvas.getContext("2d");
        var mouseX = 0;
        var mouseY = 0;

        canvas.width = innerWidth;
        canvas.height = innerHeight;

        ctx.fillStyle = "rgb(10, 10, 10)";
        ctx.strokeStyle = "rgba(255, 255, 0)";
        ctx.lineWidth = 3;

        ImageData.prototype.getPixel = function(x, y, offset) {
            return this.data[(y * this.width + x) * 4 + offset];
        };
        
        function drawLine(first, second) {
            ctx.beginPath();
            ctx.moveTo(first[0], first[1]);
            ctx.lineTo(second[0], second[1]);
            ctx.stroke();
        };
        function mousemove(e) {
            mouseX = e.clientX;
            mouseY = e.clientY;
        };
        function drawScene() {
            ctx.fillStyle = "rgba(50, 50, 50, 1)";
            ctx.fillRect(0, 0, canvas.width, canvas.height);
            ctx.fillStyle = "rgba(10, 10, 10, 1)";

            ctx.fillRect(0, canvas.height-10, 200, 10);
            ctx.fillRect(0, canvas.height-210, 10, 200);
            ctx.fillRect(10, canvas.height-210, 200, 10);
            ctx.fillRect(200, canvas.height-190, 10, canvas.height-190);
        };
        drawScene();
        function render() {
            drawScene();
            let rays = [];
            var data;
            for (let angle = 0; angle < 360; angle += 3) { // for every ray
                let xv = Math.sin(angle*(Math.PI/180))*5;
                let yv = Math.cos(angle*(Math.PI/180))*5;
                let x = mouseX;
                let y = mouseY;
                let rayinitx = x;
                let rayinity = y;
                let collisions = 0;
                let opacity = 1;
                while (x > 0 && x < canvas.width && y > 0 && y < canvas.height) { // for every movement of every ray
                    x += xv;
                    data = ctx.getImageData(x, y, 1, 1);
                    let collide = false;
                    if (data.getPixel(0, 0, 0) === 10 && data.getPixel(0, 0, 1) === 10 && data.getPixel(0, 0, 2) === 10 && data.getPixel(0, 0, 3) === 255) {
                        xv *= -1;
                        x += xv;
                        collide = true;
                    };

                    y += yv;
                    data = ctx.getImageData(x, y, 1, 1);
                    if (data.getPixel(0, 0, 0) === 10 && data.getPixel(0, 0, 1) == 10 && data.getPixel(0, 0, 2) === 10 && data.getPixel(0, 0, 3) === 255) {
                        yv *= -1;
                        y += yv;
                        collide = true;
                    };
                    if (collide) {
                        rays.push([[rayinitx, rayinity], [x, y], opacity]);
                        opacity -= 1/5;
                        rayinitx = x;
                        rayinity = y;
                        if (opacity <= 0) {
                            break;
                        };
                    };
                };
                rays.push([[rayinitx, rayinity], [x, y], opacity]);
                rayinitx = x;
                rayinity = y;
            };
            rays.forEach(ray => {
                ctx.strokeStyle = `rgba(255, 255, 0, ${ray[2]})`;
                drawLine(ray[0], ray[1]);
            });
        };
        document.body.addEventListener("keypress", function(e){
            if (e.code == "Space") render();
        });
* {
                box-sizing: border-box;
            }
            html,body {
                width: 100%;
                height: 100%;
            }
            body {
                margin: 0;
                overflow: hidden;
            }
            canvas {
                width: 100vw;
                height: 100vh;
            }
<!DOCTYPE html>
<html lang="en">
    <body onmousemove="mousemove(event);">
        <canvas id="canvas"></canvas>
    </body>
</html>
const canvas = document.getElementById("canvas");
        const ctx = canvas.getContext("2d");
        var mouseX = 0;
        var mouseY = 0;

        canvas.width = innerWidth;
        canvas.height = innerHeight;

        ctx.fillStyle = "rgb(10, 10, 10)";
        ctx.strokeStyle = "rgba(255, 255, 0)";
        ctx.lineWidth = 3;

        ImageData.prototype.getPixel = function(x, y, offset) {
            return this.data[(y * this.width + x) * 4 + offset];
        };
        
        function drawLine(first, second) {
            ctx.beginPath();
            ctx.moveTo(first[0], first[1]);
            ctx.lineTo(second[0], second[1]);
            ctx.stroke();
        };
        function mousemove(e) {
            mouseX = e.clientX;
            mouseY = e.clientY;
        };
        function drawScene() {
            ctx.fillStyle = "rgba(50, 50, 50, 1)";
            ctx.fillRect(0, 0, canvas.width, canvas.height);
            ctx.fillStyle = "rgba(10, 10, 10, 1)";

            ctx.fillRect(0, canvas.height-10, 200, 10);
            ctx.fillRect(0, canvas.height-210, 10, 200);
            ctx.fillRect(10, canvas.height-210, 200, 10);
            ctx.fillRect(200, canvas.height-190, 10, canvas.height-190);
        };
        drawScene();
        function render() {
            drawScene();
            let rays = [];
            var data = ctx.getImageData(0, 0, canvas.width, canvas.height);
            for (let angle = 0; angle < 360; angle += 3) { // for every ray
                let xv = Math.sin(angle*(Math.PI/180))*5;
                let yv = Math.cos(angle*(Math.PI/180))*5;
                let x = mouseX;
                let y = mouseY;
                let rayinitx = x;
                let rayinity = y;
                let collisions = 0;
                let opacity = 1;
                while (x > 0 && x < canvas.width && y > 0 && y < canvas.height) { // for every movement of every ray
                    x += xv;
                    let collide = false;
                    if (data.getPixel(x, y, 0) === 10 && data.getPixel(x, y, 1) === 10 && data.getPixel(x, y, 2) === 10 && data.getPixel(x, y, 3) === 255) {
                        xv *= -1;
                        x += xv;
                        collide = true;
                    };

                    y += yv;
                    if (data.getPixel(x, y, 0) === 10 && data.getPixel(x, y, 1) == 10 && data.getPixel(x, y, 2) === 10 && data.getPixel(x, y, 3) === 255) {
                        yv *= -1;
                        y += yv;
                        collide = true;
                    };
                    if (collide) {
                        rays.push([[rayinitx, rayinity], [x, y], opacity]);
                        opacity -= 1/5;
                        rayinitx = x;
                        rayinity = y;
                        if (opacity <= 0) {
                            break;
                        };
                    };
                };
                rays.push([[rayinitx, rayinity], [x, y], opacity]);
                rayinitx = x;
                rayinity = y;
            };
            rays.forEach(ray => {
                ctx.strokeStyle = `rgba(255, 255, 0, ${ray[2]})`;
                drawLine(ray[0], ray[1]);
            });
        };
        document.body.addEventListener("keypress", function(e){
            if (e.code == "Space") render();
        });
* {
                box-sizing: border-box;
            }
            html,body {
                width: 100%;
                height: 100%;
            }
            body {
                margin: 0;
                overflow: hidden;
            }
            canvas {
                width: 100vw;
                height: 100vh;
            }
<!DOCTYPE html>
<html lang="en">
    <body onmousemove="mousemove(event);">
        <canvas id="canvas"></canvas>
    </body>
</html>
qaxu7uf2

qaxu7uf21#

问题是你的xy值不是整数。这对getImageData()来说是正常的,因为这个函数被定义为接受整数。(准确地说是[EnforceRange] long),当传入浮点数时,浏览器会自动进行转换。但是Array索引访问不会进行转换,因此,当您尝试访问ImageData.data1.3424123124项时,您会得到undefined,而不是=== 10
您可以通过在getPixel方法中强制转换为整数来解决这个问题:

ImageData.prototype.getPixel = function(x, y, offset) {
  return this.data[(Math.floor(y) * this.width + Math.floor(x)) * 4 + offset];
};
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
var mouseX = 0;
var mouseY = 0;

canvas.width = innerWidth;
canvas.height = innerHeight;

ctx.fillStyle = "rgb(10, 10, 10)";
ctx.strokeStyle = "rgba(255, 255, 0)";
ctx.lineWidth = 3;

ImageData.prototype.getPixel = function(x, y, offset) {
  return this.data[(Math.floor(y) * this.width + Math.floor(x)) * 4 + offset];
};

function drawLine(first, second) {
  ctx.beginPath();
  ctx.moveTo(first[0], first[1]);
  ctx.lineTo(second[0], second[1]);
  ctx.stroke();
};

function mousemove(e) {
  mouseX = e.clientX;
  mouseY = e.clientY;
};

function drawScene() {
  ctx.fillStyle = "rgba(50, 50, 50, 1)";
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  ctx.fillStyle = "rgba(10, 10, 10, 1)";

  ctx.fillRect(0, canvas.height - 10, 200, 10);
  ctx.fillRect(0, canvas.height - 210, 10, 200);
  ctx.fillRect(10, canvas.height - 210, 200, 10);
  ctx.fillRect(200, canvas.height - 190, 10, canvas.height - 190);
};
drawScene();

function render() {
  drawScene();
  let rays = [];
  var data = ctx.getImageData(0, 0, canvas.width, canvas.height);
  for (let angle = 0; angle < 360; angle += 3) { // for every ray
    let xv = Math.sin(angle * (Math.PI / 180)) * 5;
    let yv = Math.cos(angle * (Math.PI / 180)) * 5;

    let x = mouseX;
    let y = mouseY;
    let rayinitx = x;
    let rayinity = y;
    let collisions = 0;
    let opacity = 1;
    while (x > 0 && x < canvas.width && y > 0 && y < canvas.height) { // for every movement of every ray
      x += xv;
      let collide = false;
      if (data.getPixel(x, y, 0) === 10 && data.getPixel(x, y, 1) === 10 && data.getPixel(x, y, 2) === 10 && data.getPixel(x, y, 3) === 255) {
        xv *= -1;
        x += xv;
        collide = true;
      };

      y += yv;
      if (data.getPixel(x, y, 0) === 10 && data.getPixel(x, y, 1) == 10 && data.getPixel(x, y, 2) === 10 && data.getPixel(x, y, 3) === 255) {
        yv *= -1;
        y += yv;
        collide = true;
      };
      if (collide) {
        rays.push([
          [rayinitx, rayinity],
          [x, y], opacity
        ]);
        opacity -= 1 / 5;
        rayinitx = x;
        rayinity = y;
        if (opacity <= 0) {
          break;
        };
      };
    };
    rays.push([
      [rayinitx, rayinity],
      [x, y], opacity
    ]);
    rayinitx = x;
    rayinity = y;
  };
  rays.forEach(ray => {
    ctx.strokeStyle = `rgba(255, 255, 0, ${ray[2]})`;
    drawLine(ray[0], ray[1]);
  });
};
document.body.addEventListener("keypress", function(e) {
  if (e.code == "Space") render();
});
* {
  box-sizing: border-box;
}

html,
body {
  width: 100%;
  height: 100%;
}

body {
  margin: 0;
  overflow: hidden;
}

canvas {
  width: 100vw;
  height: 100vh;
}
<!DOCTYPE html>
<html lang="en">

<body onmousemove="mousemove(event);">
  <canvas id="canvas"></canvas>
</body>

</html>

相关问题