ゲームのアルゴリズムを教えて管sai
現在、荒らしによってこの板の利用が困難になっているため、避難所を作成しています。
出来ればこちらに移動するのをお勧めします。
ゲ製作技術板(避難所)
http://bbs.gamdev.org/gamedev/
-------------専用ブラウザ(OpenJane)への登録方法-------------
板一覧ウィンドウのカテゴリのフォルダを右クリック→ここに板を追加
(⌒V⌒)
│ ^ ^ │<これからも僕を応援して下さいね(^^)。
⊂| |つ
(_)(_) 山崎パン 漏れら極悪非道のage武田騎馬ブラザーズ!
ネタもないのにageてやるからな!
 ̄ ̄∨ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
∧_ヘ ∧_ヘ
/ \〇ノゝ / \〇ノゝ age
/三/´∀`)∩ ∩/´∀`) age
(つ 丿 ( ⊂) age
( ヽノ ヽ/ ) age
し(_) (_)J こんなスレッドまで来て、ゲームアルゴリズムを真剣に
学びたい人はいないとは、思うけど、
単純な2Dシューティング(インベーダー程度)なら
配列、探索アルゴリズム、リスト、構造体
テーブル化、ソートアルゴリズム、フラグ、画像転送、
矩形の当たり判定
アドベンチャーゲームなら
自作スクリプトの字句解析、構文解析(lac,lex)
簡単な暗号化、圧縮アルゴリズム、バイナリファイル操作
画像エフェクト系(拡大縮小回転、ワイプ、ラスタースクロール、
α値操作、他いろいろ)
が分かれば作れると思います。
たぶん。 だれか、2Dアクションゲームの、スクロールとキャラクタ・当たり判定の
管理について教えてくださいな。 >>59
昔のゲームを逆アセンブルで解析してみて参考にするのは、どうだろう…
私は、解析したことがないので、どうなっているのか分かりませんが、
少し昔の2Dアクションゲーム(ロックマン、マリオ、魔界村、ソニック、スペランカー、etc)
のマップは、おそらく32×32ドット(24×24ドット)程度の大きさで区切られたマスの組み合わせで
表現されていると思われます。
それを、2次元配列でint Map[300][300]={ {0,0,0,1,0,1,…のように表して
0を当たり判定なし、0以外の値(1など)を当たり判定ありとすれば、マップデータは完成。
●そのマップデータを画面に表現するには、
sx,syをx,y方向別のスクロール管理変数
画面の解像度を320×240とすると
void DrawMap()
{
int stx=sx/32;int edx=sx+320/32;
int sty=sy/32;int edy=sy+240/32;
for(int i=stx;i<edx;i++)
{
for(int j=sty;i<edy;j++)
{
DrawMapChip(map[i][j],i*32-sx,j*32-sy)
}
}
}
●スクロールは、常にメインキャラクターを画面の中心に置いておきたい訳だから
void CalcScroll(int *sx,int *sy)
{
*sx=mx-320/2;
*sy=my-240/2;
if (sx<0) sx=0;
if (sy<0) sy=0;
if (sx>32*200) sx=32*200;
if (sy>32*200) sy=32*200;
}
だったかな…
ちなみにmx,myはメインキャラクターのx,y座標 当たり判定は、いろいろな方法(ベクトル、三平方、色判定など)があるけども、
メインキャラクターが発射した弾と敵キャラとの当たり判定なら、単純に矩形(くけい)の
当たり判定で済みます。
●弾の座標を(ax,ay)、敵の座標を(bx,by)とした場合、
if(ax<bx2 && ax2>bx && ay<by2 && ay2>by)
{
}
で当たっているか、否かが分かります。 ●メインキャラクターとマップとの当たり判定は、
□x座標の移動処理の直後に
//左上と左下
if(Map[x/32][y/32]!=0 || Map[x/32,(y+height)/32]!=0)
{
x=(x/32+1)*32;
}
//右上と右下
if(Map[(x+width)/32,y/32]!=0 || Map[(x+width)/32,(y+height)/32]!=0)
{
x=(x/32)*32;
}
で
□y座標の移動処理の直後に
//左上と右上
If(Map[x/32,y/32]!=0 || Map[(x+31)/32,y/32]!=0)
{
y=(y/32+1)*32;
}
//左下と右下
If(Map[x/32,(y+31)/32]!=0 || Map[(x+31)/32,(y+31)/32)!=0
{
y=(y/32)*32;
}
とやればできます。どうしてそうなるのかは、
計算式を参考に図を書いてみれば分かると思います。 俺も昔Javascriptで同じようなの作ったことあります。
肝心のゲームは流行らなかったけど。IE対応型RPGゲームね。
閑話休題、質問です。
SLGの六角型HEX画面ってどうやってるの?
テーブルで組んでいくと非効率的だし、実際のアルゴリズムも
かなり無駄な処理が入ってるのでしょうか? >>64
普通の2次元配列を用意すると、任意の要素の周辺には8個の要素があるが、
そのうち2個削れば6個になる。
横並びのHEXの場合、削り方には
・右上と右下
・左上と左下
の2通りあるが、行の隅・奇で決めればよい。
但し、このアドレス計算のオーバーヘッドが無視できない場合、
>>65の言うようにリスト構造か、[6方位][各セル]分の配列を
あらかじめ作ってしまう方法も検討するとよい。
>65-66
d
話が前後するけど移動に関しては↓の「2.マップ移動システム」みたいな
話もある。構造が明快ではなくなるけどXY式より処理は少なくなる。
ttp://members.jcom.home.ne.jp/masimaro/cgi/index.html
横軸分引けば下移動、足せば上移動だから、アクションでも使えるん
じゃないかな? 斜めになっている地面、斜めになっている天井とプレイヤーとの当り判定ってどーゆーふうにしたらいいんですかね?
地面は何とかなりそうなんですが天井の方がよくわかりません。 某板よりコピペ
多数のオブジェクトの衝突判定を並列化する方法
移動後の座標をボクセルに振り分ける。
1つのボクセル内に存在するキャラを総当たりで衝突判定。
処理の順序としては、移動、振り分け、衝突判定、衝突処理。
これで処理を並列化できる。
もう少し詳しく言えば、衝突判定をしやすくするために、
ボクセルに振り分ける時点で座標値などをボクセルごとの一時バッファに複製しておく。
これにより巨大なバッファをLSにロードする必要がなくなる。
衝突の連鎖については次フレームに回す。それで結果的には再帰処理になる。
普通は移動後に振り分けるというより
ボクセル内のオブジェクトを管理するバッファを常設しておいて
移動でボクセル外に出たときだけバッファの更新をするでしょ。
>>69
・坂を方程式で表す方法
例えば天井がy=-0.1*x+64の直線と考えれば、
atamay<=-0.1*atamax+64なら当たり。
地面をy=-0.1*x+480の直線と考えれば、
asiy>=-0.1*asix+480なら当たり。
atamax,atamayはキャラの頭の座標。asix,asiyはキャラの足の座標。
画面は640*480を想定。
・小さい矩形に分ける方法
天井も地面も小さい矩形がたくさん集まったものだと考え、それぞれの矩形と
の当たり判定を行う。壁(当たり判定がある地形)があるシューティングとかは
これでやってるはず。
これなら坂はまっすぐでなくてもかまわない。
・色で判定する方法
たとえば壁(当たり判定がある地形)は黄色で描くものと決める。atamax,atamay
の座標の色を読み黄色なら当たり。RGBのRが128以上なら壁とかでもいい
(言語による)。描画処理と当たり判定の順序に気をつける必要がある。地形
を描いて、キャラを描く前に当たり判定を行う。あるいは地形だけ仮想画面に
描くか。
・矩形との当たり判定
天井をたとえば10度傾いた矩形と考える。この矩形をAとする。Aの中心点
を中心として−10度回転させた矩形をBとする。同じように点(atamax,atamay)
を回転させた架空の点の座標を(kakuux,kakuuy)とする。
あとは普通に傾いてない矩形の当たり判定(Bと(kakuux,kakuuy)の当たり判定)
を行うだけ。足と地面も同様。サイン、コサイン、アークタンジェントが分かれば
できる。 ビリヤードの玉のように、円形のオブジェクトが
同じ円形のオブジェクトに当たって弾き飛ばすような
移動の仕方って、どうすればいいんでしょうか? >>75
衝突距離が出しやすいから矩形よりも簡単だったりする。
接線での水平成分、垂直成分それぞれの速度の変換を行う。高校数学(三角関数)と物理なんだが。
食い込んだ分の補正をするとなお良し。 角度を付けた移動ってどうやるんですか?45度だったら
x=x+45
y=y+45
でいいんですか? 高校の(今は中学か?)教科書嫁
というのはなんなのでヒントだけ
x = x + v * cos(angle)
y = y + v * sin(angle) せめて足すんぢゃなくてXょうゃ…
75は角度なんでそのまま使ったらヤバいょうな気がする;
角度たら360°ダロ?
75÷360ぽくね!?
少数点だし…ナンカ上手く曲がりソウぢゃん!?
こんな感じでゲームを創ってたアノ頃………
(涙)
>>79
#define RAD 3.14159/180
って定義しておいて、
x+=cos(45*RAD)*speed;
y-=sin(45*RAD)*speed;
でいけると思うよ。
質問させて下さい。
ユーザーに手書きで図形を書かせ、
それが丸なのか四角形なのか三角形なのかを判別したいのですが
どのようなアルゴリズムが考えられますでしょうか? ふたつかんがえた。もちろん使ったことはない。
・描画速度の変化をみる
(角を描くときに速度が落ちるので、2回落ち込むと三角形とか)
・描かれた線の接線のむきの分布みる
(三方向にピークが出ると三角形、とか)
・グリッドを作って通過するポイントで判定(文字認識?)
・マウスの移動方向をxyの変化量で8つに分ける(マウスジェスチャ?)
俺も作ろっと 縦スクロールシューティングゲームを作ってるんですが、
敵の出現のやり方がいまいち分かりません。
今までは、マップを描画したときに、
敵の情報があったら、同時に表示して、その敵の情報を削除
してました。
何か、いいアルゴリズムがありましたら、教えてください。 #define MAX_X 20
typedef struct _Map{
int ShowX;
int ShowY;
int Type;
int Hp;
int X;
int Y;
}_Map;
_Map Map[MAX_X][500];
void ShowEnemy(int ScY,MapChip Map)
{
for(i=0;i<MAX_X;i++)
{
if(ScrollY==Map[i][ScrollY/16].ShowY)
{
switch(Map[i][Scroll/16].EnemyNuber)
{
case 1:
CreateEnemy(i*16-ScrollX,0,1,3);
break;
case 2:
CreateEnemy(i*16-ScrollX,0,2,5);
break;
…
default:
break;
}
}
}
} ちなみに、CreateEnemyの引数は、X座標、Y座標、敵番号、耐久力だ。 >91
発生する時刻と座標のテーブル持ってればいいんじゃないの?
今、C言語でシューティングゲーム作ってるんですが、
連続した弾の出し方が分かりません。教えてください。
専門学校の先生には、配列を使えと言われたのですが、
よく分かりません。
今、作成している途中のソースコードを書きます。
void Shot(void)
{
for(i=0;i<100;i++)
{
if(Bullet[i].flag == 0 && Bullet[i].type == 0)
{
Bullet[i].flag = 1 ;
Bullet[i].x = (Jiki.x+Jiki.x+Jiki.width) / 2 ;
Bullet[i].y = Jiki.y ;
}
}
}
void KeyCheck(void)
{
if(GetAsyncKeyState(VK_SPACE)<0){ Shot(); }
} それだと一回ボタン押したら毎回100発の弾が重なって発射されるけど、それでいいの?
どうしたいの? >>97 さん
ある程度、間隔を置いて、発射させたいんですぅ。
毎回、100発の弾が重なるのは、耐え難い事実なんです。 大金を払い専門的な職業訓練を受けているはずの学生がこんなことすら自力で出来ない
「耐え難い事実」というならむしろこれw >>98
60フレーム/秒でKeyCheckは毎フレーム呼ばれるの? >>96
if文の中の最後にbreak;入れると幸せになれるぞ 適切なスレが見つからないのでここで質問させてください。
携帯電話アプリのシューティングを作っているのですが、
2D描画の処理を軽くする方法がわかりません。
個々のgifファイルを軽量化してみたりもしましたが、効果があるのかどうか分からないくらいです。
クリッピング領域を指定する方法もあるようですが、いまいちよく分かりません。
他に効果的な方法は無いものでしょうか。 >>102
画像の数を減らして、同じ画像を使いまわすとか、
1秒間あたりの描画回数(FPS)を減らすとか。
あとは、一画面に同時に出現するオブジェクトの数を減らすとか、
背景のスクロールをあきらめるとか、
あと、ベンチマークツールがあればそれを使って、
ボトルネックとなっている処理(メソッド/関数)を分析してみるとか。
>>102
プログラム実行中は結局ビットマップでメモリに保持させてるから効果がないと思うんだが…
予め画像のパレットを全て一緒の256色にしといてパレットを読み込ませないと。 >>103
ありがとうございます。
>同じ画像を使いまわす
試してみようと思います。
これは一箇所に画像を読み込んでおいて、
その画像を使うオブジェクトが描画のたびにそこを参照するようにする、
ということで良いんでしょうか?
他のは、ゲームのバランス調整と平行して考えてみます。
>>102
すいません。そういうことに理解が無いもので・・・。
>予め画像のパレットを全て一緒の256色にしといてパレットを読み込ませないと。
これは良く使われる手法なのでしょうか?
それともgifファイルの軽量化に意味を持たせるための方法なのでしょうか?
どういう風に実装すれば良いのかさっぱり分からないので、後者なら諦めます・・・。
ありがとうございました。 大きな矩形の布地から、サイズの違う小さな矩形の布地を切り取る時、
余りの布面積が一番少なくなるよう、切り取る(小さな矩形を並べる)
アルゴリズムについて書かれた書籍、HP等をご存知でしたら、
教えて下さい。
よろしくお願いします。
>>107
移動するなら移動先を書いてくれ。
実は調べたり考えたりしてたんだが最小公倍数の矩形で
バックトラックするという馬鹿な方法しか思いつかなかったんだ。 >>96
100個程度ならいいですけど配列でもいいかもしれないけど
双方向リストとかを使うようにしたほうがいいかも。c言語だし。
まあこの辺は後ほど。
でも配列を使えとかいう講師に双方向リストを実装して提出したら
うらまれそうw
unsigned int KeyShotFrmCnt = 0; //ショットキーのウェイト用カウンター
↑これはソースの頭のほうに書いてね。
void KeyCheck(void)
{
??if (KeyShotFrmCnt == 0)
??{
???if(GetAsyncKeyState(VK_SPACE)<0)
???{
????Shot();
????(KeyShotFrmCnt = 10;
???}
??} else {
???--KeyShotFrmCnt;
??}
} うは、コピーしたらなんか辺になったorz
void KeyCheck(void)
{
if (KeyShotFrmCnt == 0)
{
if(GetAsyncKeyState(VK_SPACE)<0)
{
Shot();
KeyShotFrmCnt = 10;
}
} else {
--KeyShotFrmCnt;
}
} 2chってスペース空けるの面倒だなw
AAエディタとかで整形してるのか? ↓ポーカーで、誰が有利かを調べるプログラム作りたいんたけど
http://www.pokernews.com/swf/odd_calc_full-v1.1.3.swf
いったいこれ、なにをどうやってこんなに高速に確率計算できるのか、まったくわからない
このプログラムは、近似値じゃなくて↓みたいなドローイングデッドもきっちり表示するし
http://shanbara.jp/gamble/data/zero.png
あらかじめ計算した結果をデータベースにでも叩き込んだのかと思ってるんだけど
それにしたって膨大すぎる 単純に全探索じゃなくて、なんか省略する方法があるんだろうが 誰かクイックソートが挿入法よりなぜ早いのか教えてくれ
クイックソートのほうがめんどくさそうなのに最速とか理解できん・・・ >>113
そのswfをローカルに落として実行してみたら
Odds calculator failed to get data from server.
ってエラーメッセージが出たから、
確立計算専用の外部プログラムを呼び出してるっぽい。 >>115
全部のソートにN*Nの時間がかかるとする。
これを、半分に分けてソートして、足し合わせるとすれば、かかる時間は
(N/2)*(N/2) + (N/2)*(N/2)
= N*N/4 + N*N/4
= N*N/2
N*N > N*N/2
・・・とおもったらクイックソートって2分割って訳じゃないのね?て事で、
分割を、(1/x),(1/y)とする。ただし(1/x)+(1/y) = 1
1 = 1*1 = (x+y)/xy = (xx + 2xy + yy)/xxyy
分割したものをソートして、足し合わせる時間は
(N/x)*(N/x) + (N/y)(N/y)
= N*N/x*x + N*N/y*y
= (yyNN + xxNN) / xxyy
= NN(xx + yy)/xxyy
(xx + yy)/xxyy = (xx + 2xy +yy)/xxyy - 2xy/xxyy = 1 - 2xy/xxyy
ゆえに、NN > NN(xx + yy)/xxyy
こんなんでどうだろうか。というか、この証明あってるんだろうか。 データ数によるんだよね。 少ないデータならどれでも変わらん シューティングゲーム作っているのですが、
私の数学力のなさか、敵の動きが、直線と円を描くものしか作れません
どうやったら、アーケードにあるような あたかも敵が思考を持っているような動きが
実現できるのでしょうか? >>119
敵の動きのカタログ的なものが欲しいなら……。
シューティングゲーム プログラミング ¥ 2,940 (税込)
松浦 健一郎 (著), 司 ゆき (著)
http://www.amazon.co.jp/dp/4797337214 そうではなく、どのようにして さまざまな動きを実現しているのか? その方法を知りたいわけです。
私の敵を動かす情報は 初速度、速度、角度、時間、加速度で管理しているので、直線と円のみになってしまうのです。
そこで、微妙に、プレイヤーのいる方向に向かってきたりする方法は、どのような情報で管理しているのかを
知りたいのです。
私の方法でも角度を細かく設定すれば、ある程度 色々な動きは実現できるのですが、
もっとスマートな方法はないかと思い質問したまでです。 う〜ん、ちょっと違って
人工知能で解決できるのではないかと思うのですが、
人工知能に関する知識がないので、作れないのですが、
オススメの入門書などないでしょうか? >>125
現在位置ベクトル
現在速度ベクトル
目標位置ベクトル
目標位置での速度ベクトル
この条件を満たす加速度ベクトルの時系列を求めればいいんだよね。
でもゲームだから時系列を事前に求める必要はなくて
毎フレームごとに計算するから状態マシンでいけるよ。
2Dシューティングなら普通そうだと思う。
本格的にやるなら確率過程勉強するとおもしろいよ。
実際の迎撃ミサイルがどのように制御されてるか理解できる。 敵の動きが実際にはどういうふうに実装されてるのかを知りたいなら、
>>120みたいな作り方の本が一番実践的だと思うけどなぁ。敵の動きのサンプルもあるだろうし。
STGは本格的に作ったことはないが、普通敵の動きに人工知能なんて使わないんじゃない?
俺だったら毎フレーム状態遷移を計算して、行動を決定するような実装にすると思う。
リアル迎撃ミサイルの精度で敵が弾を撃ってくるSTGとか、やってみたいがストレスがたまりそうだなw Cマガが廃刊になって以来、こういった系統の本で当たりだった試しがない
浅く、レベルも低く、よくこんな本だせたな という本だらけ
立ち読みできないから なおさらタチが悪い
まぁ、状態遷移図で検討します >>125
この手のアルゴリズムは、たぶん正解みたいなものはなくて、
プログラマーのセンスによるんだと思う。
ゲームプログラマーが技術力だけじゃなく、センスを活かせる局面なので、
いろいろ試して自分なりのノウハウを蓄積するのがいいと思う。
ちなみに、この手の処理は、パラメータによる差別化だけじゃなくて、
ちゃんとそれぞれの動きに対して別のコードを書いたほうがいいよ。 シューティングゲームを作っています。
2次元配列に初期化された敵のデータがあります。
int EnemyMap[25][300]=
{
{0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0},
{0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0},
{0,0,0,0,0, 0,1,0,1,0, 0,0,0,・・・
}}
0が無しで、0以上が敵在りで、敵の番号です。
このような場合の敵の出現方法を教えて下さい。
ちなみに縦スクロールSTGです。お願いします。 0が無しで、0より上が敵在りで、敵の番号です
の間違いでした。 テキトーに推測しながら……
時間経過をターンとする、
25マス(?)のデータが300ターンぶんあるのを表すのなら
int EnemyMap[300][25]
ではないか
gameturn を例えば10フレームごとに +1 し、
{
int i;
for(i=0;i<25;i++)
{
int enemyidx;
enemyidx = EnemyMap[gameturn][i];
if(enemyidx != 0) {addenemy(enemyidx, i);}
}
} >>130
int COLUMN = 25;
int ROW = 300;
int EnemyMap[COLUMN][ROW] = { {0,0,.....
int rowNOW = 0;
while(1)
{
/* 画面描画とか、敵機、自機の移動とか*/
//ここから敵の配置
for ( int x = 0; x < COLUMN; x++ ) {
敵を出現させる関数( EnemyMap[x][rowNow], x, 0 );
}
rowNOW++;
}
void 敵を出現させる関数( int enemyType, int x, int y )
{
switch ( enemyType ) {
case 1: { 敵1登場(x,y); break; }
case 2: { 敵2登場(x,y); break; }
case 3: { 敵3登場(x,y); break; }
case 4: { 敵4登場(x,y); break; }
case 5: { 敵5登場(x,y); break; }
...
}
}
うーん、我ながらほれぼれするなあ。 >>133に
case 0: { break; /* 敵は登場しない */ }
を追加(汗)
そのデータ構造の欠点は
・敵がいてもいなくても同じだけの容量が必要
・同じ時間に敵は1機しか出現できない
あ、ひょっとして勘違いでこの25っていうのは画面の幅のことなのか!?
25x300のマップを表現してるとか 敵が画面横や画面中央から出現するような処理はできないな。