雨弓のゲーム製作ブログ -9ページ目
<< 前のページへ最新 | 5 | 6 | 7 | 8 | 9

無題かも

ブログを作成して4日経ちました。

三日坊主にならなくてよかったなぁと思いつつ、ブログで何を書けば良いのか良く分かってなかったりします。

日記帳気分で良いんですかね。まあ、私はHTML暦が結構長いので・・・。

雨弓になる前のC&C中心のHPから考えると何年経ってるんでしょうか。

針避け1の公開日が2000年。・・・6年前?

あの頃は1MB落とすのにも結構苦労したっけ・・・。あと、DIONは1ヶ月10時間までとか決まっていて、それを超えると超過料金取られたんだよなぁ。・・・・どうでも良いですね(笑)


とりあえずどうでも良い話はテーマ:ブログにしておこうと思います。

まあ、見ている人が果たして何人いるのかという問題はありますが・・・。

効果音

ゲームに欠かせないものの一つに効果音があります。

無音のゲームってのもアリだとは思いますが、やはり音は有った方がいいですね。

MMFやC&Cで製作していたときは効果音が大量に付属されていたのですが、

自分でプログラミングして作るとなると、この効果音を使っていいのかという問題が発生。

普通に考えると、ツールで作成するソフトウェアに限り使用可能だと思われますので、使用しない方向で進めてます。


効果音といえばフリー素材で色々あると思い調べましたが、イマイチこのゲームに合わなかったり利用規約がちょっと厳しかったりとなかなかいいものが見つからず、現在自作しています。

効果音作るのもなかなか面白いですね。爆発音なんかは作るのが難しいですがその辺はマイクを使ったりなんかしてそれらしいものを作ろうと頑張っています。


一部効果音の作成にはこちらのサイトのツールを使ってます。

http://homepage1.nifty.com/sakurayama/

中々使いやすくお勧めですね。

ホーミングミサイルを作るために・・・

ホーミングミサイルの作成をするためには方向ベクトルからクォータニオンに変換する必要があります。

しかし、DirectXのライブラリにはそんな関数がない!

便利なんだか便利じゃないんだか分かりませんな・・・。

それで、どっかにソースが落ちてないかと探したのですが・・・何処にも無い。

ないなら同じようなところで困っている人もいるのではないかと思いソースを載せておこうと思います。

////////////////////////////////////////////////////////////////////////////
// 関数名   : LookAtQuaternion
// 処理概要 : 方向ベクトルからクォータニオンの作成
// 入力    : *from:開始地点
//         *to:標的座標
// 出力    : *qt:回転クオータニオン
////////////////////////////////////////////////////////////////////////////
void LookAtQuaternion(D3DXQUATERNION *qt,D3DXVECTOR3 *from,D3DXVECTOR3 *to){
   D3DXMATRIX mat;
  D3DXVECTOR3 dirvec,dmy;
   D3DXVECTOR2 xrot,yrot;
   D3DXVECTOR2 nxrot,nyrot;
  D3DXMATRIX xmat,ymat;

  //単位行列
  D3DXMatrixIdentity(&xmat);
  D3DXMatrixIdentity(&ymat);

   //方向ベクトルに変換
  D3DXVec3Subtract(&dirvec,to,from);

  //それぞれの軸での座標を設定
  //X軸回転。(-90~90度の範囲内)
   xrot.x=sqrtf(dirvec.x*dirvec.x+dirvec.z*dirvec.z);
   xrot.y=dirvec.y;

   //Y軸回転
   yrot.x=dirvec.z;
   yrot.y=dirvec.x;

   //r=1にしてrot.xをcosの値にrot.yをsinの値に
   D3DXVec2Normalize(&nxrot,&xrot);
   D3DXVec2Normalize(&nyrot,&yrot);

   //アフィン変換
   //X軸
   xmat._22=nxrot.x;
   xmat._33=nxrot.x;
   xmat._23=nxrot.y;
   xmat._32=-nxrot.y;
   //y軸
   ymat._11=nyrot.x;
   ymat._33=nyrot.x;
   ymat._31=-nyrot.y;
   ymat._13=nyrot.y;

   //行列生成
   D3DXMatrixMultiply(&mat,&ymat,&xmat);
   //クォータニオンに変換
   D3DXMatrixDecompose(&dmy,qt,&dmy,&mat);

   return;
}

丸二日悩んだ割りに簡単なソースになってしまいました。

sqrt関数使ってるのでちょっと重いかなーとも思ってるのですが。


