進捗報告

クッキー焼くゲーム

投稿日: 更新日:


cookieclickerというクッキー焼くゲームを教えてもらったのですが、
焼き始めてから、はまってしまって止め時がわからなくなったので、
ここで紹介して止めたいと思います!

cc1(ネタばれ注意)

cc2

MS4wNDY2fHwxNDE4NDc0MTIwMDUxOzE0MTg0NzQxMjAwNTE7MTQyMDA4OTczMDk3MTtOYXRhZGV8MTExMTExMDExMDB8NTEyOTcxNzE1Nzc0NzI2MzQwOzEzMjQ4NDQyMzg2MzkyNzUzMDA7NDQ4NTs3NDs2MDczNTg0MzUwNzI0MzI7Mjg4MjstMTstMTswOzA7MzswOzA7LTE7MDs3NDsxMDk4NjA0MjY5MTQxMjk2MzA7NDA4OzE0OzEzNTswOzA7Y2hyaXN0bWFzOzA7MDt8MjAwLDI1Miw1NDA5MDAwMTA3NTk0MjAsMDsyMDAsMjIyLDEzMTg3NzMyMjA3NzUyNzI2LDA7MjAwLDIyMSwyNDcyMzE2NzI4OTEsMDsxMDAsMTEwLDQxMDkzMzEwMzM5OCwwOzEwMCwxMTAsMTQ2NzYwMzM5MzE4MCwwOzEwMCwxMTEsMzgxNTc1MzAyODQzNCwwOzEwMCwxMjAsMTQ2NzU4NjE1MTU5MjMsMDsxMDAsMTQwLDI0NDY0OTI0NTc2MTk3MCwwOzEwMCwxMDIsMzEzNDUyOTE5MTAwNTg4NiwwOzEwMCwxMDAsMzA1MTY0ODU3ODQ1ODY2MzYsMDsxMDAsMTAwLDE4MDE2MTMwNjYwODgxODc1MCwwO3w0NTAzNTk5NjI3MzcwNDk1OzQ1MDM1OTk2MjczNzA0OTU7MjgxNDc0OTc2NzEwNjU1OTs0NTAzNTczNzI3MTQ4NTQzOzIyNTM5OTg4MzUzNjc5MzU7NDUwMzQ2MjE4ODQxNzAyNTsyMjUyMjQ2NDkwMjg0MDMxOzIyNTIzMjE2NTIyMTk5MDM7MjI1MTc5OTgxMzY4NTI0OTszMjc2OXw0NTAzNTk3NjE0MTA0NTc1OzIyNjAzNTIyOTUxNzQxNDM7MjMyMjE5NDQ0NTIwNDk0Mzs2MjkxNDU5%21END%21

こういうはまるゲームを私に教えないでくださいね!

最近のプログラミング状況

投稿日: 更新日:


先月はかなり忙しく、これからも忙しくなりそう。(_Σ_)
というか去年の年末より忙しい。
ひどいときは1週間の内に2回お泊りしたし。
本当にどうしてこうなった状態です。。。。゛(ノ><)ノ 

日記の方も書くネタがたまっていっていく一方で、
書く元気とか、やる気が中々でない状況。

そこで休みを利用して、作ったけど、事情で公開出来ないものとか、
公開するまでもないものとか、製作中なものとかの紹介で、消化していきます。
いつも通り全部Javaです。

A

よくあるwavプレーヤー。
とある理由で波形を取得したかったので、
wavファイルの解析から、出力デバイスへの出力まで1から制作。
一応、チャンネル数やサンプリング周波数は、2ch、44100Hz、16ビット以外でも再生できるようになっています。
いや、もしかしたら量子化ビット数は対応させてなかったかな。
もう作ってからひと月以上経つので、忘れ気味。
本当は、mp3とかも対応させたいけど、Javaだったら一度ライブラリ使ってwavに変換するしかないかな。
JavaのLGPLとかはよく分からないので、好きじゃないです。
GUIは、以前作ったsmfプレーヤー を流用。
あと波形から、FFTを利用した解析機能もついています。

B

剛体球の運動のシミュレーション。
簡易型ゲームに使用するような、めり込みを利用した当たり判定ではなくて、
速度ベクトルを持った球同士が、何秒後にぶつかるかを方程式を解いて判定しています。
(この方程式については、「実例で学ぶゲーム3D数学」が役に立ちました。)
そのため、速度をすごい速くしてもめり込んだり、通過することはほぼ絶対ありません。
衝突後に、球をどのように動かすかが、結構大変で3日間近くかかりました。
attochipさんに色々とお世話になりつつ、完成。
片方の球を止まった球だと考えるというのは、当たり判定も、衝突後の動きに関しても、同じですね。
これについては、いつか解説したいです。

