ゲーム作者の集い[ゲームヘル2000]

あめにっき

最終更新:

匿名ユーザー

- view
だれでも歓迎! 編集
なるたけ多めに更新するようがんがります。そーすつきで。
スクリーンショット入れたいんだがなぁ。
これのためにソースの整理をする決意ができたので、それだけで満足だ
ライセンスは良く判りませんが、煮るなり焼くなり(ry

とりあえず、思いついたことをドカドカ書いていくので、興味あるところはリクエストしてくださったら、もちっとマシな解説を考えます。



帰ってきた詠嘆

なんか、自作のatan2()にバグがある予感。
標準ライブラリのatan2()を使うように変更したらバグが消えたから。。。
原因は究明中。危険な箇所がみつかったら修正します。

でも、なんか修正する気が起きないんだよな~。
ヘルチャットで8086さんに「整数演算も小数演算も大して速度は変わらん」って聞いてしまったからか。。。


顔を描く時はどこから描く?(俺は目からだ~

画面にビットマップをペタリ子するときって、
キャラの座標とビットマップの対応ってどうしてます?
ソースをごらん頂くと判ると思いますが、
ワタクシは画像の中心と対応させてます。
YGS2Kでは、ビットマップ表示に
x座標、y座標、幅、高さを与える(左上座標+幅、高さ)ので…

BltRect(	0,/* 0番プレーンを表示 */
		(x>>16) - CHAR_WIDTH/2,	/* 座標xから半キャラずらして表示 */
		(y>>16) - CHAR_HEIGHT/2,/* 座標yから半キャラずらして表示 */
		BmpDx,	/* 転送元x座標。 */	
		BmpDy,	/* 転送元x座標。 */
		CHAR_WIDTH,/* キャラサイズ */
		CHAR_HEIGHT/* キャラサイズ */
		);

こんな感じですね。


昔偉いひとに相談したら
「どっちでもいいんじゃね?好みで」
と一蹴されたので、そんな程度らしいです。

個人的には、当たり判定とか自機狙いとか
中心を基準に考えた方が便利かなーと思ってます。

それはいいのだが、
ワタクシの自作描画ロジックでは中心の座標を指定する仕様にしている。
回転後の4点を計算するのには、そっちの方が楽なんで、
中心大好きなワタシには都合がよかったのが理由。
…なのを忘れてて、今日サンプルみたいな記述をして、
どうにも画像がズレておおいに悩んだとさ。

もう寝た方がいいっぽい。

この項おわり


OOなんて嫌いだ?

ヘルのチャットで8086さんと話をしていた結果、なんかワタシOOの機能を殆ど使ってないことが判ったよ。(実際は故あってOOの機能を使うのを止めた)
クラス作る意味ないのかなぁ・・・

今日、メモリリークを幾つか潰しました。つか、以前も同じトコで悩んでたことがあったので、備忘録で残しておきます。
そんなわけで、タダでさえ誰も読まない系のページなのに、C++の話とかしてひとりよがりしてみるのです。

とりあえず継承関係のクラスを作ったわけです。
class oya{ oya(); ~oya();};

class kodomo : public oya{ kodomo(); ~kodomo();};

kodomoクラスでは、コンストラクタでnew、デストラクタでdeleteしてたりなわけです。

で、ある日こんなことを
oya* = pOya;

pOya = new kodomo;

当然、生成時にコンストラクタkodomo()が呼び出されます。
で、使い終わったのでポインタをdeleteしました。

delete pOya;

なので、kodomoは消え去ったつもりだったのですが、
実はoyaポインタに対してデリートしたので、実体がkodomoでも
呼び出されるデストラクタは~oya()だったのでした。
で、kodomoで使ったデータがdeleteされることは無く、
メモリリークとなったのでありましたとさ。めでたし、めでたし。

うぇーい。

  • 後日談
つ「virtual」
デストラクタは必ずバーチャルにしろって「Effective C++」のエライ人が言ってた。 -- ( ゜ワ゜)ノ

まったくその通りだ。やっぱり勉強はしとくべきだったね。


この項おわり


担詠嘆 担詠嘆 担詠~(060125)

!!!CAUTION!!1
なんか、ワタシの作ったこの関数バグがあるっぽい。現在解析中~

今日ソースを見てたらバグだらけ~。急いで作ったからな。つうことで、バグを見つける間違い探しなんだよ!

修正する時間が無いので、とりあえずアークタンジェント関数。サインとコレがあれば大抵のことは出来るでショ。多分。

タンジェントは-90度から+90度の間で単調増加(って云うんだっけ?)なんで、入力のタンジェント値とテーブルのタンジェント値を比較した大小で走査すれば求める角度が得られる。
因みに、タンジェントの値はsin()/cos()で求まります。理由は…sinとcosの定義を調べてみてね。

ので、2分探索って云うよく知られるアルゴリズムで求めてます。これなら、4096だったら12手で必ず解が求まります。理由は4096=2の12乗だから。

(sin.h)
二分探索でアークタンジェントを求める
alpha = 1023;
beta = -1023;

for(i=0;i<12;i++)
{
ctr = (alpha + beta) / 2;

if( (Sin4096(ctr)<<15)/Cos4096(ctr) >= ((y<<15)/x) )
{
	alpha = ctr;
}
else
{
	beta = ctr;
}
}
return alpha + delta;

ところで、純粋なタンジェントの値からだけだと、2つの角度が求まってしまいます(0~360度の範囲では)。なので、xとyの符号を見て場合わけします。なので、自作アークタンジェントの入力はxとyの2つです。

if( x > 0 )
{
delta = 0;
}
else if( x < 0 )
{
delta = 2048;
}
else // ( x==0 )
{
if( y > 0 )
	return 1024;
else
	return 3072;
}

因みに、90度と270度の時はタンジェントは無限大になってしまうので、そこも場合わけしてあげやう(ホントの理由は違うんだけど

やっぱサンプルは以前のやつで。

この項おわり


自機に弾を向ける(060124)

自機に向いた角度を取得するには?
そんなときはアークタンジェント。なんかつよそうですね。

アークタンジェントは、タンジェントの値、y/xを与えると、その角度を返す関数です。
なんで、弾の発射元のx座標と自機のx座標の差、元のy座標と自機のy座標の差をアークタンジェントに食べさせればOK。

サンプルboss.cの18行目
AddTama( 320<<16, 100<<16, Atan4096( (GetPlayerX()>>16)-320, (GetPlayerY()>>16)-100 ) );

これでOK。自作のアークタンジェント関数の精度がイマイチで、
入力は65536未満?じゃないと駄目かも。

AddTama( int x, int y, int Angle );
これは(x,y)に角度Angleの弾を発生させる関数ですよ。

GetPlayerX();
GetPlayerY();
これはプレイヤのx座標、y座標を返す関数。

サンプルはやっぱり昨日のやつ。

この項おわり


とりあえず弾(060124)

とりあえず弾を飛ばす。

速さR、角度θで弾が飛ぶときはx軸y軸それぞれの成分は
Vx = Rcosθ
Vy = Rsinθ

であるから、
サンプルのTama.cの45,46行目
Tama_x[i]=Tama_x[i]+TAMA_SPEED*Cos4096( Tama_Angle[i] );
Tama_y[i]=Tama_y[i]+TAMA_SPEED*Sin4096( Tama_Angle[i] );

tama_x[i]ってのは、沢山ある弾のうち、i番目の弾のx座標。
つまり、ある特定の弾に対して考えると
x = x + SPEED * COS( Angle );
y = y + SPEED * sin( Angle );

これで速さSPEED、角度Angleで弾が飛ぶよ。

ワタシの作ったサインとかだと、
画面右が+x、画面下が+yの座標になってるので、
右が0度で時計回りに角度が増えてゆくことに注意。

サンプルは前回(060123)のやつをみてね。

この項おわり

自機狙い弾とか(060123)

取り敢えずサンプルをつくった。
解説事項が多すぎるので、解説はまた今度。
斜めブーストも修正しないとなw


  • サンプル

この項おわり


サインちゃん(060122)

友人にこのページを読んでもらったら、訳判らん意味不明とか云われました。
おーのー。
確かに意味不明文章だけど、頑張ってソースにコメント打ったりしてんねんけどなぁ。。。

で、サインウェーブです。
ゲームやってたらどこもかしこもサインちゃん。
サインに非ずんばゲームに非ず、と。

よくわからんけど、サインはマクローリン展開だがテイラー展開だか出来るんですって。
sin(x) = x - (x^3)/(3!) + (x^5)/(5!) - (x^7)/(7!) + …
cos(x) = 1 - (x^2)/(2!) + (x^4)/(4!) - (x^6)/(6!) + …

ここでxはラジアンだから注意だよ。ラジアンってのは1周を2Π(円周率)で表す角度の単位だよ。

なので、素直に代入してみましょう。
Θ:求める角度(4096で1周)
x = (1608*Θ) / 4096; //角度>ラジアンに変換 (2*PI*i/4096)*256 (256は65536固定小数にするため)

COS = 65536 //1項目
- (x*x/2)	//2項目
+ (x*x/2/256*x/3/256*x/4)	//3項目
- (x*x/2/256*x/3/256*x/4/256*x/5/256*x/6)	//4項目
;//終わり

無限に足すのは出来ないので、飽きたところで終了。
4項くらい足しておけば十分っぽいです。
↓Cの<math.h>のsin()との誤差をプロットしてみた
http://www7a.biglobe.ne.jp/~root-ame/src/sin.JPG

なんで4096を1周にしてるかと云うと、昔偉いひとにそれがいいって云われたからだよ。
よくわかんないけど、いい数字なんですって。

で、求めたサインを4096要素の配列に代入しましょう。
for(i=0;i<1024;i++)
{
x = (1608*i) / 4096; //角度>ラジアンに変換 (2*PI*i/4096)*256 (256は65536固定小数にするため)

tmp= 65536 //1項目
- (x*x/2)		//2項目
+ (x*x/2/256*x/3/256*x/4)	//3項目
- (x*x/2/256*x/3/256*x/4/256*x/5/256*x/6)	//4項目
;

SIN4096[1024-i] = tmp; // 0~ 90度
SIN4096[i+1024] = tmp; // 90~180度
SIN4096[3072-i] = -tmp; //180~270度
SIN4096[i+3072] = -tmp; //270~360度
}

展開式はxが大きくなるほど誤差が大きくなるので、
4分周だけ求めてあとは使いまわすんですって。
生活の知恵ですよね。

int SIN4096(int s )
{
return SIN4096[(s+4096)%4096];
}

int COS4096(int s )
{
return SIN4096[(s+4096+1024)%4096];
}

使うときはこんな感じでどうぞ。
COSは90度足すだけでいいからお徳ですよね。
やっほーい。

どうでしたか、わけわからんですか。わけわからんですね。
うぇーい。

  • サンプル

  • 参考文献
S.Programs NET/小さなねた/10bit 精度の sin テーブル
http://sprocket.babyblue.jp/html/hsp_koneta.htm
大変参考にさせていただきました。実はワタクシもよく判ってない。もしかしたらもっと精度を上げられるのかもしれんが、力尽きました。

暁のコード部屋(第10回)sin/cosに苦しむ
http://www.aya.or.jp/~sanami/peace/memorial/code1-10.html#CODE10
最近になってようやくじわじわ理解できるようになってきましたわー。シュゴー

この項おわり


次回予告(060118)

ネタはあれども、ソース書く暇が無いと云う。うぇーい。今はキャラ管理クラスとか書いてますよ。

次は三角関数にしようと思うのですよ。例によってさ~さんの受け売りで4096分周のテーブルでな。
ネッツで調べたらアークタンジェントの出し方もあったよ。
ほうほう結局はテーブルから探索ですか。なるへそ。
そんな感じで。

今日のおまけ
僕愛用のサインテーブル
http://www7a.biglobe.ne.jp/~root-ame/src/sin4096.h

この項おわり


固定小数のススメ(060116)

今日は寝不足で電車の中で爆睡してたので、ソース書いてません。いきなりネタがありません(笑)ので、以前書いた文章をペタリ。

ゲーム中の数式計算なんて大体正しければいいのですが、流石に整数だけでは辛いので、小数を使いましょう。
小数っつうとCで云うfloat型とかの浮動小数を使えばいいですが、通ぶって固定小数でいきましょう。

  • かんがえかた
「固定小数点型なんてCじゃサポートしてないよう」だなんて泣くことはなくて、10000を基準に考えて
十分の一の1000を0.1だと思い込んで使えば無問題。

  • つかいかた
値を代入するときにはリアル数字(人間様が認識してる数)に10000とか決められた数を掛けてやるだけ。
で、実際に使用する際(例えば画面上の座標にするとき)に10000で割るだけ。


int x,y; /* 座標 */

x = 5 * 10000; /* 固定小数への変換 */
y = 10 * 10000; /* 固定小数への変換 */


/* 値をアレコレ */
x = x + 15000; /* xに1.5(リアル数字)を足す */
x = x + 27000; /* xに2.7を足す */

/* 実際に値を使う */
DRAW( x/10000, y/10000 ); /* DRAW:架空の関数 */

先ずはxを50000で初期化。そのあとxに15000を足してみて65000に。もいっちょオマケで92000に。
で、実際に画面表示とかに使われるときは10000で割って9。5 + 1.5 + 2.7 = 9.2。
ドット以下は表示できないので、切捨てでおっけ。そんな感じ。

通は乗除する数を65536にすると素敵。ゲームとかだと2のべき乗で掛けたり割ったりすることが多い(→65536だと誤差が生じない)ので便利だし、ビットシフトで計算すれば高速(だと思う)だし。

int x,y;

x = 5 * 65536; /* 固定小数への変換 */
y = (10<<16); /* これでも同じ */

DRAW( (x>>16), (y>>16) );

注意としては、Cだとビットシフトの優先順位はびっくりするぐらい弱いので、嫌っていうほど括弧をつけるクセをつける必要があることか。

  • 注意
乗除算を行う時はちょと注意が必要。(hoge*10000) * (foo*10000) = (hoge*foo)*100000000になってしまうのでー。

int hoge, foo, bar;

/* 変換~ */
hoge = (3*10000);
foo = (5*10000);

bar = hoge * foo; /* NGggggggggggggg */
bar = (hoge/100) * (foo/100); /* OKkkkkkkkkkk */

  • サンプル
http://www7a.biglobe.ne.jp/~root-ame/bin/kotei.zip
カーソル右で加速。カーソル左で減速。なめらかな加減速を体感しやう。
例によってyaneuraoさんのYGS2Kの実行ファイルが置いてあったり。

  • 参考文献
暁のコード部屋(第22回)固定小数点における正しい乗算
http://www.aya.or.jp/%7Esanami/peace/memorial/code21-30.html#CODE22

つか、受け売りを実行してるだけなので、さっさとこちらのページにいっときましょう。

この項おわり


最近の開発


丼さんがエロSTGつくれと仰るので開発に着手。
縦STGから横STGに仕様変更。
理由は聞かないでください。

その後
波紋効果を入れてみた。
何らかの形で自機の位置を知らせるフィーチャーは必要だと
思ってみたから。
ステージスタート時の演出とカスリ時に
波紋を出したらいいんじゃね?
適当なサイトから適当なソースをぶっこ抜いてくる。
zキーでオーバードライヴ
結果:いい感じ

ダガシカシ
ワタクシの絵づらから鑑みるに
パステル調とかの方がよい気がしてきた。
半透明とか加減算のエフェクトは合わない気がしる。
ワタクシの1ヶ月は徒労に終わる。

この項おわり

やっぱり米欄つくってみた
  • この項おわりでうけた。
    すまんす。ぜんぜん役に立たぬコメントで。 -- D.K (2006-01-16 22:55:13)
  • 詠嘆めちゃ参考になった。ベンチするとどのぐらい早いんだろう。
    個人的にはatan2()の方が良く使うのでそっちのいいアルゴリズムはないかなぁ。
    >OO
    つ「virtual」
    デストラクタは必ずバーチャルにしろって「Effective C++」のエライ人が言ってた。 -- ( ゜ワ゜)ノ (2006-01-29 11:44:47)
  • あれ?今回つくったのがatan2()のつもりだったんだけど、違うのか!?

    >virtual
    ちょみっつそんな予感もしてみた!virtualにしない理由って無いですからねぇ。。。ともあれ、情報THX! -- るーと雨 (2006-01-31 01:02:06)
  • >atan2
    うわ、しまった。見逃してた。
    どう見てもatan2ですorz -- ( ゜ワ゜)ノ (2006-01-31 02:05:46)
  • 中心から表示するか、端から表示するかはジャンルによるかな。
    アクションだと足元を0にした方が管理が分かりやすいと思うし。 -- D.K (2006-02-08 10:11:00)
  • 中心がいいか端がいいかの議論はそばのツユが黒いか薄いかに匹敵する価値があると思います。つまり、「好きにしてくれ。。。」
    なぜ中心がいいかと云うと(ry

    それでも、個人的な感性で足元0は受け入れられないなぁ。。。
    その理由をちょと考えたのですが、
    左上原点のスクリーン座標と、左下原点座標のどっちに主眼を置いてゐるかにあるのかな。。。とか思ってみた。
    -- るーと雨 (2006-02-09 12:44:00)
  • それだ、それ。アクションは左下が原点で管理してました。
    まぁどっちでもいいんだけど。 -- D.K (2006-02-10 09:04:11)
  • アクションはスプライトアニメーション原点の関係で自分も左下原点で移動周りは処理してました。当たり判定とか超適当にしたかったので中心から円形にざっくりやってみたり(爆)矩形判定より判定文が短くて好きだっただけです、ごめんなさい -- わんきち (2006-02-10 09:27:48)
  • もしかしてスクリーン座標で管理してる私はマイノリティ?つか、枠とかのバイアスのある画面に対応できるように、結局ワールド座標からスクリーン座標に変換をかける処理を入れてゐるので、判りいい方を使えばいいんですね。でも左上原点は譲れない!

    円って楽なんですかね。。。?使ったことないんですけど。

    if( (dstX-srcX)^2+(dstY-srcY)^2 < (srcR + dstR)^2 )
    srcX:x座標
    srcY:Y座標
    srcR:判定の大きさ(距離)

    セオリーを知らないで考えてみたんですが、こんな感じ? -- るーと雨 (2006-02-10 12:33:24)
名前:
コメント:


ソースファイル

http://www7a.biglobe.ne.jp/~root-ame/bin/ero_src_fluu0116.lzh
(1MBくらい)
VC6とDirectXSDK8以降があればコンパイルできると思いたい。
実行ファイルも入ってるので多い日も安心。
yaneuraoさんのYaneuraoGameSdk2ndを改悪したモノが混入されてますが、
ダウソ即コンパイルできるやうに敢えて置いておきました。
そんな感じで。

タグ:

+ タグ編集
  • タグ:

このサイトはreCAPTCHAによって保護されており、Googleの プライバシーポリシー利用規約 が適用されます。

記事メニュー
目安箱バナー