純粋な Java で 2D のトップダウン タイル ゲームを作成していますが、今ではライティングを行う方法を実装しようとしています。
まず、レンダリング方法の詳細: すべてのレンダリングを処理するスクリーン クラスがあります。ピクセルは、とint[width * height]
を使用して実際の画面に描画される配列内に配置されます。BufferedImage
Graphics.drawImage()
私が現在照明を行っている方法はint[width * height]
、実際のピクセルから差し引く必要があるすべての明るさを保持する 2 番目の配列を作成することです。RGB 強度を表す0f
ためにから までの浮動小数点数のみを使用しようとしています。1f
例として、0.3f のアンビエント ライティングがあります。私がしているのは、ピクセルからピクセルへの操作です。描画されるピクセルごとに、その RGB 値が分解され、70% (1f - 0.3f) 減少し、単一の int に再構成され、2 次int[width * height]
配列内に格納されます。ピクセルを BufferedImage に転送するときに、セカンダリ配列内の対応する値を差し引いて、予想どおりより暗い画像を取得します。
これは画像を暗くする例で、問題なく動作しますが、実際にそれらを照らすと問題が発生します: プレーヤーに lightRadius と 3 つのライト カラー コンポーネント フロート (RGB) を与えました。プレーヤーをレンダリングしている間、次のようにして、セカンダリ配列内の照明もレンダリングします。
int mask = subtractMask[xx + yy * width];
int mr = (mask >> 16) & 255;
int mg = (mask >> 8) & 255;
int mb = mask & 255;
mr -= (int) (dist * light.r * mr);
mg -= (int) (dist * light.g * mg);
mb -= (int) (dist * light.b * mb);
subtractMask[xx + yy * width] = mr << 16 | mg << 8 | mb;
dist は から までの範囲の数値で0f
、1f
光源からの距離に応じてライトがフェードしlight.r/g/b
、プレーヤーから来るライトの各コンポーネントです。このコードが行うことは、基本的に「ピクセルから取り出された光を少し戻す」ことです。ご覧のとおり、mr、mg、および mb は小さく (-=) されてから、対応するピクセルから差し引かれる数値の内部で合成されるため、引き算の結果が大きく (明るく) なります。白色光の場合、望ましい結果が得られます。
問題は、青のコンポーネント (r = 0f、g = 0f、b = 1f) のみを使用すると、次のようになることです。
もちろん、これはタイルの青の値がほとんどないという事実によって説明できます。周囲光がその一部を取り去り、照明がその一部を元に戻します (最大の効果がオンになっていることがわかります)。プレーヤーのズボン、青です)。私がまだ考えられなかったのは、ピクセルからどれだけの明るさが取り除かれたかに関係なく照明を作成する方法と、コンポーネントを組み合わせる方法で単純に見栄えがする方法です(2番目の画像に期待した結果は、次のような輝度でした最初のものでは、しかし青色に着色されています)。では、どうすればそのような効果を実装できますか?
また、照明を円形にするために、単純に軽い x^2 + y^2 <= radius^2 を計算します。この文が true の場合、ピクセルは点灯し、前に示したコードを実行します。これを計算するより速い方法はありますか?(この効果で 50 FPS 近く失われました)。
編集: 私が望む効果は、2D ゲーム Tibia のようなものです。これは、茶色のピクセル上の青い光です。