3

2D ゲームで懐中電灯効果を作ろうとしています。私の懐中電灯は、エンティティから特定の角度で伸びる線分として表されます。懐中電灯はどの方向にも向けることができます。懐中電灯の強度 (懐中電灯のビームの長さ) も異なります。

懐中電灯の効果をレンダリングするための最良の (最も簡単な?) 最も柔軟な方法を見つけようとして問題が発生しました。特にタイル張りの地図では。

2つの方法が考えられます。しかし、私はそれらを実装する考えがありません:

  1. タイル マップの円錐/円セグメント部分のみを描画します
  2. 画面を黒いテクスチャで覆い、コードで黒いテクスチャに穴を開けます。このようにして、穴の属性を変更できます。

どこから始めればいいのか、何と呼ばれているのか、libGDX でできるのかどうか、私にはわかりません。

4

2 に答える 2

6

1 つはステンシル バッファーと呼ばれます。しかし、ソフトな効果を実現するのは難しいでしょう。 - 簡単。

2 番目:必要なのは、ライトを使用したテクスチャだけです。完全に黒い領域は、明るいスプライトの周りに黒いスプライトを繰り返して描画できます (左、右、上、下)。または、ステンシル バッファーと混合することもできます。または、テクスチャ座標を慎重に計算し、GL.clamp_to_edge を使用してすべての黒いピクセルを伝播することもできます。シーンのレンダリング方法に応じて、最初にアルファ情報を使用してライトをレンダリングし、次にシーンをブレンドできます (dst_alpha に従って暗くなります)。-- 実装は難しくありません。

3番目は、シェーダー (GLES 2.0) に関する研究です。メッシュをレンダリングしてホール スクリーンを埋め、いくつかのシェーダー計算で暗くすることができます。-- これは最も柔軟なオプションであり、最も困難なオプションです (ロケット科学とはかけ離れています)。

一部のオプションは他のオプションよりも優れているように聞こえますが、提供された情報を提供することで、これ以上お伝えできることはありません. 調査を開始するための適切な出発点があります。

**テクスチャを使用する場合は、バッテリーに応じていくつかの異なるテクスチャを使用することを検討してください。それらを少し拡大したり、色を付けたりすることはできますが、異なるテクスチャを使用する方がはるかに柔軟です.

于 2012-12-21T18:50:08.307 に答える
5

グラフィック要素がBufferedImageまたはGraphics2Dインスタンスの場合、次のようにアプローチできます。

白熱(黄色)ビームを使用した懐中電灯

ハロゲン(青色)ビームを使用した懐中電灯

import java.awt.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import javax.swing.*;

public class FlashLight {

    public static void main(String[] args) throws Exception {
        Robot robot = new Robot();
        int w = 500, h = 200;
        Rectangle rect = new Rectangle(0, 0, w, h);
        final BufferedImage bi = robot.createScreenCapture(rect);
        final BufferedImage bi2 = FlashLight.draw(
                bi, 10, 180, 420, 90, .3,
                new Color(255, 255, 120, 15), new Color(0, 0, 0, 220));
        final BufferedImage bi3 = FlashLight.draw(
                bi, 10, 180, 420, 90, .3,
                new Color(180, 250, 255, 15), new Color(0, 0, 0, 220));

        Runnable r = new Runnable() {

            @Override
            public void run() {
                JPanel gui = new JPanel(new GridLayout(3,0,2,2));
                gui.add(new JLabel(new ImageIcon(bi2)));
                gui.add(new JLabel(new ImageIcon(bi)));
                gui.add(new JLabel(new ImageIcon(bi3)));

                JOptionPane.showMessageDialog(null,gui);
            }
        };
        // Swing GUIs should be created and updated on the EDT
        // http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
        SwingUtilities.invokeLater(r);
    }

    public static BufferedImage draw(
            BufferedImage source,
            double x1, double y1, double x2, double y2,
            double beamWidth,
            Color beamColor, Color darknessColor) {
        RenderingHints hints = new RenderingHints(
              RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);

        BufferedImage bi = new BufferedImage(
                source.getWidth(), source.getHeight(),
                BufferedImage.TYPE_INT_ARGB);

        Graphics2D g = bi.createGraphics();
        g.setRenderingHints(hints);

        g.drawImage(source, 0, 0, null);

        // Create a conical shape to constrain the beam
        double distance = Math.sqrt(Math.pow(x1 - x2, 2d) + Math.pow(y1 - y2, 2d));
        double tangent = (y2 - y1) / (x2 - x1);
        double theta = Math.atan(tangent);
        System.out.println(
                "distance: " + distance
                + "  tangent: " + tangent
                + "  theta: " + theta);
        double minTheta = theta + beamWidth / 2;
        double maxTheta = theta - beamWidth / 2;
        double xMin = x1 + distance * Math.cos(minTheta);
        double yMin = y1 + distance * Math.sin(minTheta);

        double xMax = x1 + distance * Math.cos(maxTheta);
        double yMax = y1 + distance * Math.sin(maxTheta);

        Polygon beam = new Polygon();
        beam.addPoint((int) x1, (int) y1);
        beam.addPoint((int) xMax, (int) yMax);
        beam.addPoint((int) xMin, (int) yMin);

        g.setColor(beamColor);
        GradientPaint gp = new GradientPaint(
                (int)x1,(int)y1, beamColor,
                (int)x2,(int)y2, darknessColor);
        g.setClip(beam);
        g.setPaint(gp);
        g.fillRect(0, 0, bi.getWidth(), bi.getHeight());

        // create an area the size of the image, but lacking the beam area
        Area darknessArea = new Area(new Rectangle(0, 0, bi.getWidth(), bi.getHeight()));
        darknessArea.subtract(new Area(beam));
        g.setColor(darknessColor);
        g.setClip(darknessArea);
        g.fillRect(0, 0, bi.getWidth(), bi.getHeight());

        // fill in the beam edges with black (mostly to smooth lines)
        g.setClip(null);
        g.setColor(Color.BLACK);
        g.setStroke(new BasicStroke(2));
        g.draw(new Line2D.Double(x1,y1,xMin,yMin));
        g.draw(new Line2D.Double(x1,y1,xMax,yMax));

        g.dispose();

        return bi;
    }
}
于 2012-12-23T05:18:36.840 に答える