How to avoid clipping when player is placing objects?

Godot Version

4.3

Question

I’m working on a prototype where I want to place furniture in a room, right now im just testing with CSGBox3Ds but they’re always clipping through each other and the room floor/walls. Been messing aroun with collission settings but i cant seem to get it working so it doesnt clip with each other.

How do i avoid this?

Here’s the code but i think ill have to rewrite most of it.

extends Node

@export var new_furniture: PackedScene 

@onready var camera: Camera3D = $"../CameraArm/Camera3D"

var placement_mode: bool = false
var furniture


# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	pass # Replace with function body.



# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
	if placement_mode == true:
		var mouse_position = mouse_ray()
		furniture.global_position = mouse_position
		
		
		if Input.is_action_just_pressed("left_click"):
			placement_mode = false
			printt("Placementmode: ", placement_mode)


##Enter place mode##
func _unhandled_input(event: InputEvent) -> void:
	if event.is_action_pressed("build_1_debug"):
		placement_mode = true
		furniture = new_furniture.instantiate()
		add_child(furniture)
		printt("Placementmode: ", placement_mode)
		


func mouse_ray() -> Vector3:
	var mouse_pos = get_viewport().get_mouse_position()
	var ray_length = 1000
	var ray_start = camera.project_ray_origin(mouse_pos)
	var ray_end = ray_start + camera.project_ray_normal(mouse_pos) * ray_length
	var space = camera.get_world_3d().direct_space_state
	var ray_query = PhysicsRayQueryParameters3D.new()
	ray_query.from = ray_start
	ray_query.to = ray_end
	ray_query.collision_mask = 0b10 #Layer Mask 2
	var raycast_result = space.intersect_ray(ray_query)
	
	if raycast_result.has("position"):
		return raycast_result.position
	else:
		return ray_end

Your ray collision point will obviously be where the boundary of the red block should be. But you make no consideration for its size and only think about its origin.

The origin of the block is dead center or 1/2 of the distance to each face. You need to take that into consideration. So you probably also want the ray collision normal to know which offset direction you need to apply.

place_position = ray_collison_pos + collision_normal * (cube_size/2)
1 Like

That makes sense. How about coding it like a player? When a player moves they collide with the world around them without having to calculate its size each time, since I’ll have different types of furniture, could I not use their collision shape to properly place and move them around the scene?

Easiest option for you would be if you changed the origin point of your objects so that its (0,0,0) position is exactly at the bottom of the object. In the example of the cube - just make your CSGBox3D a child of another Node3D and move the CSGBox3D 0.5m up (assuming it’s 1m high).
Then, when placing the object into a scene, using the normal Vector, you can rotate the object so that it points upwards along the normal Vector.
It will then work with any shape correctly and any surface direction.
You might need to tweak it for your project still, because e.g. it will allow to stick a chair to a wall, so you might need to restrict some objects to which surface they can be placed on.

It should look similar to the video in this comment: