This commit is contained in:
2025-11-25 05:54:23 +11:00
parent adc91709f8
commit 12d4d5c15d
3 changed files with 176 additions and 35 deletions

View File

@@ -130,7 +130,16 @@ document.addEventListener('DOMContentLoaded', () => {
stone_pickaxe: loadItemTexture('stone_pickaxe.png'), stone_pickaxe: loadItemTexture('stone_pickaxe.png'),
iron_pickaxe: loadItemTexture('iron_pickaxe.png'), iron_pickaxe: loadItemTexture('iron_pickaxe.png'),
gold_pickaxe: loadItemTexture('gold_pickaxe.png'), gold_pickaxe: loadItemTexture('gold_pickaxe.png'),
diamond_pickaxe: loadItemTexture('diamond_pickaxe.png') diamond_pickaxe: loadItemTexture('diamond_pickaxe.png'),
tnt_side: loadTexture('tnt_side.png'),
tnt_top: loadTexture('tnt_top.png'),
tnt_bottom: loadTexture('tnt_bottom.png'),
particle: (() => {
const t = new THREE.TextureLoader().load('particle/particles.png');
t.magFilter = THREE.NearestFilter;
t.minFilter = THREE.NearestFilter;
return t;
})()
}; };
// Load destroy stages // Load destroy stages
@@ -1619,28 +1628,96 @@ document.addEventListener('DOMContentLoaded', () => {
} }
} }
// --- Animation Loop --- // --- Particle System ---
function animate() { let particles = [];
requestAnimationFrame(animate);
processMining();
updateDrops();
updateSaplings();
updateTNT();
checkCollection();
// Camera offset logic function spawnExplosionParticles(pos) {
const targetOffset = extraBlocks.length > 0 ? 3.5 : 0; if (!textures.particle) return;
if (Math.abs(cameraOffsetY - targetOffset) > 0.01) {
cameraOffsetY += (targetOffset - cameraOffsetY) * 0.05; const particleCount = 30;
camera.position.set(20, 14 + cameraOffsetY, 20); const material = new THREE.SpriteMaterial({
camera.lookAt(0, cameraOffsetY, 0); map: textures.particle,
} else if (cameraOffsetY !== targetOffset) { color: 0xffffff,
cameraOffsetY = targetOffset; transparent: true,
camera.position.set(20, 14 + cameraOffsetY, 20); blending: THREE.AdditiveBlending
camera.lookAt(0, cameraOffsetY, 0); });
for (let i = 0; i < particleCount; i++) {
const sprite = new THREE.Sprite(material);
sprite.position.copy(pos);
// Add some randomness to start position
sprite.position.x += (Math.random() - 0.5) * 0.5;
sprite.position.y += (Math.random() - 0.5) * 0.5;
sprite.position.z += (Math.random() - 0.5) * 0.5;
// Random velocity
const speed = 0.1 + Math.random() * 0.3;
sprite.userData.velocity = new THREE.Vector3(
(Math.random() - 0.5) * speed,
(Math.random() - 0.5) * speed,
(Math.random() - 0.5) * speed
);
sprite.userData.life = 1.0;
const size = 0.3 + Math.random() * 0.4;
sprite.scale.set(size, size, size);
scene.add(sprite);
particles.push(sprite);
} }
}
composer.render(); function updateParticles() {
for (let i = particles.length - 1; i >= 0; i--) {
const p = particles[i];
p.position.add(p.userData.velocity);
p.userData.velocity.y -= 0.005; // Slight gravity
p.userData.velocity.multiplyScalar(0.95); // Drag
p.userData.life -= 0.02;
p.material.opacity = Math.max(0, p.userData.life);
if (p.userData.life <= 0) {
scene.remove(p);
particles.splice(i, 1);
}
}
}
// --- Animation Loop ---
let lastTime = 0;
const fpsInterval = 1000 / 60;
function animate(currentTime) {
requestAnimationFrame(animate);
if (!currentTime) currentTime = performance.now();
const elapsed = currentTime - lastTime;
if (elapsed > fpsInterval) {
lastTime = currentTime - (elapsed % fpsInterval);
processMining();
updateDrops();
updateSaplings();
updateTNT();
updateParticles();
checkCollection();
// Camera offset logic
const targetOffset = extraBlocks.length > 0 ? 3.5 : 0;
if (Math.abs(cameraOffsetY - targetOffset) > 0.01) {
cameraOffsetY += (targetOffset - cameraOffsetY) * 0.05;
camera.position.set(20, 14 + cameraOffsetY, 20);
camera.lookAt(0, cameraOffsetY, 0);
} else if (cameraOffsetY !== targetOffset) {
cameraOffsetY = targetOffset;
camera.position.set(20, 14 + cameraOffsetY, 20);
camera.lookAt(0, cameraOffsetY, 0);
}
composer.render();
}
} }
// Handle resize // Handle resize
@@ -1976,21 +2053,67 @@ document.addEventListener('DOMContentLoaded', () => {
// Physics // Physics
for (let i = tntProjectiles.length - 1; i >= 0; i--) { for (let i = tntProjectiles.length - 1; i >= 0; i--) {
const tnt = tntProjectiles[i]; const tnt = tntProjectiles[i];
tnt.position.y -= 0.2; // Fall speed
tnt.rotation.x += 0.05; // Initialize fuse if not present (for existing TNTs)
tnt.rotation.z += 0.05; if (tnt.userData.fuse === undefined) tnt.userData.fuse = 120;
if (tnt.userData.landed === undefined) tnt.userData.landed = false;
// Check collision // Flashing effect
// Simple check: if y < something and hits a block tnt.userData.flashTimer += 1;
const gx = Math.round(tnt.position.x / BLOCK_SIZE + (GRID_SIZE/2 - 0.5)); // Flash faster as fuse runs out
const gz = Math.round(tnt.position.z / BLOCK_SIZE + (GRID_SIZE/2 - 0.5)); const flashInterval = tnt.userData.fuse < 60 ? 5 : 10;
const gy = Math.round(tnt.position.y / BLOCK_SIZE);
if (tnt.userData.flashTimer % flashInterval === 0) {
tnt.userData.isFlashing = !tnt.userData.isFlashing;
if (tnt.userData.isFlashing) {
if (!tnt.userData.whiteMaterial) {
tnt.userData.whiteMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff });
}
tnt.material = tnt.userData.whiteMaterial;
} else {
tnt.material = tnt.userData.originalMaterials;
}
}
// Check if we hit a block if (!tnt.userData.landed) {
const block = getBlockAt(gx, gy, gz); tnt.position.y -= 0.1; // Fall speed
if (block || gy < -depth - 1) { // Hit block or fell too far
explodeTNT(tnt); const gx = Math.round(tnt.position.x / BLOCK_SIZE + (GRID_SIZE/2 - 0.5));
tntProjectiles.splice(i, 1); const gz = Math.round(tnt.position.z / BLOCK_SIZE + (GRID_SIZE/2 - 0.5));
const gy = Math.round(tnt.position.y / BLOCK_SIZE);
// Check if we hit a block
const block = getBlockAt(gx, gy, gz);
if (block) {
// Land on top
tnt.userData.landed = true;
tnt.position.y = block.position.y + BLOCK_SIZE;
// Snap to grid
tnt.position.x = (gx - (GRID_SIZE/2 - 0.5)) * BLOCK_SIZE;
tnt.position.z = (gz - (GRID_SIZE/2 - 0.5)) * BLOCK_SIZE;
} else if (gy < -depth - 5) {
// Fell too far
tntProjectiles.splice(i, 1);
scene.remove(tnt);
}
} else {
// Landed logic
// Check if block below still exists
const gx = Math.round(tnt.position.x / BLOCK_SIZE + (GRID_SIZE/2 - 0.5));
const gz = Math.round(tnt.position.z / BLOCK_SIZE + (GRID_SIZE/2 - 0.5));
const gyBelow = Math.round((tnt.position.y - BLOCK_SIZE) / BLOCK_SIZE);
const blockBelow = getBlockAt(gx, gyBelow, gz);
if (!blockBelow && tnt.position.y > -depth - 1) {
tnt.userData.landed = false; // Start falling again
}
tnt.userData.fuse--;
if (tnt.userData.fuse <= 0) {
explodeTNT(tnt);
tntProjectiles.splice(i, 1);
}
} }
} }
} }
@@ -2000,8 +2123,17 @@ document.addEventListener('DOMContentLoaded', () => {
const gz = Math.floor(Math.random() * GRID_SIZE); const gz = Math.floor(Math.random() * GRID_SIZE);
const geometry = new THREE.BoxGeometry(0.6, 0.6, 0.6); const geometry = new THREE.BoxGeometry(0.6, 0.6, 0.6);
const material = new THREE.MeshLambertMaterial({ color: 0xff0000 }); // Red block for now
const tnt = new THREE.Mesh(geometry, material); const materials = [
new THREE.MeshLambertMaterial({ map: textures.tnt_side }), // px
new THREE.MeshLambertMaterial({ map: textures.tnt_side }), // nx
new THREE.MeshLambertMaterial({ map: textures.tnt_top }), // py (top)
new THREE.MeshLambertMaterial({ map: textures.tnt_bottom }), // ny (bottom)
new THREE.MeshLambertMaterial({ map: textures.tnt_side }), // pz
new THREE.MeshLambertMaterial({ map: textures.tnt_side }) // nz
];
const tnt = new THREE.Mesh(geometry, materials);
tnt.position.set( tnt.position.set(
(gx - (GRID_SIZE/2 - 0.5)) * BLOCK_SIZE, (gx - (GRID_SIZE/2 - 0.5)) * BLOCK_SIZE,
@@ -2009,11 +2141,20 @@ document.addEventListener('DOMContentLoaded', () => {
(gz - (GRID_SIZE/2 - 0.5)) * BLOCK_SIZE (gz - (GRID_SIZE/2 - 0.5)) * BLOCK_SIZE
); );
tnt.userData = {
flashTimer: 0,
isFlashing: false,
originalMaterials: materials,
fuse: 120, // 2 seconds at 60fps
landed: false
};
scene.add(tnt); scene.add(tnt);
tntProjectiles.push(tnt); tntProjectiles.push(tnt);
} }
function explodeTNT(tnt) { function explodeTNT(tnt) {
spawnExplosionParticles(tnt.position);
scene.remove(tnt); scene.remove(tnt);
// Explosion effect (simple) // Explosion effect (simple)

Binary file not shown.

After

Width:  |  Height:  |  Size: 896 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB