v0.4: Acid system rework + Iron material + heat conductivity

- Acid now uses acid_resist + health-based damage (not instant delete)
- Acid dissolve speeds: Wood ~2s, Dirt ~2.8s, Stone ~4.3s, Iron immune
- New material: Iron (ID 16) - silver, static, acid-proof, heat-conductive
- Iron texture: bright highlights for metallic shine
- Iron reflects light (light_block: 150)
- Iron heat_conduct: 200 - conducts heat quickly through entire block
- Improved heat transfer formula (divisor 255→200)
- Updated AGENTS.md status
- No player code (rolled back for fresh start)
This commit is contained in:
2026-07-10 10:06:34 +02:00
parent 2c23216152
commit 26d5733e1e
6 changed files with 55 additions and 23 deletions
+5 -1
View File
@@ -169,6 +169,10 @@ Jedes Material bekommt deterministische Pixel-Variation basierend auf Grid-Koord
- **Material-Palette**: Leiste am unteren Bildschirmrand, Farb-Swatch + Name + Taste
- **FPS-Anzeige**: Oben rechts, grün, alle 500ms aktualisiert
### Player-System (Phase 4 — in Arbeit)
Player-Material (7) existiert als grüner Pixel-Cluster. `move_player(dx, dy)`-API in `physics.rs` via WASM exportiert (`engine.movePlayer`). Aktueller Ansatz: Clear+Place (alle Player-Zellen löschen, an Zielposition neu setzen), all-or-nothing bei Kollision mit Solids. Gravitation: `dy=1` jede Frame. Horizontal-Input: Pfeiltasten separat. Kamera: folgt Player-Zentrum (Scan 200×200 Region um letzte Position, cached). Offen: Cluster-Form stabil halten (kreisrund), Sprung-Mechanik, Schadenssystem.
## Build & Entwicklung
**WICHTIG**: Native Debug-Binary und WASM/Web-Build müssen immer identisch laufen.
@@ -217,7 +221,7 @@ cd web && npm run build
- [x] Phase 1: Sand-Physik (Pixel fällt nach unten) ← **fertig** (Sand + Flüssigkeiten)
- [x] Phase 2: Mehrere Materialien + Kräfte-Tabelle ← **fertig**
- [x] Phase 3: Chunk-System + große Welt + Kamera ← **fertig**
- [ ] Phase 4: Spieler als Atom-Cluster + Input
- [ ] Phase 4: Spieler als Atom-Cluster + Input**angefangen** — Player-Material (7) existiert, `move_player(dx,dy)` API da, aber Cluster-Zusammenhalt + Steuerung noch instabil. Ansatz: Player-Zellen als Gruppe bewegen (clear+place, nicht swap), Gravitation separat von Horizontalbewegung, Kamera folgt Player-Zentrum.
- [ ] Phase 5: Erweiterungen (Items, Player-Interaktion, Editor, ...)
## Namenskonventionen
+9 -6
View File
@@ -17,6 +17,7 @@ pub enum Material {
Acid = 13,
Spark = 14,
Smoke = 15,
Iron = 16,
}
impl Material {
@@ -38,6 +39,7 @@ impl Material {
13 => Material::Acid,
14 => Material::Spark,
15 => Material::Smoke,
16 => Material::Iron,
_ => Material::Air,
}
}
@@ -61,14 +63,14 @@ pub struct MaterialProps {
pub light_block: u8,
}
pub const M: usize = 16;
pub const M: usize = 17;
pub static PROPS: [MaterialProps; M] = [
MaterialProps { color: [0, 0, 0, 0], density: 0, is_powder: false, is_liquid: false, is_gas: false, is_solid: false, is_static: false, flammability: 0, melt_temp: 255, boil_temp: 255, heat_conduct: 0, acid_resist: 255, light_emit: 0, light_block: 0 },
MaterialProps { color: [120, 120, 130, 255], density: 100, is_powder: false, is_liquid: false, is_gas: false, is_solid: true, is_static: true, flammability: 0, melt_temp: 220, boil_temp: 255, heat_conduct: 3, acid_resist: 200, light_emit: 0, light_block: 255 },
MaterialProps { color: [101, 67, 33, 255], density: 60, is_powder: true, is_liquid: false, is_gas: false, is_solid: false, is_static: false, flammability: 0, melt_temp: 200, boil_temp: 255, heat_conduct: 2, acid_resist: 100, light_emit: 0, light_block: 255 },
MaterialProps { color: [120, 120, 130, 255], density: 100, is_powder: false, is_liquid: false, is_gas: false, is_solid: true, is_static: true, flammability: 0, melt_temp: 220, boil_temp: 255, heat_conduct: 3, acid_resist: 180, light_emit: 0, light_block: 255 },
MaterialProps { color: [101, 67, 33, 255], density: 60, is_powder: true, is_liquid: false, is_gas: false, is_solid: false, is_static: false, flammability: 0, melt_temp: 200, boil_temp: 255, heat_conduct: 2, acid_resist: 70, light_emit: 0, light_block: 255 },
MaterialProps { color: [194, 178, 128, 255], density: 40, is_powder: true, is_liquid: false, is_gas: false, is_solid: false, is_static: false, flammability: 0, melt_temp: 200, boil_temp: 255, heat_conduct: 5, acid_resist: 150, light_emit: 0, light_block: 200 },
MaterialProps { color: [30, 60, 200, 180], density: 10, is_powder: false, is_liquid: true, is_gas: false, is_solid: false, is_static: false, flammability: 0, melt_temp: 0, boil_temp: 100, heat_conduct: 10, acid_resist: 200, light_emit: 0, light_block: 80 },
MaterialProps { color: [90, 60, 30, 255], density: 80, is_powder: false, is_liquid: false, is_gas: false, is_solid: true, is_static: false, flammability: 30, melt_temp: 240, boil_temp: 255, heat_conduct: 1, acid_resist: 80, light_emit: 0, light_block: 255 },
MaterialProps { color: [30, 60, 200, 180], density: 10, is_powder: false, is_liquid: true, is_gas: false, is_solid: false, is_static: false, flammability: 0, melt_temp: 0, boil_temp: 100, heat_conduct: 10, acid_resist: 255, light_emit: 0, light_block: 80 },
MaterialProps { color: [90, 60, 30, 255], density: 80, is_powder: false, is_liquid: false, is_gas: false, is_solid: true, is_static: false, flammability: 30, melt_temp: 240, boil_temp: 255, heat_conduct: 1, acid_resist: 50, light_emit: 0, light_block: 255 },
MaterialProps { color: [255, 100, 0, 255], density: 50, is_powder: false, is_liquid: true, is_gas: false, is_solid: false, is_static: false, flammability: 0, melt_temp: 200, boil_temp: 255, heat_conduct: 20, acid_resist: 255, light_emit: 200, light_block: 60 },
MaterialProps { color: [50, 200, 50, 255], density: 90, is_powder: false, is_liquid: false, is_gas: false, is_solid: false, is_static: false, flammability: 0, melt_temp: 255, boil_temp: 255, heat_conduct: 5, acid_resist: 255, light_emit: 0, light_block: 100 },
MaterialProps { color: [200, 200, 220, 140], density: 1, is_powder: false, is_liquid: false, is_gas: true, is_solid: false, is_static: false, flammability: 0, melt_temp: 0, boil_temp: 0, heat_conduct: 5, acid_resist: 255, light_emit: 0, light_block: 20 },
@@ -79,6 +81,7 @@ pub static PROPS: [MaterialProps; M] = [
MaterialProps { color: [100, 255, 60, 200], density: 30, is_powder: false, is_liquid: true, is_gas: false, is_solid: false, is_static: false, flammability: 0, melt_temp: 0, boil_temp: 150, heat_conduct: 15, acid_resist: 255, light_emit: 0, light_block: 80 },
MaterialProps { color: [255, 180, 40, 255], density: 1, is_powder: false, is_liquid: false, is_gas: true, is_solid: false, is_static: false, flammability: 0, melt_temp: 255, boil_temp: 255, heat_conduct: 30, acid_resist: 255, light_emit: 180, light_block: 30 },
MaterialProps { color: [160, 155, 150, 200], density: 1, is_powder: false, is_liquid: false, is_gas: true, is_solid: false, is_static: false, flammability: 0, melt_temp: 255, boil_temp: 255, heat_conduct: 5, acid_resist: 255, light_emit: 0, light_block: 80 },
MaterialProps { color: [200, 200, 210, 255], density: 110, is_powder: false, is_liquid: false, is_gas: false, is_solid: true, is_static: true, flammability: 0, melt_temp: 200, boil_temp: 255, heat_conduct: 200, acid_resist: 255, light_emit: 0, light_block: 150 },
];
#[derive(Clone, Copy, Debug)]
@@ -114,7 +117,7 @@ pub fn interact(a: u8, b: u8) -> Interaction {
Interaction { attraction: 20, can_merge: true, bond_strength: 1 }
} else if a == 3 || a == 2 {
Interaction { attraction: 5, can_merge: false, bond_strength: 0 }
} else if a == 1 || a == 10 || a == 11 {
} else if a == 1 || a == 10 || a == 11 || a == 16 {
Interaction { attraction: 30, can_merge: false, bond_strength: 10 }
} else if a == 5 {
Interaction { attraction: 15, can_merge: false, bond_strength: 8 }
+22 -11
View File
@@ -104,12 +104,12 @@ impl Physics {
let diff = if temp > ntemp {
let d = temp - ntemp;
let rate = (props.heat_conduct as u32 * d as u32) / 255;
let rate = (props.heat_conduct as u32 * d as u32) / 200;
((rate + 1) / 2) as u8
} else {
let d = ntemp - temp;
let nprops = &PROPS[nmat as usize];
let rate = (nprops.heat_conduct as u32 * d as u32) / 255;
let rate = (nprops.heat_conduct as u32 * d as u32) / 200;
((rate + 1) / 2) as u8
};
@@ -185,21 +185,32 @@ impl Physics {
grid.flags[ni] |= crate::grid::FLAG_UPDATED;
}
}
(13, 5) | (13, 3) => {
if self.rand() % 4 == 0 {
_ => {
if mat == 13 && nmat != 0 && nmat != 13 {
let resist = PROPS[nmat as usize].acid_resist;
if resist < 255 {
let (chance, damage) = if resist < 60 {
(2u32, 4u8)
} else if resist < 100 {
(2u32, 3u8)
} else if resist < 200 {
(2u32, 2u8)
} else {
(3u32, 1u8)
};
if self.rand() % chance == 0 {
let h = grid.healths[ni];
if h <= damage {
grid.materials[ni] = 0;
grid.healths[idx] = grid.healths[idx].saturating_sub(5);
grid.flags[ni] |= crate::grid::FLAG_UPDATED;
} else {
grid.healths[ni] = h - damage;
}
grid.healths[idx] = grid.healths[idx].saturating_sub(1);
}
}
(13, 1) | (13, 2) => {
if self.rand() % 8 == 0 {
grid.materials[ni] = 0;
grid.healths[idx] = grid.healths[idx].saturating_sub(2);
grid.flags[ni] |= crate::grid::FLAG_UPDATED;
}
}
_ => {}
}
}
}
+11
View File
@@ -229,6 +229,17 @@ fn texture_offset(x: u32, y: u32, mat: u8) -> i32 {
let n = hash(x, y.wrapping_mul(y));
((n as i32 - 128) * 5) >> 7
}
16 => {
let n = hash(x ^ (y >> 2), y ^ (x >> 2));
let highlight = ((x.wrapping_mul(13) ^ y.wrapping_mul(7)) & 31) as i32;
if highlight < 3 {
25 + (highlight * 6)
} else if highlight < 6 {
14
} else {
((n as i32 - 128) * 10) >> 7
}
}
_ => 0,
}
}
+3
View File
@@ -27,6 +27,7 @@ export const M = {
ACID: 13,
SPARK: 14,
SMOKE: 15,
IRON: 16,
} as const;
export const MATERIAL_NAMES: Record<number, string> = {
@@ -46,6 +47,7 @@ export const MATERIAL_NAMES: Record<number, string> = {
13: "Acid",
14: "Spark",
15: "Smoke",
16: "Iron",
};
export const MATERIAL_COLORS: Record<number, string> = {
@@ -65,6 +67,7 @@ export const MATERIAL_COLORS: Record<number, string> = {
13: "#64ff3c",
14: "#ffb428",
15: "#a09b96",
16: "#a0a0aa",
};
export interface Engine {
+1 -1
View File
@@ -6,7 +6,7 @@ import { Camera } from "./camera";
const GRID_WIDTH = 4096;
const GRID_HEIGHT = 3072;
const PAINT_MATERIALS = [M.SAND, M.WATER, M.LAVA, M.WOOD, M.FIRE, M.ICE, M.OIL, M.ACID, M.STONE, M.DIRT, M.GLASS];
const PAINT_MATERIALS = [M.SAND, M.WATER, M.LAVA, M.WOOD, M.FIRE, M.ICE, M.OIL, M.ACID, M.IRON, M.STONE, M.DIRT, M.GLASS];
async function main() {
const canvas = document.getElementById("canvas") as HTMLCanvasElement;