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

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

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

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

HTML

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

Q&A

解決済

1回答

929閲覧

JavascriptでFNF音ゲー制作をする

falcon_function

総合スコア6

JavaScript

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

HTML

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

0グッド

0クリップ

投稿2023/06/21 11:20

実現したいこと

  • 音楽の再生時間に応じて、キーボードが押された時点の判定枠を実装したい
  • 音声ファイルが読み込まれた時点で再生したいが、ユーザーアクションがないと再生できない問題を解決したい
  • 画像読み込み時の設計案が思い浮かばない

前提

JavaScriptでFNFの音ゲーを実装したいです。
画像描画とメモリ管理は後回しで、今現在時点では、「音声ファイルの読み込み・判定秒数の計算方法・画像読み込みの方法と描画」がわかればよしとします。

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

・keydown時のミリ秒が5桁のミリ秒(53467.93791など)になっているのに、クラスでPERFECT~BADの範囲から外れているにも関わらずなぜかPERFECTのみしか出力しないです。 ・今はEnterキーを押したら音楽が再生されるようにしていますが、再びEnterキーを押すと二重三重にも再生されてしまうため その対策をしたいです。 ・画像読み込みはcanvasで描画しようと思っています。背景→判定枠は初期段階で読み込むというのはわかります。 問題なのは、いざ曲が開始した際に上から降ってくるノーツの秒数と個数をどうやって管理しつつ描画し続けるのかがよくわかっておりません。

該当のソースコード

JavaScript(fnf.js)

1class Notes{ 2 constructor(x,y,VelX,VelY,width,height,time){ 3 this.x = x; 4 this.y = y; 5 this.VelX = VelX; 6 this.VelY = VelY; 7 this.width = width; 8 this.height = height; 9 this.time = time; 10 } 11 notesdisplay(){ 12 13 } 14} 15class notes_key extends Notes{ 16 constructor(x,y,VelX,VelY,width,height,time){ 17 super(x,y,VelX,VelY,width,height,time); 18 } 19 display(){ 20 21 } 22} 23/*ノーツと判定枠は座標・加速度・画像サイズ・到達時間の値を受け取る。*/ 24 25//下記はFNFの 26class Notes_Elements{ 27 constructor(){ 28 this.normal = 'normal'; 29 this.invisible = 'invisible'; 30 this.reverse = 'reverse'; 31 this.death = 'death'; 32 } 33} 34 35class Notes_Display extends Notes_Elements{ 36 constructor(normal,invisible,reverse,death){ 37 super(normal,invisible,reverse,death); 38 } 39} 40 41class Notes_Judge{ 42 constructor(){ 43 this.Perfect=32; 44 this.GOOD=70; 45 this.BAD=110; 46 this.MISS=150; 47 } 48 //単位はミリ秒に統一 49} 50class Pushing{ 51 constructor(up_push,down_push,left_push,right_push){ 52 this.up_push = false; 53 this,down_push = false; 54 this.left_push = false; 55 this.right_push = false; 56 } 57} 58class Pushing_continue extends Pushing{ 59 constructor(up_pushing,down_pushing,left_pushing,right_pushing){ 60 super(up_pushing,down_pushing,left_pushing,right_pushing); 61 } 62} 63 64class passed_time{ 65 constructor(s_time,e_time){ 66 this.s_time = s_time; 67 this.e_time = e_time; 68 } 69 progress(){ 70 if(this.e_time < this.s_time){ 71 return (this.s_time - this.e_time); 72 } else { 73 return (this.e_time - this.s_time); 74 } 75 76 } 77} 78let totaltime = new passed_time(); 79 80function move(key_send){ 81 if(key_send.up_push){ 82 const judgetime = totaltime.progress(); //経過時間を計算 83 const judgeup = new Notes_Judge(); 84 85 switch(true){ 86 case judgetime <= judgeup.Perfect: 87 case judgetime >=0: 88 console.log("Perfect: " + judgetime + "ms"); 89 break; 90 91 case judgetime <= judgeup.GOOD: 92 case judgetime > judgeup.Perfect: 93 console.log("GOOD: "+ judgetime + "ms"); 94 break; 95 96 case judgetime <= judgeup.BAD: 97 case judgetime > judgeup.GOOD: 98 console.log("BAD: " + judgetime + "ms"); 99 break; 100 101 102 } 103 } 104 105 if(key_send.down_push){ 106 const judgetime = totaltime.progress(); 107 const judgeup = new Notes_Judge(); 108 109 switch(true){ 110 case judgetime <= judgeup.Perfect: 111 case judgetime >= judgeup.GOOD: 112 console.log("Perfect: " + judgetime + "ms"); 113 break; 114 115 case judgetime <= judgeup.BAD: 116 case judgetime >= judgeup.GOOD: 117 console.log("GOOD: "+ judgetime + "ms"); 118 break; 119 120 case judgetime <= judgeup.MISS: 121 case judgetime >= judgeup.BAD: 122 console.log("BAD: " + judgetime + "ms"); 123 break; 124 125 126 } 127 } 128 129 if(key_send.left_push){ 130 const judgetime = Math.abs(totaltime.progress()); 131 const judgeup = new Notes_Judge(); 132 } 133 134 if(key_send.right_push){ 135 const judgetime = Math.abs(totaltime.progress()); 136 const judgeup = new Notes_Judge(); 137 } 138} 139 140document.addEventListener('keydown',(event)=>{ 141 const check = new Pushing(); 142 switch (event.key){ 143 case 'ArrowUp': 144 totaltime.s_time = performance.now(); 145 check.up_push = true; 146 break; 147 case 'ArrowDown': 148 totaltime.s_time = performance.now(); 149 check.down_push = true; 150 break; 151 case 'ArrowLeft': 152 totaltime.s_time = performance.now(); 153 check.left_push = true; 154 break; 155 case 'ArrowRight': 156 totaltime.s_time = performance.now(); 157 check.right_push = true; 158 break; 159 } 160 161 move(check); 162}); 163 164 165document.addEventListener('keyup', (event) => { 166 const check = new Pushing(); 167 switch (event.key){ 168 case 'ArrowUp': 169 totaltime.e_time = performance.now(); 170 check.up_push = false; 171 break; 172 case 'ArrowDown': 173 totaltime.e_time = performance.now(); 174 check.down_push = false; 175 break; 176 case 'ArrowLeft': 177 totaltime.e_time = performance.now(); 178 check.left_push = false; 179 break; 180 case 'ArrowRight': 181 totaltime.e_time = performance.now(); 182 check.right_push = false; 183 break; 184 } 185});

JavaScript(include_music.js)

1const start = document.addEventListener('keypress',(event)=>{ 2 if(event.key === 'Enter'){ 3 const music = new Audio('test.mp3'); 4 music.load(); 5 music.pause(); 6 //const time = music.src; 7 //console.log(time); 8 music.volume = 0.05; 9 music.autoplay = true; 10 } 11}); 12

HTML(index.html)

1<html> 2<head> 3<title>FNFもどき</title> 4<script src="fnf.js" defer></script> 5<script src="include_music.js" defer></script> 6</head> 7<body> 8</body> 9 10</html>

試したこと

・performance.now()を使い、keydownとkeyupで、キーが押されたタイミングで変数に保存し、その差を計算した。
・Event.timeStampでも同様に試したが、結果は同じだった。
・警視庁のポリズム内のソースコードを参考にしてみたが、クラスの定義についてはおおよそ分かった。しかし、肝心の画像描画の処理とノーツの管理などがどのようになっているのかわからなかった。
https://www.keishicho.metro.tokyo.lg.jp/play/rhythm/

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

ブラウザ:Chrome Ver.114.0.5735.134
PCのスペック: CPU: i7-12700 2.10 GHz
メモリ: 32GB
Windows11 Home 22H2

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

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

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

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

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

guest

回答1

0

ベストアンサー

クラスでPERFECT~BADの範囲から外れているにも関わらずなぜかPERFECTのみしか出力しないです。

js

1 switch(true){ 2 case judgetime <= judgeup.Perfect: 3 case judgetime >=0: 4 console.log("Perfect: " + judgetime + "ms");

このコードの挙動を日本語で書くと「judgetimejudgeup.Perfect以下、または judgetime が0以上なら Perfect: ... と表示」です。

switch をこのような使い方をするのはやめましょう。読みにくくて仕方がないです。
素直に、if を羅列したほうが遥かに読みやすいです。

js

1if (judgetime <= judgeup.Perfect && judgetime >= 0) { 2 console.log(`Perfect: ${judgetime}ms`); 3} else if (....

・今はEnterキーを押したら音楽が再生されるようにしていますが、再びEnterキーを押すと二重三重にも再生されてしまう

変数 music をグローバル変数にして、Enter が押されたときに変数 music に値が何か入っていたら何もしないようにコードを書きましょう。
メディアおよびウェブ音声 API の自動再生ガイド」にも目を通しましょう。


上から降ってくるノーツの秒数と個数をどうやって管理しつつ描画し続けるのかがよくわかっておりません。

音ゲーということは、おそらくどのタイミングどのキーを押すべきかは曲によって決まっているのですよね。まずはそのデータをJavaScriptでどのように表現するかを考えましょう。
それができたら、その指定タイミングで画面に何かを表示するだけのコードを書いてみましょう。
それができたら、その表示したものを一定時間後に消すにはどうしたらいいかを考えましょう。
それができたら、その指定タイミングの一定時間前に表示するように変えてみましょう。

投稿2023/06/21 13:14

編集2023/06/22 01:11
int32_t

総合スコア20914

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

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

falcon_function

2023/06/25 10:22

ありがとうございます。少し進展しましたので、お伝えいたします。 以下のようにノーツクラスに描画と動くメソッドを追加して、loop関数で移動させるようにしました しかし、描画はされるものの一切動きません。(本来は下に移動するようにしたいです。) ```JavaScript(fnf.js) let canvas = document.querySelector(".fnfcanvas"); let ctx = canvas.getContext("2d"); let width = canvas.width = 1080; let height = canvas.height = 640; //ノーツそのものの制御(座標・加速度・画像の大きさ・各秒数) class Notes{ constructor(x,y,VelX,VelY,width,height,time){ this.x = x; this.y = y; this.VelX = VelX; this.VelY = VelY; this.width = width; this.height = height; this.time = time; } notesmoving(){ //ここにVelYの挙動およびVelXなどの挙動を書く。 if(this.y + this.height >= height ){ this.VelY = -(this.VelY); } if((this.y - this.height) <= 0){ this.VelY = -(this.velY); } this.y += this.VelY; } notesdrawing(){ //ここに描画処理を書く。 ctx.fillRect(0,0,width,height); ctx.translate(width/2,height/2); const note_sprite = new Image(); note_sprite.src = "arrow_down_empty.png"; let sprite = 0; let posy = 0; note_sprite.addEventListener("load",(event)=>{ ctx.drawImage(note_sprite,(sprite * 158),0,158,157,0,0+posy,74,73.5); }); ctx.fillRect(-(width/2), -(height/2), width, height); if (posy > height/2) { let newStartPos = -((height/2) + 157); posX = Math.ceil(newStartPos); console.log(posy); } else { posy += 2; } } } const notes_LEGENDALY = []; const notes_LASO = []; const notes_SLASO = []; function loop(){ const test = new Notes(0,0,1,1,158,157,34.5); test.notesdrawing(); test.notesmoving(); } window.requestAnimationFrame(loop); ```
int32_t

2023/06/25 11:53

この質問の初期の状況からはだいぶ進展しているので、この質問は閉じて新たな質問を立ててください。
falcon_function

2023/06/26 12:20

承知しました、ありがとうございます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問