我正在用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>
1条答案
按热度按时间qaxu7uf21#
问题是你的
x
和y
值不是整数。这对getImageData()
来说是正常的,因为这个函数被定义为接受整数。(准确地说是[EnforceRange] long
),当传入浮点数时,浏览器会自动进行转换。但是Array
索引访问不会进行转换,因此,当您尝试访问ImageData
的.data
的1.3424123124
项时,您会得到undefined
,而不是=== 10
。您可以通过在
getPixel
方法中强制转换为整数来解决这个问题: