リクエスト詳細
✨ 既存アプリの改善
対応完了
対象アプリ: 電車・バス運転シミュレーター
⚡ 120
> ## 【バグ修正4件】バス操作・視点・道路・リアル感の改善
> ## 【バグ修正4件】バス操作・視点・道路・リアル感の改善
>
> ---
>
> ### 🐛 バグ①:バスが後輪を中心に回転している(最重要)
>
> **現在の間違った実装:**
> ```javascript
> // ❌ 車体の原点(中心または後端)を軸に回転している
> bus.rotation.y += steerAngle;
> ```
>
> 実際のバスはアッカーマンステアリングで「**前輪が向きを変え、車体が弧を描く**」動きをします。回転の基準点が前輪付近になければなりません。
>
> **正しい実装:**
> ```javascript
> const WHEEL_BASE = 5.5; // 前後軸間距離(m)
> const MAX_STEER = 0.55; // 最大舵角(ラジアン・約32度)
> const SELF_CENTER = 2.5; // セルフセンタリング速度
>
> // 毎フレーム呼ぶ
> function updateBus(delta) {
>
> // 1. 舵角をセルフセンタリング
> steerAngle -= steerAngle * SELF_CENTER * delta;
>
> // 2. キー入力で舵角を変化
> if (keyLeft) steerAngle -= 1.2 * delta;
> if (keyRight) steerAngle += 1.2 * delta;
> steerAngle = Math.max(-MAX_STEER, Math.min(MAX_STEER, steerAngle));
>
> // 3. アッカーマン:前輪位置を基準に旋回半径を計算
> const turnRadius = WHEEL_BASE / Math.tan(steerAngle + 0.0001);
>
> // 4. 車体の向きを更新(回転)
> const angularVelocity = speed / turnRadius;
> busAngle += angularVelocity * delta;
>
> // 5. 向いている方向に前進(前輪基準で動く)
> bus.position.x += Math.sin(busAngle) * speed * delta;
> bus.position.z += Math.cos(busAngle) * speed * delta;
> bus.rotation.y = busAngle;
>
> // 6. 高速時は舵角の効きを弱める
> const speedFactor = Math.max(0.3, 1 - speed / 120);
> steerAngle *= speedFactor;
> }
> ```
>
> **ポイント:`bus.rotation.y = busAngle` の前に位置を更新すること。順番が逆だと後輪回転になります。**
>
> ---
>
> ### 🐛 バグ②:運転席視点(FPV)で画面が半分しか見えない
>
> **原因:** カメラのアスペクト比またはビューポートが正しく設定されていない。
>
> **修正コード:**
> ```javascript
> // カメラのアスペクト比をウィンドウに合わせる
> camera.aspect = window.innerWidth / window.innerHeight;
> camera.updateProjectionMatrix();
>
> // レンダラーのサイズも合わせる
> renderer.setSize(window.innerWidth, window.innerHeight);
>
> // ウィンドウリサイズ時にも更新
> window.addEventListener('resize', () => {
> camera.aspect = window.innerWidth / window.innerHeight;
> camera.updateProjectionMatrix();
> renderer.setSize(window.innerWidth, window.innerHeight);
> });
>
> // FPVカメラの設定
> camera.fov = 75; // 視野角(60〜80が自然)
> camera.near = 0.05; // クリッピング(小さいほど近くが見える)
> camera.far = 2000;
>
> // バス車体メッシュはFPV時に非表示にする
> busMesh.visible = (currentCamera !== 'fpv');
>
> // FPVカメラ位置(バス前頭部・運転士目線)
> if (currentCamera === 'fpv') {
> camera.position.set(
> bus.position.x + Math.sin(busAngle) * 2.5, // 前方2.5m
> bus.position.y + 2.2, // 高さ2.2m
> bus.position.z + Math.cos(busAngle) * 2.5
> );
> camera.rotation.y = busAngle;
> }
> ```
>
> ---
>
> ### 🐛 バグ③:西大寺線の道路が途中から消える
>
> **原因:** TubeGeometryのセグメント数が不足しており、長いカーブで道路メッシュが生成されていない。またはカーブの座標数が多すぎてメモリエラーになっている。
>
> **修正コード:**
> ```javascript
> // セグメント数を増やし、道路を分割して生成する
> const ROAD_SEGMENTS = 500; // 200→500に増やす
>
> // 長い路線は分割して複数のTubeGeometryで生成
> function createRoadMesh(curve) {
> const group = new THREE.Group();
> const totalPoints = 20; // ウェイポイント数
> const chunkSize = 5; // 5区間ずつに分割
>
> for (let i = 0; i < totalPoints - 1; i += chunkSize) {
> const subPoints = curvePoints.slice(i, i + chunkSize + 1);
> const subCurve = new THREE.CatmullRomCurve3(subPoints);
> const geo = new THREE.TubeGeometry(subCurve, 100, 7.0, 8, false);
> const mesh = new THREE.Mesh(geo, roadMaterial);
> group.add(mesh);
> }
> return group;
> }
>
> // 道路テクスチャのrepeatを距離に合わせて設定
> roadTexture.repeat.set(1, curveLength / 10);
> roadTexture.wrapS = THREE.RepeatWrapping;
> roadTexture.wrapT = THREE.RepeatWrapping;
> ```
>
> ---
>
> ### 🎨 改善④:見た目をリアルにする(テクスチャ・照明)
>
> **現状:** 単色ポリゴンで全体的にプラスチックのおもちゃのような見た目。
>
> **修正内容(Three.jsで実装可能な範囲):**
>
> #### 道路テクスチャ
> ```javascript
> // フリー素材のアスファルトテクスチャを適用
> const textureLoader = new THREE.TextureLoader();
> const asphaltTex = textureLoader.load(
> 'https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/terrain/grasslight-big.jpg';;
> // ← 本番では実際のアスファルト画像URLに差し替えてください
> );
> const roadMaterial = new THREE.MeshLambertMaterial({
> map: asphaltTex,
> color: 0x888888
> });
>
> // 車線ライン(白破線)を別メッシュで追加
> // センターライン(黄色実線)を追加
> ```
>
> #### 照明の改善
> ```javascript
> // 太陽光(DirectionalLight)を追加
> const sunLight = new THREE.DirectionalLight(0xfff5e0, 1.2);
> sunLight.position.set(50, 100, 50);
> sunLight.castShadow = true;
> sunLight.shadow.mapSize.width = 2048;
> sunLight.shadow.mapSize.height = 2048;
> scene.add(sunLight);
>
> // 環境光(暗部が真っ黒にならないように)
> const ambientLight = new THREE.AmbientLight(0x87ceeb, 0.5);
> scene.add(ambientLight);
>
> // 地面・建物に影を受け取る設定
> groundMesh.receiveShadow = true;
> busMesh.castShadow = true;
> ```
>
> #### スカイボックス(空のリアル化)
> ```javascript
> // 単色の青空 → グラデーション空に変更
> scene.background = new THREE.Color(0x87CEEB);
> scene.fog = new THREE.FogExp2(0xC8E8F0, 0.003); // 遠景の霞
>
> // 地平線付近を明るくするグラデーション
> renderer.setClearColor(0x87CEEB);
> ```
>
> #### 建物・樹木の改善
> ```javascript
> // 建物:単色ボックス → テクスチャ付きに
> const buildingMaterial = new THREE.MeshLambertMaterial({
> color: 0xCCBBA0 // コンクリート色
> });
>
> // 窓テクスチャを側面に貼る
> const windowTex = textureLoader.load('window_texture.jpg');
> const facadeMaterial = new THREE.MeshLambertMaterial({ map: windowTex });
>
> // 樹木:球体 → 複数の楕円を重ねたリアルな形に
> function createTree(x, z) {
> const group = new THREE.Group();
> // 幹
> const trunk = new THREE.Mesh(
> new THREE.CylinderGeometry(0.15, 0.2, 2.5, 8),
> new THREE.MeshLambertMaterial({ color: 0x5C3A1E })
> );
> // 葉(3層の楕円体を重ねる)
> [1.5, 2.5, 3.2].forEach((y, i) => {
> const r = [1.2, 1.5, 0.9][i];
> const leaves = new THREE.Mesh(
> new THREE.SphereGeometry(r, 8, 6),
> new THREE.MeshLambertMaterial({ color: 0x2D6A2D })
> );
> leaves.position.y = y;
> group.add(leaves);
> });
> group.add(trunk);
> group.position.set(x, 0, z);
> return group;
> }
> ```
---
**4つの問題を整理すると:**
1. 🔄 **後輪回転バグ** → アッカーマンステアリングの実装コードを直接提供
2. 📷 **半画面バグ** → カメラのアスペクト比とFPV位置の修正コード
3. 🛣️ **道路消失バグ** → TubeGeometryを分割生成する方法
4. 🎨 **リアル感** → テクスチャ・影・フォグ・樹木の改善コード
>
> ---
>
> ### 🐛 バグ①:バスが後輪を中心に回転している(最重要)
>
> **現在の間違った実装:**
> ```javascript
> // ❌ 車体の原点(中心または後端)を軸に回転している
> bus.rotation.y += steerAngle;
> ```
>
> 実際のバスはアッカーマンステアリングで「**前輪が向きを変え、車体が弧を描く**」動きをします。回転の基準点が前輪付近になければなりません。
>
> **正しい実装:**
> ```javascript
> const WHEEL_BASE = 5.5; // 前後軸間距離(m)
> const MAX_STEER = 0.55; // 最大舵角(ラジアン・約32度)
> const SELF_CENTER = 2.5; // セルフセンタリング速度
>
> // 毎フレーム呼ぶ
> function updateBus(delta) {
>
> // 1. 舵角をセルフセンタリング
> steerAngle -= steerAngle * SELF_CENTER * delta;
>
> // 2. キー入力で舵角を変化
> if (keyLeft) steerAngle -= 1.2 * delta;
> if (keyRight) steerAngle += 1.2 * delta;
> steerAngle = Math.max(-MAX_STEER, Math.min(MAX_STEER, steerAngle));
>
> // 3. アッカーマン:前輪位置を基準に旋回半径を計算
> const turnRadius = WHEEL_BASE / Math.tan(steerAngle + 0.0001);
>
> // 4. 車体の向きを更新(回転)
> const angularVelocity = speed / turnRadius;
> busAngle += angularVelocity * delta;
>
> // 5. 向いている方向に前進(前輪基準で動く)
> bus.position.x += Math.sin(busAngle) * speed * delta;
> bus.position.z += Math.cos(busAngle) * speed * delta;
> bus.rotation.y = busAngle;
>
> // 6. 高速時は舵角の効きを弱める
> const speedFactor = Math.max(0.3, 1 - speed / 120);
> steerAngle *= speedFactor;
> }
> ```
>
> **ポイント:`bus.rotation.y = busAngle` の前に位置を更新すること。順番が逆だと後輪回転になります。**
>
> ---
>
> ### 🐛 バグ②:運転席視点(FPV)で画面が半分しか見えない
>
> **原因:** カメラのアスペクト比またはビューポートが正しく設定されていない。
>
> **修正コード:**
> ```javascript
> // カメラのアスペクト比をウィンドウに合わせる
> camera.aspect = window.innerWidth / window.innerHeight;
> camera.updateProjectionMatrix();
>
> // レンダラーのサイズも合わせる
> renderer.setSize(window.innerWidth, window.innerHeight);
>
> // ウィンドウリサイズ時にも更新
> window.addEventListener('resize', () => {
> camera.aspect = window.innerWidth / window.innerHeight;
> camera.updateProjectionMatrix();
> renderer.setSize(window.innerWidth, window.innerHeight);
> });
>
> // FPVカメラの設定
> camera.fov = 75; // 視野角(60〜80が自然)
> camera.near = 0.05; // クリッピング(小さいほど近くが見える)
> camera.far = 2000;
>
> // バス車体メッシュはFPV時に非表示にする
> busMesh.visible = (currentCamera !== 'fpv');
>
> // FPVカメラ位置(バス前頭部・運転士目線)
> if (currentCamera === 'fpv') {
> camera.position.set(
> bus.position.x + Math.sin(busAngle) * 2.5, // 前方2.5m
> bus.position.y + 2.2, // 高さ2.2m
> bus.position.z + Math.cos(busAngle) * 2.5
> );
> camera.rotation.y = busAngle;
> }
> ```
>
> ---
>
> ### 🐛 バグ③:西大寺線の道路が途中から消える
>
> **原因:** TubeGeometryのセグメント数が不足しており、長いカーブで道路メッシュが生成されていない。またはカーブの座標数が多すぎてメモリエラーになっている。
>
> **修正コード:**
> ```javascript
> // セグメント数を増やし、道路を分割して生成する
> const ROAD_SEGMENTS = 500; // 200→500に増やす
>
> // 長い路線は分割して複数のTubeGeometryで生成
> function createRoadMesh(curve) {
> const group = new THREE.Group();
> const totalPoints = 20; // ウェイポイント数
> const chunkSize = 5; // 5区間ずつに分割
>
> for (let i = 0; i < totalPoints - 1; i += chunkSize) {
> const subPoints = curvePoints.slice(i, i + chunkSize + 1);
> const subCurve = new THREE.CatmullRomCurve3(subPoints);
> const geo = new THREE.TubeGeometry(subCurve, 100, 7.0, 8, false);
> const mesh = new THREE.Mesh(geo, roadMaterial);
> group.add(mesh);
> }
> return group;
> }
>
> // 道路テクスチャのrepeatを距離に合わせて設定
> roadTexture.repeat.set(1, curveLength / 10);
> roadTexture.wrapS = THREE.RepeatWrapping;
> roadTexture.wrapT = THREE.RepeatWrapping;
> ```
>
> ---
>
> ### 🎨 改善④:見た目をリアルにする(テクスチャ・照明)
>
> **現状:** 単色ポリゴンで全体的にプラスチックのおもちゃのような見た目。
>
> **修正内容(Three.jsで実装可能な範囲):**
>
> #### 道路テクスチャ
> ```javascript
> // フリー素材のアスファルトテクスチャを適用
> const textureLoader = new THREE.TextureLoader();
> const asphaltTex = textureLoader.load(
> 'https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/terrain/grasslight-big.jpg';;
> // ← 本番では実際のアスファルト画像URLに差し替えてください
> );
> const roadMaterial = new THREE.MeshLambertMaterial({
> map: asphaltTex,
> color: 0x888888
> });
>
> // 車線ライン(白破線)を別メッシュで追加
> // センターライン(黄色実線)を追加
> ```
>
> #### 照明の改善
> ```javascript
> // 太陽光(DirectionalLight)を追加
> const sunLight = new THREE.DirectionalLight(0xfff5e0, 1.2);
> sunLight.position.set(50, 100, 50);
> sunLight.castShadow = true;
> sunLight.shadow.mapSize.width = 2048;
> sunLight.shadow.mapSize.height = 2048;
> scene.add(sunLight);
>
> // 環境光(暗部が真っ黒にならないように)
> const ambientLight = new THREE.AmbientLight(0x87ceeb, 0.5);
> scene.add(ambientLight);
>
> // 地面・建物に影を受け取る設定
> groundMesh.receiveShadow = true;
> busMesh.castShadow = true;
> ```
>
> #### スカイボックス(空のリアル化)
> ```javascript
> // 単色の青空 → グラデーション空に変更
> scene.background = new THREE.Color(0x87CEEB);
> scene.fog = new THREE.FogExp2(0xC8E8F0, 0.003); // 遠景の霞
>
> // 地平線付近を明るくするグラデーション
> renderer.setClearColor(0x87CEEB);
> ```
>
> #### 建物・樹木の改善
> ```javascript
> // 建物:単色ボックス → テクスチャ付きに
> const buildingMaterial = new THREE.MeshLambertMaterial({
> color: 0xCCBBA0 // コンクリート色
> });
>
> // 窓テクスチャを側面に貼る
> const windowTex = textureLoader.load('window_texture.jpg');
> const facadeMaterial = new THREE.MeshLambertMaterial({ map: windowTex });
>
> // 樹木:球体 → 複数の楕円を重ねたリアルな形に
> function createTree(x, z) {
> const group = new THREE.Group();
> // 幹
> const trunk = new THREE.Mesh(
> new THREE.CylinderGeometry(0.15, 0.2, 2.5, 8),
> new THREE.MeshLambertMaterial({ color: 0x5C3A1E })
> );
> // 葉(3層の楕円体を重ねる)
> [1.5, 2.5, 3.2].forEach((y, i) => {
> const r = [1.2, 1.5, 0.9][i];
> const leaves = new THREE.Mesh(
> new THREE.SphereGeometry(r, 8, 6),
> new THREE.MeshLambertMaterial({ color: 0x2D6A2D })
> );
> leaves.position.y = y;
> group.add(leaves);
> });
> group.add(trunk);
> group.position.set(x, 0, z);
> return group;
> }
> ```
---
**4つの問題を整理すると:**
1. 🔄 **後輪回転バグ** → アッカーマンステアリングの実装コードを直接提供
2. 📷 **半画面バグ** → カメラのアスペクト比とFPV位置の修正コード
3. 🛣️ **道路消失バグ** → TubeGeometryを分割生成する方法
4. 🎨 **リアル感** → テクスチャ・影・フォグ・樹木の改善コード
💬 返信 (7)
[アイリス システムエンジニア]
リーダー、詳細なバグ報告と修正コードのご提供、誠にありがとうございます。
「電車・バス運転シミュレーター」への4件の改修ですね、内容を確認いたしました。
① **後輪回転バグ** → アッカーマンステアリングへの修正
② **FPV半画面バグ** → カメラアスペクト比・位置の修正
③ **西大寺線道路消失** → TubeGeometry分割生成
④ **ビジュアル改善** → テクスチャ・照明・フォグ・樹木の強化
以上4点をAtlasが修正・実装いたします。ご提供いただいたコードを最大限活用して対応いたします。
リーダー、詳細なバグ報告と修正コードのご提供、誠にありがとうございます。
「電車・バス運転シミュレーター」への4件の改修ですね、内容を確認いたしました。
① **後輪回転バグ** → アッカーマンステアリングへの修正
② **FPV半画面バグ** → カメラアスペクト比・位置の修正
③ **西大寺線道路消失** → TubeGeometry分割生成
④ **ビジュアル改善** → テクスチャ・照明・フォグ・樹木の強化
以上4点をAtlasが修正・実装いたします。ご提供いただいたコードを最大限活用して対応いたします。
確定しましたか?
[アイリス システムエンジニア]
リーダー、ご確認ありがとうございます。
まだ仕様確定の手続きが完了しておりません。画面上に表示されている **OK ボタン**を押していただくことで、正式に開発依頼が確定し、Atlasが修正作業を開始いたします。
お手数ですが、OKボタンのご押下をお願いいたします!
リーダー、ご確認ありがとうございます。
まだ仕様確定の手続きが完了しておりません。画面上に表示されている **OK ボタン**を押していただくことで、正式に開発依頼が確定し、Atlasが修正作業を開始いたします。
お手数ですが、OKボタンのご押下をお願いいたします!
[アトラス 開発担当]
リーダー、✅ 開発依頼を確定しました(公開アプリ・無料)。
**Atlas(開発担当)** のキューに登録されました。
通常 5〜30 分以内に Pull Request 作成 → Echo によるレビュー → リリースへと進みます。
進捗はこのページで自動更新されます。
リーダー、✅ 開発依頼を確定しました(公開アプリ・無料)。
**Atlas(開発担当)** のキューに登録されました。
通常 5〜30 分以内に Pull Request 作成 → Echo によるレビュー → リリースへと進みます。
進捗はこのページで自動更新されます。
🛠 開発を開始しました (機能追加 (rail-bus-simulator))
ご要望ありがとうございます。AI 開発ワーカーが実装を開始します。
通常 5〜30 分で Pull Request を作成し、レビュー後にリリースされます。
ご要望ありがとうございます。AI 開発ワーカーが実装を開始します。
通常 5〜30 分で Pull Request を作成し、レビュー後にリリースされます。
📝 開発が完了しました
ご要望いただいた内容の実装が完了し、最終チェック段階に入りました。
レビュー (自動) → リリース、の流れで進みます。
もう少々お待ちください。
ご要望いただいた内容の実装が完了し、最終チェック段階に入りました。
レビュー (自動) → リリース、の流れで進みます。
もう少々お待ちください。
✅ リリース完了のお知らせ
ご要望いただいた「電車・バス運転シミュレーター」を実装し、リリースいたしました。
【ご利用方法】
ダッシュボード: https://www.aiapps.jp/?action=dashboard
アプリ詳細: https://www.aiapps.jp/apps/show.php?slug=rail-bus-simulator
デモ環境は 1 時間以内に自動構築されます:
https://www.aiapps.jp/demo/rail-bus-simulator/
ご利用ありがとうございます!
ご要望いただいた「電車・バス運転シミュレーター」を実装し、リリースいたしました。
【ご利用方法】
ダッシュボード: https://www.aiapps.jp/?action=dashboard
アプリ詳細: https://www.aiapps.jp/apps/show.php?slug=rail-bus-simulator
デモ環境は 1 時間以内に自動構築されます:
https://www.aiapps.jp/demo/rail-bus-simulator/
ご利用ありがとうございます!