質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

1回答

5838閲覧

テトリスの衝突判定がうまくできない

hozumi_45

総合スコア8

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2014/12/22 17:16

下記のコードでテトリスを作ったのですがミノブロックが壁にめり込んでしまいます。考え方自体はあっていると思うのですが、どうしても内部だけで動き、積みあがる処理ができません。大変申し訳ありませんが下記のコードのどこが問題なのかご指摘いただけないでしょうか?よろしくお願いいたします。

lang

1コード

import java.applet.Applet;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;

public class Tetris extends Applet implements Runnable,KeyListener {
/*縦22マス/
public static final int HEIGHT=22;
/*横13マス/
public static final int WIDTH=13;
/*ブロックの大きさ/
public static final int SIZE =30;

private int [][]field=new int[WIDTH][HEIGHT]; /**色の選択*/ public static final Color[] COLOR_SELECT={Color.WHITE,Color.ORANGE,Color.GREEN,Color.YELLOW,Color.GRAY,Color.MAGENTA,Color.BLUE,Color.RED,Color.BLACK}; /**ブロックの向き*/ public static final int DIRECTION=0; public static final int SPACE=0; public static final int WALL=1; /**中心のブロックの初期座標*/ Point point = new Point(6,0); /**テトリミノの座標*/ Point minoPoint; /**ブロックの種類*/ private Point data[][][]= //L字型ブロック {{{new Point(-1,0),new Point(0,0),new Point(1,0),new Point(-1,1)},// 初期 {new Point(0,-1),new Point(1,-1),new Point(0,0),new Point(1,1)},// 90度回転 {new Point(1,0),new Point(0,0),new Point(0,1),new Point(1,1)}, // 180度回転 {new Point(-1,-1),new Point(0,-1),new Point(0,0),new Point(0,1)},},//270度回転 //田字型ブロック {{new Point(-1,0),new Point(0,0),new Point(-1,1),new Point(0,1)}, // 初期 {new Point(-1,0),new Point(0,0),new Point(-1,1),new Point(0,1)}, // 90度回転 {new Point(-1,0),new Point(0,0),new Point(-1,1),new Point(0,1)}, // 180度回転 {new Point(-1,0),new Point(0,0),new Point(-1,1),new Point(0,1)},},// 270度回転 //I字型ブロック {{new Point(-2,0),new Point(-1,0),new Point(0,0),new Point(1,0)}, // 初期 {new Point(0,-1),new Point(0,0),new Point(0,1),new Point(0,1)}, // 90度回転 {new Point(-2,0),new Point(-1,0),new Point(0,0),new Point(1,0)}, // 180度回転 {new Point(0,-1),new Point(0,0),new Point(0,1),new Point(0,2)},},// 270度回転 //Z字型ブロック {{new Point(0,0),new Point(1,0),new Point(-1,1),new Point(0,1)}, // 初期 {new Point(-1,-1),new Point(-1,0),new Point(0,0),new Point(0,1)}, // 90度回転 {new Point(0,0),new Point(1,0),new Point(-1,1),new Point(0,1)}, // 180度回転 {new Point(-1,-1),new Point(-1,0),new Point(0,0),new Point(0,1)},}, // 270度回転 //T字型ブロック {{new Point(-1,0),new Point(0,0),new Point(1,0),new Point(0,1)}, // 初期 {new Point(0,-1),new Point(0,0),new Point(1,0),new Point(0,1)}, // 90度回転 {new Point(0,0),new Point(-1,1),new Point(0,1),new Point(1,1)}, // 180度回転 {new Point(0,-1),new Point(-1,0),new Point(0,0),new Point(0,1)},}, // 270度回転 //逆Z字型ブロック {{new Point(-1,0),new Point(0,0),new Point(0,1),new Point(1,1)}, // 初期 {new Point(1,-1),new Point(0,0),new Point(1,0),new Point(0,1)}, // 90度回転 {new Point(-1,0),new Point(0,0),new Point(0,1),new Point(1,1)}, // 180度回転 {new Point(1,-1),new Point(0,0),new Point(1,0),new Point(0,1)},}, // 270度回転 //逆L字型ブロック {{new Point(-1,0),new Point(0,0),new Point(1,0),new Point(1,1)}, // 初期 {new Point(0,-1),new Point(1,-1),new Point(0,0),new Point(0,1)}, // 90度回転 {new Point(0,0),new Point(-1,1),new Point(0,1),new Point(1,1)}, // 180度回転 {new Point(0,-1),new Point(0,0),new Point(-1,1),new Point(0,1)},}};// 270度回転 /**乱数生成*/ Random random = new Random(); /**ランダムな色のブロック表示*/ private int colorSelect =random.nextInt(7)+2; /**ランダムな形のブロック表示*/ private int blockSelect =random.nextInt(7)+2; /**初期化処理*/ @Override public void init(){ addKeyListener(this); requestFocus(); for(int y=0;y<HEIGHT;y++) { for(int x=0;x<WIDTH; x++) { field[x][y]=SPACE; } } for (int x=0;x<WIDTH;x++) { field[x][HEIGHT-1]=WALL; } for(int y=0;y<HEIGHT;y++) { field[0][y]=WALL; field[WIDTH-1][y]=WALL; } initBlock(); for(int i=0;i<4;i++){ minoPoint=data[blockSelect][DIRECTION][i]; } } /**@param e KeyEvent e*/ @Override public void keyPressed(KeyEvent e){ int key = e.getKeyCode(); if (key==KeyEvent.VK_LEFT){// 方向キー左が押されたとき if(field[(point.x-1)+minoPoint.x][point.y+minoPoint.y]==SPACE){// ブロックがSPACEのとき point.x--; repaint(); } }else if (key==KeyEvent.VK_RIGHT){// 方向キー右が押されたとき if(field[(point.x+1)+minoPoint.x][point.y+minoPoint.y]==SPACE){// ブロックがSPACEのとき point.x++; repaint(); } }else if (key==KeyEvent.VK_DOWN){// 方向キー下が押されたとき if(field[point.x+minoPoint.x][(point.y+1)+minoPoint.y]==SPACE){// ブロックがSPACEのとき point.y++; repaint(); }else{// 底辺もしくは他のブロックに接したとき initBlock(); field[point.x+minoPoint.x][point.y+minoPoint.y]=colorSelect; repaint(); } }else if(key==KeyEvent.VK_SPACE){//回転させる処理 } } @Override public void keyReleased(KeyEvent e){ } @Override public void keyTyped(KeyEvent e){ } /**スレッド開始*/ @Override public void start(){ Thread th = new Thread(this); th.start(); } /**落下メソッド*/ @Override public void run(){ while(true){ try { Thread.sleep(1000); // 1秒 } catch (InterruptedException e) { e.printStackTrace(); } if(field[minoPoint.x+point.x][minoPoint.y+(point.y+1)]==SPACE){// ブロックがSPACEのとき point.y++; repaint(); }else{//底辺もしくは他のブロックに接したとき initBlock(); field[minoPoint.x+point.x][minoPoint.y+point.y]=colorSelect; } repaint(); } } /**@param g Graphics*/ @Override public void update(Graphics g){ paint(g); } /**@param g Graphics*/ @Override public void paint(Graphics g){ Dimension size=getSize(); Image back=createImage(size.width, size.height); Graphics buffer=back.getGraphics(); // 移動ブロックの描画 if(field[point.x+minoPoint.x][point.y+minoPoint.y]==SPACE){ buffer.setColor(COLOR_SELECT[colorSelect]); buffer.fillRect((point.x+minoPoint.x)*SIZE,(point.y+minoPoint.y)*SIZE,SIZE,SIZE); } // 外壁の描画 for(int i = 0;i <WIDTH;i++){ for(int j = 0;j <HEIGHT;j++){ if(field[i][j]!=SPACE){ // fieldがSPACE以外のとき buffer.setColor(COLOR_SELECT[field[i][j]]); buffer.fillRect(i*SIZE,j*SIZE,SIZE,SIZE); } } } buffer.setColor(COLOR_SELECT[colorSelect]); for (int i = 0; i<4; i++) { buffer.fillRect(SIZE*(point.x+data[blockSelect][DIRECTION][i].x),SIZE*(point.y+data[blockSelect][DIRECTION][i].y),SIZE,SIZE); } // マス目描画 buffer.setColor(Color.black); for(int i=0;i<=HEIGHT;i++){ buffer.drawLine(0,i*SIZE,WIDTH*SIZE,i*SIZE); } for(int j=0;j<=WIDTH;j++){ buffer.drawLine(j*SIZE,0,j*SIZE,HEIGHT*SIZE); } g.drawImage(back, 0, 0, this); } /**ランダムな色で次のブロックを生成*/ public void initBlock(){ point = new Point(6, 0);// 初期配置に戻す colorSelect = random.nextInt(7)+2; blockSelect =random.nextInt(7)+2; }

}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