シミュレーションということで、色々設定を変えたりしなきゃいけないです。
ですが、GUI作るのは面倒なので、HSP風な言語?で右側から指定するという形にしました。
凝ったものではないので、REPEAT文・GOTO文・IF文・変数・計算など使えません。
いわゆる指定された命令のみ使えるというものです。

こだわり機能として、左側の画面を、自由に拡大・縮小・回転・移動が出来ます。
ここは3D処理ではお馴染みのアフィン変換を利用してます。
ところで、Graphics2Dで線の太さを、実数で指定できるのは驚きました。
0.5とかに指定した場合は、色が薄くなり細くなります。

C

重さを持つ粒子同士にバネがついていると考えた場合のシミュレーション。
4次のルンゲクッタ法で多変数の2階微分方程式を解いています。
多変数はできたけど、2階っていうのが難しかったです。
上のは、境界が自由端になっています。
固定端は、両端の重さを無限大として考えればいいのかな。
適当に考えたので、違う可能性大だけど。うん。

GUIは、作品Bを流用。
拡大・縮小・回転・移動のオマケ機能もそのままついています。

D

ゲーム制作ツールと、3Dソフトウェアレンダリング関連。
3D描写に関しては、以前のバージョン(1月1日のブログ)から
・メタセコイアのデータインポート機能追加
・独自3Dモデル形式のインポート・エクスポート機能追加
・複数のデータのパッケージ化追加
・それにともなって、使い易いI/O関連のライブラリを作った。
・ハードグラウンド機能(90度のデコボコ)の追加
・バンプマップからの法線マップ生成の高速化(DirectX9シェーダプログラミングを参考)
・パーティクル描写の最適化(高速化)
・3D上の線と、表示画面とのクリッピングの追加(3各ポリゴンのクリッピングは未対応)
・反射マッピングの追加。(法線を0.5ずらしたものをテクスチャのUVに利用する例の方法。これを参考)
・水の表現の追加。(2つのノイズを一定時間ごとにずらし重ねたものを、UVに利用したり、法線に利用したり)
・なんかGUIに利用できるようなアイコン制作とその配置。
・簡易型のテクスチャの生成言語(以前作った画像処理ツールオレンジビューアを利用)
・パーリンノイズを利用して、2つのテクスチャを自然に合成とかできる。(SSの緑とレンガの中間のテクスチャ)

順調に進んでいる?ように見えますが、3月中旬から進んでません。
マップエディタには魔物が潜んでいます。気をつけてください。ヽ(^o^)丿

それはおいておいて、水の表現なのですが、
最初、次の用な感じで実装しました。
・ 2次元のパーリンノイズを2つ生成しておいて、それをずらし重ねて、波を表現。
※ずらし重ねるときに、小数点の場合も考えて補間法を用意しておく。
・ 上記で生成した波みたいなものを高さマップと考え、各頂点の法線を生成。(頂点の位置は固定)
・ 法線から、反射マッピング用のUV生成。
・ あとは、半透明で描写。

で、この方法。正直640×480じゃ30fpsはきついです。
最近のPCだといけると思いますが、その他のPCじゃかなり危険です。
描写部分のみをマルチスレッドで動かしてもです。
というわけで、結局妥協して、
テクスチャを利用しない(反射マッピングを行わない)、上記のSSのような感じになりました。

でもなんか、動作速度上の都合での妥協っていうのは自分的には悲しい感じがして、
グラフィックがもっと綺麗なのがいいなあって思ってきて、開発停滞中。
この先、オブジェクトの配置・描写とかの表示とかも考えると、いけるかなとか。
立ち絵的なものは、「g.drawImage」を使えばJavaの機能で、高速に描写できるから問題ないと思うけど。
とにかく、こういう事考えたりしていて、なかなか進まなかったりする。

JOGL使っておけばよかったかも。
シェーダ言語とか使ってみたいし。自影が表現できるシャドウマッピングとかやってみたいなあ。
その前に、やる気出したり時間を作ったり、という根本的な課題が。

話が変わりますが、saharanさんの「Jhun」がすごすぎる。

進捗 6

投稿日: 更新日:


・描写関連のみ完全に別スレッド化!
本当は、頂点の座標変換&頂点ライト計算と、ピクセル描写部分とでもスレッド化できそうだったけど、
メモリの受け渡しが大変そうなので、諦めました。
※座標変換・光の計算を終わったデータのバッファだけで、1更新当たり2MBぐらいになりそう
あと、まだ世間的にはデュアルコアが主流だと思うしうん。 

・アクティブレンダリング
アクティブレンダリング – Javaでゲーム作りますが何か?」をみながら実装。
いや、実装してから分かるけどぜんぜん違う。
やばい。データの描写中による

paintComponentのちらつきが全然なくなった。
ティアリング?が残っているから、ちらつきが全くなくなったわけじゃないけど。
今までは

    synchronized public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if(!isShowing()){
            return;
        }
        g.drawImage(solid.getBufferedImage(),0,0,this);
        Toolkit.getDefaultToolkit().sync();
    }

ってやっておいて、タイマでthis.repaint();しまくってたけど、
アクティブレンダリングはぜんぜん違う。アクティブレンダリングばんざい!

・SoftGround(勝手に呼んでる)の対応
←こういうの

実際の実行した画面。(紫が法線)

テクスチャは、U反転・V反転・右に回転(1回~3回)といろいろ対応。
これで、洞窟とか平地とか、滑らかな地形は作れそう。

次は、HardGround(これも自分で勝手によんでる)というのを対応させたい。
←こういうの

こっちは難しそう。
1つのブロックに3つの面があれば実装できそうだけど、
壁に当たる部分は凹んだり凸ったりすることもあるから、
カリングの問題でサーフェイスを、先に単純に張っておくってことも出来ない?
でもHardGroundは、家の中とか、遺跡の中とかそういう整形された地形には欠かせない。
うん。

ゲームでも使えるように速度・メモリ重視っていうのが難しい。
考えてるだけで時間が過ぎていく。
でもアルゴリズムを考えてるときって楽しいよね。

Javaで3D 5

投稿日: 更新日:


以前の続きでテクスチャのパーリンノイズの補間法の話です。
いい加減補間について調べようといろいろとプログラムして作ってみました。
テクスチャなので、上下と左右が繋がるように補間します。

8x8px → 256x256px と、各補間法で32倍拡大してみます。

最近傍補間(NearestNeighbor)(1×1の格子点を使用)

線形補間(Biliner)(2×2の格子点を使用)

三角関数による補間(Cosine)(2×2の格子点を使用)

5次のエルミート曲線による補間(2×2の格子点を使用)

バイキュービック法(Bicubic)
(4×4の格子点を用いたsinc関数の近似補間関数を用いる)
sinc関数はrect関数をフーリエ変換・逆フーリエ変換したもの。

Lanczos2
(4×4の格子点を用いた近似補間関数を用いない手法)

Lanczos3
(6×6の格子点を用いた近似補間関数を用いない手法)

近似関数を用いたバイキュービック法の方が、近似関数を用いないLanczos2より画質がいいと思う。速度も速いですし。Lanczos3はバイキュービック法とほぼ変わらない。近似関数とほぼ一致。

結論
綺麗に拡大したい。 → バイキュービック補完
早く綺麗に拡大したい → 3次のエルミート曲線による補間
速度重視で拡大したい → 最近傍補間

バイキュービック補間の係数については、koujinz blogさんのブログの「画像の拡大「Bicubic法」」を用いています。

この係数なんですが、Javaの※拡大機能のバイキュービック補間は、速度重視で多分違う係数を用いていると思う。上記の係数を用いた方が綺麗に補完できましたし。それか、固定小数点で計算していて誤差が出るとか?

※g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);の方法

.NET TIPSの「画像を高品質に拡大/縮小するには?」を見ると
.NETのバイキュービック補間でも「Bicubic」と「HighQualityBicubic」の2種類があるから、
きっと同じバイキュービック補間でも、係数が変えて速度変えるとかあるのかな。

というか「HighQualityBilinear」ってまじで線形補完なのか。どうやってるんだろう。

三角関数による補間とエルミート曲線による補間の元ネタは、t-potの管理人さんが執筆した「DirectX 9 シェーダプログラミングブック」のパーリンノイズの章です。一番後ろの方です。

Javaで3D 4

投稿日: 更新日:


3Dと言ったらやっぱりテクスチャ。

パーリンノイズを作ってみた。
ノイズの間は線形補完しています。
本当はバイキュービックとか、しっかりした補完がいいと思うのですが、技術力不足で無理でした。(>_<)

こんなのが出来上がるなんて、ランダムって不思議です!

