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

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

新規登録して質問してみよう
ただいま回答率
85.46%
Three.js

Three.jsはWebGLをサポートしているJavaScriptの3D描画用ライブラリです。

JavaScript

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

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Processing

Processingは、オープンソースプロジェクトによるCGのためのプログラミング言語です。Javaをベースにしており、グラフィック機能に特化しています。イメージの生成やアニメーションなど、視覚的なフィードバックを簡単に得ることが可能です。

Q&A

解決済

1回答

1339閲覧

【Three.js】シューティングゲームで弾クラスの配列化と描画が上手くいかない

ASOBU_dev

総合スコア103

Three.js

Three.jsはWebGLをサポートしているJavaScriptの3D描画用ライブラリです。

JavaScript

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

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Processing

Processingは、オープンソースプロジェクトによるCGのためのプログラミング言語です。Javaをベースにしており、グラフィック機能に特化しています。イメージの生成やアニメーションなど、視覚的なフィードバックを簡単に得ることが可能です。

0グッド

0クリップ

投稿2021/11/28 10:16

編集2021/11/30 04:38

###何に取り組んでいるか
Three.jsというjavaScriptのフレームワークでシューティングゲームを作っています。(Three.jsの文法自体はほとんどjavaScriptみたいなものだと思います)

###実装したい仕様
実装したい仕様としては、画面の左端に自機を配置しており、上下のみ動くことができます。また、弾は画面のスペースキーを押したら自機から右端方向へと発射されるという仕組みです。

###コード(抜粋)

※関係のない宣言、コードは一部端折って質問させていただきます。

javaScript

