android テトリス
解決済
回答 1
投稿
- 評価
- クリップ 0
- VIEW 2,045
アンドロイドアプリでテトリスを作成しています。
次に落ちてくるブロックを別のリニアーレイアウトに表示したいのですがやり方がわかりません。どうしたらいいでしょうか。
ソースコード
public class MainActivity extends AppCompatActivity {
private class FieldView extends SurfaceView {
Random mRand = new Random(System.currentTimeMillis());
int[][][] blocks = {
//省略
};
int[][] block = blocks[mRand.nextInt(blocks.length)];
int posx=4, posy;
int mapWidth = 10;
int mapHeight = 20;
int[][] map = new int[mapHeight][];
public FieldView(Context context) {
super(context);
setBackgroundColor(0xFFFFFFFF);
setFocusable(true);
setFocusableInTouchMode(true);
requestFocus();
}
public void initGame() {
for (int y = 0; y < mapHeight; y++) {
map[y] = new int[mapWidth];
for (int x = 0; x < mapWidth; x++) {
map[y][x] = 0;
}
}
}
private void paintMatrix(Canvas canvas, int[][] matrix, int offsetx, int offsety, int color) {
ShapeDrawable rect = new ShapeDrawable(new RectShape());
rect.getPaint().setColor(color);
int h = matrix.length;
int w = matrix[0].length;
for (int y = 0; y < h; y ++) {
for (int x = 0; x < w; x ++) {
if (matrix[y][x] != 0) {
int px = (x + offsetx) * 60;
int py = (y + offsety) * 60;
rect.setBounds(px, py, px + 60, py + 60);
rect.draw(canvas);
}
}
}
}
boolean check(int[][] block, int offsetx, int offsety) {
if (offsetx < 0 || offsety < 0 ||
mapHeight < offsety + block.length ||
mapWidth < offsetx + block[0].length) {
return false;
}
for (int y = 0; y < block.length; y ++) {
for (int x = 0; x < block[y].length; x ++) {
if (block[y][x] != 0 && map[y + offsety][x + offsetx] != 0) {
return false;
}
}
}
return true;
}
void mergeMatrix(int[][] block, int offsetx, int offsety) {
for (int y = 0; y < block.length; y ++) {
for (int x = 0; x < block[0].length; x ++) {
if (block[y][x] != 0) {
map[offsety + y][offsetx + x] = block[y][x];
}
}
}
}
void clearRows() {
// 埋まった行は消す。nullで一旦マーキング
for (int y = 0; y < mapHeight; y ++) {
boolean full = true;
for (int x = 0; x < mapWidth; x ++) {
if (map[y][x] == 0) {
full = false;
break;
}
}
if (full) map[y] = null;
}
// 新しいmapにnull以外の行を詰めてコピーする
int[][] newMap = new int[mapHeight][];
int y2 = mapHeight - 1;
for (int y = mapHeight - 1; y >= 0; y--) {
if (map[y] == null) {
continue;
} else {
newMap[y2--] = map[y];
}
}
// 消えた行数分新しい行を追加する
for (int i = 0; i <= y2; i++) {
int[] newRow = new int[mapWidth];
for (int j = 0; j < mapWidth; j ++) {
newRow[j] = 0;
}
newMap[i] = newRow;
}
map = newMap;
}
/**
* Draws the 2D layer.
*/
@Override
protected void onDraw(Canvas canvas) {
ShapeDrawable rect = new ShapeDrawable(new RectShape());
rect.setBounds(0, 0, 750, 1100);
rect.getPaint().setColor(0xFFFFFFFF);
rect.draw(canvas);
paintMatrix(canvas, block, posx, posy, 0xFFFF0000);
paintMatrix(canvas, map, 0, 0, 0xFF808080);
}
int[][] rotate(final int[][] block) {
int[][] rotated = new int[block[0].length][];
for (int x = 0; x < block[0].length; x ++) {
rotated[x] = new int[block.length];
for (int y = 0; y < block.length; y ++) {
rotated[x][block.length - y - 1] = block[y][x];
}
}
return rotated;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_ENTER:
int[][] newBlock = rotate(block);
if (check(newBlock, posx, posy)) {
block = newBlock;
}
break;
case KeyEvent.KEYCODE_D:
if (check(block, posx + 1, posy)) {
posx = posx + 1;
}
break;
case KeyEvent.KEYCODE_A:
if (check(block, posx - 1, posy)) {
posx = posx - 1;
}
break;
case KeyEvent.KEYCODE_W:
int y = posy;
while (check(block, posx, y)) { y++; }
if (y > 0) posy = y - 1;
break;
case KeyEvent.KEYCODE_S:
if(check(block,posx,posy+1)){
posy = posy + 1;
}
break;
}
mHandler.sendEmptyMessage(INVALIDATE);
return true;
}
public void startAnime() {
mHandler.sendEmptyMessage(INVALIDATE);
mHandler.sendEmptyMessage(DROPBLOCK);
}
public void stopAnime() {
mHandler.removeMessages(INVALIDATE);
mHandler.removeMessages(DROPBLOCK);
}
private static final int INVALIDATE = 1;
private static final int DROPBLOCK = 2;
LinearLayout layout2;
/**
* Controls the animation using the message queue. Every time we receive an
* INVALIDATE message, we redraw and place another message in the queue.
*/
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case INVALIDATE:
invalidate();
break;
case DROPBLOCK:
if (check(block, posx, posy + 1)) {
posy++;
} else {
mergeMatrix(block, posx, posy);
clearRows();
layout2 =(LinearLayout)findViewById(R.id.lay2);
posx = 4; posy = 0;
block = blocks[mRand.nextInt(blocks.length)];
layout2.addView((View)mergeMatrix(block,posx,posy));
}
invalidate();
Message massage = new Message();
massage.what = DROPBLOCK;
sendMessageDelayed(massage, 500);
break;
}
}
};
}
FieldView mFieldView;
private void setFieldView() {
if (mFieldView == null) {
setContentView(R.layout.activity_main);
mFieldView = new FieldView(this);
LinearLayout layout = (LinearLayout)findViewById(R.id.lay);
layout.addView(mFieldView);
}
}
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
}
@Override
protected void onResume() {
super.onResume();
setFieldView();
mFieldView.initGame();
mFieldView.startAnime();
Looper.myQueue().addIdleHandler(new Idler());
}
@Override
protected void onPause() {
super.onPause();
mFieldView.stopAnime();
}
@Override
protected void onStop() {
super.onStop();
mFieldView.stopAnime();
}
class Idler implements MessageQueue.IdleHandler {
public Idler() {
super();
}
public final boolean queueIdle() {
return false;
}
}
}
です。
layout2.addView((View)mergeMatrix(block,posx,posy));
という記述でできるかと思ったのですがさすがにできませんでした。
イメージとしてはゲーム画面を左半分のリニアーレイアウトに割り当て、残りの半分のリニアーレイアウトの中の上の位置に次落ちてくるブロックを表示したいです。
どのように記述したらよいでしょうか。
必要そうでしたらxmlも載せます。
よろしくお願いします。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
0
次のブロックを管理するViewもSurfaceViewで管理し、ActivityがそのViewから次に表示するブロックの情報をFieldViewに渡すようにすればできそうですね。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.32%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2016/06/06 13:53
2016/06/07 10:35