自動生成を利用すれば、小さなファイルサイズでも、高解像度テクスチャを利用できます。


↑ライトのテクスチャもプログラムで生成してみました。

他にも波の高さに用いたり、地形を作ったりできるそうです。
ただパラメータが面倒だったり、この後の加工が面倒だったりするので、
結局は他のソフトを使用して作ったものを利用しそう。(・ω・` )

Javaで3D 3

投稿日: 更新日:


今週は地味なことを。li(A´・ω・)

・ シーンの追加
シーンに表示したいのをまとめてから、シーンをレンダラーに描写っていう感じに。
これによって、レンダリングを、スレッドとして別に走らせたり、
パーティクルや半透明オブジェクトを、最後にZソートして表示とかを自動で出来るようになります。

表示で、対応しているものとして、
「オブジェクト」と「アルファブレンドつきオブジェクト」と「パーティクル」と3種類あります。
というわけで、シーンを描写する際に、
「アルファブレンドつきオブジェクト」と「パーティクル」の2種類をそれぞれクイックソートを行って、
最終的な表示は、「オブジェクト」を表示後に、この問題の2種類をマージソートしながら描写という形にしました。
なんで、2種類をいっきにクイックソートしないのかというと、ただ単にクラスが違う種類になっていたのではい。

今はライトの数・位置は、Rendererクラスに登録する感じになってるのですが、
Sceneクラスに登録できたほうが自然かもしれません。
SceneクラスをRendererクラスに渡すというような。うん。

・ 4×4行列を4×3行列にした。
通常、回転のみの行列は3×3行列で、移動をともなうから4×4行列にします。
しかし、4列目は透視変換を行列に表すときしか使いません。
ということで、透視変換は、行列として一緒にまとめなければ、4×3行列の方が計算やメモリなどの効率がいいです。
4×3行列といっても、回転用の3×3行列と移動用の3×1行列を別々にもっているという感じなので、
逆行列の計算も簡単にできます。ベクトルへの掛け算や行列同士の掛け算は工夫が必要ですが。はい。

・ 回転がおかしい。
左手系で、DirectXの座標系(上がY軸、奥がZ軸、右がX軸)で作っていたのですが、よくみると回転がおかしい。
具体的には、Y軸の回転は上に向かって時計回り、
Z軸とX軸の回転は、奥に対して、反時計回り、というものです。Σ(・ω・`|||)!!
たしか、本当は軸のむいている方向に対して、時計回りが正しいような。はい。
というわけでビュー行列を久しぶりに触ってなおしてみようと。

3Dネットゲーム製作時代のビュー行列

//視点を原点にする。
this.m_t1.setTranslate(-this.cameraposition.x,-this.cameraposition.y,-this.cameraposition.z);
//注視方向をZ軸にする。
double delta_x = this.viewposition.x - this.cameraposition.x;
double delta_y = this.viewposition.y - this.cameraposition.y;
double delta_z = this.viewposition.z - this.cameraposition.z;
this.distance = Math.sqrt(delta_x*delta_x + 【delta_y*delta_y】 + delta_z*delta_z); ←【】はバグ
this.m_ry.setRotateY(Math.atan2(-delta_x,delta_z));
this.m_rz.setRotateZ(Math.PI);
this.m_rx.setRotateX(Math.atan2(-delta_y,this.distance));
this.distance = 1;
//視点位置を(0,0,-r)にする。rの距離だけ離す
this.m_t2.setTranslate(0, 0, this.distance);
//変換行列をまとめる
this.m_first.setMatrix(this.m_t1);
this.m_first.mul(this.m_ry);
this.m_first.mul(this.m_rz);
this.m_first.mul(this.m_rx);
this.m_first.mul(this.m_t2);

バージョン2

//視点を原点にする。
this.m_t1.setTranslate(-this.cameraposition.x,-this.cameraposition.y,-this.cameraposition.z);
//注視方向をZ軸にする。
double delta_x = this.viewposition.x - this.cameraposition.x;
double delta_y = this.viewposition.y - this.cameraposition.y;
double delta_z = this.viewposition.z - this.cameraposition.z;
this.m_ry.setRotateY(Math.atan2(-delta_x,delta_z));
this.m_rz.setRotateZ(-Math.PI);
this.m_rx.setRotateX(Math.atan2(-delta_y,Math.sqrt(delta_x*delta_x+delta_z*delta_z)));
this.m_reflection.setScale(-1, 1, 1);
this.distance = 1;
//視点位置を(0,0,-r)にする。rの距離だけ離す
this.m_t2.setTranslate(0, 0, this.distance);
//変換行列をまとめる
this.m_first.setMatrix(this.m_t1);
this.viewmatrix.setMatrix(this.m_ry);
this.viewmatrix.mul3(this.m_rz);
this.viewmatrix.mul3(this.m_rx);
//反転
this.viewmatrix.mul3(this.m_reflection);
this.m_first.mul4x3(this.viewmatrix);
this.m_first.mul4x3(this.m_t2);

