Spaces:
Running
Running
gini1
commited on
Update index.html
Browse files- index.html +113 -44
index.html
CHANGED
@@ -42,6 +42,22 @@
|
|
42 |
#fileUpload.hidden {
|
43 |
display: none;
|
44 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
#startButton {
|
46 |
margin-top: 10px;
|
47 |
padding: 10px 20px;
|
@@ -55,6 +71,22 @@
|
|
55 |
background: #666;
|
56 |
cursor: not-allowed;
|
57 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
</style>
|
59 |
<script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>
|
60 |
<script type="importmap">
|
@@ -85,10 +117,14 @@
|
|
85 |
<div id="fileUpload">
|
86 |
<h2>3D Open World Game</h2>
|
87 |
<p>Upload your character model (GLB file)</p>
|
88 |
-
<
|
89 |
-
|
|
|
|
|
|
|
90 |
<button id="startButton" disabled>Start Game</button>
|
91 |
</div>
|
|
|
92 |
|
93 |
<script type="module">
|
94 |
import * as THREE from 'three';
|
@@ -98,15 +134,23 @@
|
|
98 |
let scene, camera, renderer, controls;
|
99 |
let character = null;
|
100 |
let uploadedModel = null;
|
|
|
|
|
|
|
|
|
101 |
|
102 |
-
//
|
103 |
const fileInput = document.getElementById('glbFile');
|
104 |
const startButton = document.getElementById('startButton');
|
105 |
const uploadDiv = document.getElementById('fileUpload');
|
|
|
|
|
|
|
106 |
|
107 |
fileInput.addEventListener('change', function(e) {
|
108 |
const file = e.target.files[0];
|
109 |
if (file) {
|
|
|
110 |
uploadedModel = URL.createObjectURL(file);
|
111 |
startButton.disabled = false;
|
112 |
}
|
@@ -119,6 +163,59 @@
|
|
119 |
}
|
120 |
});
|
121 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
122 |
function initGame() {
|
123 |
// ๊ธฐ๋ณธ ์ค์
|
124 |
scene = new THREE.Scene();
|
@@ -128,6 +225,10 @@
|
|
128 |
renderer.shadowMap.enabled = true;
|
129 |
document.body.appendChild(renderer.domElement);
|
130 |
|
|
|
|
|
|
|
|
|
131 |
// ๋ฌผ๋ฆฌ ์์คํ
๋ณ์
|
132 |
const gravity = -0.5;
|
133 |
let velocity = new THREE.Vector3();
|
@@ -135,10 +236,6 @@
|
|
135 |
let canJump = true;
|
136 |
let playerHeight = 2;
|
137 |
|
138 |
-
// ์บ๋ฆญํฐ ์ํ
|
139 |
-
let hp = 100;
|
140 |
-
const hpElement = document.getElementById('hp');
|
141 |
-
|
142 |
// ํฌ์ธํฐ ๋ฝ ์ปจํธ๋กค
|
143 |
controls = new PointerLockControls(camera, document.body);
|
144 |
|
@@ -230,45 +327,15 @@
|
|
230 |
}
|
231 |
};
|
232 |
|
233 |
-
// NPC ์์คํ
|
234 |
-
class NPC {
|
235 |
-
constructor(position) {
|
236 |
-
const geometry = new THREE.CapsuleGeometry(1, 2, 4, 8);
|
237 |
-
const material = new THREE.MeshPhongMaterial({ color: 0xff0000 });
|
238 |
-
this.mesh = new THREE.Mesh(geometry, material);
|
239 |
-
this.mesh.position.copy(position);
|
240 |
-
this.mesh.castShadow = true;
|
241 |
-
this.velocity = new THREE.Vector3();
|
242 |
-
this.direction = new THREE.Vector3();
|
243 |
-
scene.add(this.mesh);
|
244 |
-
}
|
245 |
-
|
246 |
-
update(playerPosition) {
|
247 |
-
this.direction.subVectors(playerPosition, this.mesh.position);
|
248 |
-
this.direction.normalize();
|
249 |
-
this.velocity.add(this.direction.multiplyScalar(0.1));
|
250 |
-
this.velocity.multiplyScalar(0.95);
|
251 |
-
this.mesh.position.add(this.velocity);
|
252 |
-
|
253 |
-
const distance = this.mesh.position.distanceTo(playerPosition);
|
254 |
-
if (distance < 2) {
|
255 |
-
hp -= 1;
|
256 |
-
hpElement.textContent = hp;
|
257 |
-
if (hp <= 0) {
|
258 |
-
alert('Game Over!');
|
259 |
-
location.reload();
|
260 |
-
}
|
261 |
-
}
|
262 |
-
}
|
263 |
-
}
|
264 |
-
|
265 |
// NPC ์์ฑ
|
266 |
const npcs = [];
|
267 |
for (let i = 0; i < 5; i++) {
|
|
|
|
|
268 |
const position = new THREE.Vector3(
|
269 |
-
|
270 |
2,
|
271 |
-
|
272 |
);
|
273 |
npcs.push(new NPC(position));
|
274 |
}
|
@@ -322,7 +389,9 @@
|
|
322 |
|
323 |
// ๋ฐ์ ์์ฑ
|
324 |
const rockGeometry = new THREE.DodecahedronGeometry(2);
|
325 |
-
const rockMaterial = new THREE.
|
|
|
|
|
326 |
addEnvironmentObject(rockGeometry, rockMaterial, 50, 1);
|
327 |
|
328 |
// ์บ๋ฆญํฐ ๋ชจ๋ธ ๋ก๋
|
@@ -392,7 +461,7 @@
|
|
392 |
// ๋น ์
๋ฐ์ดํธ
|
393 |
if (rain.visible) {
|
394 |
const positions = rain.geometry.attributes.position.array;
|
395 |
-
for (let i = 1; i < positions.length; i +=3) {
|
396 |
positions[i] -= 2;
|
397 |
if (positions[i] < 0) {
|
398 |
positions[i] = 500;
|
@@ -426,4 +495,4 @@
|
|
426 |
};
|
427 |
</script>
|
428 |
</body>
|
429 |
-
</html>
|
|
|
42 |
#fileUpload.hidden {
|
43 |
display: none;
|
44 |
}
|
45 |
+
.custom-file-upload {
|
46 |
+
display: inline-block;
|
47 |
+
padding: 12px 24px;
|
48 |
+
background: #2196F3;
|
49 |
+
color: white;
|
50 |
+
border-radius: 5px;
|
51 |
+
cursor: pointer;
|
52 |
+
margin: 10px 0;
|
53 |
+
transition: background 0.3s;
|
54 |
+
}
|
55 |
+
.custom-file-upload:hover {
|
56 |
+
background: #1976D2;
|
57 |
+
}
|
58 |
+
input[type="file"] {
|
59 |
+
display: none;
|
60 |
+
}
|
61 |
#startButton {
|
62 |
margin-top: 10px;
|
63 |
padding: 10px 20px;
|
|
|
71 |
background: #666;
|
72 |
cursor: not-allowed;
|
73 |
}
|
74 |
+
#selectedFileName {
|
75 |
+
margin-top: 10px;
|
76 |
+
color: #4CAF50;
|
77 |
+
}
|
78 |
+
#safeTimer {
|
79 |
+
position: absolute;
|
80 |
+
top: 50%;
|
81 |
+
left: 50%;
|
82 |
+
transform: translate(-50%, -50%);
|
83 |
+
background: rgba(0,0,0,0.7);
|
84 |
+
color: white;
|
85 |
+
padding: 20px;
|
86 |
+
border-radius: 10px;
|
87 |
+
font-size: 24px;
|
88 |
+
display: none;
|
89 |
+
}
|
90 |
</style>
|
91 |
<script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>
|
92 |
<script type="importmap">
|
|
|
117 |
<div id="fileUpload">
|
118 |
<h2>3D Open World Game</h2>
|
119 |
<p>Upload your character model (GLB file)</p>
|
120 |
+
<label class="custom-file-upload">
|
121 |
+
Choose GLB File
|
122 |
+
<input type="file" id="glbFile" accept=".glb" />
|
123 |
+
</label>
|
124 |
+
<div id="selectedFileName"></div>
|
125 |
<button id="startButton" disabled>Start Game</button>
|
126 |
</div>
|
127 |
+
<div id="safeTimer"></div>
|
128 |
|
129 |
<script type="module">
|
130 |
import * as THREE from 'three';
|
|
|
134 |
let scene, camera, renderer, controls;
|
135 |
let character = null;
|
136 |
let uploadedModel = null;
|
137 |
+
let hp = 100;
|
138 |
+
let gameStartTime = 0;
|
139 |
+
let isSafePeriod = true;
|
140 |
+
const SAFE_PERIOD = 30; // 30์ด ์์ ์๊ฐ
|
141 |
|
142 |
+
// ํ์ผ ์
๋ก๋ ์ฒ๋ฆฌ
|
143 |
const fileInput = document.getElementById('glbFile');
|
144 |
const startButton = document.getElementById('startButton');
|
145 |
const uploadDiv = document.getElementById('fileUpload');
|
146 |
+
const selectedFileName = document.getElementById('selectedFileName');
|
147 |
+
const safeTimer = document.getElementById('safeTimer');
|
148 |
+
const hpElement = document.getElementById('hp');
|
149 |
|
150 |
fileInput.addEventListener('change', function(e) {
|
151 |
const file = e.target.files[0];
|
152 |
if (file) {
|
153 |
+
selectedFileName.textContent = `Selected: ${file.name}`;
|
154 |
uploadedModel = URL.createObjectURL(file);
|
155 |
startButton.disabled = false;
|
156 |
}
|
|
|
163 |
}
|
164 |
});
|
165 |
|
166 |
+
// NPC ํด๋์ค
|
167 |
+
class NPC {
|
168 |
+
constructor(position) {
|
169 |
+
const geometry = new THREE.CapsuleGeometry(1, 2, 4, 8);
|
170 |
+
const material = new THREE.MeshPhongMaterial({ color: 0xff0000 });
|
171 |
+
this.mesh = new THREE.Mesh(geometry, material);
|
172 |
+
this.mesh.position.copy(position);
|
173 |
+
this.mesh.castShadow = true;
|
174 |
+
this.velocity = new THREE.Vector3();
|
175 |
+
this.direction = new THREE.Vector3();
|
176 |
+
this.speed = 0.05; // ๊ฐ์๋ ๊ธฐ๋ณธ ์๋
|
177 |
+
this.damage = 0.5; // ๊ฐ์๋ ๋ฐ๋ฏธ์ง
|
178 |
+
scene.add(this.mesh);
|
179 |
+
}
|
180 |
+
|
181 |
+
update(playerPosition) {
|
182 |
+
// ์์ ์๊ฐ ์ฒดํฌ
|
183 |
+
if (isSafePeriod) {
|
184 |
+
const elapsedTime = Math.floor((Date.now() - gameStartTime) / 1000);
|
185 |
+
const remainingTime = SAFE_PERIOD - elapsedTime;
|
186 |
+
|
187 |
+
if (remainingTime > 0) {
|
188 |
+
safeTimer.style.display = 'block';
|
189 |
+
safeTimer.textContent = `Safe Period: ${remainingTime}s`;
|
190 |
+
return; // NPC ์์ง์ ์ค์ง
|
191 |
+
} else {
|
192 |
+
safeTimer.style.display = 'none';
|
193 |
+
isSafePeriod = false;
|
194 |
+
}
|
195 |
+
}
|
196 |
+
|
197 |
+
// ๊ฑฐ๋ฆฌ์ ๋ฐ๋ฅธ ์๋์ ๋ฐ๋ฏธ์ง ์กฐ์
|
198 |
+
const distance = this.mesh.position.distanceTo(playerPosition);
|
199 |
+
this.speed = Math.min(0.05 + (50 - distance) * 0.001, 0.15);
|
200 |
+
|
201 |
+
this.direction.subVectors(playerPosition, this.mesh.position);
|
202 |
+
this.direction.normalize();
|
203 |
+
this.velocity.add(this.direction.multiplyScalar(this.speed));
|
204 |
+
this.velocity.multiplyScalar(0.95);
|
205 |
+
this.mesh.position.add(this.velocity);
|
206 |
+
|
207 |
+
// ์ถฉ๋ ๋ฐ ๋ฐ๋ฏธ์ง ์ฒ๋ฆฌ
|
208 |
+
if (distance < 2 && !isSafePeriod) {
|
209 |
+
hp -= this.damage;
|
210 |
+
hpElement.textContent = Math.floor(hp);
|
211 |
+
if (hp <= 0) {
|
212 |
+
alert('Game Over! Play again?');
|
213 |
+
location.reload();
|
214 |
+
}
|
215 |
+
}
|
216 |
+
}
|
217 |
+
}
|
218 |
+
|
219 |
function initGame() {
|
220 |
// ๊ธฐ๋ณธ ์ค์
|
221 |
scene = new THREE.Scene();
|
|
|
225 |
renderer.shadowMap.enabled = true;
|
226 |
document.body.appendChild(renderer.domElement);
|
227 |
|
228 |
+
// ๊ฒ์ ์์ ์๊ฐ ๊ธฐ๋ก
|
229 |
+
gameStartTime = Date.now();
|
230 |
+
isSafePeriod = true;
|
231 |
+
|
232 |
// ๋ฌผ๋ฆฌ ์์คํ
๋ณ์
|
233 |
const gravity = -0.5;
|
234 |
let velocity = new THREE.Vector3();
|
|
|
236 |
let canJump = true;
|
237 |
let playerHeight = 2;
|
238 |
|
|
|
|
|
|
|
|
|
239 |
// ํฌ์ธํฐ ๋ฝ ์ปจํธ๋กค
|
240 |
controls = new PointerLockControls(camera, document.body);
|
241 |
|
|
|
327 |
}
|
328 |
};
|
329 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
330 |
// NPC ์์ฑ
|
331 |
const npcs = [];
|
332 |
for (let i = 0; i < 5; i++) {
|
333 |
+
const angle = (i / 5) * Math.PI * 2;
|
334 |
+
const radius = 100; // ๋ ๋ฉ๋ฆฌ ๋ฐฐ์น
|
335 |
const position = new THREE.Vector3(
|
336 |
+
Math.cos(angle) * radius,
|
337 |
2,
|
338 |
+
Math.sin(angle) * radius
|
339 |
);
|
340 |
npcs.push(new NPC(position));
|
341 |
}
|
|
|
389 |
|
390 |
// ๋ฐ์ ์์ฑ
|
391 |
const rockGeometry = new THREE.DodecahedronGeometry(2);
|
392 |
+
const rockMaterial = new THREE.MeshSt
|
393 |
+
|
394 |
+
const rockMaterial = new THREE.MeshStandardMaterial({ color: 0x666666 });
|
395 |
addEnvironmentObject(rockGeometry, rockMaterial, 50, 1);
|
396 |
|
397 |
// ์บ๋ฆญํฐ ๋ชจ๋ธ ๋ก๋
|
|
|
461 |
// ๋น ์
๋ฐ์ดํธ
|
462 |
if (rain.visible) {
|
463 |
const positions = rain.geometry.attributes.position.array;
|
464 |
+
for (let i = 1; i < positions.length; i += 3) {
|
465 |
positions[i] -= 2;
|
466 |
if (positions[i] < 0) {
|
467 |
positions[i] = 500;
|
|
|
495 |
};
|
496 |
</script>
|
497 |
</body>
|
498 |
+
</html>
|