でもこういうのって需要あるんですかね?

反応無ければもうやらないかも(笑)

製作情報

昨日は久々に製作が捗りました。

下の画像は、武器選択画面です。

まだ武器数が少ないですがこれから増やしていく予定です。

デザインがどうかなーとも思うのですが、面倒なのでこのままで行くかも。

製作rb2

※画像は開発中のものです

開発状況:65%

現在製作中のゲームの製作情報でも

現在DirectXとC++で製作中の3人称シューティングです。

3Dは2度目ですが、色々と難しいです。

多分2Dの10倍ぐらい難しいかと・・・。

ホーミング処理で2日ほど迷いました。サンプル置いてあるサイト探してもないですし。

方向ベクトルからクォータニオンに変換するだけなのですが、それが色々と面倒でして。

sqrt使っているので重いかなぁと思いつつ、他の手が思いつかないのでそのままにしてます。

何か良い方法がありましたら是非コメントを・・・。

製作rb1

※画像は開発中のものです

進行状況:40%

ポインタについて

とりあえずテストも兼ねてHPの読み物からそのまま持ってきたり。


C/C++プログラミング初心者最初の壁となる「ポインタ」。
そんなポインタについてちょっと解説してみたりします。
ちなみに初心者向けなので中級者ぐらいの人にとっては「何コレ。当たり前じゃん」程度のことしか書かれていませんので悪しからず・・・。

とはいえ私もC使って1年ちょい(しかも演習で週1+趣味のゲーム製作程度)ですので、間違いがあると思われます。


元々ポインタってなんだっけ。

ポインタは「アドレスを示す変数」と良く書かれています。
実際その通りです。・・・でもそれで終わってしまったらこのテキストの意味は無いわけで。

とりあえず
アドレスとはメモリの番地のことです。
変数aが100番地にあればアドレスは100です。
この番地はコンパイラが勝手に決めるのでプログラマは分かりません(知ろうと思えば簡単に分かりますが)
でもプログラミング中では
a=10;
などと記述すると勝手に
100番地の値=10;
とコンパイラが書き直してくれるのでプログラマはアドレスを意識しなくてすみます。
簡単に言えば変数名は、ある番地に名前をつけた。ともいえるのではないかと思います。

さて、
int a;で宣言したなら
a→int型の値 &a→aのアドレス
int *a;で宣言したなら
*a→int型の値 a→(*a)のアドレス

であると言うことは覚えていると思います。
・・・が。これは正しいのですがちょっとだけ・・・言いたいことがあります。
不思議だと思いませんか?宣言した形が違うとはいえ、意味が違うなんて。
じゃあ例えばint a;で宣言して*aって入力したらどうなるの?とか
逆にint *a;で&aって入れたらどうなるの?とか。
まあ、やるとセグメント例外とか出て結局確認できなかったりしますが、実は
aは「変数aの値」
*aは「a番地の値」
&aは「変数aのあるアドレス」

となってます。これはint a;で宣言しようがint *a;で宣言しようが同じことです。
例えば

int a;
a=20;

と入れたとき、*aの値はどうなるでしょうか。
これは20番地の値、となります。
勿論通常20番地に何が入っているかなんて分からないので変な値が出たり、セグメント例外が出たりするわけですが・・・。

この辺は普通に本に載っていると思いますので参照してみてください。
まあ、それ言っちゃったらこのテキストの意味も無いんじゃないかと言われそうですが(笑)




関数に値を渡す時、ポインタは特別なの?

int main(){

int a,*b;
a=10;
*b=10;
test(a);
ptest(b);
printf("%d,%d\n",a,*b);
return 0;

}

void test(int a){

a=30;
return;

}

void ptest(int *a){

*a=30;
return;

}

上のはincludeやプロトタイプ宣言は省略してますけど、簡単なプログラムです。
「この場合出力はどうなりますか?」の問題。
そう、「10,30」と出力されますね。
普通に渡すと変数のコピーを渡すので中身が変更されないけどポインタなら変更される。
「だからscanfの時も&が要るんですよ~」みたいな。
これ、結果としては合っていますが概念としてはちょっと違います。

実はポインタを渡す時もコピーを渡しているんです。
「アドレス」と言ってもそれ自体単なる自然数です。つまり12547236とか。
すなわち
int *b;
で宣言した時、100番地に変数を作ったならbは100です。
*b=10;
より100番地の値は10になりました。
ptest(b);で「*b」ではなく「b」を渡していますよね。すなわち「100という値をコピーして渡す」ということです。
ptest関数の*a=30;により、100番地の値を30に設定。
ということになり、結果的に*bの値を変更させることが出来た。というわけです。
つまり。
ポインタだからと言って、値を渡すこと自体に特別なことは何もしていない。と言えます。