バージョン3

//視点を原点にする。
this.m_first.setTranslate(-this.cameraposition.x,-this.cameraposition.y,-this.cameraposition.z);
//注視方向をZ軸にする。
double delta_x = this.cameraposition.x - this.viewposition.x;
double delta_y = this.cameraposition.y - this.viewposition.y;
double delta_z = this.cameraposition.z - this.viewposition.z;
this.m_ry.setRotateY(-Math.atan2(delta_x,delta_z));
this.m_rx.setRotateX(Math.atan2(delta_y,Math.sqrt(delta_x*delta_x+delta_z*delta_z)));
this.m_reflection.setScale(-1, -1, -1);
//変換行列をまとめる
this.viewmatrix.setMatrix(this.m_ry);
this.viewmatrix.mul3(this.m_rx);
//反転
this.viewmatrix.mul3(this.m_reflection);
this.m_first.mul(this.viewmatrix);

うん。
バージョン2からバージョン3へと色々いじったのですが、軸の回転直りませんでした。/(^o^)\

そういえば、
「視点位置を(0,0,-r)にする。rの距離だけ離す」とか習ったけど、これ使わなくていいですね。
あと、「透視変換をZ値にも適用して奥行き情報の保存」とかも習ったけど、実際はZ値に適用しない方がいいです。
え?習った?いえ。なんでもありません。(。・ω・。)ノ
まあ、このままにしておきます。

・ Planeクラス
平面のMeshクラスじゃなくて、平面の当たり判定関係のクラス。
今回作ったのはこれだけ。
・任意の3点から平面を設定
・任意の点から平面への距離
・任意の点から一番近い平面上の点
・v0からv1への線分と、平面との交点
作るにあたって「はじめての3Dゲーム開発」と「実例で学ぶゲーム3D数学」の2冊を参考。
「はじめての3Dゲーム開発」の方は、P285にそのことが書いてあります。
説明は分かりやすいのですが、誤植がとてもひどい。(;-ω-)
2冊のうち、1冊購入するとしたら後者がおすすめ。

次は、3Dマップのクラスの製作にとりかかります。
あれ、何を目指しているんだろう……。
いや、目指しているものはあるんですが、
ここに書いて、できなかったら恥ずかしいので書きません。(´・ω・`)


鎌田 茂雄 はじめての3Dゲーム開発―「DirectX9」の使い方から「1人称3Dフィールド・ゲーム」の制作まで

P284の「これを、tについて解きます。」から、tがTになっている。
すると、P284の「これを、tについて解きます。」の下の式が間違っていることに気づきます。
T = – ( a*x1 + b*y1 + c*z1 + d) / ( a*vx + b*vy + c*vz)

t = – ( a*x0 + b*y0 + c*z0 + d) / ( a*vx + b*vy + c*vz)
このまま、x0とx1が逆になるように式を修正していき、P285で今までの修正式を利用すると、
交差していないときにTRUEを返す式になります。

P285のソースは、修正式から一度式を見直すことで作れるコードで、
これはこれで、正直に利用すれば変なことは起きないと思いますが、
数式の流れからみるとソースコードはおかしなことになると思います。

また、P285は交点を求める関数と書いてありますが、コードのとおり交差を調べる関数です
交点を調べるには、fTを利用する必要があります。

Javaで3D 2

投稿日: 更新日:


ビルボードとポイントスプライトに対応しました。
ビルボードで、オブジェクトを全部カメラ側に向かせています。
方法としては、ビュー行列の回転要素のみを、転置行列にして逆行列作成。(回転行列は転置行列が逆行列になる)
その後はつじつま合わせ。

ポイントスプライトは、画面で丸いやつです。
高速化のために加算のみしか対応しませんでした。パーティクルって通常は加算ばっかりですもんね。
サイズは、係数ABCから「1/(A+d*B+d^2*C)」(dはカメラとパーティクルとの距離)という方法で求められます。
通常は、AとBは0にして、Cは小さな値を入れておきます。これで、それっぽい大きさになります。