- ベストアンサー
C#で壁の当たり判定と自キャラの移動で困っています
- C#のコンソールアプリケーションでゲーム作りをしているC#初心者が、壁の当たり判定と自キャラの移動に困っています。
- 自キャラを丸で描画して動かすと、壁の当たり判定が分からず、壁をすり抜けてしまいます。壁の当たり判定を教えてほしいです。
- また、Graphicsを使って自キャラの移動をしているのですが、数秒後にフォームが停止してしまい、キャラが動かなくなります。プログラムの記述方法も教えてほしいです。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
>一応いままでのおおまかなプログラムを載せておきます。 プログラムが見当たらないようですが、添付忘れでしょうか? >質問なのですが、自キャラを丸で描画して動かすと、壁の当たり判定が分からないので、キャラ(ただの丸ですが)が壁をすり抜けてしまいます。壁にぶつかった時にそれ以上進めないようにするために壁の当たり判定をどなたか教えてほしいです。 壁というのが、画面の端なのか、画面上に存在する障害物なのかでソースの複雑さが変わってきます。 基本的な考え方としては点AB間の距離から衝突してるか判定していく感じです。 (この場合は壁A、自機Bの距離) 以下は障害物に対する矩形判定の処理を書いておきます。画面端の判定にも使えます。 最近C#に触ってないので、C++ライクなソースになってますがこんな感じです。 //矩形(四角形) struct square{ int x,y,w,h; //中央の点xyとその点からの横、縦の長さwh(=矩形の幅、高さの半分) }; //衝突判定 衝突したらtrueを返す bool Collision(square a, square b){ int r = a.w + b.w; if( (a.x - b.x + r) < 0 ) return false; if( (a.x - b.x) > r ) return false; r = a.h + b.h; if( (a.y - b.y + r) < 0 ) return false; if( (a.y - b.y) > r ) return false; return true; } void main(){ square wall, player; //壁と自機のそれぞれの当たり判定 bool b = Collision(wall, player); if(b){ ... } //衝突した else { ... } //衝突していない } >やっぱりDirectXは難しいですかorz C++で使われるのがDirectXで、C#はManaged DirectX(以下mdと表記)というものを使います。現在開発は停止されていて、mdの後継としてXNAがあります。 私はC++のDirectX経験者ですが、C#のmdはC++に比べて遥かに簡単ですよ。 C++での経験があるとはいえ、C#に手を出して3日で簡単なゲームが作れた時は感動しました。 MDXの参考はこちら。 http://www.clks.jp/csg/dx001.html C#全般に関する参考はこちら。 http://homepage3.nifty.com/midori_no_bike/CS/
その他の回答 (3)
- sankaku197
- ベストアンサー率47% (29/61)
ソース拝見いたしました。 max,mayが画面のサイズという事でよろしいでしょうか? 以下そのつもりで話を進めます。 画面端と自機の衝突判定について。 障害物との判定に比べたら分かりやすいと思います。 //左 if(a.x-a.w < 0) { /* 左端にぶつかった */ } //右 if(max < a.x+a.w) { /* 右端にぶつかった */ } //上 if(a.y - a.h < 0) { /* 上端にぶつかった */ } //下 if(may < a.y + a.h) { /* 下端にぶつかった */ } こうやって4箇所判定していけばいいわけです。 障害物と自機の衝突判定についてはNo.2で回答した通りです。 >数秒は意図した通りに移動できるのですが何故かキャラを移動しても、しなくても数秒後にフォームがとまってしまい動かなくなります。 申し訳ありませんがC#の作法をほとんど忘れてしまったため、具体的な指摘が出来ない状態です。 >class GraphicsEx : Form >Application.Run(new GraphicsEx()); ただ一つ言えるのはkinoshita_garyuさんはコンソールアプリと書かれてますが、これは間違いなくフォームアプリです。 あとOnPaintメソッドは、ウィンドウが移動されるなどして再描画が必要になったら呼び出されるイベント系の関数です。この関数内でループ処理をするのはバグ要因に成り得ると思います。 正しいループ処理する場所については、こちらを参考に。 http://www.clks.jp/csg/gt001.html
お礼
画面端の判定まで回答いただきありがとうございます。 >ただ一つ言えるのはkinoshita_garyuさんはコンソールアプリと書かれてますが、これは間違いなくフォームアプリです。 出力先をコンソールにしていたので気にせず普通に勘違いしていましたorz恥ずかしい話ですが。 正しくループ処理するのははじめから不安だったので助かりました。参考にさせていただきます。
- sankaku197
- ベストアンサー率47% (29/61)
すみません、誤植です。 MDXの参考はこちら。 ↓ mdの参考はこちら。
お礼
まともに実行もできない駄文ではありますがもう少しお付き合いいただけたら嬉しいです。 回答ありがとうございました。
補足
g.FillRectangle(brush, 160, 360, 40, 40); // 壁 //7 g.FillRectangle(brush, 200, 280, 120, 40); // 壁 //8 (brush, 160, 480, 40, 40); // 壁 //9 (brush, 240, 80, 40, 80); // 壁 //10 (brush, 240, 200, 40, 80); // 壁 //11 (brush, 200, 360, 80, 80); // 壁 //12 (brush, 240, 480, 40, 80); // 壁 //13 (brush, 320, 40, 80, 80); // 壁 //14 while (true) { g.FillEllipse(backbrush3, oldx, oldy, size, size); oldx = x1; oldy = y1; brush.Color = Color.LightSeaGreen; g.FillEllipse(brush, x1, y1, size, size); Thread.Sleep(100); ConsoleKeyInfo c = Console.ReadKey(); switch (c.Key) { case ConsoleKey.UpArrow: y1 -= width; break; case ConsoleKey.DownArrow: y1 += width; break; case ConsoleKey.LeftArrow: x1 -= height; break; case ConsoleKey.RightArrow: x1 += height; break; case ConsoleKey.Escape: Application.Exit(); break; } } } } } 壁をすべて書くとすごい文字数になったので、略して書きます。 壁を略して書かずにそのままプログラムを実行するとできるとは思いますが、キャラの移動するしないにかかわらず、プログラム実行後数秒ほどで止まると思いますorz
- sygh
- ベストアンサー率76% (42/55)
「ゲームプログラマになる前に覚えておきたい技術」(秀和システム、平山 尚) 衝突判定に関する章(8章)を読んでください。まずはこの本を買うことです。 上記の書籍はC++ユーザー向けですが、C#が多少なりとも使えるのであれば、C++のロジック部分はそれなりに理解できるはず。 DirectXはC++中級者以上でないと使いこなすのが難しいため、C#ユーザーであればまずXNAを使ったゲーム開発にチャレンジしてみては? ちなみに「コンソール アプリケーション」というのはコマンド プロンプト上で動作するような文字ベースのプログラムのことですが、「Windowsフォーム アプリケーション」と勘違いしていませんか? 用語を間違えると回答者の皆さんも混乱するので。
お礼
回答ありがとうございました。 やっぱりDirectXは難しいですかorz Windowsフォームアプリケーションはあんまり使ったことないので分かりませんが、コンソールアプリケーションよりゲーム作りに向いてるのかな?って思って書きました。紛らわしい書きかたしてすみません。 紹介していただいた本に関しては検討します。ありがとうございました。
補足
回答ありがとうございました。 プログラムの添付を忘れていました。すみません。 壁は画面の範囲と範囲内の四角形(障害物)を壁として壁がないところを進んでいく迷路、あるいはイライラ棒みたいにした感じです。実際には迷路の中に敵を出現させますが。 おおまかなプログラムはこんな感じです。無駄が多いですが(汗 namespace question { class GraphicsEx : Form { int size = 40; //キャラのサイズ static void Main(string[] args) { Console.WriteLine("マップを表示"); Application.Run(new GraphicsEx()); } public GraphicsEx() { int max, may; max = 900; may = 600; Text = "GraphicsEx"; BackColor = Color.SkyBlue; ClientSize = new Size(max, may); } protected override void OnPaint(PaintEventArgs pea) { Graphics g = pea.Graphics; Pen pen = new Pen(Color.White, 2); Pen extent = new Pen(Color.Black, 5); //外側の壁 SolidBrush brush = new SolidBrush(Color.DeepPink); SolidBrush backbrush3 = new SolidBrush(Color.SkyBlue); //描画を消す背景色です int space, x1, y1,oldx,oldy; //x1とy1が自キャラの座標ですが変える分には問題ありません space = 40; x1 = space ; //自キャラの座標をスタート位置にもって行きます y1 = space ; oldx = oldy = 0; //描画の軌跡を消す変数です //画面の範囲 g.DrawRectangle(extent, space, space, 720, 520); //マップ作成 g.FillRectangle(brush, 81, 81, 38, 78); //1 壁 g.FillRectangle(brush, 80, 200, 80, 80); //2 壁 g.FillRectangle(brush, 40, 320, 40, 80); //3 壁 g.FillRectangle(brush, 80, 440, 40, 80); //4 壁 g.FillRectangle(brush, 160, 40, 40, 80); // 壁 //5 g.FillRectangle(brush, 120, 320, 40, 80); // 壁 //6 次に続きを書きます。