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

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

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

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

Q&A

解決済

1回答

1005閲覧

操作キー同時押しの処理

0m02mintone

総合スコア1

JavaScript

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

0グッド

0クリップ

投稿2021/12/03 17:15

前提・実現したいこと

プログラミングを勉強中のものです。
フラッピーワールドのようなものを作成中です。
https://flappy.netfarm.ne.jp/

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

矢印キーの同時押しをすると、グレーの壁にめり込んでしまうバグ?が発生しています。
ソースコード中のloop処理が終わる前に別のキーが入力されるのが原因だと考えています。

該当のソースコード

html,javascript

1<!DOCTYPE html> 2<html> 3<body> 4<script> 5 const canvas = document.createElement('canvas'); 6 const ctx = canvas.getContext('2d'); 7 canvas.width = 440; 8 canvas.height = 680; 9 10 canvas.setAttribute('style', 'display:block; margin: auto; background-color: #ddd'); 11 12 document.body.appendChild(canvas); 13 14 15 //不必要 16 const ball = { 17 x: null, 18 y: null, 19 width: 5, 20 height: 5, 21 speed: 0, 22 dx: null, 23 dy: null, 24 25 update: function () { 26 ctx.fillRect(this.x, this.y, this.width, this.height); 27 ctx.fill(); 28 29 if (this.x < 0 || this.x > canvas.width) this.dx *= -1; 30 if (this.y < 0 || this.y > canvas.height) this.dy *= -1; 31 32 this.x += this.dx; 33 this.y += this.dy; 34 } 35 36 } 37 //操作するキャラクター 38 const paddle = { 39 x: null, 40 y: null, 41 width: 40, 42 height: 40, 43 speedX: 0, 44 speedY: 0, 45 46 update: function () { 47 //ctx.beginPath(); 48 ctx.clearRect(this.x, this.y, this.width, this.height); 49 //ctx.save(); 50 /*ctx.translate(this.x, this.y);*/ 51 this.x += this.speedX; 52 this.y += this.speedY; 53 ctx.fillStyle = "rgb(251,208,29,0.7)"; 54 //ctx.strokeRect(this.x, this.y, this.width, this.height); 55 //ctx.stroke(); 56 ctx.fillRect(this.x, this.y, this.width, this.height); 57 ctx.fill(); 58 //ctx.restore(); 59 //ctx.closePath(); 60 } 61 } 62 //マップに配置されているモブブロック 63 const block = { 64 width: 40, 65 height: 40, 66 data: [], 67 68 update: function () { 69 this.data.forEach(brick => { 70 ctx.clearRect(brick.x, brick.y, brick.width, brick.height); 71 ctx.fillStyle = "rgb(30,30,30,0.3)"; 72 ctx.strokeRect(brick.x, brick.y, brick.width, brick.height); 73 ctx.stroke(); 74 ctx.fillRect(brick.x, brick.y, brick.width, brick.height); 75 ctx.fill(); 76 }) 77 } 78 } 79 //下に二つたまっている小ブロック 80 const smallblockdown = { 81  //blockと同様 82 } 83 //上に二つたまっている小ブロック 84 const smallblockup = { 85  //blockと同様 86 } 87 //ゴールブロック 88 const clearblock = { 89  //blockと同様 90 } 91 //ムーブブロック 92 const moveblock = { 93  //blockと同様 94 } 95 //クリアムーブブロック 96 const CMblock = { 97  //blockと同様 98 } 99 //全ブロックのアップデート 100 const mapupdate = () =>{ 101 //paddle.update(); 102 block.update(); 103 smallblockdown.update(); 104 smallblockup.update(); 105 clearblock.update(); 106 moveblock.update(); 107 CMblock.update(); 108 } 109 110 //マップの構成(二次元配列) 111 const level = [ 112 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 113 [1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1], 114 [1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1], 115 [1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1], 116 [1, 0, 5, 0, 0, 0, 0, 0, 5, 0, 1], 117 [1, 0, 5, 0, 0, 1, 0, 0, 5, 0, 1], 118 [1, 0, 5, 0, 0, 1, 0, 0, 6, 0, 1], 119 [1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1], 120 [1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1], 121 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 122 [1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1], 123 [1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1], 124 [1, 4, 0, 0, 0, 1, 3, 1, 0, 0, 1], 125 [1, 3, 3, 3, 3, 1, 3, 1, 3, 3, 1], 126 [1, 3, 3, 3, 3, 1, 0, 1, 3, 3, 1], 127 [1, 0, 0, 0, 0, 1, 3, 1, 0, 0, 1], 128 [1, 3, 3, 3, 3, 1, 0, 1, 0, 0, 1], 129 ] 130 131 //初期値の設定 132 const init = () => { //初期化処理 133 } 134 135 //obj1とobj2の当たり判定(単体) 136 const collide = (obj1, obj2) => { 137 return obj1.x < obj2.x + obj2.width && 138 obj2.x < obj1.x + obj1.width && 139 obj1.y < obj2.y + obj2.height && 140 obj2.y < obj1.y + obj1.height; 141 } 142 143 ////////////////////////////////////// 144 /////////obj1とobj2の順番に注意/////// 145 ////////obj2が操作キャラ////////////// 146 ////////////////////////////////////// 147 //obj1とobj2のx軸の接触{obj1<obj2} 148 const collideLeft = (obj1, obj2) => { 149 return obj1.x + obj1.width == obj2.x; 150 } 151 //obj1とobj2のx軸の接触{obj2<obj1} 152 const collideRight = (obj1, obj2) => { 153 return obj1.x == obj2.x + obj2.width; 154 } 155 //obj1とobj2のy軸の接触{obj1/obj2} 156 const collideUp = (obj1, obj2) => { 157 return obj1.y == obj2.y - obj2.height; 158 } 159 //obj1とobj2のy軸の接触{obj2/obj1} 160 const collideDown = (obj1, obj2) => { 161 return obj1.y - obj1.height == obj2.y; 162 } 163 const collideX = (obj1, obj2) => { 164 return obj1.x == obj2.x || //obj1とobj2のx軸が完全一致 165 obj1.x == obj2.x + obj2.width / 2 || //obj1の0.5マス左にobj2 166 obj1.x + obj1.width/2 == obj2.x; //obj1の0.5マス右にobj2 167 } 168 const collideY = (obj1, obj2) => { 169 return obj1.y == obj2.y || //obj1とobj2のy軸が完全一致 170 obj1.y == obj2.y + obj2.height / 2 || //obj1の0.5マス上にobj2 171 obj1.y + obj1.height/2 == obj2.y; //obj1の0.5マス下にobj2 172 } 173 174 /////////////////////////////////////// 175 /////////////////////////////////////// 176 var movekeyleft = 0; 177 var movekeyright = 0; 178 var movekeyup = 0; 179 var movekeydown = 0; 180 181 182 const loop = () => { 183 mapupdate(); 184 185 if (collide(ball, paddle)) { 186 ball.dy *= -1; 187 ball.y = paddle.y - ball.height; 188 } 189 190 block.data.forEach((brick, index) => { 191 if (collide(ball, brick)) { 192 ball.dy *= -1; 193 block.data.splice(index, 1); 194 } 195 196 }) 197 movekeyleft = 0; 198 block.data.forEach((brick, index) => { 199 if (collideY(brick, paddle)) { 200 if (collideLeft(brick, paddle)) { 201 movekeyleft = 1; 202 } 203 } 204 }) 205 movekeyright = 0; 206 block.data.forEach((brick, index) => { 207 if (collideY(brick, paddle)) { 208 if (collideRight(brick, paddle)) { 209 movekeyright = 1; 210 } 211 } 212 }) 213 movekeyup = 0; 214 block.data.forEach((brick, index) => { 215 if (collideX(brick, paddle)) { 216 if (collideUp(brick, paddle)) { 217 movekeyup = 1; 218 } 219 } 220 }) 221 movekeydown = 0; 222 block.data.forEach((brick, index) => { 223 if (collideX(brick, paddle)) { 224 if (collideDown(brick, paddle)) { 225 movekeydown = 1; 226 } 227 } 228 }) 229 230 console.log(movekeyleft); 231 232 window.requestAnimationFrame(loop); 233 } 234 //window.requestAnimationFrame(loop); 235 236 init(); 237 loop(); 238 239 var movekey = 0; 240 var movekey2 = [0, 0, 0, 0]; 241 document.addEventListener('keydown', keydown_ivent); 242 243 function keydown_ivent(e) { 244 console.log(e.key) 245 switch (e.key) { 246 case 'ArrowLeft': 247 if (movekeyleft == 0) { 248 paddle.speedX = -20; 249 } else { paddle.speedX = 0; } 250 break; 251 252 case 'ArrowRight': 253 if (movekeyright == 0) { 254 paddle.speedX = 20; 255 } else { paddle.speedX = 0; } 256 break; 257 258 case 'ArrowUp': 259 if (movekeyup == 0) { 260 paddle.speedY = -20; 261 } else { paddle.speedY = 0; } 262 break; 263 264 case 'ArrowDown': 265 if (movekeydown == 0) { 266 paddle.speedY = 20; 267 } else { paddle.speedY = 0; } 268 break; 269 } 270 paddle.update(); 271 return false; 272 } 273 document.addEventListener('keyup', () => { 274 paddle.speedX = 0; 275 paddle.speedY = 0; 276 return false; 277 }); 278 279</script> 280</body> 281</html>

試したこと

キーダウンしたときにキーアップするまで次のキーを受け付けないようにしました。そうすると、長押し移動ができなくなってしまいました。
そのほかいろいろ試しましたが、行き詰ってしまいました。

補足情報(FW/ツールのバージョンなど)

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

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

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

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

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

guest

回答1

0

ベストアンサー

キーアップまで次のキーを受け付けないようにする処理までは問題ないと思います。

基本的な仕様として、キーを押しっぱなしにしている状態であれば、setTimeoutを使って、一定時間に同じ処理を繰り返す仕様にするのがいいでしょう。

キーダウンで繰り返し処理をなくして、連続移動ができなくなったということは、
キーボードのリピート機能を使って処理をしていたということで、それだと、最初にキーダウンしてから少し間が空いて、繰り返し処理になるので、タイムラグが発生して気持ち悪い動きになります。

なので、キーを押しっぱなしのときには、setTimeoutで、30フレームか、60フレームぐらいの感覚で処理を繰り返し、setTimeoutの戻り値をグローバル変数で保持しておいて、キーアップの時に、その変数をclearTimeoutしてあげるといいでしょう。

ブラウザベースのキー操作では、これが基本になるので、カーソル操作関数を作っておくと便利ですよ。

投稿2021/12/12 07:29

geta

総合スコア241

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

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

0m02mintone

2021/12/12 10:18

ご助言の通り作ってみたところ、無事できました! とても参考になりました! ありがとうございます!
geta

2021/12/13 01:16

お役に立ててなによりです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問