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

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

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

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

解決済

2回答

724閲覧

テトリスにて障害存在による左右移動を制限したい

yasuaki640

総合スコア8

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

0クリップ

投稿2018/09/04 05:04

編集2018/09/06 15:31

前提・実現したいこと

html、jsを用いてブラウザ上で動作するテトリスゲームを作成しています。
キー入力による左右移動時について、障害物があるときのブロック移動を制限したいです。

発生している問題・エラーメッセージ

左右のセルに何もない状態においてブロックは問題なく左右移動します。
発生する問題は以下の二点です。

1.落下中のブロックが左右両端の列にあり左右移動を試みると、ブロックが変形します。
2.落下中のブロックが左右移動を試みると、固定されたブロックを貫通します。

main.js:208 Uncaught TypeError: Cannot set property 'className' of undefined at moveLeft (main.js:208) at HTMLDocument.onKeyDown (main.js:181) main.js:193 Uncaught TypeError: Cannot set property 'className' of undefined at moveRight (main.js:193) at HTMLDocument.onKeyDown (main.js:183)

該当のソースコード

lang

1document.getElementById("hello_text").textContent = "はじめてのJavaScript"; 2 3// キーボードイベントを監視する 4document.addEventListener("keydown", onKeyDown); 5 6var count = 0; 7 8var cells; 9 10// ブロックのパターン 11var blocks = { 12 i: { 13 class: "i", 14 pattern: [ 15 [1, 1, 1, 1] 16 ] 17 }, 18 o: { 19 class: "o", 20 pattern: [ 21 [1, 1], 22 [1, 1] 23 ] 24 }, 25 t: { 26 class: "t", 27 pattern: [ 28 [0, 1, 0], 29 [1, 1, 1] 30 ] 31 }, 32 s: { 33 class: "s", 34 pattern: [ 35 [0, 1, 1], 36 [1, 1, 0] 37 ] 38 }, 39 z: { 40 class: "z", 41 pattern: [ 42 [1, 1, 0], 43 [0, 1, 1] 44 ] 45 }, 46 j: { 47 class: "j", 48 pattern: [ 49 [1, 0, 0], 50 [1, 1, 1] 51 ] 52 }, 53 l: { 54 class: "l", 55 pattern: [ 56 [0, 0, 1], 57 [1, 1, 1] 58 ] 59 } 60}; 61 62loadTable(); 63setInterval(function () { 64 count++; 65 document.getElementById("hello_text").textContent = "はじめてのJavaScript(" + count + ")"; 66 if (hasFallingBlock()) { // 落下中のブロックがあるか確認する 67 fallBlocks();// あればブロックを落とす 68 } else { // なければ 69 deleteRow();// そろっている行を消す 70 generateBlock();// ランダムにブロックを作成する 71 } 72}, 200); 73 74/* ------ ここから下は関数の宣言部分 ------ */ 75 76function loadTable() { 77 cells = []; 78 var td_array = document.getElementsByTagName("td"); 79 var index = 0; 80 for (var row = 0; row < 20; row++) { 81 cells[row] = []; 82 for (var col = 0; col < 10; col++) { 83 cells[row][col] = td_array[index]; 84 index++; 85 } 86 } 87 88} 89 90function fallBlocks() { 91 // 1. 底についていないか? 92 for (var col = 0; col < 10; col++) { 93 if (cells[19][col].blockNum === fallingBlockNum) { 94 isFalling = false; 95 return; // 一番下の行にブロックがいるので落とさない 96 } 97 } 98 // 2. 1マス下に別のブロックがないか? 99 for (var row = 18; row >= 0; row--) { 100 for (var col = 0; col < 10; col++) { 101 if (cells[row][col].blockNum === fallingBlockNum) { 102 if (cells[row + 1][col].className !== "" && cells[row + 1][col].blockNum !== fallingBlockNum){ 103 isFalling = false; 104 return; // 一つ下のマスにブロックがいるので落とさない 105 } 106 } 107 } 108 } 109 // 下から二番目の行から繰り返しクラスを下げていく 110 for (var row = 18; row >= 0; row--) { 111 for (var col = 0; col < 10; col++) { 112 if (cells[row][col].blockNum === fallingBlockNum) { 113 cells[row + 1][col].className = cells[row][col].className; 114 cells[row + 1][col].blockNum = cells[row][col].blockNum; 115 cells[row][col].className = ""; 116 cells[row][col].blockNum = null; 117 } 118 } 119 } 120} 121 122var isFalling = false; 123function hasFallingBlock() { 124 // 落下中のブロックがあるか確認する 125 return isFalling; 126} 127 128function deleteRow() { 129 // そろっている行を消す 130 for (var row = 19; row >= 0; row--) { 131 var canDelete = true; 132 for (var col = 0; col < 10; col++) { 133 if (cells[row][col].className === "") { 134 canDelete = false; 135 } 136 } 137 if (canDelete) { 138 // 1行消す 139 for (var col = 0; col < 10; col++) { 140 cells[row][col].className = ""; 141 } 142 // 上の行のブロックをすべて1マス落とす 143 for (var downRow = row - 1; row >= 0; row--) { 144 for (var col = 0; col < 10; col++) { 145 cells[downRow + 1][col].className = cells[downRow][col].className; 146 cells[downRow + 1][col].blockNum = cells[downRow][col].blockNum; 147 cells[downRow][col].className = ""; 148 cells[downRow][col].blockNum = null; 149 } 150 } 151 } 152 } 153} 154 155var fallingBlockNum = 0; 156function generateBlock() { 157 // ランダムにブロックを生成する 158 // 1. ブロックパターンからランダムに一つパターンを選ぶ 159 var keys = Object.keys(blocks); 160 var nextBlockKey = keys[Math.floor(Math.random() * keys.length)]; 161 var nextBlock = blocks[nextBlockKey]; 162 var nextFallingBlockNum = fallingBlockNum + 1; 163 // 2. 選んだパターンをもとにブロックを配置する 164 var pattern = nextBlock.pattern; 165 for (var row = 0; row < pattern.length; row++) { 166 for (var col = 0; col < pattern[row].length; col++) { 167 if (pattern[row][col]) { 168 cells[row][col + 3].className = nextBlock.class; 169 cells[row][col + 3].blockNum = nextFallingBlockNum; 170 } 171 } 172 } 173 // 3. 落下中のブロックがあるとする 174 isFalling = true; 175 fallingBlockNum = nextFallingBlockNum; 176} 177 178// キー入力によってそれぞれの関数を呼び出す 179function onKeyDown(event) { 180 if (event.keyCode === 37) { 181 moveLeft(); 182 } else if (event.keyCode === 39) { 183 moveRight(); 184 } 185} 186 187function moveRight() { 188 denyMv(); 189 // ブロックを右に移動させる 190 for (var row = 0; row < 20; row++) { 191 for (var col = 9; col >= 0; col--) { 192 if (cells[row][col].blockNum === fallingBlockNum) { 193 cells[row][col + 1].className = cells[row][col].className; 194 cells[row][col + 1].blockNum = cells[row][col].blockNum; 195 cells[row][col].className = ""; 196 cells[row][col].blockNum = null; 197 } 198 } 199 } 200} 201 202function moveLeft() { 203 denyMv() 204 // ブロックを左に移動させる 205 for (var row = 0; row < 20; row++) { 206 for (var col = 0; col < 10; col++) { 207 if (cells[row][col].blockNum === fallingBlockNum) { 208 cells[row][col - 1].className = cells[row][col].className; 209 cells[row][col - 1].blockNum = cells[row][col].blockNum; 210 cells[row][col].className = ""; 211 cells[row][col].blockNum = null; 212 } 213 } 214 } 215} 216 217var isRlDenied = false 218function denyMv() { 219 //障害があるとき左右に移動させない 220 //1. 左右に障害がないか? 221 for(var row = 0; row < 20; row++){ 222 if(cells[row][9].blockNum === fallingBlockNum) { 223 isRlDenied = true; 224 return; //左右に障害があるので動かさない 225 } 226 } 227} 228

