ローグライクのリアルな影

画像



楽しい時間、Habrコミュニティ。



何年も前に、私はポスト(1)に出会いました。 その後、ローグライクゲームの面白い要素を作成する機会に戸惑いました(2) 。 敵が壁の後ろにいると仮定すると、視線で彼に出会うまで彼を見ることができません。 しかし、私は、ダンジョンの廊下に沿って移動し、可視領域に基づいてオブジェクトの位置の特徴を徐々に明らかにする状況を好みます。



後の投稿: (3)(4) 、および(5) 、2Dゲームでの影付けの問題が考慮されました。 著者自身およびコメントで述べられているように、影の計算は計算機にとっても設計にとっても非常に膨大であり、簡単な作業ではありません。



どういうわけか、私はいくつかの自由な日がありました、そして、私はより有望な影の質問に戻ることに決めました。 ビデオカードがシャドウを正常かつ迅速に処理することは明らかですが、この場合、2Dゲームのシャドウを処理したかったので、ビデオカードに計算を転送するのは不要でした。 はい、そして全体として近年のプロセッサー能力は成長しました、実際には最後に何が起こったかについての投稿です。



プログラムは私がよく知っているという理由だけでPascalで書かれており、Lazarusは幅広いコンポーネントを備えたオープンIDEです。



元のアイデアは、観察者からタイルの各コーナーまで線を引き、結果の図を暗くすることでした。



画像



ただし、このような影は、画角が変わると多少不自然に見えます。 影は広くなり、今では狭くなっています。



画像



丸いオブジェクトの影はずっと良く見えます。 このような影を作成するには、観測点から円と画面の境界までの2つの接線を描く必要があります。 円の直径は、タイルのサイズに対応します。



私のプログラムでは、次の関数を使用しました。



//       function tangent_to_circle(x1,y1,x2,y2,r:Single; var x3,y3,x4,y4:Single):Boolean; var l,dx,dy,i,ii,ij:Single; begin dx := x1 - x2; dy := y1 - y2; l := Sqrt(dx*dx + dy*dy); if l<=r then begin tangent_to_circle:=false; exit; end; i := r/l; ii := i*i; ij := i * Sqrt(1 - ii); x3 := x2 + dx*ii - dy*ij; y3 := y2 + dx*ij + dy*ii; x4 := x2 + dx*ii + dy*ij; y4 := y2 - dx*ij + dy*ii; tangent_to_circle:=true; end;
      
      





ここで、(x1、y1)は観測点、(x2、y2)は円の中心、®はその半径、(x3、y3)と(x4、y4)は線と円の交点です。 この関数は、オブザーバーが円の外側にある場合にのみtrueを返します。



プロセッサは三角法にあまり馴染みがないため、最小限に使用しようとしました。 実際には、単純なルール(大まかなモデル)に依存しており、専門家はその理由を説明します。



(悪い)SIN、COS ..> '/'、SQRT> 'DIV'、 'MOD'> 'SHR'、 'SHL'> '*'> ':='、 '+'、 '-'、 'AND '、' XOR '..(良い)



プリミティブのグラフィック部分をキャンバスに実装するのは楽しいことです。作業を容易にする多くのライブラリとエンジンがあります。 Delphiで開発するとき、Agg2Dライブラリを使用しなければなりませんでした。Lazarusにはそのポート(6)があり 、その上でアイデアを実現することにしました。 実際、ライブラリからの利点は、アルファチャネルがRGBカラーに追加され、プリミティブが平滑化されることです。また、ピクセルやさまざまなトリックへの直接アクセスにより、処理はキャンバスよりもはるかに高速です。



タイルの影を描くとき、​​もともとセクターを影で塗りつぶそうとしていましたが、タイル内の画像はほとんど識別できませんでした(図3の問題のセクターは緑で塗りつぶされています)。 さまざまなオプションを試した後、私は影の領域からセクターを選択するのを止めました。



扇形を描くには、ラジアン単位の角度が必要ですが、三角法ではまだできません。 (arctan2-数学モジュールライブラリ関数)



 //     function alpha_angle(x1,y1,x2,y2:Single):Single; begin alpha_angle := arctan2(y1 - y2, x1 - x2); end;
      
      





実際、すべてが画像の組み立ての準備ができています。 タイルのマップを取得し、別のレイヤーに1つずつ順番に影を適用します。 木では影はより暗く、他のオブジェクトでは影はより透明です。



画像



完成した画像は、タイルのメインレイヤーに適用されます。 背景デザインのビットとよりカラフルなタイルセットをピックアップ。 実際、パブリックドメインにあるか、品質が非常に低いか、コストがかかるタイルセットを検索するのに2日かかりました。 その結果、彼は自分で木を描き、ユーザーJoe Williamson (7) (優れたスタイル)から他の要素を借りました。



画像



それはすべて終わりますが、パフォーマンスに関していくらかの堆積物がありました。 オブジェクトの数で約500のドローダウンが始まります。 さまざまな最適化方法が検討され、カーネルに分割され、描画領域を特定の半径に制限し、影の形状を変更します(アークよりも安価に)、計算をビデオに転送することさえ考えました。



その結果、シャドウマスクとして機能する画像の離散化を減らすことが最善の選択肢であるという結論に達しました。 計算の数が大幅に削減されるとともに、影の輪郭のピクセル化の予期せぬ効果により、特定の昔ながらの魅力が与えられます。



画像



私はこの効果が非常に好きだったので、与えられた多重度パラメーターを使って、スケーリングを動的プロセスにする必要がありました。



画像



残ったのは、不透明な壁を作成し、その結果をコミュニティに提示することだけでした。



画像



この効果またはその開発を使用する新しいゲームを楽しみにしています。

よろしくお願いします!



ハンドルに触れることができるデモ版 (Windows用のexe)。



パート2パート3



参照:
1)habr.com/post/16927/

2)en.wikipedia.org/wiki/Roguelike

3)habr.com/post/204782/

4)habr.com/post/305252/

5)habr.com/post/319530/

6)wiki.freepascal.org/BGRABitmap

7)twitter.com/joecreates




All Articles