我目前正在用 Javascript 制作 2D 游戏,但我希望游戏具有不同的照明级别,例如,如果我要创建一个昼夜循环。但是,我希望能够在照明/前景上打洞,或者做一些事情,以便我可以点亮屏幕的某些部分,例如手电筒或蜡烛。注意:我也在使用 P5.js 库。
在创建前景时想到的最明显的想法就是创建一个覆盖整个屏幕的具有一定不透明度的矩形。这很好,但我应该如何解决这个问题?显然,下面的代码不起作用,因为我只是在另一个元素上分层,并且矩形仍然被遮挡并且不完全清晰。
function setup() {
noStroke();
createCanvas(400, 400);
}
function draw() {
background(255); //white
fill(255, 0, 0);
rect(200, 200, 25, 25); //Example object
fill(150, 150, 150, 100); //Gray with opacity
rect(0, 0, 400, 400); //Darkness covering entire screen, foreground
fill(255, 255, 255, 100)
ellipse(mouseX, mouseY, 50, 50); //object that is supposed to penetrate foreground.
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/addons/p5.sound.min.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
</head>
<body>
<script src="sketch.js"></script>
</body>
</html>
我该怎么做呢?我希望它不仅适用于简单的背景和简单的形状,还适用于图像。有没有办法在形状上切孔,或者我需要使用其他东西,比如着色器或蒙版?
谢谢。
最佳答案
erase()
function可能是您正在寻找的东西。它比试图在您想要覆盖的区域上显式绘制更灵活(例如在使用圆形和矩形的笔触来覆盖除圆形之外的所有内容的方法中)。而且比beginContour()
更容易使用因为您可以将它与任何内置的绘图原语(矩形、椭圆、三 Angular 形等)一起使用。
let overlay;
function setup() {
noStroke();
createCanvas(windowWidth, windowHeight);
overlay = createGraphics(width, height);
overlay.noStroke();
overlay.fill(255);
overlay.background(150, 150, 150, 200);
}
function mouseMoved() {
// Only update the overlay when something changes
// Clear the overlay so that alpha doesn't accumulate
overlay.clear()
//Gray with opacity, covering entire screen, foreground
overlay.background(150, 150, 150, 200);
// The color and alpha values for shapes drawn when erasing basically do not matter. You can effect the % of erasure with the arguments erase.
overlay.erase(100);
overlay.ellipse(mouseX, mouseY, 50, 50); //object that is supposed to penetrate foreground.
overlay.noErase();
}
function draw() {
background(255); //white
fill(255, 0, 0);
rect(width / 2, height / 2, 25, 25); //Example object
image(overlay, 0, 0, width, height);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
如果您想通过更完整的 Alpha channel 支持从叠加层中删除形状,您可以使用
blendMode(ERASE)
.let overlay;
let overlayCtx;
let gradient;
function setup() {
noStroke();
createCanvas(windowWidth, windowHeight);
overlay = createGraphics(width, height);
overlayCtx = overlay.drawingContext;
overlay.noStroke();
overlay.background(150, 150, 150, 200);
// Using the raw canvas API to make a radial gradient
gradient = overlayCtx.createRadialGradient(0, 0, 5, 0, 0, 25);
// The colors here don't matter, only the alpha channel
gradient.addColorStop(0, 'rgba(0,0,0,1)');
gradient.addColorStop(1, 'rgba(0,0,0,0)');
overlayCtx.fillStyle = gradient;
}
function mouseMoved() {
// Only update the overlay when something changes
// Clear the overlay so that alpha doesn't accumulate
overlay.clear()
//Gray with opacity, covering entire screen, foreground
overlay.background(150, 150, 150, 200);
overlay.push();
// Use blend mode REMOVE to remove the color (using only the alpha channel?)
overlay.blendMode(REMOVE);
// Because of the way gradients work we have to translate and draw our ellipse at the origin.
overlay.translate(mouseX, mouseY);
overlay.ellipse(0, 0, 50, 50); //object that is supposed to penetrate foreground.
overlay.blendMode(BLEND);
overlay.pop();
}
function draw() {
background(255); //white
fill(255, 0, 0);
rect(width / 2, height / 2, 25, 25); //Example object
image(overlay, 0, 0, width, height);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
关于javascript - 如何通过 2D 前景穿透或切孔,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70807530/