Switch back to Jolt Physics in Voxel demo (#1257)

This commit is contained in:
Mikael Hermansson
2025-10-02 23:35:34 +02:00
committed by GitHub
parent 7d5f9269ca
commit d7b6f86b0b
5 changed files with 43 additions and 40 deletions

View File

@@ -19,7 +19,7 @@ var _selected_block := 6
@onready var raycast: RayCast3D = $Head/RayCast3D
@onready var camera_attributes: CameraAttributes = $Head/Camera3D.attributes
@onready var selected_block_texture: TextureRect = $SelectedBlock
@onready var voxel_world: Node = $"../VoxelWorld"
@onready var voxel_world: VoxelWorld = $"../VoxelWorld"
@onready var crosshair: CenterContainer = $"../PauseMenu/Crosshair"
@onready var aim_preview: MeshInstance3D = $AimPreview
@onready var neutral_fov: float = camera.fov

View File

@@ -155,7 +155,7 @@ pick_block={
[physics]
common/physics_ticks_per_second=120
3d/physics_engine="GodotPhysics3D"
3d/physics_engine="Jolt Physics"
common/physics_interpolation=true
[rendering]

View File

@@ -4,23 +4,25 @@ extends StaticBody3D
# After that, chunks finish setting themselves up in the _ready() function.
# If a chunk is changed, its "regenerate" method is called.
const CHUNK_SIZE = 16 # Keep in sync with TerrainGenerator.
const TEXTURE_SHEET_WIDTH = 8
const CHUNK_LAST_INDEX = CHUNK_SIZE - 1
const TEXTURE_TILE_SIZE = 1.0 / TEXTURE_SHEET_WIDTH
const CHUNK_SIZE := 16 # Keep in sync with TerrainGenerator.
const TEXTURE_SHEET_WIDTH := 8
const CHUNK_LAST_INDEX := CHUNK_SIZE - 1
const TEXTURE_TILE_SIZE := 1.0 / TEXTURE_SHEET_WIDTH
const CHUNK_EXTENTS := Vector3.ONE / 2.0
const DIRECTIONS: Array[Vector3i] = [Vector3i.LEFT, Vector3i.RIGHT, Vector3i.DOWN, Vector3i.UP, Vector3i.FORWARD, Vector3i.BACK]
var data := {}
var data: Dictionary[Vector3i, int] = {}
var chunk_position := Vector3i()
var is_initial_mesh_generated: bool = false
var is_initial_mesh_generated := false
var mesh_task_id := 0
var _thread: Thread
static var box_shape: BoxShape3D = null
@onready var voxel_world := get_parent()
@onready var voxel_world := get_parent() as VoxelWorld
func _ready() -> void:
func _init(pos: Vector3i) -> void:
chunk_position = pos
transform.origin = Vector3(chunk_position * CHUNK_SIZE)
name = str(chunk_position)
if Settings.world_type == 0:
@@ -32,17 +34,27 @@ func _ready() -> void:
_generate_chunk_collider()
func _notification(what: int) -> void:
if what == NOTIFICATION_PREDELETE:
if mesh_task_id >= 1:
WorkerThreadPool.wait_for_task_completion(mesh_task_id)
mesh_task_id = 0
func try_initial_generate_mesh(all_chunks: Dictionary[Vector3i, Chunk]) -> void:
# We can use a thread for mesh generation.
for dir in DIRECTIONS:
if not all_chunks.has(chunk_position + dir):
return
is_initial_mesh_generated = true
_thread = Thread.new()
_thread.start(_generate_chunk_mesh)
mesh_task_id = WorkerThreadPool.add_task(_generate_chunk_mesh, true)
func regenerate() -> void:
# Making shape changes to bodies with many/complex shapes, while the body is in the scene tree,
# can be expensive when using Jolt Physics, so we temporarily remove it from the scene tree.
voxel_world.remove_child(self)
# Clear out all old nodes first.
for c in get_children():
remove_child(c)
@@ -52,18 +64,14 @@ func regenerate() -> void:
_generate_chunk_collider()
_generate_chunk_mesh()
voxel_world.add_child(self)
func _generate_chunk_collider() -> void:
if data.is_empty():
# Avoid errors caused by StaticBody3D not having colliders.
_create_block_collider(Vector3.ZERO)
collision_layer = 0
collision_mask = 0
return
# For each block, generate a collider. Ensure collision layers are enabled.
collision_layer = 0xFFFFF
collision_mask = 0xFFFFF
# For each block, generate a collider.
for block_position: Vector3i in data.keys():
var block_id: int = data[block_position]
if block_id != 27 and block_id != 28:
@@ -201,10 +209,13 @@ func _draw_block_face(surface_tool: SurfaceTool, verts: Array[Vector3], uvs: Arr
func _create_block_collider(block_sub_position: Vector3) -> void:
if not box_shape:
box_shape = BoxShape3D.new()
box_shape.extents = CHUNK_EXTENTS
var collider := CollisionShape3D.new()
collider.shape = BoxShape3D.new()
collider.shape.extents = Vector3.ONE / 2
collider.transform.origin = Vector3(block_sub_position) + Vector3.ONE / 2
collider.shape = box_shape
collider.transform.origin = block_sub_position + CHUNK_EXTENTS
add_child(collider)

View File

@@ -3,12 +3,12 @@ extends Resource
const RANDOM_BLOCK_PROBABILITY = 0.015
static func empty() -> Dictionary:
static func empty() -> Dictionary[Vector3i, int]:
return {}
static func random_blocks() -> Dictionary:
var random_data := {}
static func random_blocks() -> Dictionary[Vector3i, int]:
var random_data: Dictionary[Vector3i, int] = {}
for x in Chunk.CHUNK_SIZE:
for y in Chunk.CHUNK_SIZE:
for z in Chunk.CHUNK_SIZE:
@@ -19,8 +19,8 @@ static func random_blocks() -> Dictionary:
return random_data
static func flat(chunk_position: Vector3i) -> Dictionary:
var data := {}
static func flat(chunk_position: Vector3i) -> Dictionary[Vector3i, int]:
var data: Dictionary[Vector3i, int] = {}
if chunk_position.y != -1:
return data
@@ -36,7 +36,7 @@ static func flat(chunk_position: Vector3i) -> Dictionary:
# Used to create the project icon.
static func origin_grass(chunk_position: Vector3i) -> Dictionary:
static func origin_grass(chunk_position: Vector3i) -> Dictionary[Vector3i, int]:
if chunk_position == Vector3i.ZERO:
return { Vector3i.ZERO: 3 }

View File

@@ -1,3 +1,4 @@
class_name VoxelWorld
extends Node
# This file manages the creation and deletion of Chunks.
@@ -47,8 +48,7 @@ func _process(_delta: float) -> void:
if _chunks.has(chunk_position):
continue
var chunk := Chunk.new()
chunk.chunk_position = chunk_position
var chunk := Chunk.new(chunk_position)
_chunks[chunk_position] = chunk
add_child(chunk)
chunk.try_initial_generate_mesh(_chunks)
@@ -104,11 +104,6 @@ func set_block_global_position(block_global_position: Vector3i, block_id: int) -
func clean_up() -> void:
for chunk_position_key: Vector3i in _chunks.keys():
var thread: Thread = _chunks[chunk_position_key]._thread
if thread:
thread.wait_to_finish()
_chunks = {}
set_process(false)
@@ -129,9 +124,6 @@ func _delete_far_away_chunks(player_chunk: Vector3i) -> void:
# Also take the opportunity to delete far away chunks.
for chunk_position_key: Vector3i in _chunks.keys():
if Vector3(player_chunk).distance_to(Vector3(chunk_position_key)) > _delete_distance:
var thread: Thread = _chunks[chunk_position_key]._thread
if thread:
thread.wait_to_finish()
_chunks[chunk_position_key].queue_free()
_chunks.erase(chunk_position_key)
deleted_this_frame += 1