98 lines
3.3 KiB
GDScript
98 lines
3.3 KiB
GDScript
@tool
|
|
extends StaticBody3D
|
|
|
|
@export var item: Item:
|
|
set(val):
|
|
item = val
|
|
if !is_node_ready(): await ready
|
|
$Props.multimesh.mesh = item.model
|
|
$Cone.material_override = item.model.surface_get_material(0)
|
|
|
|
@export var count: int = 10:
|
|
set(val):
|
|
count = val
|
|
update()
|
|
@export var item_volume: float = 0.2:
|
|
set(val):
|
|
item_volume = val
|
|
item_radius = pow(item_volume,1.0/3.0)
|
|
update()
|
|
@export var item_radius: float = 0.0:
|
|
set(val):
|
|
item_radius = val
|
|
item_volume = pow(item_radius, 3.0)
|
|
update()
|
|
@export_range(0,60) var slope_angle: float = 45:
|
|
set(val):
|
|
slope_angle = val
|
|
slope_ratio = cos(deg_to_rad(slope_angle)) / sin(deg_to_rad(slope_angle))
|
|
print("slope ratio: %f" % slope_ratio)
|
|
update()
|
|
var slope_ratio: float = 1.0
|
|
|
|
@onready var cone: MeshInstance3D = $Cone
|
|
@onready var props: MultiMeshInstance3D = $Props
|
|
@onready var collision_shape: CollisionShape3D = $CollisionShape3D
|
|
|
|
func _ready() -> void:
|
|
props.multimesh = props.multimesh.duplicate()
|
|
|
|
func update() -> void:
|
|
var volume: float = count * item_volume
|
|
var three_v_over_pi: float = (3 * volume) / PI
|
|
var height: float = pow(three_v_over_pi, 1.0/3.0) / pow(slope_ratio, 2.0/3.0)
|
|
var radius: float = height * slope_ratio
|
|
var v: float = (1.0/3.0) * PI * pow(radius,2) * height
|
|
assert(is_equal_approx(v,volume))
|
|
cone.scale = Vector3(radius,height,radius)
|
|
cone.position.y = height/2.0
|
|
|
|
var slope_length: float = Vector2(radius,height).length()
|
|
var ring_count: int = ceili(slope_length / (item_radius*2))
|
|
|
|
var positions: PackedVector3Array = []
|
|
|
|
var angle: float = 0.0
|
|
for ring in range(ring_count):
|
|
#var perc: float = ring/float(ring_count-1)
|
|
var slope_l: float = ring * (item_radius * 2)
|
|
var ring_y: float = height-( sin(deg_to_rad(slope_angle)) * slope_l )
|
|
var ring_radius: float = cos(deg_to_rad(slope_angle)) * slope_l
|
|
var ring_circ: float = ring_radius * TAU
|
|
var ring_item_count: int = ceili(ring_circ / (item_radius*2))
|
|
if ring_item_count == 0:
|
|
ring_item_count = 1
|
|
var ring_angle_offset: float = TAU / ring_item_count
|
|
for i in range(ring_item_count):
|
|
angle += ring_angle_offset
|
|
#var angle: float = ring_angle_offset * i
|
|
var x: float = cos(angle) * ring_radius
|
|
var z: float = sin(angle) * ring_radius
|
|
var pos: Vector3 = Vector3(x,ring_y,z)
|
|
positions.append(pos)
|
|
|
|
props.multimesh.instance_count = positions.size()
|
|
for i in range(positions.size()):
|
|
#DebugDraw3D.draw_sphere(positions[i], item_radius, Color.RED, 0.1)
|
|
#var y_rot: float = randf() * TAU
|
|
var y_rot: float = 0
|
|
props.multimesh.set_instance_transform(i, Transform3D(Basis(Vector3.UP,y_rot),positions[i]))
|
|
|
|
props.multimesh.visible_instance_count = min(count, positions.size())
|
|
|
|
#print("Rings: %d, Items: %d" % [ring_count, positions.size()])
|
|
|
|
#var surface_item_count: int = ceil(pow(count, 2.0/3.0))
|
|
#props.multimesh.instance_count = ceil(surface_item_count)
|
|
|
|
#var theta: float = chord_offset / distance_offset
|
|
#for i in range(surface_item_count):
|
|
#var away: float = distance_offset * theta
|
|
#var around: float = theta + 0
|
|
#var x: float = cos(around) * away
|
|
#var z: float = sin(around) * away
|
|
#var y: float = height - (away * slope_ratio)
|
|
#var trans: Transform3D = Transform3D(Basis(), Vector3(x,y,z))
|
|
#props.multimesh.set_instance_transform(i,trans)
|
|
#theta += chord_offset / away
|