まず、キー入力時に壁にめり込んでしまう問題は、ブロックの各セルの位置ごとに判定が必要ですね。
下記のように、「動かせるかどうか」を判定するメソッドを定義して、それを呼ぶようにすると良いです。

lang

1 if (key==KeyEvent.VK_LEFT){// 方向キー左が押されたとき 2 // if(field[(point.x-1)+minoPoint.x][point.y+minoPoint.y]==SPACE){// ブロックがSPACEのとき 3 if (canMove(-1, 0)) { // ★ここ★ 4 point.x--; 5 repaint(); 6 } 7 } 8 // 右方向の場合は、canMove(1, 0)、 9 // 下方向の場合は、canMove(0, 1)で判定 10 11// (中略) 12 13 /** 14 * ブロックが動かせるかどうかを調べる。 15 * @param xRel X方向の相対値 16 * @param yRel Y方向の相対値 17 * @return 動かせるなら true そうでなければ false 18 */ 19 boolean canMove(int xRel, int yRel) { 20 Point[] pa = data[blockSelect][DIRECTION]; 21 for (int i = 0; i < 4; i++) { 22 Point p = pa[i]; 23 if (field[point.x + p.x + xRel][point.y + p.y + yRel] != SPACE) { 24 return false; 25 } 26 } 27 return true; 28 }

積み上げる部分は、下記のような「ブロックを固定する」処理を行うメソッドを定義して、それを呼ぶようにすると良いと思います。
直接は関係ないですが、普通のスレッドから描画処理を呼ぶのは良くないので、EventQueue.invokeLaterを使います。

lang

1 /**落下メソッド*/ 2 @Override 3 public void run() { 4 Runnable callRepaint = new Runnable() { 5 public void run() { 6 repaint(); 7 } 8 }; 9 while (true) { 10 try { 11 Thread.sleep(1000); // 1秒 12 } catch (InterruptedException e) { 13 e.printStackTrace(); 14 } 15 if (canMove(0, 1)) { 16 point.y++; 17 } 18 else {//底辺もしくは他のブロックに接したとき 19 fixBlock(); // ★ここ★ 20 initBlock(); 21 } 22 EventQueue.invokeLater(callRepaint); // ★必ず呼ばれるので1箇所で良いでしょう 23 } 24 } 25 26 /** 27 * ブロックを固定する。 28 */ 29 void fixBlock() { 30 Point[] pa = data[blockSelect][DIRECTION]; 31 for (int i = 0; i < 4; i++) { 32 Point p = pa[i]; 33 field[point.x + p.x][point.y + p.y] = colorSelect; 34 } 35 }

投稿2014/12/23 01:20

argius

総合スコア9390

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hozumi_45

2014/12/23 06:28

argiusさん、何度も助けていただきありがとうございます。上記のコードを参考にさせていただきました。おかげ様でなんとか処理を成功させることができました。もう少しで完成させることができそうです!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問