javascript - 如何通过 2D 前景穿透或切孔

标签 javascript p5.js 2d-games

我目前正在用 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/

相关文章:

javascript - 在 javascript 事件上触发表单

javascript - JSP 聊天 - 如何将 HTML 中的值解析为 JSP 页面?

javascript - p5 : resize canvas, 具有固定的起始宽度/高度?

javascript - 使用 p5.js 在路径上移动对象

c++ - 检测 8x8 矩阵中连续值的策略

javascript - leadbolt html 广告未显示

javascript - 在 JQuery 中打印一个 DIV 标签

javascript - 如何在实例模式下将p5.dom添加到p5.js

Java 2D 游戏编程 : Missile shooting is too fast?

java - JavaFX 2D 游戏中的对象动画