Klimawaechter 2D: Canvas-Fix + alle Massnahmen sichtbar + Vulkan flacher
- Canvas-Fix: min-height:450px + overflow:visible (Canvas war unsichtbar) - Neue Renderer: Radwege (Fahrraeder), Mangroven, Sand-Aufschuettung, Kohlekraftwerk, Flughafen (mit fliegendem Flugzeug), Wolkenimpfung - Vulkan: flacher (120→95), breiter, weiter im Hintergrund - Eiskegel: breiter, deckt braune Raender komplett ab Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -56,7 +56,7 @@
|
||||
/* === CENTER: Game Canvas + Controls === */
|
||||
.center { display:flex; flex-direction:column; gap:.6rem; }
|
||||
|
||||
.canvas-wrap { background:var(--white); border-radius:14px; border:1px solid rgba(0,0,0,.05); overflow:hidden; box-shadow:0 4px 16px rgba(0,0,0,.05); position:relative; }
|
||||
.canvas-wrap { background:var(--white); border-radius:14px; border:1px solid rgba(0,0,0,.05); overflow:visible; box-shadow:0 4px 16px rgba(0,0,0,.05); position:relative; min-height:450px; }
|
||||
|
||||
/* Tutorial Overlay */
|
||||
.tutorial-overlay { position:absolute; inset:0; background:rgba(15,30,40,.85); backdrop-filter:blur(8px); display:flex; align-items:center; justify-content:center; z-index:10; padding:1.5rem; }
|
||||
|
||||
@@ -192,6 +192,26 @@ export class KlimawaechterRenderer {
|
||||
const x = 0.95
|
||||
return { type: 'sea-wall', x, scale: 1 + index * 0.08, ownerId: stableId, builtTick: tick }
|
||||
}
|
||||
if (id === 'bikes') {
|
||||
return { type: 'bikes', x: 0.35 + index * 0.04, scale: 1, ownerId: stableId, builtTick: tick }
|
||||
}
|
||||
if (id === 'mangrove') {
|
||||
const x = 0.75 + index * 0.03
|
||||
return { type: 'mangrove', x, scale: baseScale, ownerId: stableId, builtTick: tick }
|
||||
}
|
||||
if (id === 'sand-fill') {
|
||||
const x = 0.82 + index * 0.025
|
||||
return { type: 'sand-fill', x, scale: 1, ownerId: stableId, builtTick: tick }
|
||||
}
|
||||
if (id === 'coal') {
|
||||
return { type: 'coal', x: 0.12, scale: 1 + index * 0.05, ownerId: stableId, builtTick: tick }
|
||||
}
|
||||
if (id === 'airport') {
|
||||
return { type: 'airport', x: 0.55, scale: 1, ownerId: stableId, builtTick: tick }
|
||||
}
|
||||
if (id === 'cloud-seed') {
|
||||
return { type: 'cloud-seed', x: 0.5, scale: 1, ownerId: stableId, builtTick: tick }
|
||||
}
|
||||
return { type: 'tree', x: 0.5, scale: 1, ownerId: stableId, builtTick: tick }
|
||||
}
|
||||
|
||||
@@ -312,9 +332,9 @@ export class KlimawaechterRenderer {
|
||||
// === VULKAN mit Gletscher-Deckel (links, ragt aus der Landschaft) ===
|
||||
const volcanoBaseX = W * 0.16
|
||||
const volcanoBaseY = landSurface(volcanoBaseX) - 2
|
||||
const volcanoHeight = 120
|
||||
const volcanoHalfBase = 55
|
||||
const volcanoTopHalf = 14
|
||||
const volcanoHeight = 95 // flacher
|
||||
const volcanoHalfBase = 65 // breiter
|
||||
const volcanoTopHalf = 16 // breitere Spitze
|
||||
// Fels
|
||||
ctx.fillStyle = `rgb(${106 + tempStress * 20},${90 + tempStress * 10},${74})`
|
||||
ctx.beginPath()
|
||||
@@ -337,8 +357,9 @@ export class KlimawaechterRenderer {
|
||||
const glacierBaseY = volcanoBaseY - (volcanoHeight - glacierFullH + glacierFullH - glacierH)
|
||||
const grime = (1 - glacierFraction) * 40
|
||||
// Die Deckel-Form ist ein Trapez, breiter als der Vulkan-Top
|
||||
const capBottomHalf = (volcanoTopHalf + 6) * (0.5 + glacierFraction * 0.5)
|
||||
const capTopHalf = volcanoTopHalf * (0.6 + glacierFraction * 0.4)
|
||||
// Breiter: Eis deckt die gesamte Spitze ab (keine braunen Raender)
|
||||
const capBottomHalf = (volcanoTopHalf + 12) * (0.6 + glacierFraction * 0.4)
|
||||
const capTopHalf = (volcanoTopHalf + 4) * (0.7 + glacierFraction * 0.3)
|
||||
ctx.fillStyle = `rgb(${240 - grime},${246 - grime},${250 - grime})`
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(volcanoBaseX - capBottomHalf, glacierBaseY)
|
||||
@@ -445,13 +466,88 @@ export class KlimawaechterRenderer {
|
||||
}
|
||||
ctx.globalAlpha = 1
|
||||
|
||||
// ===== DEICHE & MAUERN =====
|
||||
// ===== KÜSTENBAUWERKE =====
|
||||
for (const obj of this.placed.filter(p => p.type === 'sand-fill')) {
|
||||
// Sand-Aufschüttung: kleine Hügel an der Wasserlinie
|
||||
const sx = obj.x * W, sy = seaY
|
||||
ctx.fillStyle = '#d4c090'
|
||||
ctx.beginPath()
|
||||
ctx.ellipse(sx, sy, 12, 5, 0, Math.PI, 0)
|
||||
ctx.fill()
|
||||
ctx.fillStyle = '#c8b480'
|
||||
ctx.beginPath()
|
||||
ctx.ellipse(sx + 8, sy, 8, 3, 0, Math.PI, 0)
|
||||
ctx.fill()
|
||||
}
|
||||
for (const obj of this.placed.filter(p => p.type === 'mangrove')) {
|
||||
// Mangroven: grüne Büsche an der Uferlinie
|
||||
const mx = obj.x * W, my = seaY - 4
|
||||
ctx.fillStyle = '#2a6a3a'
|
||||
ctx.beginPath(); ctx.arc(mx, my, 6 * obj.scale, 0, Math.PI * 2); ctx.fill()
|
||||
ctx.fillStyle = '#3a8a4a'
|
||||
ctx.beginPath(); ctx.arc(mx + 4, my - 2, 4 * obj.scale, 0, Math.PI * 2); ctx.fill()
|
||||
// Wurzeln im Wasser
|
||||
ctx.strokeStyle = '#3a5a2a'; ctx.lineWidth = 1
|
||||
ctx.beginPath(); ctx.moveTo(mx - 3, my + 3); ctx.lineTo(mx - 5, my + 10); ctx.stroke()
|
||||
ctx.beginPath(); ctx.moveTo(mx + 2, my + 3); ctx.lineTo(mx + 4, my + 8); ctx.stroke()
|
||||
}
|
||||
for (const obj of this.placed.filter(p => p.type === 'dike')) {
|
||||
this.drawDike(ctx, obj.x * W, groundY)
|
||||
}
|
||||
for (const obj of this.placed.filter(p => p.type === 'sea-wall')) {
|
||||
this.drawSeaWall(ctx, obj.x * W, groundY - 18, baseSeaY)
|
||||
}
|
||||
// Kohlekraftwerk: vor dem Vulkan
|
||||
for (const obj of this.placed.filter(p => p.type === 'coal')) {
|
||||
const cx = obj.x * W, cy = this.landSurfaceFn(obj.x * W) - 5
|
||||
ctx.fillStyle = '#5a5a5a'
|
||||
ctx.fillRect(cx - 10, cy - 12, 20, 12)
|
||||
// Schornstein
|
||||
ctx.fillStyle = '#4a4a4a'
|
||||
ctx.fillRect(cx + 4, cy - 22, 6, 12)
|
||||
// Rauch
|
||||
ctx.fillStyle = 'rgba(80,80,80,0.3)'
|
||||
ctx.beginPath(); ctx.arc(cx + 7, cy - 26 - Math.sin(this.t) * 3, 4, 0, Math.PI * 2); ctx.fill()
|
||||
ctx.beginPath(); ctx.arc(cx + 9, cy - 32 - Math.sin(this.t * 0.7) * 4, 3, 0, Math.PI * 2); ctx.fill()
|
||||
}
|
||||
// Radwege: Fahrräder auf der Strasse (vor den Häusern)
|
||||
for (const obj of this.placed.filter(p => p.type === 'bikes')) {
|
||||
const bx = obj.x * W, by = groundY - 2
|
||||
// Kleines Fahrrad-Symbol
|
||||
ctx.strokeStyle = '#4a8a4a'; ctx.lineWidth = 1.2
|
||||
ctx.beginPath(); ctx.arc(bx - 3, by, 2.5, 0, Math.PI * 2); ctx.stroke()
|
||||
ctx.beginPath(); ctx.arc(bx + 3, by, 2.5, 0, Math.PI * 2); ctx.stroke()
|
||||
ctx.beginPath(); ctx.moveTo(bx - 3, by); ctx.lineTo(bx, by - 3); ctx.lineTo(bx + 3, by); ctx.stroke()
|
||||
}
|
||||
// Flughafen
|
||||
for (const obj of this.placed.filter(p => p.type === 'airport')) {
|
||||
const ax = obj.x * W, ay = groundY - 8
|
||||
// Landebahn
|
||||
ctx.fillStyle = '#5a5a5a'; ctx.fillRect(ax - 18, ay, 36, 4)
|
||||
ctx.strokeStyle = '#fff'; ctx.lineWidth = 0.5; ctx.setLineDash([3, 2])
|
||||
ctx.beginPath(); ctx.moveTo(ax - 16, ay + 2); ctx.lineTo(ax + 16, ay + 2); ctx.stroke()
|
||||
ctx.setLineDash([])
|
||||
// Flugzeug
|
||||
const flyX = ax + Math.sin(this.t * 0.3) * 40
|
||||
const flyY = ay - 15 - Math.abs(Math.sin(this.t * 0.3)) * 20
|
||||
ctx.fillStyle = '#eee'; ctx.globalAlpha = 0.7
|
||||
ctx.beginPath(); ctx.ellipse(flyX, flyY, 6, 1.5, Math.sin(this.t * 0.3) * 0.3, 0, Math.PI * 2); ctx.fill()
|
||||
ctx.globalAlpha = 1
|
||||
}
|
||||
// Wolkenimpfung
|
||||
for (const obj of this.placed.filter(p => p.type === 'cloud-seed')) {
|
||||
// Spezialwolke mit Partikeln
|
||||
const cx = W * 0.5 + Math.sin(this.t * 0.2) * 30, cy = H * 0.12
|
||||
ctx.fillStyle = 'rgba(200,220,240,0.4)'
|
||||
ctx.beginPath(); ctx.ellipse(cx, cy, 20, 8, 0, 0, Math.PI * 2); ctx.fill()
|
||||
ctx.beginPath(); ctx.ellipse(cx - 10, cy + 2, 14, 6, 0, 0, Math.PI * 2); ctx.fill()
|
||||
// Partikel
|
||||
ctx.fillStyle = 'rgba(180,200,220,0.3)'
|
||||
for (let i = 0; i < 4; i++) {
|
||||
const px = cx - 8 + i * 5 + Math.sin(this.t + i) * 2
|
||||
ctx.beginPath(); ctx.arc(px, cy + 10 + Math.sin(this.t * 2 + i) * 3, 1.5, 0, Math.PI * 2); ctx.fill()
|
||||
}
|
||||
}
|
||||
|
||||
// ===== BEWOHNER =====
|
||||
const popLossPct = Math.max(0, 10000 - snap.resources.population) / 10000
|
||||
|
||||
Reference in New Issue
Block a user