テトリスの作り方について質問

このQ&Aのポイント
  • テトリスの作り方について質問します。ゲームプログラミングの勉強をしています。今のお題はテトリスなのですが、積み上がるブロックの表現方法について悩んでいます。
  • テトリスの作り方について質問します。ゲームプログラミングの勉強をしていますが、積み上がるブロックの表現方法に苦戦しています。
  • テトリスの作り方について質問します。現在、ゲームプログラミングの勉強中で、積み上がるブロックの表現方法についてアドバイスをお願いします。
回答を見る
  • ベストアンサー

テトリスの作り方について質問します。

テトリスの作り方について質問します。 ゲームプログラミングの勉強をしています。 今のお題はテトリスなのですが、少々行き詰ってしまいました。 今の進行状況ですが、 落下ブロックの生成 ↓ 自動落下処理 ↓ キー判定でブロック移動処理 ↓ 徐々にブロックが落ちてきて、一番下のラインまで落ちる までいったのですが、その次のブロックの着地処理といいますか、落下ブロックが下まで落ちた時に積み上がる処理のイメージが湧かずに困っています。 まだ、『積み上がったブロックが揃っている段があるか』まで実装するつもりはありませんので、まず『積み上がるブロックの表現』について悩んでいます。 例えば、積み上がるブロック用のPictureBoxを用意して、落下ブロックをコピーして描画していく、とか、背景になっている親コントロールに直接描画してしまう、とか。 いずれにしても、後々、『積み上がったブロックに揃っている段があり、そのラインが消えて、そこから上のブロックがダンッ!と落ちる』処理がやり易くなる方法を探しています。 何かアドバイスをください。

質問者が選んだベストアンサー

  • ベストアンサー
  • yama1718
  • ベストアンサー率41% (670/1618)
回答No.5

私よりもゲームプログラムに長けた人からアドバイスがあるかなと思っていたのですが、 ゲームなどでは画像表示にBitBlt関数を使う事が多いみたいですね。 http://www005.upp.so-net.ne.jp/h-masuda/vb6/vb6api/vb6api04.html それを使った方法を1つ考案しました。 1.非表示のバッファ用ピクチャボックスを用意する。 2.一段消して、それより上部の画像をバッファにBitBltでコピーする。 3.バッファから表示用ピクチャボックスに座標を下にずらしてコピーする。 単純に画像の表示をずらすだけだと一番上が消し残しになるので、ずらす分だけ画像の上部を空白にしておいて、上部の空白を含めて画像を転送すると消し残しを削除する手間が省けますね。 5.あとはこれを数回繰り返す、どれだけずつずらすかは処理速度や表示イメージによるが、マス目の1/2~1/4ぐらいが適当でしょうか。

hatopo7979
質問者

お礼

Win32APIのBitBlt関数ですね。 VBにも、GraphicsクラスのCopyFromScreen関数という、たぶん、BitBlt関数と似ている(BitBlt関数をラップした?)ものを発見したので、そっちを使おうかと思っていました。 (関数の説明では、ビットブロック転送を行う、などと書かれています。) API関数の宣言と使い方の研究は寄り道になりそうなので。 CopyFromScreen関数かBitBlt関数を使って、示していただいた方法を検討してみたいと思います。 アドバイスありがとうございます。

その他の回答 (5)

  • yama1718
  • ベストアンサー率41% (670/1618)
回答No.6

補足で、今まで発売された多くのテトリスを含めた落ち物系のパズルを観察すれば、落下ブロックの落下と移動・回転はマス目単位が圧倒的に多いです。 瞬間的に中間表示している物はありそうですが、じわじわとリアルに落下するゲームはあまり見た事がありません。 これは、プログラムが非常に複雑になるのと、動作が遅くなったり操作がやりにくくなるのが原因だと思います。 あと落下ブロックが引っ掛かって固定される直前にコンマ何秒かの待ち時間があります、上級者はこの瞬間に移動したり回転してハメ込みますね。 質問者様が悩んでいる段消し後の落下も、実はマス目単位の表示で済ましているゲームも多いですね。 この部分はプレイヤーが操作を介入しないので、演出をしやすい部分ですし、特にぷよぷよなど連鎖が発生するゲームでは見せ場でもありますから、手を抜いて瞬間的に動かしたり、凝ってアニメーションさせたりとゲームによってピンキリです。 操作や動作、演出などは、他人やプロが作ったゲームをじっくり観察するだけでも発見する事があると思います。

noname#149523
noname#149523
回答No.4

2次元配列上の4変数で1ブロックとするというのはどうでしょうか。

hatopo7979
質問者

お礼

なるほど。落下ブロックについての考え方ですね。 参考にさせていただきます。 おかげ様でいいアイディアが浮かびました。 積みブロックと落下ブロックを1つの二次元配列で管理できるアルゴリズムです。 落下中のブロックがある座標に全て1をいれておいて、積まれているブロックの座標に2をいれる。 具体的には、 落下前の条件は、『1の値がある座標の下の座標に2があるか調べる』 ↓ 『2が無ければ落下、あれば1を2に変更』 ↓ 落下処理では、『1の値を各々、下から順番に1つ下へ移動させる』 私と一緒にテトリスのノウハウを築き上げてみませんか? 引き続き新しいアドバイスお待ちしています。

  • yama1718
  • ベストアンサー率41% (670/1618)
回答No.3

>中間の落下中の表現ができないんです! そこまで凝りたいのですね、 なら画像を少しずつ下方向に部分的にコピーするとかスクロールさせるとかですね。 どのみち1段下にスクロールさせるのですから、その中間の表示を入れるだけですね。 結構面倒なグラフィック処理が必要だと思います。 色々と検索してみましたが、良さそうなVBのサンプルは見つけられませんでした。 シェアウェアで「VB用ピクチャーボックススクロール関数」が見つかったぐらいかな。 http://www.vector.co.jp/soft/win95/prog/se239518.html

hatopo7979
質問者

お礼

ご回答いただきありがとうございます。 そうですよね、面倒そうなんです。 揃って消えたラインから下は動かないのに、そこから上だけを下方向にスクロールするだなんて・・・ いろいろ考えてみていますが、いいアイディアが浮かびません。 積みブロックを1マス単位でPictureBoxとして生成して、揃って消えたらその上半分のPictureBoxを下方向に移動、とか・・・? 誰か正解を~。

  • ts3m-ickw
  • ベストアンサー率43% (1248/2897)
回答No.2

先人の知恵を借りましょう。 VisualBASICでプログラム組めるなら↓のソースを読むのは苦労しないでしょう。 わずか565バイトテトリスのプログラミング解説 http://zapanet.info/blog/item/1125 で、参考にしながらもオリジナルのプログラムを組めるようになれば一歩前進。

hatopo7979
質問者

お礼

せっかくご回答くださったのですが、 コードが読み難すぎて内容がよくわかりませんでした。 もう少し解り易く解説されているWebページなどはありませんか?

  • yama1718
  • ベストアンサー率41% (670/1618)
回答No.1

私ならマス目の二次元配列を作りますね。 落下ブロック(テトリミノと言うらしい)は一段落ちる毎に配列を見て引っ掛かるかどうか判定させる 引っ掛かったら落下ブロックの形を配列に書き込む 揃ったラインがあるかどうかの判定 揃ったラインの消去と上のブロックの落下 次の落下ブロックの生成へ 落下ブロックの生成で配列と重なっている部分が出たら終了! こんな感じでしょうか。

hatopo7979
質問者

補足

積まれたブロックを二次元配列で管理していく、という方法ですよね。 それは解ってはいたのですが、なんというか・・・ 二次元配列で目に見えないデータ管理する部分はわかるんですが、 私の悩みはむしろ目に見える部分の表現なんです。 というのは、 テトリミノが着地した位置に対応する配列の座標にデータを書き込み、積みブロックを描画するとして、 揃ったラインが消えた後、その上にあった積みブロックが落下後、一瞬で書き換わるだと、落ちてきた感じがしないということです。 テトリミノが下に着いた ↓ そのラインが揃った ↓ 揃ったラインが消えた ↓ 揃ったラインの上に積まれていたブロックがダンッ!と落ちる ※この時のアニメーションが出来ずに困っているんです。 落下前の配列を基に描画 ↓ 落下後の配列を基に描画 だと、中間の落下中の表現ができないんです! 悩みが正しく伝わりましたでしょうか? 引き続き、お待ちしております。

関連するQ&A

  • Javaでテトリスを作成(OOPで)

    JavaでGUIのテトリスを作成しているのですが、処理でちょっと困っています。 次のようにオブジェクト指向で作っているのですが、なにか違和感が感じます。 問題点があったら教えてください>< Field.java テトリス全体のmap どこにブロックがあるかを保持 Block.java テトリスのBlock(テトリミノ)のスーパークラス。このサブクラスでそのBlockの形を保持 TetrisProcess.java テトリスの処理をする。Blockの移動、移動できるかを確認。Threadをたてる。 Blockが落ちてくる処理なんですが、TetrisProcessからBlockに『次の形はなに?』と聞いて、Fieldに『次の形はこれだから、下(横)へ進める?』っていう処理を考えているのですがどうでしょうか?? 駄文、本当にごめんなさい・・・

  • VB .net Form_Load時、または関数内でPictureBoxにライン描画を行ないたい。

    Form上にPictureBox,Buttonを配置して、Botton_Click処理時にPictureBox上へのライン描画は Dim g As Graphics = PictureBox1.CreateGraphics g.DrawLine(Pens.Red, 0, 0, 100, 200) g,Dispose() にて行なえましたが、同じような描画を Form_Load時に上記の処理を入れても全く描画されません。Button_Clickイベントのように1クッション置かないと実現できないのでしょうか? Form_Load時、関数内などで周期的にライン描画を 行なってやりたいのですが、どなたか解決方法をご存知の方がいましたら回答の程よろしくお願いいたします。

  • Pictureboxについて

    VB.netで開発を行っていますが、Pictureboxの描画処理で困っています。 プログラム、処理は以下のような感じです。 プログラム ・1つのPictureboxに対して、8台の機械の状態をそれぞれグラフ描画して、さらに全ての機械の実績値の合計を1つのグラフに  描画する。(計9つのグラフを描画します。) ・画面で任意の機械の絵を選択、スクロールで移動できます。(わかりづらいですが、ライン構想のようなものです。) ・スレッドで10秒間隔で毎回更新されます。(毎回描画しています。) 以上のような描画処理を行っておりますが、納品するパソコンがタッチパネルPC(windows xp embedded)なので、 スペックが低く、機械の絵を動かすと、描画が遅いと客から指摘を受けました。 機械の絵を動かした時、グラフを含め全ての描画を行っていることが原因だと思いますが、前回描画したグラフの内容を消去しないまま、 現在、動かしている機械の絵のみ描画するという方法はPictureboxで可能でしょうか。 (1つのPictureboxの特定の部分のみ描画したい。) また、何か他によい方法があれば教えて頂けないでしょうか。

  • VB2005 リソースの開放

    VBは始めたばかりで、妙な質問ですが。 CAD等で直線描画中のラバーライン(始点は決定で終点が未定)の処理ですが Private Sub MouseMoveイベント Dim g As Graphics = PictureBox1.CreateGraphics() If ラバーライン描画中 Then ラバーライン描画処理 End If g.Dispose() End Sub Dim g As Graphics = PictureBox1.CreateGraphics()とg.Dispose()の記述はこのSubの中に書かなくてはいけないのですか? 描画処理中リソースの開放g.Dispose()するのは効率よさそうではないみたいで。 終点が決定してから開放の方が気分的にいいのですが。 なにかもっといい方法があったら御指南お願いします。

  • C# PictureBoxへの描画を行うとメッセージボックスが表示されません。

    いつもお世話になっております。 ふと、PictureBoxに描画をしてみようかと思い Paintイベントに以下のようにして描画を行いました。   myBitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height);   Graphics g = Graphics.FromImage(myBitmap);   pictureBox1.Image = myBitmap;      ・      ・(g.FillRectangle(・・・);など)      ・ (myBitmapはBitmap型のグローバル変数です。) PictureBoxは、自由にサイズ変更可能なフォームに貼り付け、四方をanchorで固めています。 そのためサイズが変更されるたびに、描画するときBitmapのサイズも変更しないといけないので この処理を毎回通っています。 (その部分が何だか無駄な気がするのですが、他にいい方法が思いつきませんでした。) ところが、描画はうまくいったのですが、メッセージボックスを出すと そのメッセージボックスが一度Altキーを押さないと表示されません。 色々調べて、ダブルバッファリングというものがあると知りました。 そこでPaintイベントで最初にこの処理をし   Image image = new Bitmap(pictureBox1.Width, pictureBox1.Height);   g = Graphics.FromImage(image); gに描画し終わってから   e.Graphics.DrawImage(image, 0, 0); としてみると、今度はフォームを移動するのにも一瞬フリーズするようになってしまいました。 (あまり深くプログラミングをしたことがないので、理解しきれなくてやり方が悪いのかも知れません・・・) メッセージボックスが表示されないのは、PictureBoxの描画のため 他のコントロールの描画ができていなためだと推測しているのですが どう直していいかわかりません。 どなたか、わかる方がいましたらよろしくお願いします。 <補足> OS:Vista VisualStudio2008 .NET Framework3.5

  • PictureBoxの描画を消さない方法

    VisualBasic2005において、プログラミングを制作しています。 計測器にて計測した値を読み込み、くり返し処理を用いてPictureBoxに描画したいのですが、前のデータを消さずに次のデータをプロットしていく方法がわかりません。 前のデータを消さずに塗り足していく方法はないでしょうか? また、この値はコンボボックスから読み込んでいるのですが、くり返し処理によってコンボボックスの値を読み取る場合、終了値はどのように設定すればいいのでしょう? 初期値はいいとして、終了値は計測回数によって変わるため明確な値はないのですが、「値がなくなったら終わり」ということを指定するにはどうコードを組めばいいのでしょうか? ご指導よろしくお願いいたします。 全体的な流れを記しておきます。 計測→コンボボックスに値を格納→ボタンによってコンボボックスの値を(全て)読み込み、PictureBoxに全て描画 コンボボックスの値の読み込み、描画にくり返し処理を用いています。 よろしくお願いいたします。

  • アクションゲームを作りたいのですが・・・

    「マ●オ」のようなアクションゲームを作りたいと考えているのですが手こずっています。 マップ上にブロックを配置して乗れるようにしたいのですが、どうプログラミングしていいかわかりません。ブロックの描画は配列を使って表現することができましたが、乗っているように見せるにはどういった処理をさせればいいのでしょう? なにぶん初心者なもので、できるだけわかりやすく説明していただけるとうれしいです。

  • Javascriptテトリスに機能を追加したいです

    ネットでソースを落としたテトリスに次の機能を追加したいのですが、可能でしょうか? 1、ゲーム開始のボタンを追加して、それが押された後にゲームを開始する。 2、背景画像を選択 現在のソース HTML <!DOCTYPE html> <html> <head> <title>Tetris</title> <meta charset = "UTF-8"> <h1>テトリス</h1> <link rel='stylesheet' href='style.css' /> </head> <body background = "hakugin.jpg" /body> <body> <audio id="clearsound" src="sound/pop.ogg" preload="auto"></audio> <canvas width='300' height='600'></canvas> <script src='js/tetris.js'></script> <script src='js/controller.js'></script> <script src='js/render.js'></script> </body> </html> js var COLS = 10, ROWS = 20; // 盤面のマスの数 var board = []; // 盤面の状態を保持する変数 var lose; // 一番うえまで積み重なっちゃったフラグ var interval; // ゲームタイマー保持用変数 var current; // 現在操作しているブロック var currentX, currentY; // 現在操作しているブロックのいち // ブロックのパターン var shapes = [ [ 1, 1, 1, 1 ], [ 1, 1, 1, 0, 1 ], [ 1, 1, 1, 0, 0, 0, 1 ], [ 1, 1, 0, 0, 1, 1 ], [ 1, 1, 0, 0, 0, 1, 1 ], [ 0, 1, 1, 0, 1, 1 ], [ 0, 1, 0, 0, 1, 1, 1 ] ]; // ブロックの色 var colors = [ 'brown', 'orange', 'blue', 'yellow', 'red', 'green', 'pink' ]; // shapesからランダムにブロックのパターンを出力し、盤面の一番上へセットする function newShape() { var id = Math.floor( Math.random() * shapes.length ); // ランダムにインデックスを出す var shape = shapes[ id ]; // パターンを操作ブロックへセットする current = []; for ( var y = 0; y < 4; ++y ) { current[ y ] = []; for ( var x = 0; x < 4; ++x ) { var i = 4 * y + x; if ( typeof shape[ i ] != 'undefined' && shape[ i ] ) { current[ y ][ x ] = id + 1; } else { current[ y ][ x ] = 0; } } } // ブロックを盤面の上のほうにセットする currentX = 5; currentY = 0; } // 盤面を空にする function init() { for ( var y = 0; y < ROWS; ++y ) { board[ y ] = []; for ( var x = 0; x < COLS; ++x ) { board[ y ][ x ] = 0; } } } // newGameで指定した秒数毎に呼び出される関数。 // 操作ブロックを下の方へ動かし、 // 操作ブロックが着地したら消去処理、ゲームオーバー判定を行う function tick() { // 1つ下へ移動する if ( valid( 0, 1 ) ) { ++currentY; } // もし着地していたら(1つしたにブロックがあったら) else { freeze(); // 操作ブロックを盤面へ固定する clearLines(); // ライン消去処理 if (lose) { // もしゲームオーバなら最初から始める newGame(); return false; } // 新しい操作ブロックをセットする newShape(); } } // 操作ブロックを盤面にセットする関数 function freeze() { for ( var y = 0; y < 4; ++y ) { for ( var x = 0; x < 4; ++x ) { if ( current[ y ][ x ] ) { board[ y + currentY ][ x + currentX ] = current[ y ][ x ]; } } } } // 操作ブロックを回す処理 function rotate( current ) { var newCurrent = []; for ( var y = 0; y < 4; ++y ) { newCurrent[ y ] = []; for ( var x = 0; x < 4; ++x ) { newCurrent[ y ][ x ] = current[ 3 - x ][ y ]; } } return newCurrent; } // 一行が揃っているか調べ、揃っていたらそれらを消す function clearLines() { for ( var y = ROWS - 1; y >= 0; --y ) { var rowFilled = true; // 一行が揃っているか調べる for ( var x = 0; x < COLS; ++x ) { if ( board[ y ][ x ] == 0 ) { rowFilled = false; break; } } // もし一行揃っていたら, サウンドを鳴らしてそれらを消す。 if ( rowFilled ) { document.getElementById( 'clearsound' ).play(); // 消滅サウンドを鳴らす // その上にあったブロックを一つずつ落としていく for ( var yy = y; yy > 0; --yy ) { for ( var x = 0; x < COLS; ++x ) { board[ yy ][ x ] = board[ yy - 1 ][ x ]; } } ++y; // 一行落としたのでチェック処理を一つ下へ送る } } } // キーボードが押された時に呼び出される関数 function keyPress( key ) { switch ( key ) { case 'left': if ( valid( -1 ) ) { --currentX; // 左に一つずらす } break; case 'right': if ( valid( 1 ) ) { ++currentX; // 右に一つずらす } break; case 'down': if ( valid( 0, 1 ) ) { ++currentY; // 下に一つずらす } break; case 'rotate': // 操作ブロックを回す var rotated = rotate( current ); if ( valid( 0, 0, rotated ) ) { current = rotated; // 回せる場合は回したあとの状態に操作ブロックをセットする } break; } } // 指定された方向に、操作ブロックを動かせるかどうかチェックする // ゲームオーバー判定もここで行う function valid( offsetX, offsetY, newCurrent ) { offsetX = offset

  • アクションスクリプト3.0のエラーが分からないです

    入力するために使っているソフトはAdobe Flash CS4です http://www40.atwiki.jp/spellbound/pages/1028.html このwikiを参考にテトリス製作をしているのですが、初心者なのでエラーが全く分かりません・・ 調べてもいまいち把握できず・・・; 盤面の部分で、 // ブロックが地面に落ちて、位置が確定した後の処理 private function endProcess():void { // ENTER_FRAMEを一度止める removeEventListener(Event.ENTER_FRAME, onEnterFrame); lock(); // ブロックを固定 deleteLine(); // 削除 draw(); // 描画 1093:シンタックスエラー draw(); // 描画って出てしまいます>_< 分かる方教えてください;;

  • プリント基板の段積みについて。

    いつもお世話になります。 プリント基板の装置実装で困っていることがあり、どなたか御知恵を拝借したくよろしくお願いします。 現在小筐体にプリント版を5枚段積みしております。実装方法は一番下の段は筐体片面に圧入ナットを取付け、その上の段はカンカクボルトで固定です。プリント板の間の接続が筐体の外形の条件により、スタックコネクタの接続となっており、上から取りつけていくことが、必須となっています。 ここで問題なのですが、製造側からネジの本数の多さをクレームとしてあげられており、困っております。 何か取り付け方法でいい知恵はないでしょうか? 側面実装となっておりますので、片持ち状態で落下試験に耐えるような構造でないとまずいのです。

専門家に質問してみよう