oggata commited on
Commit
f6eab66
·
verified ·
1 Parent(s): c1d18c9

Update static/js/three_map.js

Browse files
Files changed (1) hide show
  1. static/js/three_map.js +119 -15
static/js/three_map.js CHANGED
@@ -1,5 +1,6 @@
1
  // Three.jsを使用した3Dマップの実装
2
  let scene, camera, renderer, buildings = {}, residents = {};
 
3
 
4
  function init() {
5
  // シーンの作成
@@ -14,6 +15,7 @@ function init() {
14
  // レンダラーの設定
15
  renderer = new THREE.WebGLRenderer({ antialias: true });
16
  renderer.setSize(window.innerWidth, window.innerHeight);
 
17
  document.getElementById('three-container').appendChild(renderer.domElement);
18
 
19
  // 光源の追加
@@ -21,6 +23,7 @@ function init() {
21
  scene.add(ambientLight);
22
  const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
23
  directionalLight.position.set(50, 50, 50);
 
24
  scene.add(directionalLight);
25
 
26
  // 地面の作成
@@ -31,8 +34,14 @@ function init() {
31
  });
32
  const ground = new THREE.Mesh(groundGeometry, groundMaterial);
33
  ground.rotation.x = -Math.PI / 2;
 
34
  scene.add(ground);
35
 
 
 
 
 
 
36
  // アニメーションループの開始
37
  animate();
38
 
@@ -40,11 +49,46 @@ function init() {
40
  window.addEventListener('resize', onWindowResize, false);
41
  }
42
 
43
- function createBuilding(name, position, color = 0x808080) {
44
- const geometry = new THREE.BoxGeometry(10, 10, 10);
45
- const material = new THREE.MeshStandardMaterial({ color: color });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  const building = new THREE.Mesh(geometry, material);
47
- building.position.set(position.x, 5, position.z);
 
 
48
  scene.add(building);
49
  buildings[name] = building;
50
 
@@ -59,15 +103,53 @@ function createBuilding(name, position, color = 0x808080) {
59
  const texture = new THREE.CanvasTexture(canvas);
60
  const labelMaterial = new THREE.SpriteMaterial({ map: texture });
61
  const label = new THREE.Sprite(labelMaterial);
62
- label.position.set(position.x, 15, position.z);
63
  scene.add(label);
64
  }
65
 
66
- function createResident(name, position, color = 0xff0000) {
67
- const geometry = new THREE.SphereGeometry(1, 32, 32);
68
- const material = new THREE.MeshStandardMaterial({ color: color });
69
- const resident = new THREE.Mesh(geometry, material);
70
- resident.position.set(position.x, 1, position.z);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  scene.add(resident);
72
  residents[name] = resident;
73
 
@@ -82,7 +164,7 @@ function createResident(name, position, color = 0xff0000) {
82
  const texture = new THREE.CanvasTexture(canvas);
83
  const labelMaterial = new THREE.SpriteMaterial({ map: texture });
84
  const label = new THREE.Sprite(labelMaterial);
85
- label.position.set(position.x, 3, position.z);
86
  scene.add(label);
87
  }
88
 
@@ -90,20 +172,41 @@ function updatePositions(state) {
90
  // 建物の位置を更新
91
  state.locations.forEach(location => {
92
  if (!buildings[location.name]) {
93
- createBuilding(location.name, location.position);
 
 
 
 
 
94
  }
95
  });
96
 
97
  // 住民の位置を更新
98
  state.residents.forEach(resident => {
99
  if (!residents[resident.name]) {
100
- createResident(resident.name, resident.position);
101
  } else {
102
- residents[resident.name].position.set(
 
 
103
  resident.position.x,
104
- 1,
105
  resident.position.z
106
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  }
108
  });
109
  }
@@ -116,6 +219,7 @@ function onWindowResize() {
116
 
117
  function animate() {
118
  requestAnimationFrame(animate);
 
119
  renderer.render(scene, camera);
120
  }
121
 
 
1
  // Three.jsを使用した3Dマップの実装
2
  let scene, camera, renderer, buildings = {}, residents = {};
3
+ let controls;
4
 
5
  function init() {
6
  // シーンの作成
 
15
  // レンダラーの設定
16
  renderer = new THREE.WebGLRenderer({ antialias: true });
17
  renderer.setSize(window.innerWidth, window.innerHeight);
18
+ renderer.shadowMap.enabled = true;
19
  document.getElementById('three-container').appendChild(renderer.domElement);
20
 
21
  // 光源の追加
 
23
  scene.add(ambientLight);
24
  const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
25
  directionalLight.position.set(50, 50, 50);
26
+ directionalLight.castShadow = true;
27
  scene.add(directionalLight);
28
 
29
  // 地面の作成
 
34
  });
35
  const ground = new THREE.Mesh(groundGeometry, groundMaterial);
36
  ground.rotation.x = -Math.PI / 2;
37
+ ground.receiveShadow = true;
38
  scene.add(ground);
39
 
40
+ // カメラコントロールの追加
41
+ controls = new THREE.OrbitControls(camera, renderer.domElement);
42
+ controls.enableDamping = true;
43
+ controls.dampingFactor = 0.05;
44
+
45
  // アニメーションループの開始
46
  animate();
47
 
 
49
  window.addEventListener('resize', onWindowResize, false);
50
  }
51
 
52
+ function createBuilding(name, position, type) {
53
+ let geometry, material, color;
54
+
55
+ // 建物の種類に応じて形状と色を設定
56
+ switch(type) {
57
+ case '住宅':
58
+ geometry = new THREE.BoxGeometry(8, 6, 8);
59
+ color = 0xFFB6C1; // ピンク系
60
+ break;
61
+ case '公園':
62
+ geometry = new THREE.CylinderGeometry(5, 5, 2, 32);
63
+ color = 0x228B22; // 森の緑
64
+ break;
65
+ case '図書館':
66
+ geometry = new THREE.BoxGeometry(12, 8, 12);
67
+ color = 0x8B4513; // 茶色
68
+ break;
69
+ case 'カフェ':
70
+ geometry = new THREE.BoxGeometry(10, 6, 10);
71
+ color = 0xDEB887; // ベージュ
72
+ break;
73
+ case '商店':
74
+ geometry = new THREE.BoxGeometry(10, 5, 10);
75
+ color = 0x4682B4; // スチールブルー
76
+ break;
77
+ default:
78
+ geometry = new THREE.BoxGeometry(10, 10, 10);
79
+ color = 0x808080;
80
+ }
81
+
82
+ material = new THREE.MeshStandardMaterial({
83
+ color: color,
84
+ roughness: 0.7,
85
+ metalness: 0.2
86
+ });
87
+
88
  const building = new THREE.Mesh(geometry, material);
89
+ building.position.set(position.x, geometry.parameters.height / 2, position.z);
90
+ building.castShadow = true;
91
+ building.receiveShadow = true;
92
  scene.add(building);
93
  buildings[name] = building;
94
 
 
103
  const texture = new THREE.CanvasTexture(canvas);
104
  const labelMaterial = new THREE.SpriteMaterial({ map: texture });
105
  const label = new THREE.Sprite(labelMaterial);
106
+ label.position.set(position.x, geometry.parameters.height + 2, position.z);
107
  scene.add(label);
108
  }
109
 
110
+ function createResident(name, position, profession) {
111
+ let geometry, material, color;
112
+
113
+ // 職業に応じて色を設定
114
+ switch(profession) {
115
+ case '教師':
116
+ color = 0x0000FF; // 青
117
+ break;
118
+ case '看護師':
119
+ color = 0xFF0000; // 赤
120
+ break;
121
+ case 'エンジニア':
122
+ color = 0x00FF00; // 緑
123
+ break;
124
+ case 'デザイナー':
125
+ color = 0xFF00FF; // マゼンタ
126
+ break;
127
+ case '商店主':
128
+ color = 0xFFA500; // オレンジ
129
+ break;
130
+ default:
131
+ color = 0xFFFFFF; // 白
132
+ }
133
+
134
+ // 頭部
135
+ const headGeometry = new THREE.SphereGeometry(1, 32, 32);
136
+ const headMaterial = new THREE.MeshStandardMaterial({ color: 0xFFE4C4 });
137
+ const head = new THREE.Mesh(headGeometry, headMaterial);
138
+ head.position.y = 2;
139
+ head.castShadow = true;
140
+
141
+ // 胴体
142
+ const bodyGeometry = new THREE.CylinderGeometry(0.7, 0.7, 2, 32);
143
+ const bodyMaterial = new THREE.MeshStandardMaterial({ color: color });
144
+ const body = new THREE.Mesh(bodyGeometry, bodyMaterial);
145
+ body.position.y = 0.5;
146
+ body.castShadow = true;
147
+
148
+ // グループ化
149
+ const resident = new THREE.Group();
150
+ resident.add(head);
151
+ resident.add(body);
152
+ resident.position.set(position.x, 0, position.z);
153
  scene.add(resident);
154
  residents[name] = resident;
155
 
 
164
  const texture = new THREE.CanvasTexture(canvas);
165
  const labelMaterial = new THREE.SpriteMaterial({ map: texture });
166
  const label = new THREE.Sprite(labelMaterial);
167
+ label.position.set(position.x, 4, position.z);
168
  scene.add(label);
169
  }
170
 
 
172
  // 建物の位置を更新
173
  state.locations.forEach(location => {
174
  if (!buildings[location.name]) {
175
+ const type = location.name.includes('住宅') ? '住宅' :
176
+ location.name.includes('公園') ? '公園' :
177
+ location.name.includes('図書館') ? '図書館' :
178
+ location.name.includes('カフェ') ? 'カフェ' :
179
+ location.name.includes('商店') ? '商店' : 'その他';
180
+ createBuilding(location.name, location.position, type);
181
  }
182
  });
183
 
184
  // 住民の位置を更新
185
  state.residents.forEach(resident => {
186
  if (!residents[resident.name]) {
187
+ createResident(resident.name, resident.position, resident.profession);
188
  } else {
189
+ // 現在位置から目標位置への移動をアニメーション
190
+ const currentPos = residents[resident.name].position;
191
+ const targetPos = new THREE.Vector3(
192
  resident.position.x,
193
+ 0,
194
  resident.position.z
195
  );
196
+
197
+ // 移動速度
198
+ const speed = 0.1;
199
+
200
+ // 現在位置から目標位置への方向ベクトル
201
+ const direction = targetPos.sub(currentPos).normalize();
202
+
203
+ // 移動
204
+ currentPos.add(direction.multiplyScalar(speed));
205
+
206
+ // 住民の向きを移動方向に合わせる
207
+ if (direction.length() > 0) {
208
+ residents[resident.name].lookAt(targetPos);
209
+ }
210
  }
211
  });
212
  }
 
219
 
220
  function animate() {
221
  requestAnimationFrame(animate);
222
+ controls.update();
223
  renderer.render(scene, camera);
224
  }
225