lang

1<!DOCTYPE html> 2<html> 3 <head> 4 <meta charset="utf-8"> 5 <title></title> 6 <link rel="stylesheet" href="./css/style.css"> 7 </head> 8 <body> 9 <h1 id="hello_text">Hello World</h1> 10 <table> 11 <tr> <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td> </tr> 12 <tr> <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td> </tr> 13 <tr> <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td> </tr> 14 <tr> <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td> </tr> 15 <tr> <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td> </tr> 16 <tr> <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td> </tr> 17 <tr> <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td> </tr> 18 <tr> <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td> </tr> 19 <tr> <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td> </tr> 20 <tr> <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td> </tr> 21 <tr> <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td> </tr> 22 <tr> <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td> </tr> 23 <tr> <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td> </tr> 24 <tr> <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td> </tr> 25 <tr> <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td> </tr> 26 <tr> <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td> </tr> 27 <tr> <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td> </tr> 28 <tr> <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td> </tr> 29 <tr> <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td> </tr> 30 <tr> <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td> </tr> 31 </table> 32 <script src="./js/main.js"></script> 33 </body> 34</html>

lang

1body { 2 background-color: #263238; 3} 4 5h1 { 6 color: #FFFFFF; 7} 8 9table { 10 width: 400px; /* 表の幅 */ 11 height: 800px; /* 表の高さ */ 12 /* 中央揃えにする */ 13 margin-left: auto; 14 margin-right: auto; 15} 16 17td { 18 width: 10%; /* セルの幅 */ 19 height: 5%; /* セルの高さ */ 20 background-color: #455A64; /* 背景色 */ 21} 22 23.i { 24 background-color: #00BCD4; /* cyan */ 25} 26 27.o { 28 background-color: #FFEB3B; /* yellow */ 29} 30 31.t { 32 background-color: #9C27B0; /* purple */ 33} 34 35.s { 36 background-color: #4CAF50; /* green */ 37} 38 39.z { 40 background-color: #F44336; /* red */ 41} 42 43.j { 44 background-color: #2196F3; /* blue */ 45} 46 47.l { 48 background-color: #FF9800; /* orange */ 49}

試したこと

ある企業のエンジニアブログを参考にしているのですがそのサイトにブロック左右移動制限についてはコードが書かれていませんでした。しかし定義したfallBlocksをヒントに作成せよとのことなのでソースコード最下部にisRlDeniedを追加し、moveLeft、moveRightで呼び出していますが状況は変わりません。

###詳細情報
以下、ファイルを置いたアドレスです。
https://s3-ap-northeast-1.amazonaws.com/ttls/index.html

以下、参考にしたブログサイトです。
http://tech.mti.co.jp/entry/2017/07/21/608/

###追記
上記2つのバグは解決しました。
ご回答ありがとうございました。
AWS上のファイルはバグ修正済みです

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

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

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

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

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

m.ts10806

2018/09/04 05:17

html部分もコードブロック囲ってください。
guest

回答2

0

(falling)blockNumというのがどういった役割なのか分かりづらかったのですが、要は当該ブロックのID(識別子)を意味していますね?

結論から言うと、下記のように生成されたブロックのマス全てにIDを指定してあげる必要があります。

Javascript

1generateBlock() { 2 ... 3 for (var row = 0; row < pattern.length; row++) { 4 for (var col = 0; col < pattern[row].length; col++) { 5 if (pattern[row][col]) { 6 cells[row][col + 3].className = nextBlock.class; 7 } 8 // pattern[row][col]の真偽に関わらず、ブロックのIDは保持しておく 9 cells[row][col + 3].blockNum = nextFallingBlockNum; 10 } 11 } 12

少し解説すると、落下中のブロックが複数行(row)で、それぞれの列(col)が異なるパターンの場合は形にしたくない部分を0で埋めていますね。

Javascript

1 // 例えばこういうの 2 t: { 3 class: "t", 4 pattern: [ 5 [0, 1, 0], 6 [1, 1, 1] 7 ] 8 }

左右へ移動した際に、移動先のマスへ落下中の各パターンのパラメータを格納していると思います。
なぜ端に当たったときに形が変形してしまうのかと言うと、移動先に格納するブロッグのIDがないからです。そこで、上記のように0の部分も含めてブロックのIDを指定してあげることで発生している問題(1)は解消されると思います。
問題(2)については、この移動処理の際に衝突判定と適切な処理が必要になりますが、まずは試行錯誤で頑張ってみてください。(単純に移動先にブロックがあるかどうかを見てあげればよいです。今回都合がよいのはclassNameですかね?)

ちなみにご提示のエラーについては、ループ処理中に存在しないオブジェクトを参照していることが原因です。

Javascript

1 // main.js:208 Uncaught TypeError: Cannot set property 'className' of undefined 2 for (var row = 0; row < 20; row++) { 3 for (var col = 0; col < 10; col++) { 4 // col === 0 の時、存在しない cells[row][-1] を参照してしまっている 5 cells[row][col - 1]

今回の問題には関係なさそうですが、if文などで回避しておくとよいです。

投稿2018/09/04 07:23

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

yasuaki640

2018/09/06 15:29

回答ありがとうございます。 ご教示いただいた「pattern[row][col]の真偽に関わらず、ブロックのIDは保持しておく」でブロックは端にあたっても変形しなくなりました。しかし、ブロックのないセルでも当たり判定をしてしまう(ブロックが宙に浮いたまま停止し次のブロックが生成されてしまう)ために別の方の回答をBAとさせて頂きました。IDによる衝突判定の説明は非常にわかりやすく、ソースコード理解に非常に役立ちました。ご丁寧な回答いただきありがとうございました。
退会済みユーザー

退会済みユーザー

2018/09/06 23:45

他のバグが発生してしまうことまで推測できなかったのは私の力不足を感じ勉強にもなりました。方向性は違っていたようですがご理解のお手伝いができて何よりです。
guest

0

ベストアンサー

必要となるのは
function fallBlocks()
ので言う所の、
// 1. 底についていないか?
// 2. 1マス下に別のブロックがないか?
の部分だと思います。

それぞれ、
function moveRight()

function moveLeft()
に追記して、
・左(右)の壁についていないか?
・1マス左(右)に別のブロックがないか?
に、改訂しましょう。

isRlDenied と denyMv は
恐らく不要かと思います。

投稿2018/09/04 07:21

torisan

総合スコア678

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

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

yasuaki640

2018/09/06 15:22

回答ありがとうございます。 ご教示いただいたとおりに参考にしたブログサイトのfunction fallBlocks()を改定したところ確認された2つのバグは消え新たなバグも発生しませんでした。よってこちらをBAとさせて頂きます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問