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

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

新規登録して質問してみよう
ただいま回答率
85.50%
オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

JavaScript

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

enchant.js

enchant.jsとは、アプリやゲームを簡単に開発できるオープンソースのHTML5+JavaScriptベースのフレームワークです。プログラミング学習にも用いられ、多くの素材やプラグインが用意されています。

Q&A

解決済

4回答

972閲覧

シューティングゲームで自機と弾の関係について

aruto

総合スコア175

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

JavaScript

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

enchant.js

enchant.jsとは、アプリやゲームを簡単に開発できるオープンソースのHTML5+JavaScriptベースのフレームワークです。プログラミング学習にも用いられ、多くの素材やプラグインが用意されています。

0グッド

0クリップ

投稿2018/09/24 16:26

編集2018/09/25 10:06

前提・実現したいこと

javascriptでシューティングゲームを作っています。
自機が弾を撃つとき、誰がどう管理すればいいかについてお聞きしたいです。

やりたいこととしては
・自機が弾を撃つ
・main関数のbullets配列に弾を入れ管理したい

該当のソースコード

phina.jsというゲームエンジン(enchan.jsのようなもの)で作っているので下記のコードは実際のものとは違うのですがイメージとしてのコードを載せます。

javascript

1class Player { 2 constructor(x, y, arr) { 3 this.x = x 4 this.y = y 5 this.bullets = arr 6 } 7 shot() { 8 const bullet = new Bulllet(this.x, this.y) 9 this.bullets.push(bullet) 10 } 11} 12 13class Bullet { 14 constructor(x, y) { 15 this.x = x 16 this.y = y 17 } 18} 19 20const main = () => { 21 let bullets = [] 22 const player = new Player(0, 0, bullets) 23 if (key入力があったら) { 24 player.shot() 25 } 26 bulletsを使った処理 27} 28

現在は上記のようにクラスに配列を渡し、そのクラスのメソッドでインスタンスを作り配列に詰めています。

試したこと

・配列をインスタンス時ではなく、メソッドの引数として渡す
異なるクラスで同名のメソッドを用いて抽象化している部分があり、クラスによって渡す配列を変えるという処理を導入しづらいです。
(具体的には当たり判定で各クラスのhitメソッドを呼び、ここでも渡したい配列があります)

質問したいこと

・Playerクラスにわざわざbullets配列を渡すのが変な感じがする
(実際のコードだと他の要素も管理したいため、Playerクラスに様々な配列を渡しています)

・Playerクラスの中でインスタンスを生成するというはどうなのか
(密結合になりすぎている気がします)

上記の点が気になっています。
特に1点目に関してはPlayerにエフェクトを追加するたびにPlayerインスタンスの生成を書き換えなくてはいけないため良くない方法なのだなとは感じています。

シューティングゲームに限らずよくある処理だとは思うのですが、どう管理するのが良いでしょうか。
よろしくお願い致します。

解決後

まとめてコメントさせていただきます。
どの方もとても参考になりました。
少しずつオブジェクト指向を理解するために、とりあえずは戻り値で代入する方法を取りたいと思います。
理由としては状態の変更がmain関数から把握できるため、今の自分でもこんがらがらずに作れそうだからです。
これに慣れたらWorldクラスなどを作ってオブジェクト指向を理解していきたいと思います。

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

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

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

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

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

guest

回答4

0

そもそもプレイヤーは撃ち出した弾をなんで所持しているんですか?
タオパイパイみたいに鉄砲から飛び出した弾を数メートル先まで走ってキャッチでもしてるんでしょうか?

プレイヤーが撃ち出した弾は世界に登場して、
直進を続けてエネミーに命中したらダメージという作りになっているはずです。
なのでプレイヤーが撃ち出した弾丸は世界というクラスが所持することになるはずです。

そこから先はDIを使いながらプログラミングしていって下さい。
誰が何を持っているか、そして誰に通知しなければならないかを意識するのがオブジェクト指向プログラミングのキモになります。

JavaScript

