[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
どうも、本編初登場の大西( はかせ )です。
C++やシェーダー以外にもC#とかいろんなツールいじったり手広くやってます。
今までコメント欄だけだったのですが、記事を書いた順番がドベだけは避けたかったので…
( これで記事書いてないの上原といいんちょだけだよねって煽ってみたり。 )
今回は2年生向けに( 3年生にも通じる部分もある )プログラムのアドバイスなんかをしようと思います。
現在、2年生はJavaでゲームを作っていると思います。そこでいくつかコード例を挙げます。
まず、静的初期化ブロック。
Javaでは static なメンバに対してのコードをこのブロック内に記述できます。
書き方はクラス内で static { …処理… } とします。
/*
ゲームでUI等、よく文字を表示することがあると思いますが、
授業でも文字を表示する場合は環境依存を避けるために画像で用意しておき、
それを表示するように言われていると思います。
このクラスはそれらの機能を持ったクラスとします。シングルトンパターンで実装。
*/
class Font
{
/*
MyImageクラスは皆さんが作った画像ファイルを読み込んで表示するクラスとします。
画像を読み込むLoadメソッドなどがあるものとして話を進めます。
本来 static はプログラムの間メモリに存在し続けるので、画像に限らずリソースは
必要な時に読み込んで要らなくなったら解放するほうがいいのですが、
今回のような小さいゲーム程度やこのクラスのようにどこでも必要な場合は
最初に一度だけ読み込んでしまうのも手です。
*/
private static MyImage image = new MyImage();
// null で初期化しておいて後で new する方法もあり( 後述 )
private static Font instance = new Font();
// これが静的初期化ブロック
static
{
image.Load("皆さんが作成したフォント用画像ファイルへのパス"); // 読み込み
}
// コンストラクタ
private Font() {}
// インスタンス取得メソッド
public static Font GetInstance()
{
/*
他のJavaでのシングルトンパターンでの実装方法として null で初期化しておき、ここで
if( instance == null )
{
instance = new Font();
}
する方法もありますが、マルチコア・マルチスレッドが当たり前となってきた現在では
マルチスレッドでこのメソッドに複数がアクセスしたときに if文内のコードに同時に
入りこめてしまいマズイので上のように宣言と同時に new で初期化しておきます。
*/
return instance ;
}
// 画面の指定した場所に指定された文字を描画するメソッド
public void Draw( char c , int x , int y , int width , int height )
{
// 以下に指定された場所に指定サイズで文字を描画する処理を書いていきます。
// 指定された文字の部分に合うように読み込んだ画像の左上座標と描画( 切り取り )範囲を
// sx , sy , sw , sh に求めてやる。
image.Draw( x , y , width , height , sx , sy , sw , sh );
}
}
今までC言語でプログラムを書いてきた2年生の皆さんは
今まで定数をマクロ( もしくはenum )で振ってきたんだけどJavaではどうするんって人もいると思います。
Javaでは定数( リテラル )を アクセス指定子 static final 型 変数名 = 値 ; の形で記述できます。
class A
{
public static final int LITERAL = 1 ; // TEISUUとか止めようね。ローマジカッコワルイ
}
class B
{
private static final float LITERAL = 1.0f ;
public void Method()
{
int a = A.LITERAL ; // こんな感じでアクセスできます。( クラス名.変数名 )
float b = LITERAL ; // B.LITERAL にアクセスしています。同じクラス内ならクラス名の指定は省けます。
// 下に処理が続いてる
}
}
こんな感じです。
最初のコメントは識別子にローマ字使ってる人を見かけることがあるので…( 和英辞書でも使えよ。)
ちなみに final 修飾子はクラスやメソッドにつけると、これ以上継承やオーバーライドできないようになります。
C++ではムリですが、C#やJavaならこうすることで自分のクラスを使う人に継承してほしくない等の
自分の意思を伝えることができますので、複数人でのプログラムの際には思い出してみて下さい。
定数をどっかにまとめて記述しておきたいけどイチイチ アクセス指定子 static final 付けるのダルイって人は
interfaceを利用してみてはどうでしょう。抽象メソッドの宣言がインターフェースの主な使い方ですが、
機能の一つとしてインターフェース内で変数を書くとデフォルトで public static final になります。
interface C
{
String NAME = "大西" ; // アクセスするには C.NAME でアクセス
}
このほうが楽ですね。
さらに今回の定数や数学系の関数や定数( Math.sin や Math.PI )などを使うときに
クラス名をつけるが面倒な人もいるでしょう。
本来は識別子が競合しないようにこういったものは( C++の名前空間等も含めて )略さない方がいいのですが、sin関数とか円周率(パイ)とかは数学以外まずないだろうとか、
自分しか使わないものなので一緒に作ってる他の人のコードとかを汚さないと感じた場合はstaticインポート を使ってみるのも手です。
import static java.lang.Math.* ;
と最初に書いておくと後のコードは Math に所属する静的メンバに Math. なしでアクセスできます。
// シューティングゲームとかの弾の角度とかで三角関数が必要なコードの一部とします。
{
float radian = sin( ~ ); // Math. なしでOK( ()内の数値は適当 )
}
ただ、この staticインポート 少し注意があります。
staticインポート は Java 2( バージョンはうろ覚え )からの機能です。
授業でエクリプスのコンパイルのオプションとかを設定したと思いますが、
その設定でこの機能をサポートしているバージョンでなければなりません。
( ちなみに僕らの場合は 1.4 ぐらいだったので、僕がしようとしたら ~以上でないとムリって怒られました。)
この辺りは後藤田先生に聞いてください。( 後藤田先生よろしくお願いします。)
あと、C++の場合は定数などがほしいとき static const を使う以外にインライン関数を使うという手もあります。
インライン関数の場合は呼び出してる所にコードを展開してくれるので、
関数呼び出しのオーバーヘッドがありませんね。
namespace MyLib
{
namespace Color
{
/*
今回はD3DCOLOR( DWORD )型ですが、シェーダーなどで色を渡す時にfloat型4つの型
( D3DXVECTOR4 )とかがほしい時もあるのでそちらのバージョンを作っておくのもいいでしょう。
*/
inline D3DCOLOR White() { return 0xFFFFFFFF ; }
// 戻り値の違いだけではオーバーロードはできないので仕方なくこんな関数名に…
inline D3DXVECTOR4 White4() { return D3DXVECTOR4( 1.0f , 1.0f , 1.0f , 1.0f ); }
}
}
DirectXのプログラムで IDirect3DDevice9::Clear や ID3DXEffect::SetVector などに
// using namespace MyLib ; を記述しているとします。
デバイスへのポインタ->Clear( 0 , NULL , flag , Color::White() , z , stencil );
としたり、
// シェーダー( .fxファイル側のグローバル変数に float4 Diffuse ; があるとします。)
エフェクト->SetVector("Diffuse", &( Color::White4() ) );
と見やすくできますね。今回は名前空間で区切りましたが何かのクラスなどに所属する場合は
staticな関数にしてしまえばいいでしょう。
namespace MyLib
{
// 自作ベクトル構造体
struct Vector3 : public D3DXVECTOR3
{
// コンストラクタ
Vector3( const float x = 0.0f , const float y = 0.0f , const float z = 0.0f ) :
D3DXVECTOR3( x , y , z ) {}
// ワールド座標系での各軸ベクトルを返すメソッド郡
// D3DXMatrixLookAtLHなどのアップベクトルに使うなら関数名は Up でもよかったかも…
inline static Vector3 Y() { return Vector3( 0.0f , 1.0f ); }
// Z軸と内積とるようなとこには D3DXVec3Dot( &vec , &( Vector3::Z() ) ); みたいに使ってやる。
inline static Vector3 Z() { return Vector3( 0.0f , 0.0f , 1.0f ); }
// この下にも便利なメソッドを追加してやる
}
}
ってな感じです。以上が定数の記述の例です。マジックナンバーがコード上に現れないようにしましょう。
まあ敵とかのパラメータとかは後で変更しやすいように外部ファイルから読みこんでくるのが一番でしょうが…
長くなりましたが、今回はこんなところです。
最後まで読んでくれた奇特な方ありがとうございます。
PS. GESメンバーへ。シェーダー講座を担当することになると思うけど、何かいい講座名ある?
適当に思いついたの↓
某S崎さんの"シェーダーやろうぜ"を引き継いで
"シェーダーやろうぜやろうども( モチロン女子も大歓迎 )"
ネタでしかない上に読みにくい。我ながらネーミングセンスね~なぁ…
COMMENT
無題
非常に参考になりました
また、ぜひシェーダー講座参加したいです
よろしくお願いします
無題
シェーダー講座はGESで行う、DirectXをクラスにまとめてみる
セミナーの後ほど予定しておりますので期待していてください。