1function init(){ 2    const sprites = []; //弾(sprite)を格納するための配列 3 tick(); //毎秒描画される関数 4 5 window.addEventListener("keydown", handleKeydown); 6 function handleKeydown(event){ 7     var keyCode = event.keyCode; 8     //スペースキーを押したら弾(sprite)を作成 9     if (keyCode == 32) { 10     makeSprite(); 11      } 12 } 13 14 function makeSprite(){ 15 const sprite = new bullets(); 16         //box~は自機の座標 17 sprite.position.set(box.position.x, box.position.y); 18 sprites.push(sprite); 19 sprites.forEach(function(s) { 20                                //画面に弾を追加(sceneはシーンのこと) 21 scene.add(s); 22 }); 23 } 24 25 //毎フレーム時に実行されるループイベントです 26 function tick() { 27 sprite.update(); 28 renderer.render(scene, camera); 29 requestAnimationFrame(tick); 30 } 31 } 32} 33 34 class bullets extends THREE.Mesh{ 35 //constructor()は省略 36 update(){ 37         //弾のx座標が画面幅を超えたら(spriteのdisposeの方法が不明) 38 if(this.sprite.position.x > 900){ //900は画面の右端と仮定(width) 39 40 }else{ 41 this.sprite.position.x += 10; 42 } 43 } 44}

現在困っていること

現在困っているのは、弾を打つ関数makeSprite()内にある、

jsx

1const sprite = new bullets();

という関数の扱いです。

現在のmakeSprite()内にspriteを宣言すると、弾はスペースキーを押した回数分だけscene上の自機の座標の上に生成されますが、tick()内にあるsprite.update()が機能しないため、弾は進みません。(spriteがスコープ外なので当然)

イメージ説明

一方で、初期化関数init内で宣言すると、今度は最初の一発だけ想定通りに画面の端まで動いてくれます。しかし、スペースキーを押した際に複数発発射されることはなく、キーを押すたびに(x,y)=(900,現在のbox(自機)のy座標)に弾の位置が更新されます。

jsx

1function init(){ 2//キャンバスサイズを指定 3//レンダラー、カメラ、平行光源、シーン等を作成 4 //★【ここに宣言】 5 const sprite = new bullets(); 6 //弾(sprite)を格納するための配列 7 const sprites = []; 8 //毎秒描画される関数 9 tick();

イメージ説明

試してみたこと

spriteにidを設定したり、spriteを格納したsprites配列をforeachで回してみるなど、色々と試しているのですが、自分の持っている知識と経験では限界で、想定通り動かすことはできていません。

bulletのクラス化につきましては以下の記事を参考にさせていただきました。

シューティングゲームで弾を連射したい
https://teratail.com/questions/85720

###やりたいこと
やりたいこととしては、とりあえず「スペースキーを押されたら自機からspriteを発射し、毎フレームx座標に+10しながら画面の右端に到達して止まる(スペースキーを何度も押されたら押された分だけ弾を生成し、同様に動く)」ということをやりたいです。
(弾が消える処理は自分で考えようと思っています)
イメージ説明

どうかご教示の程をよろしくお願いいたします。

###補足
Processingだとdraw()関数のなかにぶっ込んでforループで入れ子構造にして回してあげると動いてくれますが、それをthree.jsで試した結果、キーを押した瞬間にいきなり右端に表示されました(あと処理が重たくなるような気がします)

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

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

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

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

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

guest

回答1

0

ベストアンサー

2か所ほど修正してみました。罫線で強調表示している箇所になります。
<対応概要>
・makeSprite() の中で弾丸を生成するよう変更
・tick() の中で弾丸毎に update() を呼び出すよう変更

javascript

1 const sprites = []; 2 //===================================================== 3 //const sprite = new bullets(); … makeSprite() に移動 4 //===================================================== 5 tick(); 6 7 //飛行機の処理 8 window.addEventListener("keydown", handleKeydown); 9 function handleKeydown(event){ 10 // キーコード 11 var keyCode = event.keyCode; 12 13 if (keyCode == 38) { 14 // 上 15 box.position.y += 50; 16 } 17 if (keyCode == 40) { 18 // 下 19 box.position.y -= 50; 20 } 21 if (keyCode == 32) { 22 makeSprite(); 23 } 24 } 25 //弾を打つ処理 26 function makeSprite(){ 27 //===================================================== 28 const sprite = new bullets(); 29 //===================================================== 30 sprite.position.set(box.position.x, box.position.y); 31 sprites.push(sprite); 32 sprites.forEach(function(s) { 33 scene.add(s); 34 }); 35 } 36 37 // 毎フレーム時に実行されるループイベン 38 function tick() { 39 // sprites の各要素毎に update() の呼び出しを実施 40 //===================================================== 41 for (let i = 0; i < sprites.length; i++) { 42 sprites[i].update(); 43 } 44 //===================================================== 45 renderer.render(scene, camera); // レンダリング 46 requestAnimationFrame(tick); 47 } 48

■ 実行イメージ
イメージ説明

投稿2021/11/28 10:54

cx20

総合スコア4633

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

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

ASOBU_dev

2021/11/28 15:21

ご回答ありがとうございました!動きました^^ javaScriptではfor文の時にletで宣言するのですね。 自分が試した時にうまくいかなかった原因の一つにiをletではなくvarで宣言していたというものもありました。 https://teratail.com/questions/62502 いい勉強になりました。ご回答いただき、ありがとうございました。
cx20

2021/11/28 15:36

> javaScriptではfor文の時にletで宣言するのですね。 回答の例であれば var でも動作するかと思いますが、モダンなブラウザであれば let を使った方が良いかと思います。 あと、質問自体とは少し話がそれますが、クラス名と変数名が少し気になりました。 クラス名としては複数形ではなく単数形にした方が分かりやすいかと思います。 変更前)  const sprites = [];  const sprite = new bullets();  sprites.push(sprite); 変更後)  const bullets = [];  const bullet = new Bullet();  bullets.push(bullet);
ASOBU_dev

2021/11/30 04:41

コードレビュー、ご指摘ありがとうございます...! 命名規則、きちんと書けるように努力します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問