1class Player { 2 constructor(position, weapon) { 3 this.position = position 4 this.weapon = weapon 5 } 6 shot(world) { 7 if (!world) { 8 console.log('私は今どの世界線に居るのだろうか?(哲学)') 9 return 10 } 11 if (!this.weapon) { 12 console.log('damn it! 俺は武器を持っていない!!') 13 return 14 } 15 world.addBullet(weapon.fire(this.position)) 16 } 17} 18 19class Weapon { 20 constructor(speed, power, BulletType) { 21 this.speed = speed 22 this.power = power 23 this.BulletType = BulletType 24 } 25 fire(position) { 26 if (!position) { 27 console.log('いや、あなたは何処で撃ち出したんですか?') 28 return 29 } 30 return new this.BulletType(position, this.speed, this.power) 31 } 32} 33 34class Bullet { 35 constructor(position, speed, power) { 36 this.position = position 37 this.speed = speed 38 this.power = power 39 } 40 // 世界が1秒経過したものとみなす 41 recalculate() { 42 // これだとどっちに飛べばいいか分からんけど、縦シューなら真上に飛べばいいかな 43 this.position.y += speed 44 } 45} 46 47class World { 48 constructor() { 49 this.bullets = [] 50 } 51 addBullet(bullet) { 52 this.bullets.push(bullet) 53 } 54} 55 56const main = () => { 57 const world = new World() 58 const firstWeapon = new Weapon(100, 10, Bullet) 59 const player = new Player({x: 0, y:0}, firstWeapon) 60 61 if (key入力があったら) { 62 player.shot(world) 63 } 64 65 // bulletsを使った処理 66 // 全ての弾を移動させる 67 world.bullets.forEach(it => it.recalculate()) 68}

投稿2018/09/25 08:51

miyabi-sun

総合スコア21158

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

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

aruto

2018/09/25 09:14

ありがとうございます。 いろいろ管理するWorldクラスを作る。 弾を撃つ際に、worldインスタンスを渡して、そこでwolrdのbullets配列に詰めるのですね。 たしかにPlayerは撃った弾を保持する必要はないですね。 Playerに持たせちゃうとPlayerの消滅時に弾も消えちゃいますもんね。
miyabi-sun

2018/09/25 09:33

後は武器に弾の型みたいなのをもたせてみたりと、 設計が捗りそうな小ネタを仕込んでおきました。 「世界」は今後プレイヤーや敵を所持している必要があると思うので、後付けで足すメソッドが欲しくなると思います。 普通のゲームは30FPSや60FPSで動作してまして、1フレーム毎に弾の座標を滑らせるように移動し、移動後の座標がプレイヤーや敵に接触したら被弾という扱いになるでしょう。 画面端の座標を超えた弾は退場ですかね? ただし、世界は一歩間違えればすぐにぶくぶくと膨れ上がったクラスに成長してしまうので、 世界はただお前ら(弾、プレイヤー、敵)を所持して時間を進めるだけ、 後のことはお前らのメソッドを実行するから勝手にやってくれみたいな立ち位置をキープする必要があるでしょう。 こんな感じで誰が何を持っているかを上手く整備してみて下さい。
aruto

2018/09/25 10:08

ありがとうございます。 現状main関数でロジックと状態の管理をしていて、まだ許せるのですがいずれ肥大化しそうなので、状態の管理はWorldクラスに移行させてみようと思います。
guest

0

ベストアンサー

Playerクラスにわざわざbullets配列を渡すのが変な感じがする

shot関数の戻り値として返せばよいのでは

JavaScript

1class Player { 2 constructor(x, y, arr) { 3 this.x = x 4 this.y = y 5 this.bullets = arr 6 } 7 shot() { 8 return new Bullet(this.x, this.y); 9 } 10} 11const main = () => { 12 let bullets = [] 13 const player = new Player(0, 0) 14 if (key入力があったら) { 15 bullets.push(player.shot()) 16 }

Playerクラスの中でインスタンスを生成するというはどうなのか

当たり判定の処理で自機が撃った弾なのか、敵が撃った弾なのかの生成元の判定がどこかに必要になる事が多いため、
Playerクラスのshot関数内でインスタンスの生成を回避しても最終的にはどこかに処理が必要になるかと。

投稿2018/09/24 22:27

umyu

総合スコア5846

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

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

aruto

2018/09/25 08:51

ありがとうございます。 戻り値で代入するとは思いつきませんでした。 とてもシンプルにできますね。
guest

0

オブジェクト指向で考えるなら、プレイヤーは武器を装備して、撃ちます。
残弾数は武器に紐付く情報です。
プレイヤーが持っている弾は予備であるはずで、装填時にしか利用しません。

JavaScript

1const player = new Player(0, 0); 2player.shotArms[0] = new MachineGun(30); // 残弾数30のマシンガンを装備する 3player.shotArms[0].shot(); // 撃つ(残弾数 -1) 4player.shotArms[0].reload(); // マシンガンの最大装填数まで弾を補充

Re: aruto さん

投稿2018/09/25 03:11

think49

総合スコア18156

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

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

aruto

2018/09/25 08:59

main関数でbullets配列に弾を入れて管理するのではなく、各Playerが独自のbullets配列を持つといったことでしょうか。 たしかに、bullets配列はPlayerクラスに直接実装したほうが見通しが良い気がしてきました。
guest

0

phina.jsというのがあるのですね。
さらっと眺めたのですが、

JavaScript

1phina.define('Bullet', { 2 superClass: 'Sprite', 3 //... 4 update: function() { 5 // 弾自身の処理

みたいな感じでBulletを定義すれば、Player側では弾(Bullet)を打ち出したら
あとは弾自身が自分でなんとかするように出来るのではないでしょうか?
Player側はせいぜい最大弾数チェックぐらいで。

投稿2018/09/25 05:04

daisuke7

総合スコア1563

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

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

aruto

2018/09/25 08:53

ありがとうございます。 弾の動きなどはそのようにして実現できているのですが、main関数で"弾の配列"と"敵の配列"で当たり判定をする際に配列への詰め方をどうしたらよいかについてご質問いたしました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問