Update index.html
Browse files- index.html +126 -33
index.html
CHANGED
@@ -2,8 +2,9 @@
|
|
2 |
<html>
|
3 |
<head>
|
4 |
<meta charset="utf-8">
|
5 |
-
<title>A-Frame Space Shooter with 3D Editor</title>
|
6 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/aframe/1.2.0/aframe.min.js"></script>
|
|
|
7 |
<style>
|
8 |
.ui-panel {
|
9 |
position: fixed;
|
@@ -49,16 +50,17 @@
|
|
49 |
</div>
|
50 |
|
51 |
<div class="animation-panel">
|
52 |
-
<h3>
|
53 |
-
<p>
|
54 |
-
<input id="
|
55 |
-
<input id="
|
56 |
-
<input id="
|
57 |
<p>Rotation (degrees):</p>
|
58 |
<input id="rx" type="number" placeholder="X">
|
59 |
<input id="ry" type="number" placeholder="Y">
|
60 |
<input id="rz" type="number" placeholder="Z">
|
61 |
-
<button onclick="
|
|
|
62 |
</div>
|
63 |
|
64 |
<a-scene fog="type: linear; color: #87CEEB; near: 0; far: 50">
|
@@ -86,12 +88,84 @@
|
|
86 |
// Editor functionality
|
87 |
let selectedObject = null;
|
88 |
let isGameMode = true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
|
90 |
function addPrimitive(type) {
|
91 |
const scene = document.querySelector('a-scene');
|
92 |
const newEntity = document.createElement('a-entity');
|
93 |
newEntity.setAttribute('geometry', `primitive: ${type}`);
|
94 |
-
|
|
|
|
|
|
|
|
|
95 |
newEntity.setAttribute('position', '0 1.5 -3');
|
96 |
newEntity.setAttribute('class', 'editable');
|
97 |
newEntity.addEventListener('click', function() { selectObject(this); });
|
@@ -100,44 +174,62 @@
|
|
100 |
|
101 |
function selectObject(obj) {
|
102 |
if (selectedObject) {
|
103 |
-
selectedObject.setAttribute('material', '
|
104 |
}
|
105 |
selectedObject = obj;
|
106 |
-
selectedObject.setAttribute('material', '
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
107 |
}
|
108 |
|
109 |
-
function
|
110 |
if (!selectedObject) {
|
111 |
alert('Please select an object first');
|
112 |
return;
|
113 |
}
|
114 |
|
115 |
-
const
|
116 |
-
const
|
117 |
-
const
|
118 |
const rx = parseFloat(document.getElementById('rx').value) || 0;
|
119 |
const ry = parseFloat(document.getElementById('ry').value) || 0;
|
120 |
const rz = parseFloat(document.getElementById('rz').value) || 0;
|
121 |
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
141 |
}
|
142 |
|
143 |
function toggleGameMode() {
|
@@ -151,6 +243,7 @@
|
|
151 |
}
|
152 |
|
153 |
// Modify the click event listener to work with both game and edit modes
|
|
|
154 |
scene.addEventListener('click', (event) => {
|
155 |
if (isGameMode) {
|
156 |
fireLaser(player, '#00FF00');
|
|
|
2 |
<html>
|
3 |
<head>
|
4 |
<meta charset="utf-8">
|
5 |
+
<title>Enhanced A-Frame Space Shooter with 3D Editor</title>
|
6 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/aframe/1.2.0/aframe.min.js"></script>
|
7 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/simplex-noise/2.4.0/simplex-noise.min.js"></script>
|
8 |
<style>
|
9 |
.ui-panel {
|
10 |
position: fixed;
|
|
|
50 |
</div>
|
51 |
|
52 |
<div class="animation-panel">
|
53 |
+
<h3>Object Controls</h3>
|
54 |
+
<p>Position:</p>
|
55 |
+
<input id="px" type="number" placeholder="X">
|
56 |
+
<input id="py" type="number" placeholder="Y">
|
57 |
+
<input id="pz" type="number" placeholder="Z">
|
58 |
<p>Rotation (degrees):</p>
|
59 |
<input id="rx" type="number" placeholder="X">
|
60 |
<input id="ry" type="number" placeholder="Y">
|
61 |
<input id="rz" type="number" placeholder="Z">
|
62 |
+
<button onclick="applyTransform()">Apply Transform</button>
|
63 |
+
<button onclick="placeInFrontOfCamera()">Place in Front of Camera</button>
|
64 |
</div>
|
65 |
|
66 |
<a-scene fog="type: linear; color: #87CEEB; near: 0; far: 50">
|
|
|
88 |
// Editor functionality
|
89 |
let selectedObject = null;
|
90 |
let isGameMode = true;
|
91 |
+
const simplex = new SimplexNoise();
|
92 |
+
|
93 |
+
function generateProceduralTexture(size = 256) {
|
94 |
+
const canvas = document.createElement('canvas');
|
95 |
+
canvas.width = canvas.height = size;
|
96 |
+
const ctx = canvas.getContext('2d');
|
97 |
+
const imageData = ctx.createImageData(size, size);
|
98 |
+
const data = imageData.data;
|
99 |
+
|
100 |
+
for (let x = 0; x < size; x++) {
|
101 |
+
for (let y = 0; y < size; y++) {
|
102 |
+
const i = (x + y * size) * 4;
|
103 |
+
const value = (simplex.noise2D(x / 20, y / 20) + 1) / 2;
|
104 |
+
const hue = Math.floor(value * 360);
|
105 |
+
const [r, g, b] = HSVtoRGB(hue / 360, 0.7, 0.9);
|
106 |
+
data[i] = r;
|
107 |
+
data[i + 1] = g;
|
108 |
+
data[i + 2] = b;
|
109 |
+
data[i + 3] = 255;
|
110 |
+
}
|
111 |
+
}
|
112 |
+
|
113 |
+
ctx.putImageData(imageData, 0, 0);
|
114 |
+
return canvas.toDataURL();
|
115 |
+
}
|
116 |
+
|
117 |
+
function generateBumpMap(size = 256) {
|
118 |
+
const canvas = document.createElement('canvas');
|
119 |
+
canvas.width = canvas.height = size;
|
120 |
+
const ctx = canvas.getContext('2d');
|
121 |
+
const imageData = ctx.createImageData(size, size);
|
122 |
+
const data = imageData.data;
|
123 |
+
|
124 |
+
for (let x = 0; x < size; x++) {
|
125 |
+
for (let y = 0; y < size; y++) {
|
126 |
+
const i = (x + y * size) * 4;
|
127 |
+
const value = (simplex.noise2D(x / 10, y / 10) + 1) / 2;
|
128 |
+
const intensity = Math.floor(value * 255);
|
129 |
+
data[i] = data[i + 1] = data[i + 2] = intensity;
|
130 |
+
data[i + 3] = 255;
|
131 |
+
}
|
132 |
+
}
|
133 |
+
|
134 |
+
ctx.putImageData(imageData, 0, 0);
|
135 |
+
return canvas.toDataURL();
|
136 |
+
}
|
137 |
+
|
138 |
+
function HSVtoRGB(h, s, v) {
|
139 |
+
let r, g, b, i, f, p, q, t;
|
140 |
+
i = Math.floor(h * 6);
|
141 |
+
f = h * 6 - i;
|
142 |
+
p = v * (1 - s);
|
143 |
+
q = v * (1 - f * s);
|
144 |
+
t = v * (1 - (1 - f) * s);
|
145 |
+
switch (i % 6) {
|
146 |
+
case 0: r = v, g = t, b = p; break;
|
147 |
+
case 1: r = q, g = v, b = p; break;
|
148 |
+
case 2: r = p, g = v, b = t; break;
|
149 |
+
case 3: r = p, g = q, b = v; break;
|
150 |
+
case 4: r = t, g = p, b = v; break;
|
151 |
+
case 5: r = v, g = p, b = q; break;
|
152 |
+
}
|
153 |
+
return [
|
154 |
+
Math.round(r * 255),
|
155 |
+
Math.round(g * 255),
|
156 |
+
Math.round(b * 255)
|
157 |
+
];
|
158 |
+
}
|
159 |
|
160 |
function addPrimitive(type) {
|
161 |
const scene = document.querySelector('a-scene');
|
162 |
const newEntity = document.createElement('a-entity');
|
163 |
newEntity.setAttribute('geometry', `primitive: ${type}`);
|
164 |
+
|
165 |
+
const textureUrl = generateProceduralTexture();
|
166 |
+
const bumpMapUrl = generateBumpMap();
|
167 |
+
|
168 |
+
newEntity.setAttribute('material', `src: ${textureUrl}; normalMap: ${bumpMapUrl}`);
|
169 |
newEntity.setAttribute('position', '0 1.5 -3');
|
170 |
newEntity.setAttribute('class', 'editable');
|
171 |
newEntity.addEventListener('click', function() { selectObject(this); });
|
|
|
174 |
|
175 |
function selectObject(obj) {
|
176 |
if (selectedObject) {
|
177 |
+
selectedObject.setAttribute('material', 'emissive', '#000000');
|
178 |
}
|
179 |
selectedObject = obj;
|
180 |
+
selectedObject.setAttribute('material', 'emissive', '#FF0000');
|
181 |
+
|
182 |
+
// Update position inputs
|
183 |
+
const position = selectedObject.getAttribute('position');
|
184 |
+
document.getElementById('px').value = position.x;
|
185 |
+
document.getElementById('py').value = position.y;
|
186 |
+
document.getElementById('pz').value = position.z;
|
187 |
+
|
188 |
+
// Update rotation inputs
|
189 |
+
const rotation = selectedObject.getAttribute('rotation');
|
190 |
+
document.getElementById('rx').value = rotation.x;
|
191 |
+
document.getElementById('ry').value = rotation.y;
|
192 |
+
document.getElementById('rz').value = rotation.z;
|
193 |
}
|
194 |
|
195 |
+
function applyTransform() {
|
196 |
if (!selectedObject) {
|
197 |
alert('Please select an object first');
|
198 |
return;
|
199 |
}
|
200 |
|
201 |
+
const px = parseFloat(document.getElementById('px').value) || 0;
|
202 |
+
const py = parseFloat(document.getElementById('py').value) || 0;
|
203 |
+
const pz = parseFloat(document.getElementById('pz').value) || 0;
|
204 |
const rx = parseFloat(document.getElementById('rx').value) || 0;
|
205 |
const ry = parseFloat(document.getElementById('ry').value) || 0;
|
206 |
const rz = parseFloat(document.getElementById('rz').value) || 0;
|
207 |
|
208 |
+
selectedObject.setAttribute('position', `${px} ${py} ${pz}`);
|
209 |
+
selectedObject.setAttribute('rotation', `${rx} ${ry} ${rz}`);
|
210 |
+
}
|
211 |
+
|
212 |
+
function placeInFrontOfCamera() {
|
213 |
+
if (!selectedObject) {
|
214 |
+
alert('Please select an object first');
|
215 |
+
return;
|
216 |
+
}
|
217 |
+
|
218 |
+
const camera = document.querySelector('[camera]');
|
219 |
+
const cameraPosition = camera.getAttribute('position');
|
220 |
+
const cameraRotation = camera.getAttribute('rotation');
|
221 |
+
|
222 |
+
// Calculate position 3 units in front of the camera
|
223 |
+
const radians = THREE.MathUtils.degToRad(cameraRotation.y);
|
224 |
+
const x = cameraPosition.x - Math.sin(radians) * 3;
|
225 |
+
const z = cameraPosition.z - Math.cos(radians) * 3;
|
226 |
+
|
227 |
+
selectedObject.setAttribute('position', `${x} ${cameraPosition.y} ${z}`);
|
228 |
+
|
229 |
+
// Update position inputs
|
230 |
+
document.getElementById('px').value = x;
|
231 |
+
document.getElementById('py').value = cameraPosition.y;
|
232 |
+
document.getElementById('pz').value = z;
|
233 |
}
|
234 |
|
235 |
function toggleGameMode() {
|
|
|
243 |
}
|
244 |
|
245 |
// Modify the click event listener to work with both game and edit modes
|
246 |
+
const scene = document.querySelector('a-scene');
|
247 |
scene.addEventListener('click', (event) => {
|
248 |
if (isGameMode) {
|
249 |
fireLaser(player, '#00FF00');
|