- 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>
282 lines
9.2 KiB
GDScript
282 lines
9.2 KiB
GDScript
extends Node3D
|
|
class_name Chunk
|
|
|
|
const CHUNK_SIZE: int = 16
|
|
|
|
var _blocks: PackedInt32Array = PackedInt32Array()
|
|
var _mesh_instance: MeshInstance3D = null
|
|
var _static_body: StaticBody3D = null
|
|
|
|
static var shared_material: StandardMaterial3D = null
|
|
|
|
static func _init_material() -> void:
|
|
if shared_material == null:
|
|
shared_material = StandardMaterial3D.new()
|
|
shared_material.albedo_texture = load("res://assets/textures/block_atlas.png")
|
|
shared_material.texture_filter = BaseMaterial3D.TEXTURE_FILTER_NEAREST_WITH_MIPMAPS
|
|
shared_material.vertex_color_use_as_albedo = false
|
|
shared_material.shading_mode = BaseMaterial3D.SHADING_MODE_PER_VERTEX
|
|
|
|
func _ready() -> void:
|
|
if _blocks.size() == 0:
|
|
_blocks.resize(4096)
|
|
|
|
func init_blocks(data: PackedInt32Array) -> void:
|
|
_blocks = data
|
|
|
|
func get_block(x: int, y: int, z: int) -> int:
|
|
if x < 0 or x >= CHUNK_SIZE or y < 0 or y >= CHUNK_SIZE or z < 0 or z >= CHUNK_SIZE:
|
|
return BlockDatabase.BlockType.AIR
|
|
return _blocks[x + y * CHUNK_SIZE + z * 256]
|
|
|
|
func set_block(x: int, y: int, z: int, id: int) -> void:
|
|
if x < 0 or x >= CHUNK_SIZE or y < 0 or y >= CHUNK_SIZE or z < 0 or z >= CHUNK_SIZE:
|
|
return
|
|
_blocks[x + y * CHUNK_SIZE + z * 256] = id
|
|
|
|
func generate_mesh() -> void:
|
|
if _mesh_instance != null:
|
|
_mesh_instance.queue_free()
|
|
_mesh_instance = null
|
|
if _static_body != null:
|
|
_static_body.queue_free()
|
|
_static_body = null
|
|
|
|
_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)
|
|
|
|
# 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 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):
|
|
for z: int in range(CHUNK_SIZE):
|
|
var block_id: int = get_block(x, y, z)
|
|
if not BlockDatabase.is_solid(block_id):
|
|
continue
|
|
|
|
var uv_tl: Vector2 = BlockDatabase.get_atlas_uv(block_id)
|
|
|
|
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
|
|
|
|
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
|
|
|
|
# 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
|
|
add_child(_mesh_instance)
|
|
|
|
var shape: ConcavePolygonShape3D = ConcavePolygonShape3D.new()
|
|
shape.set_faces(mesh.get_faces())
|
|
|
|
var col_shape: CollisionShape3D = CollisionShape3D.new()
|
|
col_shape.shape = shape
|
|
|
|
_static_body = StaticBody3D.new()
|
|
_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
|
|
return BlockDatabase.is_solid(get_block(x, y, z))
|
|
|
|
# UV layout for a quad: TL, TR, BR, BL
|
|
# Face vertices are added as two triangles: TL-TR-BR and TL-BR-BL
|
|
|
|
func _add_face_top(st: SurfaceTool, x: int, y: int, z: int, uv_tl: Vector2, tw: float, th: float) -> void:
|
|
var fx: float = float(x)
|
|
var fy: float = float(y)
|
|
var fz: float = float(z)
|
|
# tri 1
|
|
st.set_uv(uv_tl)
|
|
st.add_vertex(Vector3(fx, fy + 1.0, fz))
|
|
st.set_uv(uv_tl + Vector2(tw, 0.0))
|
|
st.add_vertex(Vector3(fx + 1.0, fy + 1.0, fz))
|
|
st.set_uv(uv_tl + Vector2(tw, th))
|
|
st.add_vertex(Vector3(fx + 1.0, fy + 1.0, fz + 1.0))
|
|
# tri 2
|
|
st.set_uv(uv_tl)
|
|
st.add_vertex(Vector3(fx, fy + 1.0, fz))
|
|
st.set_uv(uv_tl + Vector2(tw, th))
|
|
st.add_vertex(Vector3(fx + 1.0, fy + 1.0, fz + 1.0))
|
|
st.set_uv(uv_tl + Vector2(0.0, th))
|
|
st.add_vertex(Vector3(fx, fy + 1.0, fz + 1.0))
|
|
|
|
func _add_face_bottom(st: SurfaceTool, x: int, y: int, z: int, uv_tl: Vector2, tw: float, th: float) -> void:
|
|
var fx: float = float(x)
|
|
var fy: float = float(y)
|
|
var fz: float = float(z)
|
|
st.set_uv(uv_tl)
|
|
st.add_vertex(Vector3(fx, fy, fz + 1.0))
|
|
st.set_uv(uv_tl + Vector2(tw, 0.0))
|
|
st.add_vertex(Vector3(fx + 1.0, fy, fz + 1.0))
|
|
st.set_uv(uv_tl + Vector2(tw, th))
|
|
st.add_vertex(Vector3(fx + 1.0, fy, fz))
|
|
st.set_uv(uv_tl)
|
|
st.add_vertex(Vector3(fx, fy, fz + 1.0))
|
|
st.set_uv(uv_tl + Vector2(tw, th))
|
|
st.add_vertex(Vector3(fx + 1.0, fy, fz))
|
|
st.set_uv(uv_tl + Vector2(0.0, th))
|
|
st.add_vertex(Vector3(fx, fy, fz))
|
|
|
|
func _add_face_right(st: SurfaceTool, x: int, y: int, z: int, uv_tl: Vector2, tw: float, th: float) -> void:
|
|
var fx: float = float(x)
|
|
var fy: float = float(y)
|
|
var fz: float = float(z)
|
|
st.set_uv(uv_tl)
|
|
st.add_vertex(Vector3(fx + 1.0, fy, fz))
|
|
st.set_uv(uv_tl + Vector2(tw, 0.0))
|
|
st.add_vertex(Vector3(fx + 1.0, fy, fz + 1.0))
|
|
st.set_uv(uv_tl + Vector2(tw, th))
|
|
st.add_vertex(Vector3(fx + 1.0, fy + 1.0, fz + 1.0))
|
|
st.set_uv(uv_tl)
|
|
st.add_vertex(Vector3(fx + 1.0, fy, fz))
|
|
st.set_uv(uv_tl + Vector2(tw, th))
|
|
st.add_vertex(Vector3(fx + 1.0, fy + 1.0, fz + 1.0))
|
|
st.set_uv(uv_tl + Vector2(0.0, th))
|
|
st.add_vertex(Vector3(fx + 1.0, fy + 1.0, fz))
|
|
|
|
func _add_face_left(st: SurfaceTool, x: int, y: int, z: int, uv_tl: Vector2, tw: float, th: float) -> void:
|
|
var fx: float = float(x)
|
|
var fy: float = float(y)
|
|
var fz: float = float(z)
|
|
st.set_uv(uv_tl)
|
|
st.add_vertex(Vector3(fx, fy, fz + 1.0))
|
|
st.set_uv(uv_tl + Vector2(tw, 0.0))
|
|
st.add_vertex(Vector3(fx, fy, fz))
|
|
st.set_uv(uv_tl + Vector2(tw, th))
|
|
st.add_vertex(Vector3(fx, fy + 1.0, fz))
|
|
st.set_uv(uv_tl)
|
|
st.add_vertex(Vector3(fx, fy, fz + 1.0))
|
|
st.set_uv(uv_tl + Vector2(tw, th))
|
|
st.add_vertex(Vector3(fx, fy + 1.0, fz))
|
|
st.set_uv(uv_tl + Vector2(0.0, th))
|
|
st.add_vertex(Vector3(fx, fy + 1.0, fz + 1.0))
|
|
|
|
func _add_face_front(st: SurfaceTool, x: int, y: int, z: int, uv_tl: Vector2, tw: float, th: float) -> void:
|
|
var fx: float = float(x)
|
|
var fy: float = float(y)
|
|
var fz: float = float(z)
|
|
st.set_uv(uv_tl)
|
|
st.add_vertex(Vector3(fx + 1.0, fy, fz + 1.0))
|
|
st.set_uv(uv_tl + Vector2(tw, 0.0))
|
|
st.add_vertex(Vector3(fx, fy, fz + 1.0))
|
|
st.set_uv(uv_tl + Vector2(tw, th))
|
|
st.add_vertex(Vector3(fx, fy + 1.0, fz + 1.0))
|
|
st.set_uv(uv_tl)
|
|
st.add_vertex(Vector3(fx + 1.0, fy, fz + 1.0))
|
|
st.set_uv(uv_tl + Vector2(tw, th))
|
|
st.add_vertex(Vector3(fx, fy + 1.0, fz + 1.0))
|
|
st.set_uv(uv_tl + Vector2(0.0, th))
|
|
st.add_vertex(Vector3(fx + 1.0, fy + 1.0, fz + 1.0))
|
|
|
|
func _add_face_back(st: SurfaceTool, x: int, y: int, z: int, uv_tl: Vector2, tw: float, th: float) -> void:
|
|
var fx: float = float(x)
|
|
var fy: float = float(y)
|
|
var fz: float = float(z)
|
|
st.set_uv(uv_tl)
|
|
st.add_vertex(Vector3(fx, fy, fz))
|
|
st.set_uv(uv_tl + Vector2(tw, 0.0))
|
|
st.add_vertex(Vector3(fx + 1.0, fy, fz))
|
|
st.set_uv(uv_tl + Vector2(tw, th))
|
|
st.add_vertex(Vector3(fx + 1.0, fy + 1.0, fz))
|
|
st.set_uv(uv_tl)
|
|
st.add_vertex(Vector3(fx, fy, fz))
|
|
st.set_uv(uv_tl + Vector2(tw, th))
|
|
st.add_vertex(Vector3(fx + 1.0, fy + 1.0, fz))
|
|
st.set_uv(uv_tl + Vector2(0.0, th))
|
|
st.add_vertex(Vector3(fx, fy + 1.0, fz))
|