feat(biome): abyssal bioluminescent + glow blocks + abyssal jellyfish + particles
- BlockDatabase: GLOW_CORAL_CYAN(10), GLOW_CORAL_VIOLET(11), LAVA_VENT(12) with emission data - WorldGenerator: abyssal blocks at y<-40 (cyan 4%, violet 1%, vent 0.5% via 3D noise) - Chunk.gd: multi-surface mesh (solid + 3 emissive surfaces with StandardMaterial3D emission) - MobSpawner: abyssal jellyfish spawn when player y<-30, max 8 - AbyssalJellyfish: cyan fluo, slower, double damage (10), bioluminescent flash on attack - BioluminescentParticles: 200 cyan-green particles follow player, only emit in abyss Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -44,13 +44,25 @@ func generate_mesh() -> void:
|
||||
|
||||
_init_material()
|
||||
|
||||
var tile_w: float = BlockDatabase.ATLAS_TILE_SIZE.x
|
||||
var tile_h: float = BlockDatabase.ATLAS_TILE_SIZE.y
|
||||
|
||||
# Surface 0: solid blocks (atlas texture)
|
||||
var st: SurfaceTool = SurfaceTool.new()
|
||||
st.begin(Mesh.PRIMITIVE_TRIANGLES)
|
||||
|
||||
var has_faces: bool = false
|
||||
# Emissive surfaces: cyan (1), violet (2), vent (3)
|
||||
var st_cyan: SurfaceTool = SurfaceTool.new()
|
||||
st_cyan.begin(Mesh.PRIMITIVE_TRIANGLES)
|
||||
var st_violet: SurfaceTool = SurfaceTool.new()
|
||||
st_violet.begin(Mesh.PRIMITIVE_TRIANGLES)
|
||||
var st_vent: SurfaceTool = SurfaceTool.new()
|
||||
st_vent.begin(Mesh.PRIMITIVE_TRIANGLES)
|
||||
|
||||
var tile_w: float = BlockDatabase.ATLAS_TILE_SIZE.x
|
||||
var tile_h: float = BlockDatabase.ATLAS_TILE_SIZE.y
|
||||
var has_faces: bool = false
|
||||
var has_cyan: bool = false
|
||||
var has_violet: bool = false
|
||||
var has_vent: bool = false
|
||||
|
||||
for x: int in range(CHUNK_SIZE):
|
||||
for y: int in range(CHUNK_SIZE):
|
||||
@@ -61,35 +73,80 @@ func generate_mesh() -> void:
|
||||
|
||||
var uv_tl: Vector2 = BlockDatabase.get_atlas_uv(block_id)
|
||||
|
||||
if not _is_opaque_at(x, y + 1, z):
|
||||
_add_face_top(st, x, y, z, uv_tl, tile_w, tile_h)
|
||||
has_faces = true
|
||||
if not _is_opaque_at(x, y - 1, z):
|
||||
_add_face_bottom(st, x, y, z, uv_tl, tile_w, tile_h)
|
||||
has_faces = true
|
||||
if not _is_opaque_at(x + 1, y, z):
|
||||
_add_face_right(st, x, y, z, uv_tl, tile_w, tile_h)
|
||||
has_faces = true
|
||||
if not _is_opaque_at(x - 1, y, z):
|
||||
_add_face_left(st, x, y, z, uv_tl, tile_w, tile_h)
|
||||
has_faces = true
|
||||
if not _is_opaque_at(x, y, z + 1):
|
||||
_add_face_front(st, x, y, z, uv_tl, tile_w, tile_h)
|
||||
has_faces = true
|
||||
if not _is_opaque_at(x, y, z - 1):
|
||||
_add_face_back(st, x, y, z, uv_tl, tile_w, tile_h)
|
||||
has_faces = true
|
||||
var target_st: SurfaceTool = st
|
||||
var emit_type: int = 0 # 0=none, 1=cyan, 2=violet, 3=vent
|
||||
if block_id == BlockDatabase.BlockType.GLOW_CORAL_CYAN:
|
||||
target_st = st_cyan
|
||||
emit_type = 1
|
||||
elif block_id == BlockDatabase.BlockType.GLOW_CORAL_VIOLET:
|
||||
target_st = st_violet
|
||||
emit_type = 2
|
||||
elif block_id == BlockDatabase.BlockType.LAVA_VENT:
|
||||
target_st = st_vent
|
||||
emit_type = 3
|
||||
|
||||
if not has_faces:
|
||||
var added: bool = false
|
||||
if not _is_opaque_at(x, y + 1, z):
|
||||
_add_face_top(target_st, x, y, z, uv_tl, tile_w, tile_h)
|
||||
added = true
|
||||
if not _is_opaque_at(x, y - 1, z):
|
||||
_add_face_bottom(target_st, x, y, z, uv_tl, tile_w, tile_h)
|
||||
added = true
|
||||
if not _is_opaque_at(x + 1, y, z):
|
||||
_add_face_right(target_st, x, y, z, uv_tl, tile_w, tile_h)
|
||||
added = true
|
||||
if not _is_opaque_at(x - 1, y, z):
|
||||
_add_face_left(target_st, x, y, z, uv_tl, tile_w, tile_h)
|
||||
added = true
|
||||
if not _is_opaque_at(x, y, z + 1):
|
||||
_add_face_front(target_st, x, y, z, uv_tl, tile_w, tile_h)
|
||||
added = true
|
||||
if not _is_opaque_at(x, y, z - 1):
|
||||
_add_face_back(target_st, x, y, z, uv_tl, tile_w, tile_h)
|
||||
added = true
|
||||
|
||||
if added:
|
||||
match emit_type:
|
||||
0: has_faces = true
|
||||
1: has_cyan = true
|
||||
2: has_violet = true
|
||||
3: has_vent = true
|
||||
|
||||
var mesh: ArrayMesh = ArrayMesh.new()
|
||||
|
||||
if has_faces:
|
||||
st.generate_normals()
|
||||
mesh = st.commit() # surface 0 — will apply material via surface_set_material below
|
||||
|
||||
if has_cyan:
|
||||
st_cyan.generate_normals()
|
||||
st_cyan.commit(mesh)
|
||||
if has_violet:
|
||||
st_violet.generate_normals()
|
||||
st_violet.commit(mesh)
|
||||
if has_vent:
|
||||
st_vent.generate_normals()
|
||||
st_vent.commit(mesh)
|
||||
|
||||
if mesh.get_surface_count() == 0:
|
||||
return
|
||||
|
||||
st.generate_normals()
|
||||
|
||||
var mesh: ArrayMesh = st.commit()
|
||||
# Assign materials per surface
|
||||
var surf_idx: int = 0
|
||||
if has_faces:
|
||||
mesh.surface_set_material(surf_idx, shared_material)
|
||||
surf_idx += 1
|
||||
if has_cyan:
|
||||
mesh.surface_set_material(surf_idx, _make_emissive_mat(Color(0.2, 0.8, 1.0), 3.0))
|
||||
surf_idx += 1
|
||||
if has_violet:
|
||||
mesh.surface_set_material(surf_idx, _make_emissive_mat(Color(0.7, 0.3, 0.9), 3.0))
|
||||
surf_idx += 1
|
||||
if has_vent:
|
||||
mesh.surface_set_material(surf_idx, _make_emissive_mat(Color(1.0, 0.5, 0.1), 3.0))
|
||||
|
||||
_mesh_instance = MeshInstance3D.new()
|
||||
_mesh_instance.mesh = mesh
|
||||
_mesh_instance.material_override = shared_material
|
||||
add_child(_mesh_instance)
|
||||
|
||||
var shape: ConcavePolygonShape3D = ConcavePolygonShape3D.new()
|
||||
@@ -102,6 +159,15 @@ func generate_mesh() -> void:
|
||||
_static_body.add_child(col_shape)
|
||||
add_child(_static_body)
|
||||
|
||||
|
||||
func _make_emissive_mat(emission_color: Color, energy: float) -> StandardMaterial3D:
|
||||
var mat: StandardMaterial3D = StandardMaterial3D.new()
|
||||
mat.albedo_color = emission_color
|
||||
mat.emission_enabled = true
|
||||
mat.emission = emission_color
|
||||
mat.emission_energy_multiplier = energy
|
||||
return mat
|
||||
|
||||
func _is_opaque_at(x: int, y: int, z: int) -> bool:
|
||||
if x < 0 or x >= CHUNK_SIZE or y < 0 or y >= CHUNK_SIZE or z < 0 or z >= CHUNK_SIZE:
|
||||
return false
|
||||
|
||||
@@ -26,6 +26,11 @@ static func generate_chunk(chunk_x: int, chunk_y: int, chunk_z: int, seed: int)
|
||||
noise_wreck.noise_type = FastNoiseLite.TYPE_CELLULAR
|
||||
noise_wreck.frequency = 0.03
|
||||
|
||||
var noise_glow: FastNoiseLite = FastNoiseLite.new()
|
||||
noise_glow.seed = seed + 7777
|
||||
noise_glow.noise_type = FastNoiseLite.TYPE_SIMPLEX_SMOOTH
|
||||
noise_glow.frequency = 0.08
|
||||
|
||||
for lx: int in range(CHUNK_SIZE):
|
||||
for lz: int in range(CHUNK_SIZE):
|
||||
var wx: int = chunk_x * CHUNK_SIZE + lx
|
||||
@@ -45,7 +50,7 @@ static func generate_chunk(chunk_x: int, chunk_y: int, chunk_z: int, seed: int)
|
||||
var idx: int = lx + ly * CHUNK_SIZE + lz * 256
|
||||
|
||||
data[idx] = _get_block_at(wy, ground_height, biome, wx, wz, lx, lz,
|
||||
is_wreck_center, noise_detail, seed)
|
||||
is_wreck_center, noise_detail, noise_glow, seed)
|
||||
|
||||
return data
|
||||
|
||||
@@ -61,11 +66,28 @@ static func _get_biome(biome_val: float, ground_height: int) -> int:
|
||||
|
||||
static func _get_block_at(wy: int, ground_height: int, biome: int,
|
||||
wx: int, wz: int, lx: int, lz: int,
|
||||
is_wreck_center: bool, noise_detail: FastNoiseLite, seed: int) -> int:
|
||||
is_wreck_center: bool, noise_detail: FastNoiseLite, noise_glow: FastNoiseLite, seed: int) -> int:
|
||||
|
||||
if wy <= -60:
|
||||
return BlockDatabase.BlockType.BEDROCK
|
||||
|
||||
# --- Abyssal bioluminescent decorations (deep zone) ---
|
||||
if ground_height < -30 and wy >= ground_height and wy < ground_height + 3:
|
||||
if wy < -40:
|
||||
var glow_val: float = noise_glow.get_noise_3d(float(wx), float(wy), float(wz))
|
||||
# GLOW_CORAL_CYAN patches — 4% density on surfaces
|
||||
if glow_val > 0.65:
|
||||
return BlockDatabase.BlockType.GLOW_CORAL_CYAN
|
||||
# GLOW_CORAL_VIOLET rare columns — 1%
|
||||
var violet_val: float = noise_glow.get_noise_3d(float(wx) * 1.3, float(wy) * 0.5, float(wz) * 1.3)
|
||||
if violet_val > 0.82:
|
||||
return BlockDatabase.BlockType.GLOW_CORAL_VIOLET
|
||||
# LAVA_VENT columns — 0.5% density, very deep
|
||||
if wy < -50 and wy < ground_height + 3:
|
||||
var vent_val: float = noise_glow.get_noise_3d(float(wx) * 0.5, float(wy) * 2.0, float(wz) * 0.5)
|
||||
if vent_val > 0.88:
|
||||
return BlockDatabase.BlockType.LAVA_VENT
|
||||
|
||||
if wy < ground_height - 5:
|
||||
return BlockDatabase.BlockType.ROCK
|
||||
|
||||
|
||||
Reference in New Issue
Block a user