配列とポインタ

本にも良く書かれてることなので書かなくてもいい気がしましたが一応。
1次元配列を考えて見ましょう。
仮に

int a[10]={1,2,3,4,5,6,7,8,9,10};

としたとします。
このとき「a[0]」はいくつでしょう?そう、「1」ですね。
では「a」はいくつでしょう?
これはa[0]のアドレスになります。つまり「&a[0]」です。
だから「関数に変数を渡しても中身を変えられないけど配列を渡すと変えられる
という不思議な現象が起きるわけです。アドレス渡してるんですから当たり前ですね(笑)

さて、なぜそんな仕様になっているのでしょうか。
a[0]のアドレスは先頭のアドレスです。
ここが分かればそこから先a[1]やa[5]などのアドレスが一発で分かります。
配列は連続したメモリを取ります。(メモリが足りなくて連続して取れない場合エラーになります)
つまり、a[0]が100番地だった場合、int型は通常4バイトなので

変数 a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9]
1 2 3 4 5 6 7 8 9 10
アドレス 100 104 108 112 116 120 124 128 132 136

となっています。
即ち先頭の番地が分かれば、
a[3]と入れたら、100+3*4=112番地を見れば良いということが分かります。
a[n]番地なら100+n*4番地ですね。

配列とポインタなのでついでに言うと
int a[];

int *a;
は、全く同じ意味です
int a[10];
とか内部的には
int *a;
a = (int *)malloc(sizeof(int)*10);
とほぼ一緒と思ってもらってもいいかも。mallocについては次で書いています。




動的な配列確保。
注)メモリ不足のためのエラー処理は省略してます。

C++ではnew演算子がありますがC言語ではmallocを使用します。
mallocは変数を動的に確保する目的で使われます。
mallocはstdlibにあって、
void *malloc(size_t size);
となっていて、簡単に言うとsizeバイト分のメモリを確保し、その先頭のアドレスを返します。
細かいことはやっぱり本で・・・(笑)
deleteに対応する開放する関数はfreeです。
このmallocを使うと

int *a;
int b;
scanf("%d",&b);
a = (int *)malloc(sizeof(int)*b);

で、長さbの配列が作れます
では、2次元配列を動的に確保するにはどうするでしょうか。

int **a;
int b,c,i;
scanf("%d,%d",&b,%c);
a = (int **)malloc(sizeof(int *)*b);
for(i=0;i<b;i++){

a[i] = (int *)malloc(sizeof(int)*c);

}

for文が必要になってなんか良く分かりにくいですね。
それはいいとして、for文内
a[i] = (int *)malloc(sizeof(int)*c);となっています。
aはint型のポインタのポインタ型(int **)です。
ではa[i]は?そう。int型のポインタ型(int *)です。
a[i][j]の中身は普通にint型の値です。ココは説明不要ですね。
例えばbに3、cに2を入れたとしましょう。
「a」や「a[0]」、「a[1]」、「a[2]」の値はどうなっているでしょうか。
答えは下の表のようになっています。

変数
a a[0]のアドレス
a[0] a[0][0]のアドレス
a[1] a[1][0]のアドレス
a[2] a[2][0]のアドレス

このようになっていれば配列は連続したメモリを取るので、a[1][1]などと入れれば何処を見ればいいかが分かりますね。
メモリは1次元なわけですから擬似的に2次元配列を作っているということです。




・どうしても良く分からない!なら・・・。
アセンブラをやってみることをお勧めします。
実はアセンブラをやってみるとポインタを理解するのが簡単になります。
そんなに難しいプログラミングをしなくても、乗算や除算、剰余を求めるプログラムぐらいでも理解できるのではないかと。
MPLABとかW-CASLIIでエミュレーションしてみるだけでも結構違うと思うのですが・・・。

とりあえず作ってみた

ブログを作成してみました。

とりあえず感たっぷりですが、自作ゲーム、DirectX、C++についてをメインに書いていこうかと思います。

ブログ作ったお陰でHPの読み物とUnlimitedのコンテンツがいらなくなったかも。

最悪掲示板と製作情報も要らない?

HPを編集する必要があるかもしれませんね。

<< 前のページへ最新 | 5 | 6 | 7 | 8 | 9