------------------------------------------------------------
commit a3e0f244d92b914fc760a2ed7d08b3a217ae4a45
Author: Breck Yunits <breck7@gmail.com>
Date: Tue Nov 26 19:00:40 2024 -0800
diff --git a/wavewar.css b/wavewar.css
index eac14ac..ee744dc 100644
--- a/wavewar.css
+++ b/wavewar.css
@@ -22,8 +22,11 @@ canvas {
}
#summaryLink {
position: absolute;
- top: 3px;
- left: 3px;
+ top: 20px;
+ left: 20px;
+ padding: 10px 20px;
text-decoration: none;
- color: rgba(255, 255, 255, 0.5);
+ color: #4CAF50;
+ font-size: 24px;
+ font-family: monospace;
}
------------------------------------------------------------
commit 63a5eb53ef7391aca7bdc7a9b55dc935badede56
Author: Breck Yunits <breck7@gmail.com>
Date: Tue Nov 26 18:55:16 2024 -0800
diff --git a/WaveWar.js b/WaveWar.js
index 8d3caca..249dcb7 100644
--- a/WaveWar.js
+++ b/WaveWar.js
@@ -193,10 +193,7 @@ class Globe {
// Wave and weapon settings
this.activeWaves = []
- this.empCooldown = false
- this.soundCooldown = false
- this.empCooldownDuration = 1000
- this.soundCooldownDuration = 1000
+ this.cooldownDuration = 1000
// Drone settings
this.drones = []
@@ -303,19 +300,6 @@ class Globe {
// Add styles for the cooldown animation
const style = document.createElement("style")
style.textContent = `
- @keyframes cooldown {
- from {
- background: linear-gradient(to top,
- var(--button-color) 0%,
- transparent 0%);
- }
- to {
- background: linear-gradient(to top,
- var(--button-color) 100%,
- transparent 100%);
- }
- }
-
.control-button {
width: 40px;
height: 40px;
@@ -326,7 +310,7 @@ class Globe {
font-weight: bold;
color: white;
position: relative;
- transition: transform 0.2s ease;
+ transition: transform 0.5s ease;
}
.control-button:not(.cooldown):hover {
@@ -335,8 +319,7 @@ class Globe {
.control-button.cooldown {
cursor: not-allowed;
- opacity: 0.7;
- animation: cooldown 1s linear;
+ background-color: transparent !important;
}
`
document.head.appendChild(style)
@@ -412,7 +395,7 @@ class Globe {
setTimeout(() => {
this[cooldownProperty] = false
button.classList.remove("cooldown")
- }, this.soundCooldownDuration)
+ }, this.cooldownDuration)
}
}
triggerEMP() {
@@ -490,25 +473,8 @@ class Globe {
maxScale,
}
- // Start animation loop for this wave
- const animateWave = () => {
- const elapsed = Date.now() - wave.startTime
- const progress = elapsed / wave.duration
-
- if (progress >= 1) {
- this.scene.remove(wave.mesh)
- wave.geometry.dispose()
- wave.material.dispose()
- this.activeWaves = this.activeWaves.filter((w) => w !== wave)
- } else {
- const scale = 1 + (wave.maxScale - 1) * progress
- wave.mesh.scale.set(scale, scale, scale)
- wave.material.uniforms.time.value = progress
- requestAnimationFrame(animateWave)
- }
- }
-
- requestAnimationFrame(animateWave)
+ // Add to active waves and return
+ this.activeWaves.push(wave)
return wave
}
@@ -829,6 +795,24 @@ class Globe {
const delta = (currentTime - (this.lastFrameTime || currentTime)) / 1000
this.lastFrameTime = currentTime
+ // Update all waves in the main animation loop
+ this.activeWaves = this.activeWaves.filter((wave) => {
+ const elapsed = currentTime - wave.startTime
+ const progress = elapsed / wave.duration
+
+ if (progress >= 1) {
+ this.scene.remove(wave.mesh)
+ wave.geometry.dispose()
+ wave.material.dispose()
+ return false
+ }
+
+ const scale = 1 + (wave.maxScale - 1) * progress
+ wave.mesh.scale.set(scale, scale, scale)
+ wave.material.uniforms.time.value = progress
+ return true
+ })
+
// Spawn new drones
if (
currentTime - this.lastDroneSpawn > this.droneSpawnInterval &&
------------------------------------------------------------
commit 4269d448cbd546b3dd55e0736f5d0ca67617266c
Author: Breck Yunits <breck7@gmail.com>
Date: Tue Nov 26 18:42:49 2024 -0800
diff --git a/WaveWar.js b/WaveWar.js
index 945c3b0..8d3caca 100644
--- a/WaveWar.js
+++ b/WaveWar.js
@@ -155,54 +155,117 @@ class Drone {
class Globe {
constructor() {
+ // Keep only the essential properties that shouldn't be reset
this.renderer = null
this.scene = null
this.camera = null
+ this.animationId = null
+ this.gameOverScreen = null
+ this.empButton = null
+ this.soundButton = null
+
+ // Basic initialization
+ this.createScoreDisplay()
+ this.isDragging = false
+ this.previousMousePosition = { x: 0, y: 0 }
+ this.shouldRotate = true
+ }
+
+ setupGame() {
+ // Game state
this.earth = null
this.spikes = []
- this.animationId = null
this.stars = null
- this.earthHealth = 1.0 // 1.0 = full health, 0 = dead
+ this.earthHealth = 1.0
this.gameOver = false
this.score = 0
- this.createScoreDisplay()
-
- // Camera control properties
- this.isDragging = false
- this.previousMousePosition = {
- x: 0,
- y: 0,
- }
- // Camera orbit properties
+ // Camera settings
this.cameraDistance = 1
this.cameraRotation = {
- x: Math.PI * 0.1, // slightly above equator
- y: Math.PI * 0.6, // west of prime meridian
+ x: Math.PI * 0.1,
+ y: Math.PI * 0.6,
}
-
- // Zoom properties
this.minZoom = 0.1
this.maxZoom = 10
this.currentZoom = 0.7
this.zoomSpeed = 0.02
- // Replace separate wave arrays with unified array
+ // Wave and weapon settings
this.activeWaves = []
this.empCooldown = false
this.soundCooldown = false
this.empCooldownDuration = 1000
this.soundCooldownDuration = 1000
- // Store button references
- this.empButton = null
- this.soundButton = null
-
+ // Drone settings
this.drones = []
this.droneSpeedMultiplier = 0
this.lastDroneSpawn = 0
- this.droneSpawnInterval = 1000 // Spawn a new drone every 2 seconds
- this.maxDrones = 200 // Maximum number of drones allowed
+ this.droneSpawnInterval = 1000
+ this.maxDrones = 200
+
+ // Initialize scene, camera, renderer
+ this.scene = new THREE.Scene()
+ const height = window.innerHeight - 100
+ this.camera = new THREE.PerspectiveCamera(
+ 75,
+ window.innerWidth / height,
+ 0.1,
+ 1000,
+ )
+ this.updateCameraPosition()
+
+ // Set up renderer
+ this.renderer = new THREE.WebGLRenderer({ antialias: true })
+ this.renderer.setSize(window.innerWidth, height)
+ this.renderer.setClearColor(0x000000)
+ document.body.prepend(this.renderer.domElement)
+
+ // Create game elements
+ this.createStarField()
+ this.createEarth()
+ this.setupLighting()
+
+ // Set up controls
+ this.setupMouseControls()
+ this.setupZoomControls()
+
+ // Reset score display
+ document.getElementById("score-display").textContent = "Drones Destroyed: 0"
+
+ // Start animation
+ this.animate()
+ }
+
+ createEarth() {
+ const geometry = new THREE.SphereGeometry(0.5, 32, 32)
+ const texture = new THREE.TextureLoader().load("earth_atmos_2048.jpg")
+ const material = new THREE.MeshPhongMaterial({
+ map: texture,
+ specular: 0x333333,
+ shininess: 5,
+ emissive: 0xff0000,
+ emissiveIntensity: 0,
+ })
+
+ this.earth = new THREE.Mesh(geometry, material)
+ this.scene.add(this.earth)
+ }
+
+ setupLighting() {
+ const ambientLight = new THREE.AmbientLight(0xfffffff)
+ this.scene.add(ambientLight)
+
+ const directionalLight = new THREE.DirectionalLight(0xffffff, 0.4)
+ directionalLight.position.set(5, 3, 5)
+ this.scene.add(directionalLight)
+ }
+
+ createGlobe() {
+ this.removeGlobe()
+ this.setupGame()
+ return this
}
createScoreDisplay() {
@@ -498,66 +561,6 @@ class Globe {
this.scene.add(this.stars)
}
- createGlobe() {
- // Ensure any previous globe and animation is removed
- this.removeGlobe()
-
- // Initialize scene, camera, renderer, etc.
- this.scene = new THREE.Scene()
- const height = window.innerHeight - 100
- this.camera = new THREE.PerspectiveCamera(
- 75,
- window.innerWidth / height,
- 0.1,
- 1000,
- )
-
- // Set initial camera position
- this.cameraDistance = 1
- this.updateCameraPosition()
-
- // Set up renderer with alpha and better quality
- this.renderer = new THREE.WebGLRenderer({ antialias: true })
- this.renderer.setSize(window.innerWidth, height)
- this.renderer.setClearColor(0x000000) // Set background to black
- document.body.prepend(this.renderer.domElement)
-
- // Create starry background
- this.createStarField()
-
- // Create Earth with better lighting
- const geometry = new THREE.SphereGeometry(0.5, 32, 32)
- const texture = new THREE.TextureLoader().load("earth_atmos_2048.jpg")
- const material = new THREE.MeshPhongMaterial({
- map: texture,
- specular: 0x333333,
- shininess: 5,
- emissive: 0xff0000, // Red glow for damage
- emissiveIntensity: 0, // Start with no damage glow
- })
-
- this.earth = new THREE.Mesh(geometry, material)
- this.scene.add(this.earth)
-
- // Add ambient light
- const ambientLight = new THREE.AmbientLight(0xfffffff)
- this.scene.add(ambientLight)
-
- // Add directional light
- const directionalLight = new THREE.DirectionalLight(0xffffff, 0.4)
- directionalLight.position.set(5, 3, 5)
- this.scene.add(directionalLight)
-
- // Add mouse and zoom controls
- this.setupMouseControls()
- this.setupZoomControls()
-
- // Start the animation loop
- this.animate()
-
- return this
- }
-
damageEarth() {
if (this.gameOver) return
@@ -609,25 +612,97 @@ class Globe {
// Hide Earth
this.earth.visible = false
- // Create game over text
- const gameOverDiv = document.createElement("div")
- gameOverDiv.style.position = "fixed"
- gameOverDiv.style.top = "50%"
- gameOverDiv.style.left = "50%"
- gameOverDiv.style.transform = "translate(-50%, -50%)"
- gameOverDiv.style.color = "#ff0000"
- gameOverDiv.style.fontSize = "64px"
- gameOverDiv.style.fontFamily = "Arial, sans-serif"
- gameOverDiv.style.fontWeight = "bold"
- gameOverDiv.style.textShadow = "0 0 10px #ff0000"
- gameOverDiv.style.zIndex = "1000"
- gameOverDiv.innerHTML = `GAME OVER<br>Score: ${this.score}`
- document.body.appendChild(gameOverDiv)
+ // Create game over screen
+ this.createGameOverScreen()
// Start explosion animation
this.animateExplosion()
}
+ createGameOverScreen() {
+ // Create container for game over screen
+ const gameOverScreen = document.createElement("div")
+ gameOverScreen.style.position = "fixed"
+ gameOverScreen.style.top = "50%"
+ gameOverScreen.style.left = "50%"
+ gameOverScreen.style.transform = "translate(-50%, -50%)"
+ gameOverScreen.style.textAlign = "center"
+ gameOverScreen.style.color = "#ff0000"
+ gameOverScreen.style.fontFamily = "Arial, sans-serif"
+ gameOverScreen.style.zIndex = "1000"
+
+ // Game Over text
+ const gameOverText = document.createElement("div")
+ gameOverText.textContent = "GAME OVER"
+ gameOverText.style.fontSize = "64px"
+ gameOverText.style.fontWeight = "bold"
+ gameOverText.style.textShadow = "0 0 10px #ff0000"
+ gameOverText.style.marginBottom = "20px"
+
+ // Score text
+ const scoreText = document.createElement("div")
+ scoreText.textContent = `Score: ${this.score}`
+ scoreText.style.fontSize = "32px"
+ scoreText.style.marginBottom = "40px"
+
+ // Play Again button
+ const playAgainButton = document.createElement("button")
+ playAgainButton.textContent = "Play Again"
+ playAgainButton.style.padding = "15px 30px"
+ playAgainButton.style.fontSize = "24px"
+ playAgainButton.style.backgroundColor = "#4CAF50"
+ playAgainButton.style.color = "white"
+ playAgainButton.style.border = "none"
+ playAgainButton.style.borderRadius = "5px"
+ playAgainButton.style.cursor = "pointer"
+ playAgainButton.style.transition = "background-color 0.3s"
+
+ // Hover effect
+ playAgainButton.addEventListener("mouseover", () => {
+ playAgainButton.style.backgroundColor = "#45a049"
+ })
+ playAgainButton.addEventListener("mouseout", () => {
+ playAgainButton.style.backgroundColor = "#4CAF50"
+ })
+
+ // Click event
+ playAgainButton.addEventListener("click", () => this.resetGame())
+
+ // Add elements to game over screen
+ gameOverScreen.appendChild(gameOverText)
+ gameOverScreen.appendChild(scoreText)
+ gameOverScreen.appendChild(playAgainButton)
+
+ // Store reference and add to document
+ this.gameOverScreen = gameOverScreen
+ document.body.appendChild(gameOverScreen)
+ }
+
+ resetGame() {
+ // Remove existing elements
+ this.removeGlobe()
+
+ if (this.gameOverScreen) {
+ this.gameOverScreen.remove()
+ this.gameOverScreen = null
+ }
+
+ // Reset buttons
+ if (this.empButton) {
+ this.empButton.classList.remove("cooldown")
+ this.empButton.style.cursor = "pointer"
+ this.empButton.style.opacity = "1"
+ }
+ if (this.soundButton) {
+ this.soundButton.classList.remove("cooldown")
+ this.soundButton.style.cursor = "pointer"
+ this.soundButton.style.opacity = "1"
+ }
+
+ // Reinitialize game
+ this.setupGame()
+ }
+
animateExplosion() {
if (!this.explosionParticles) return
------------------------------------------------------------
commit d1078dd99c18d41409de28df705aa9aa6f224328
Author: Breck Yunits <breck7@gmail.com>
Date: Tue Nov 26 18:32:39 2024 -0800
diff --git a/WaveWar.js b/WaveWar.js
index 07eb0b3..945c3b0 100644
--- a/WaveWar.js
+++ b/WaveWar.js
@@ -1,7 +1,7 @@
class Drone {
constructor(globe) {
this.globe = globe
- this.speed = 0.01 + Math.random() * 0.2
+ this.speed = 0.01 + Math.random() * 0.2 + globe.droneSpeedMultiplier
this.mesh = this.createDroneMesh()
this.position = this.getRandomPosition()
this.target = this.getRandomPosition()
@@ -80,21 +80,10 @@ class Drone {
this.checkWaveCollisions()
}
+ // Update the Drone class's checkWaveCollisions method
checkWaveCollisions() {
- // Check EMP waves
- this.globe.activeEMPWaves.forEach((wave) => {
- const waveRadius = wave.mesh.scale.x * 0.5
- const distanceFromCenter = this.position.length()
- if (
- Math.abs(distanceFromCenter - waveRadius) < 0.05 &&
- !this.isExploding
- ) {
- this.startExplosion()
- }
- })
-
- // Check Sound waves
- this.globe.activeSoundWaves.forEach((wave) => {
+ // Check all active waves
+ this.globe.activeWaves.forEach((wave) => {
const waveRadius = wave.mesh.scale.x * 0.5
const distanceFromCenter = this.position.length()
if (
@@ -198,16 +187,19 @@ class Globe {
this.currentZoom = 0.7
this.zoomSpeed = 0.02
- this.activeEMPWaves = []
+ // Replace separate wave arrays with unified array
+ this.activeWaves = []
this.empCooldown = false
- this.empCooldownDuration = 20 // 300ms cooldown
-
- // Add sound wave properties
- this.activeSoundWaves = []
this.soundCooldown = false
- this.soundCooldownDuration = 20 // 300ms cooldown like EMP
+ this.empCooldownDuration = 1000
+ this.soundCooldownDuration = 1000
+
+ // Store button references
+ this.empButton = null
+ this.soundButton = null
this.drones = []
+ this.droneSpeedMultiplier = 0
this.lastDroneSpawn = 0
this.droneSpawnInterval = 1000 // Spawn a new drone every 2 seconds
this.maxDrones = 200 // Maximum number of drones allowed
@@ -245,17 +237,46 @@ class Globe {
controlPanel.style.alignItems = "center"
controlPanel.style.gap = "10px"
- // Controller shape background
- const controllerShape = document.createElement("div")
- controllerShape.style.position = "absolute"
- controllerShape.style.top = "0"
- controllerShape.style.left = "0"
- controllerShape.style.right = "0"
- controllerShape.style.bottom = "0"
- controllerShape.style.borderRadius = "15px"
- controllerShape.style.border = "2px solid rgba(255, 255, 255, 0.2)"
- controllerShape.style.boxShadow = "0 0 10px rgba(0, 0, 0, 0.5)"
- controlPanel.appendChild(controllerShape)
+ // Add styles for the cooldown animation
+ const style = document.createElement("style")
+ style.textContent = `
+ @keyframes cooldown {
+ from {
+ background: linear-gradient(to top,
+ var(--button-color) 0%,
+ transparent 0%);
+ }
+ to {
+ background: linear-gradient(to top,
+ var(--button-color) 100%,
+ transparent 100%);
+ }
+ }
+
+ .control-button {
+ width: 40px;
+ height: 40px;
+ border: none;
+ border-radius: 50%;
+ cursor: pointer;
+ font-size: 16px;
+ font-weight: bold;
+ color: white;
+ position: relative;
+ transition: transform 0.2s ease;
+ }
+
+ .control-button:not(.cooldown):hover {
+ transform: scale(1.1);
+ }
+
+ .control-button.cooldown {
+ cursor: not-allowed;
+ opacity: 0.7;
+ animation: cooldown 1s linear;
+ }
+ `
+ document.head.appendChild(style)
const buttonContainer = document.createElement("div")
buttonContainer.style.display = "flex"
@@ -266,36 +287,22 @@ class Globe {
const createButton = (text, color, action) => {
const button = document.createElement("button")
button.textContent = text
- button.style.width = "40px"
- button.style.height = "40px"
+ button.className = "control-button"
+ button.style.setProperty("--button-color", color)
button.style.backgroundColor = color
- button.style.color = "white"
- button.style.border = "none"
- button.style.borderRadius = "50%"
- button.style.cursor = "pointer"
- button.style.fontSize = "16px"
- button.style.fontWeight = "bold"
- button.style.boxShadow = "0 0 5px rgba(0, 0, 0, 0.3)"
- button.style.transition = "all 0.2s ease"
-
- button.addEventListener("mouseenter", () => {
- if (!this[action.toLowerCase() + "Cooldown"]) {
- button.style.transform = "scale(1.1)"
- button.style.boxShadow = "0 0 10px " + color
- }
- })
- button.addEventListener("mouseleave", () => {
- button.style.transform = "scale(1)"
- button.style.boxShadow = "0 0 5px rgba(0, 0, 0, 0.3)"
- })
button.addEventListener("click", () => this.handleAction(action))
return button
}
+ // Create buttons with their base colors
const empButton = createButton("E", "#4CAF50", "EMP")
const soundButton = createButton("S", "#2196F3", "SOUND")
+ // Store button references
+ this.empButton = empButton
+ this.soundButton = soundButton
+
buttonContainer.appendChild(empButton)
buttonContainer.appendChild(soundButton)
controlPanel.appendChild(buttonContainer)
@@ -326,6 +333,8 @@ class Globe {
handleAction(action) {
const cooldownProperty = action.toLowerCase() + "Cooldown"
+ const button = action === "EMP" ? this.empButton : this.soundButton
+
if (!this[cooldownProperty]) {
if (action === "EMP") {
this.triggerEMP()
@@ -333,169 +342,111 @@ class Globe {
this.triggerSound()
}
- // Handle cooldown
+ // Handle cooldown and animation
this[cooldownProperty] = true
+ button.classList.add("cooldown")
+
setTimeout(() => {
this[cooldownProperty] = false
+ button.classList.remove("cooldown")
}, this.soundCooldownDuration)
}
}
-
- triggerSound() {
- const soundGeometry = new THREE.SphereGeometry(0.5, 32, 32)
- const soundMaterial = new THREE.ShaderMaterial({
- transparent: true,
- uniforms: {
- time: { value: 0 },
- color: { value: new THREE.Color(0x2196f3) },
- maxRadius: { value: 5.0 },
- },
- vertexShader: `
- varying vec3 vNormal;
- void main() {
- vNormal = normalize(normalMatrix * normal);
- gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
- }
- `,
- fragmentShader: `
- uniform float time;
- uniform vec3 color;
- uniform float maxRadius;
- varying vec3 vNormal;
-
- void main() {
- float intensity = 1.0 - (time * time);
- float edge = 0.5;
- float rim = smoothstep(0.5 - edge, 0.5 + edge, dot(vNormal, vec3(0.0, 0.0, 1.0)));
- float wave = sin(time * 20.0) * 0.5 + 0.5;
- gl_FragColor = vec4(color, intensity * (1.0 - rim) * wave * 0.7);
- }
- `,
+ triggerEMP() {
+ const wave = this.triggerWave({
+ type: "emp",
+ color: 0x00ff00,
+ duration: 2000,
+ maxScale: 10,
+ pulseEffect: false,
})
-
- const soundWave = new THREE.Mesh(soundGeometry, soundMaterial)
- this.scene.add(soundWave)
-
- const wave = {
- mesh: soundWave,
- geometry: soundGeometry,
- material: soundMaterial,
- startTime: Date.now(),
- duration: 4000, // Increased from 2000 to 4000 for slower wave
- maxScale: 8,
- }
-
- this.activeSoundWaves.push(wave)
-
- if (this.activeSoundWaves.length === 1) {
- this.animateSoundWaves()
- }
+ this.activeWaves.push(wave)
}
- animateSoundWaves() {
- for (let i = this.activeSoundWaves.length - 1; i >= 0; i--) {
- const wave = this.activeSoundWaves[i]
- const elapsed = Date.now() - wave.startTime
- const progress = elapsed / wave.duration
-
- if (progress >= 1) {
- this.scene.remove(wave.mesh)
- wave.geometry.dispose()
- wave.material.dispose()
- this.activeSoundWaves.splice(i, 1)
- } else {
- // Slower expansion rate
- const scale = 1 + (wave.maxScale - 1) * (progress * 0.5) // Added 0.5 multiplier to slow expansion
- wave.mesh.scale.set(scale, scale, scale)
- wave.material.uniforms.time.value = progress
- }
- }
-
- if (this.activeSoundWaves.length > 0) {
- requestAnimationFrame(() => this.animateSoundWaves())
- }
+ triggerSound() {
+ const wave = this.triggerWave({
+ type: "sound",
+ color: 0x2196f3,
+ duration: 4000,
+ maxScale: 8,
+ pulseEffect: true,
+ })
+ this.activeWaves.push(wave)
}
- triggerEMP() {
- // Create a sphere geometry for the EMP wave
- const empGeometry = new THREE.SphereGeometry(0.5, 32, 32)
- const empMaterial = new THREE.ShaderMaterial({
+ triggerWave(config) {
+ const {
+ type,
+ color = 0x00ff00,
+ duration = 2000,
+ maxScale = 10,
+ pulseEffect = false,
+ } = config
+
+ const waveGeometry = new THREE.SphereGeometry(0.5, 32, 32)
+ const waveMaterial = new THREE.ShaderMaterial({
transparent: true,
uniforms: {
time: { value: 0 },
- color: { value: new THREE.Color(0x00ff00) },
+ color: { value: new THREE.Color(color) },
maxRadius: { value: 5.0 },
},
vertexShader: `
- varying vec3 vNormal;
- void main() {
- vNormal = normalize(normalMatrix * normal);
- gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
- }
- `,
+ varying vec3 vNormal;
+ void main() {
+ vNormal = normalize(normalMatrix * normal);
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
+ }
+ `,
fragmentShader: `
- uniform float time;
- uniform vec3 color;
- uniform float maxRadius;
- varying vec3 vNormal;
-
- void main() {
- float intensity = 1.0 - (time * time); // Inverse square law decay
- float edge = 0.2;
- float rim = smoothstep(0.5 - edge, 0.5 + edge, dot(vNormal, vec3(0.0, 0.0, 1.0)));
- gl_FragColor = vec4(color, intensity * (1.0 - rim) * 0.5);
- }
- `,
+ uniform float time;
+ uniform vec3 color;
+ uniform float maxRadius;
+ varying vec3 vNormal;
+
+ void main() {
+ float intensity = 1.0 - (time * time);
+ float edge = 0.5;
+ float rim = smoothstep(0.5 - edge, 0.5 + edge, dot(vNormal, vec3(0.0, 0.0, 1.0)));
+ ${pulseEffect ? "float wave = sin(time * 20.0) * 0.5 + 0.5;" : "float wave = 1.0;"}
+ gl_FragColor = vec4(color, intensity * (1.0 - rim) * wave * 0.7);
+ }
+ `,
})
- const empWave = new THREE.Mesh(empGeometry, empMaterial)
- this.scene.add(empWave)
+ const waveMesh = new THREE.Mesh(waveGeometry, waveMaterial)
+ this.scene.add(waveMesh)
- // Create wave object to track this specific wave
const wave = {
- mesh: empWave,
- geometry: empGeometry,
- material: empMaterial,
+ type,
+ mesh: waveMesh,
+ geometry: waveGeometry,
+ material: waveMaterial,
startTime: Date.now(),
- duration: 2000, // 2 seconds
- maxScale: 10,
+ duration,
+ maxScale,
}
- // Add to active waves array
- this.activeEMPWaves.push(wave)
-
- // Modify the animate method to handle multiple waves
- if (this.activeEMPWaves.length === 1) {
- // Only start if this is the first wave
- this.animateEMPWaves()
- }
- }
-
- animateEMPWaves() {
- // Process all active waves
- for (let i = this.activeEMPWaves.length - 1; i >= 0; i--) {
- const wave = this.activeEMPWaves[i]
+ // Start animation loop for this wave
+ const animateWave = () => {
const elapsed = Date.now() - wave.startTime
const progress = elapsed / wave.duration
if (progress >= 1) {
- // Remove completed wave
this.scene.remove(wave.mesh)
wave.geometry.dispose()
wave.material.dispose()
- this.activeEMPWaves.splice(i, 1)
+ this.activeWaves = this.activeWaves.filter((w) => w !== wave)
} else {
- // Update wave
const scale = 1 + (wave.maxScale - 1) * progress
wave.mesh.scale.set(scale, scale, scale)
wave.material.uniforms.time.value = progress
+ requestAnimationFrame(animateWave)
}
}
- // Continue animation if there are still active waves
- if (this.activeEMPWaves.length > 0) {
- requestAnimationFrame(() => this.animateEMPWaves())
- }
+ requestAnimationFrame(animateWave)
+ return wave
}
updateCameraPosition() {
@@ -812,6 +763,7 @@ class Globe {
this.drones.push(new Drone(this))
this.lastDroneSpawn = currentTime
this.droneSpawnInterval = Math.max(10, this.droneSpawnInterval * 0.95)
+ this.droneSpeedMultiplier += 0.001
}
// Check for drone collisions with Earth
------------------------------------------------------------
commit 00aea62201f0fa3833968abf8e09acedf70cfd03
Author: Breck Yunits <breck7@gmail.com>
Date: Tue Nov 26 18:08:16 2024 -0800
diff --git a/WaveWar.js b/WaveWar.js
index e005cf8..07eb0b3 100644
--- a/WaveWar.js
+++ b/WaveWar.js
@@ -56,8 +56,8 @@ class Drone {
)
}
- update(delta) {
- if (this.globe.gameOver) return;
+ update(delta) {
+ if (this.globe.gameOver) return
if (this.isExploding) {
this.updateExplosion(delta)
return
@@ -110,8 +110,9 @@ class Drone {
this.isExploding = true
this.explosionStartTime = Date.now()
// Increment score when drone is destroyed
- this.globe.score++;
- document.getElementById('score-display').textContent = `Drones Destroyed: ${this.globe.score}`;
+ this.globe.score++
+ document.getElementById("score-display").textContent =
+ `Drones Destroyed: ${this.globe.score}`
// Create explosion particles
const particleCount = 20
@@ -138,28 +139,28 @@ class Drone {
this.globe.scene.add(particles)
this.explosionParticles = particles
}
-// Modify the Drone class's updateExplosion method
+ // Modify the Drone class's updateExplosion method
updateExplosion(delta) {
- const elapsed = Date.now() - this.explosionStartTime;
- const progress = elapsed / this.explosionDuration;
+ const elapsed = Date.now() - this.explosionStartTime
+ const progress = elapsed / this.explosionDuration
if (progress >= 1) {
// Remove drone and particles
- this.globe.scene.remove(this.mesh);
- this.globe.scene.remove(this.explosionParticles);
- this.globe.drones = this.globe.drones.filter((d) => d !== this);
-
- return;
+ this.globe.scene.remove(this.mesh)
+ this.globe.scene.remove(this.explosionParticles)
+ this.globe.drones = this.globe.drones.filter((d) => d !== this)
+
+ return
}
// Update particle positions and scale
this.explosionParticles.children.forEach((particle) => {
- particle.position.add(particle.velocity);
- particle.scale.multiplyScalar(0.95);
- });
+ particle.position.add(particle.velocity)
+ particle.scale.multiplyScalar(0.95)
+ })
// Fade out original drone
- this.mesh.scale.multiplyScalar(0.9);
+ this.mesh.scale.multiplyScalar(0.9)
}
}
@@ -172,10 +173,10 @@ class Globe {
this.spikes = []
this.animationId = null
this.stars = null
-this.earthHealth = 1.0; // 1.0 = full health, 0 = dead
- this.gameOver = false;
- this.score = 0;
- this.createScoreDisplay();
+ this.earthHealth = 1.0 // 1.0 = full health, 0 = dead
+ this.gameOver = false
+ this.score = 0
+ this.createScoreDisplay()
// Camera control properties
this.isDragging = false
@@ -194,7 +195,7 @@ this.earthHealth = 1.0; // 1.0 = full health, 0 = dead
// Zoom properties
this.minZoom = 0.1
this.maxZoom = 10
- this.currentZoom = .7
+ this.currentZoom = 0.7
this.zoomSpeed = 0.02
this.activeEMPWaves = []
@@ -212,26 +213,24 @@ this.earthHealth = 1.0; // 1.0 = full health, 0 = dead
this.maxDrones = 200 // Maximum number of drones allowed
}
-
- createScoreDisplay() {
- const scoreDisplay = document.createElement("div");
- scoreDisplay.style.position = "fixed";
- scoreDisplay.style.top = "20px";
- scoreDisplay.style.right = "20px";
- scoreDisplay.style.padding = "10px 20px";
- scoreDisplay.style.backgroundColor = "rgba(0, 0, 0, 0.8)";
- scoreDisplay.style.color = "#4CAF50";
- scoreDisplay.style.borderRadius = "10px";
- scoreDisplay.style.fontSize = "24px";
- scoreDisplay.style.fontFamily = "monospace";
- scoreDisplay.style.zIndex = "1000";
- scoreDisplay.style.border = "1px solid rgba(76, 175, 80, 0.3)";
- scoreDisplay.id = "score-display";
- scoreDisplay.textContent = "Drones Destroyed: 0";
- document.body.appendChild(scoreDisplay);
+ createScoreDisplay() {
+ const scoreDisplay = document.createElement("div")
+ scoreDisplay.style.position = "fixed"
+ scoreDisplay.style.top = "20px"
+ scoreDisplay.style.right = "20px"
+ scoreDisplay.style.padding = "10px 20px"
+ scoreDisplay.style.backgroundColor = "rgba(0, 0, 0, 0.8)"
+ scoreDisplay.style.color = "#4CAF50"
+ scoreDisplay.style.borderRadius = "10px"
+ scoreDisplay.style.fontSize = "24px"
+ scoreDisplay.style.fontFamily = "monospace"
+ scoreDisplay.style.zIndex = "1000"
+ scoreDisplay.style.border = "1px solid rgba(76, 175, 80, 0.3)"
+ scoreDisplay.id = "score-display"
+ scoreDisplay.textContent = "Drones Destroyed: 0"
+ document.body.appendChild(scoreDisplay)
}
-
createControlPanel() {
const controlPanel = document.createElement("div")
controlPanel.style.position = "fixed"
@@ -315,12 +314,11 @@ this.earthHealth = 1.0; // 1.0 = full health, 0 = dead
document.addEventListener("keydown", (e) => {
if (e.key.toLowerCase() === "e") {
this.handleAction("EMP")
- }else if (e.key.toLowerCase() === " ") {
+ } else if (e.key.toLowerCase() === " ") {
this.handleAction("EMP")
} else if (e.key.toLowerCase() === "s") {
this.handleAction("SOUND")
- }
- else if (e.key.toLowerCase() === "f") {
+ } else if (e.key.toLowerCase() === "f") {
this.toggleFullScreen()
}
})
@@ -343,7 +341,7 @@ this.earthHealth = 1.0; // 1.0 = full health, 0 = dead
}
}
- triggerSound() {
+ triggerSound() {
const soundGeometry = new THREE.SphereGeometry(0.5, 32, 32)
const soundMaterial = new THREE.ShaderMaterial({
transparent: true,
@@ -576,20 +574,17 @@ this.earthHealth = 1.0; // 1.0 = full health, 0 = dead
// Create starry background
this.createStarField()
-
-
// Create Earth with better lighting
const geometry = new THREE.SphereGeometry(0.5, 32, 32)
-const texture = new THREE.TextureLoader().load("earth_atmos_2048.jpg")
+ const texture = new THREE.TextureLoader().load("earth_atmos_2048.jpg")
const material = new THREE.MeshPhongMaterial({
map: texture,
specular: 0x333333,
shininess: 5,
- emissive: 0xff0000, // Red glow for damage
- emissiveIntensity: 0 // Start with no damage glow
+ emissive: 0xff0000, // Red glow for damage
+ emissiveIntensity: 0, // Start with no damage glow
})
-
this.earth = new THREE.Mesh(geometry, material)
this.scene.add(this.earth)
@@ -613,85 +608,84 @@ const texture = new THREE.TextureLoader().load("earth_atmos_2048.jpg")
}
damageEarth() {
- if (this.gameOver) return;
-
- this.earthHealth = Math.max(0, this.earthHealth - 0.1); // Reduce health by 10%
- this.earth.material.emissiveIntensity = 1 - this.earthHealth; // Increase red glow
+ if (this.gameOver) return
+
+ this.earthHealth = Math.max(0, this.earthHealth - 0.1) // Reduce health by 10%
+ this.earth.material.emissiveIntensity = 1 - this.earthHealth // Increase red glow
if (this.earthHealth <= 0) {
- this.triggerGameOver();
+ this.triggerGameOver()
}
}
-
triggerGameOver() {
- this.gameOver = true;
-
+ this.gameOver = true
+
// Create explosion particles
- const particleCount = 1000;
- const particles = new THREE.Group();
-
+ const particleCount = 1000
+ const particles = new THREE.Group()
+
for (let i = 0; i < particleCount; i++) {
- const geometry = new THREE.BoxGeometry(0.02, 0.02, 0.02);
+ const geometry = new THREE.BoxGeometry(0.02, 0.02, 0.02)
const material = new THREE.MeshPhongMaterial({
color: Math.random() > 0.5 ? 0xff4444 : 0xff7700,
emissive: 0x441111,
- });
- const particle = new THREE.Mesh(geometry, material);
-
+ })
+ const particle = new THREE.Mesh(geometry, material)
+
// Position particles on earth's surface
- const theta = Math.random() * Math.PI * 2;
- const phi = Math.random() * Math.PI;
- const radius = 0.5;
-
- particle.position.x = radius * Math.sin(phi) * Math.cos(theta);
- particle.position.y = radius * Math.sin(phi) * Math.sin(theta);
- particle.position.z = radius * Math.cos(phi);
-
+ const theta = Math.random() * Math.PI * 2
+ const phi = Math.random() * Math.PI
+ const radius = 0.5
+
+ particle.position.x = radius * Math.sin(phi) * Math.cos(theta)
+ particle.position.y = radius * Math.sin(phi) * Math.sin(theta)
+ particle.position.z = radius * Math.cos(phi)
+
// Add velocity for explosion
const velocity = new THREE.Vector3()
.copy(particle.position)
.normalize()
- .multiplyScalar(0.03);
- particle.velocity = velocity;
-
- particles.add(particle);
+ .multiplyScalar(0.03)
+ particle.velocity = velocity
+
+ particles.add(particle)
}
-
- this.scene.add(particles);
- this.explosionParticles = particles;
+
+ this.scene.add(particles)
+ this.explosionParticles = particles
// Hide Earth
- this.earth.visible = false;
+ this.earth.visible = false
// Create game over text
- const gameOverDiv = document.createElement('div');
- gameOverDiv.style.position = 'fixed';
- gameOverDiv.style.top = '50%';
- gameOverDiv.style.left = '50%';
- gameOverDiv.style.transform = 'translate(-50%, -50%)';
- gameOverDiv.style.color = '#ff0000';
- gameOverDiv.style.fontSize = '64px';
- gameOverDiv.style.fontFamily = 'Arial, sans-serif';
- gameOverDiv.style.fontWeight = 'bold';
- gameOverDiv.style.textShadow = '0 0 10px #ff0000';
- gameOverDiv.style.zIndex = '1000';
- gameOverDiv.innerHTML = `GAME OVER<br>Score: ${this.score}`;
- document.body.appendChild(gameOverDiv);
+ const gameOverDiv = document.createElement("div")
+ gameOverDiv.style.position = "fixed"
+ gameOverDiv.style.top = "50%"
+ gameOverDiv.style.left = "50%"
+ gameOverDiv.style.transform = "translate(-50%, -50%)"
+ gameOverDiv.style.color = "#ff0000"
+ gameOverDiv.style.fontSize = "64px"
+ gameOverDiv.style.fontFamily = "Arial, sans-serif"
+ gameOverDiv.style.fontWeight = "bold"
+ gameOverDiv.style.textShadow = "0 0 10px #ff0000"
+ gameOverDiv.style.zIndex = "1000"
+ gameOverDiv.innerHTML = `GAME OVER<br>Score: ${this.score}`
+ document.body.appendChild(gameOverDiv)
// Start explosion animation
- this.animateExplosion();
+ this.animateExplosion()
}
animateExplosion() {
- if (!this.explosionParticles) return;
-
- this.explosionParticles.children.forEach(particle => {
- particle.position.add(particle.velocity);
- particle.scale.multiplyScalar(0.98);
- });
-
- requestAnimationFrame(() => this.animateExplosion());
+ if (!this.explosionParticles) return
+
+ this.explosionParticles.children.forEach((particle) => {
+ particle.position.add(particle.velocity)
+ particle.scale.multiplyScalar(0.98)
+ })
+
+ requestAnimationFrame(() => this.animateExplosion())
}
setupMouseControls() {
@@ -812,24 +806,25 @@ const texture = new THREE.TextureLoader().load("earth_atmos_2048.jpg")
// Spawn new drones
if (
currentTime - this.lastDroneSpawn > this.droneSpawnInterval &&
- this.drones.length < this.maxDrones && !this.gameOver
+ this.drones.length < this.maxDrones &&
+ !this.gameOver
) {
this.drones.push(new Drone(this))
this.lastDroneSpawn = currentTime
- this.droneSpawnInterval = Math.max(10, this.droneSpawnInterval * .95)
+ this.droneSpawnInterval = Math.max(10, this.droneSpawnInterval * 0.95)
}
-
// Check for drone collisions with Earth
this.drones.forEach((drone) => {
if (!drone.isExploding) {
- const distanceFromCenter = drone.position.length();
- if (distanceFromCenter <= 0.52) { // Slightly larger than Earth's radius (0.5)
- this.damageEarth();
- drone.startExplosion();
+ const distanceFromCenter = drone.position.length()
+ if (distanceFromCenter <= 0.52) {
+ // Slightly larger than Earth's radius (0.5)
+ this.damageEarth()
+ drone.startExplosion()
}
}
- });
+ })
// Update drones
this.drones.forEach((drone) => drone.update(delta))
@@ -923,19 +918,18 @@ const texture = new THREE.TextureLoader().load("earth_atmos_2048.jpg")
}
toggleFullScreen() {
-if (!document.fullscreenElement) {
- document.body.requestFullscreen().catch((err) => {
- console.log(
- `Error trying to go fullscreen: ${err.message} (${err.name})`,
- )
- })
- } else {
- document.exitFullscreen()
- }
+ if (!document.fullscreenElement) {
+ document.body.requestFullscreen().catch((err) => {
+ console.log(
+ `Error trying to go fullscreen: ${err.message} (${err.name})`,
+ )
+ })
+ } else {
+ document.exitFullscreen()
+ }
}
shouldRotate = true
-
}
window.globe = new Globe().createGlobe().listenToResize()
------------------------------------------------------------
commit b1f85e919787f7a33936fcb520e4ae584966d83e
Author: Breck Yunits <breck7@gmail.com>
Date: Sun Nov 24 15:32:32 2024 -0800
diff --git a/WaveWar.js b/WaveWar.js
index 7fcfea8..e005cf8 100644
--- a/WaveWar.js
+++ b/WaveWar.js
@@ -209,7 +209,7 @@ this.earthHealth = 1.0; // 1.0 = full health, 0 = dead
this.drones = []
this.lastDroneSpawn = 0
this.droneSpawnInterval = 1000 // Spawn a new drone every 2 seconds
- this.maxDrones = 500 // Maximum number of drones allowed
+ this.maxDrones = 200 // Maximum number of drones allowed
}
------------------------------------------------------------
commit 237586d9e6db57e61b1509e9d5d8953059347686
Author: Breck Yunits <breck7@gmail.com>
Date: Sun Nov 24 15:31:17 2024 -0800
diff --git a/WaveWar.js b/WaveWar.js
index ac8a82e..7fcfea8 100644
--- a/WaveWar.js
+++ b/WaveWar.js
@@ -209,7 +209,7 @@ this.earthHealth = 1.0; // 1.0 = full health, 0 = dead
this.drones = []
this.lastDroneSpawn = 0
this.droneSpawnInterval = 1000 // Spawn a new drone every 2 seconds
- this.maxDrones = 1000 // Maximum number of drones allowed
+ this.maxDrones = 500 // Maximum number of drones allowed
}
@@ -816,7 +816,7 @@ const texture = new THREE.TextureLoader().load("earth_atmos_2048.jpg")
) {
this.drones.push(new Drone(this))
this.lastDroneSpawn = currentTime
- this.droneSpawnInterval = Math.max(10, this.droneSpawnInterval * .98)
+ this.droneSpawnInterval = Math.max(10, this.droneSpawnInterval * .95)
}
------------------------------------------------------------
commit 2d2763e5abe34808bc18e04c807353f66d9a6995
Author: Breck Yunits <breck7@gmail.com>
Date: Sun Nov 24 15:29:29 2024 -0800
diff --git a/WaveWar.js b/WaveWar.js
index 76e816d..ac8a82e 100644
--- a/WaveWar.js
+++ b/WaveWar.js
@@ -816,7 +816,7 @@ const texture = new THREE.TextureLoader().load("earth_atmos_2048.jpg")
) {
this.drones.push(new Drone(this))
this.lastDroneSpawn = currentTime
- this.droneSpawnInterval = Math.max(10, this.droneSpawnInterval * .99)
+ this.droneSpawnInterval = Math.max(10, this.droneSpawnInterval * .98)
}
------------------------------------------------------------
commit b1ab71f7d0992f861c10338464fc12cead1484a2
Author: Breck Yunits <breck7@gmail.com>
Date: Sun Nov 24 15:27:38 2024 -0800
diff --git a/WaveWar.js b/WaveWar.js
index acd763a..76e816d 100644
--- a/WaveWar.js
+++ b/WaveWar.js
@@ -812,7 +812,7 @@ const texture = new THREE.TextureLoader().load("earth_atmos_2048.jpg")
// Spawn new drones
if (
currentTime - this.lastDroneSpawn > this.droneSpawnInterval &&
- this.drones.length < this.maxDrones
+ this.drones.length < this.maxDrones && !this.gameOver
) {
this.drones.push(new Drone(this))
this.lastDroneSpawn = currentTime
------------------------------------------------------------
commit 4d0d9575443368de665d7e88821cb692634a3c8e
Author: Breck Yunits <breck7@gmail.com>
Date: Sun Nov 24 15:26:29 2024 -0800
diff --git a/WaveWar.js b/WaveWar.js
index b8dc4f3..acd763a 100644
--- a/WaveWar.js
+++ b/WaveWar.js
@@ -1,7 +1,7 @@
class Drone {
constructor(globe) {
this.globe = globe
- this.speed = 0.01 + Math.random() * 0.02
+ this.speed = 0.01 + Math.random() * 0.2
this.mesh = this.createDroneMesh()
this.position = this.getRandomPosition()
this.target = this.getRandomPosition()
@@ -56,7 +56,8 @@ class Drone {
)
}
- update(delta) {
+ update(delta) {
+ if (this.globe.gameOver) return;
if (this.isExploding) {
this.updateExplosion(delta)
return
@@ -171,7 +172,8 @@ class Globe {
this.spikes = []
this.animationId = null
this.stars = null
-
+this.earthHealth = 1.0; // 1.0 = full health, 0 = dead
+ this.gameOver = false;
this.score = 0;
this.createScoreDisplay();
@@ -574,17 +576,20 @@ class Globe {
// Create starry background
this.createStarField()
+
+
// Create Earth with better lighting
const geometry = new THREE.SphereGeometry(0.5, 32, 32)
- const texture = new THREE.TextureLoader().load("earth_atmos_2048.jpg")
-
- // Use PhongMaterial for better lighting
+const texture = new THREE.TextureLoader().load("earth_atmos_2048.jpg")
const material = new THREE.MeshPhongMaterial({
map: texture,
specular: 0x333333,
shininess: 5,
+ emissive: 0xff0000, // Red glow for damage
+ emissiveIntensity: 0 // Start with no damage glow
})
+
this.earth = new THREE.Mesh(geometry, material)
this.scene.add(this.earth)
@@ -607,6 +612,88 @@ class Globe {
return this
}
+ damageEarth() {
+ if (this.gameOver) return;
+
+ this.earthHealth = Math.max(0, this.earthHealth - 0.1); // Reduce health by 10%
+ this.earth.material.emissiveIntensity = 1 - this.earthHealth; // Increase red glow
+
+ if (this.earthHealth <= 0) {
+ this.triggerGameOver();
+ }
+ }
+
+
+ triggerGameOver() {
+ this.gameOver = true;
+
+ // Create explosion particles
+ const particleCount = 1000;
+ const particles = new THREE.Group();
+
+ for (let i = 0; i < particleCount; i++) {
+ const geometry = new THREE.BoxGeometry(0.02, 0.02, 0.02);
+ const material = new THREE.MeshPhongMaterial({
+ color: Math.random() > 0.5 ? 0xff4444 : 0xff7700,
+ emissive: 0x441111,
+ });
+ const particle = new THREE.Mesh(geometry, material);
+
+ // Position particles on earth's surface
+ const theta = Math.random() * Math.PI * 2;
+ const phi = Math.random() * Math.PI;
+ const radius = 0.5;
+
+ particle.position.x = radius * Math.sin(phi) * Math.cos(theta);
+ particle.position.y = radius * Math.sin(phi) * Math.sin(theta);
+ particle.position.z = radius * Math.cos(phi);
+
+ // Add velocity for explosion
+ const velocity = new THREE.Vector3()
+ .copy(particle.position)
+ .normalize()
+ .multiplyScalar(0.03);
+ particle.velocity = velocity;
+
+ particles.add(particle);
+ }
+
+ this.scene.add(particles);
+ this.explosionParticles = particles;
+
+ // Hide Earth
+ this.earth.visible = false;
+
+ // Create game over text
+ const gameOverDiv = document.createElement('div');
+ gameOverDiv.style.position = 'fixed';
+ gameOverDiv.style.top = '50%';
+ gameOverDiv.style.left = '50%';
+ gameOverDiv.style.transform = 'translate(-50%, -50%)';
+ gameOverDiv.style.color = '#ff0000';
+ gameOverDiv.style.fontSize = '64px';
+ gameOverDiv.style.fontFamily = 'Arial, sans-serif';
+ gameOverDiv.style.fontWeight = 'bold';
+ gameOverDiv.style.textShadow = '0 0 10px #ff0000';
+ gameOverDiv.style.zIndex = '1000';
+ gameOverDiv.innerHTML = `GAME OVER<br>Score: ${this.score}`;
+ document.body.appendChild(gameOverDiv);
+
+ // Start explosion animation
+ this.animateExplosion();
+ }
+
+ animateExplosion() {
+ if (!this.explosionParticles) return;
+
+ this.explosionParticles.children.forEach(particle => {
+ particle.position.add(particle.velocity);
+ particle.scale.multiplyScalar(0.98);
+ });
+
+ requestAnimationFrame(() => this.animateExplosion());
+ }
+
setupMouseControls() {
const canvas = this.renderer.domElement
@@ -732,6 +819,18 @@ class Globe {
this.droneSpawnInterval = Math.max(10, this.droneSpawnInterval * .99)
}
+
+ // Check for drone collisions with Earth
+ this.drones.forEach((drone) => {
+ if (!drone.isExploding) {
+ const distanceFromCenter = drone.position.length();
+ if (distanceFromCenter <= 0.52) { // Slightly larger than Earth's radius (0.5)
+ this.damageEarth();
+ drone.startExplosion();
+ }
+ }
+ });
+
// Update drones
this.drones.forEach((drone) => drone.update(delta))