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

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

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

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

JavaScript

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

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

Vite

Viteは、フロントエンド向けのビルドツール。JavaScriptはもちろん、さまざまな環境での利用が可能です。ES Modulesを利用することで高速ビルドを実現でき、ファイルの変更時も変更箇所のみを更新できるといった特徴があります。

Q&A

解決済

1回答

699閲覧

matter.jsの衝突イベント発火時に自前の配列の検索と抽出が正しく完了できない

Tokino

総合スコア8

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

JavaScript

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

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

Vite

Viteは、フロントエンド向けのビルドツール。JavaScriptはもちろん、さまざまな環境での利用が可能です。ES Modulesを利用することで高速ビルドを実現でき、ファイルの変更時も変更箇所のみを更新できるといった特徴があります。

0グッド

0クリップ

投稿2023/10/22 08:50

実現したいこと

  • matter.jsのcollisionStartなどの衝突イベント内で、自前の配列にArray.findIndexで検索したインデックスの次の要素を取得したい

前提

TypeScript, SolidStart, Matter.jsでスイカゲームを作っています。
同じフルーツが衝突して次のフルーツに進化する機能を実装中に以下の問題が発生しました。

発生している問題

進化順は本家?switch版と同じです。

進化前と進化後のフルーツ名をコンソールに出力するようにしているのですが、時折意図しないものが生成されてしまっています。
うまくいく時もあるので不安定な感じです。

//理想 old: orange new: kaki //問題 old: orange new: orange //問題2 old: kaki new: orange

イメージ説明

レンダリングでは衝突後に消えて新しいフルーツが生成されるまでは正常に動作しています。
生成するフルーツの種類をArray.findIndexで検索し、1を足して再度配列を参照するところでつまずいているみたいです。

該当のソースコード

実際はファイルを分けてexportしています。

  • データ定義

TypeScript

1type FruitData = { 2 name: string 3 point: number 4 radius: number 5 imageURL: string 6 } 7 8// データ自動生成 9const boxWidth = 300 10const maxRadius = boxWidth * (2 / 7) 11const fruitRadius = (num: number) => maxRadius / (1.2 ** num) 12 13// 定義 14const fruitList: FruitData[] = [ 15 { 16 name: 'cherry', 17 point: 1, 18 radius: fruitRadius(10), 19 imageURL: '' 20 }, 21//... 中略 22 { 23 name: 'watermelon', 24 point: 66, 25 radius: maxRadius, 26 imageURL: '' 27 } 28]
  • 処理

TypeScript

1/* 前略 */ 2 3// 進化後のフルーツの情報を取得 4const newFruitData = (list: FruitData[], name: string) => { 5 6 console.log(`old: ${name}`) // 進化前のフルーツ 7 8 // 進化後のフルーツのインデックス 9 const newIndex = list.findIndex(e => e.name === name) + 1 10 11 // スイカの時は生成しない 12 if (newIndex === list.length) return undefined 13 14 // もしもの為 15 if (newIndex === -1) return undefined 16 17 // 進化後のフルーツ 18 const newData = list[newIndex] 19 console.log(`new: ${newData.name}`) 20 return newData 21} 22 23// フルーツのbodyを生成するための関数 24type FruitObject = (data: FruitData, x: number, y: number) => Matter.Body 25const fruitObject: FruitObject = (data, x, y) => Bodies.circle(x, y, data.radius, { 26 label: data.name 27}) 28 29/* 中略 */ 30 31Events.on(engine, 'collisionStart', e => { 32 e.pairs.forEach(pair => { 33 if (pair.bodyA.label === pair.bodyB.label) { 34 // 間の座標を算出 35 const halfXY = () => { 36 const halfGapX = (pair.bodyA.position.x - pair.bodyB.position.x) / 2 37 const halfGapY = (pair.bodyA.position.y - pair.bodyB.position.y) / 2 38 return {x: pair.bodyA.position.x + halfGapX, y: pair.bodyB.position.y + halfGapY} 39 } 40 const newPos = halfXY() 41 42 // 衝突した2つを削除 43 Composite.remove(fruitsComposite, pair.bodyA) 44 Composite.remove(fruitsComposite, pair.bodyB) 45 46 // 上で定義した関数で新しいフルーツの情報を取得 47 const data = newFruitData(fruitList, pair.bodyA.label) 48 if (!data) return 49 console.log(data) 50 51 // 追加 52 const newFruit = fruitObject(data, newPos.x, newPos.y) 53 54 Composite.add(fruitsComposite, newFruit) 55 } 56 }) 57 })

試したこと

vitestで関数を抽出してテストしたところ何回試しても一貫して正常でした。

TypeScript

1const newFruitData = (list: FruitData[], name: string) => { 2 3 console.log(`old: ${name}`) // 進化前のフルーツ 4 5 // 進化後のフルーツのインデックス 6 const newIndex = list.findIndex(e => e.name === name) + 1 7 8 // スイカの時は生成しない 9 if (newIndex === list.length) return undefined 10 11 // もしもの為 12 if (newIndex === -1) return undefined 13 14 // 進化後のフルーツ 15 const newData = list[newIndex] 16 console.log(`new: ${newData.name}`) 17 return newData 18} 19 20 21test.only('config', () => { 22 // ランダムにフルーツの名前を生成 23 const randomName = fruitList[Math.trunc(Math.random() * fruitList.length)].name 24 25 const data = newFruitData(fruitList, randomName) 26 if (!data) return 27 console.log(data) 28})
old: orange new: kaki { name: 'kaki', point: 15, radius: 28.705540858318642, imageURL: '' }

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

Node.js v18.16.0
"solid-js": "^1.7.12"
"vite": "^4.4.9"
"solid-start": "^0.3.6"
"vitest": "^0.26.3"
"matter-js": "^0.19.0"

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

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

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

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

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

Lhankor_Mhy

2023/10/23 01:21

ご提示のコードから言えることはありませんが、私であれば fruitList の値をチェックするとは思います。
Tokino

2023/10/23 01:31

fruitListの値はmatter.js内とvitestでそれぞれ同じソースからimportしています。 vitestでは正常に動作しているので値に問題はないと思われます。
Lhankor_Mhy

2023/10/23 01:47

なるほど。 fruitList はミュータブルでしょうから、テスト時に実行されていない部分のコードで書き替え可能なのではないかと思ったのですが、問題ないのであれば失礼しました。
Tokino

2023/10/23 02:06

ミュータブルなので他で書き換え可能、というところが気になったので試しにfruitListを関数の引数からではなくグローバル変数に直接structurdCloneでディープコピーしてから利用してみたら正常に動きました。ヒントをくださりありがとうございます。 機能的にはミュータブルである必要はないので意図せず書き換えてしまっている部分を探してみます。
Lhankor_Mhy

2023/10/23 03:17

ご解決されて何よりです。
guest

回答1

0

自己解決

コメントで頂いたアドバイスをもとに解決できました。ありがとうございます。

問題のコード

実際のコードにはfruitListだけでなく、新しくフルーツを投下する用の配列を準備し、実際にフルーツを透過する時に使用していました。

TypeScript

1// 定義 2const dropData = fruitList.slice(0, 5) 3 4// この関数でランダムに呼び出していた 5const dropFruit = (fruitList: FruitData[]) => fruitList[Math.trunc(Math.random() * fruitList.length)]

このdropDatafruitListの参照をslice()していたので、fruitListに不必要な書き換えを引き起こしていました。

解決方法

TypeScript

1// 問題のコード 2const dropData = fruitList.slice(0, 5) 3 4// 解決後 5const dropData = structuredClone(fruitList).slice(0, 5)

structuredCloneでディープコピーして定義することでfruitListに影響が及ばなくなりました。

投稿2023/10/23 02:33

編集2023/10/23 03:35
Tokino

総合スコア8

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問