Compare commits

...

3 Commits

6 changed files with 212 additions and 1 deletions

52
objects/ItemPile.tscn Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,14 @@
[gd_scene format=3 uid="uid://d0dvo6n5onnni"]
[node name="Vision Preview Light" type="OmniLight3D"]
light_color = Color(0.491223, 1, 0, 1)
light_indirect_energy = 0.0
light_volumetric_fog_energy = 0.0
light_negative = true
light_specular = 0.0
light_bake_mode = 0
light_cull_mask = 4294967289
shadow_enabled = true
shadow_caster_mask = 4294967289
omni_range = 43.0
omni_attenuation = -0.4

97
scripts/item_pile.gd Normal file
View File

@ -0,0 +1,97 @@
@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

1
scripts/item_pile.gd.uid Normal file
View File

@ -0,0 +1 @@
uid://b742u7cr6efqm

View File

@ -53,6 +53,47 @@ class MoveAction extends UnitAction:
#DebugDraw3D.draw_text(global_position + Vector3(0,1,0), "%f" % nav_agent_3d.distance_to_target()) #DebugDraw3D.draw_text(global_position + Vector3(0,1,0), "%f" % nav_agent_3d.distance_to_target())
return Unit.TaskStatus.IN_PROGRESS return Unit.TaskStatus.IN_PROGRESS
class ChaseAction extends UnitAction:
var target: Unit
var target_position: Vector3
var last_distance_to_target: float = 99999999.9
var stuck_timer: float = 0.0
func process(delta: float) -> Unit.TaskStatus:
if target == null or target.is_queued_for_deletion():
return Unit.TaskStatus.IMPOSSIBLE
if target.global_position.distance_squared_to(target_position) >= 4.0:
# TODO: we could try to intercept the target by:
# - calculating our approximate time to reach the target
# - forcasting the target's position that time in the future based on it's velocity
# - do a raycast in that direction to prevent the future position from going through a wall
target_position = target.global_position
unit.nav_agent_3d.target_position = target_position
if unit.nav_agent_3d.is_navigation_finished():
if unit.nav_agent_3d.is_target_reachable():
return Unit.TaskStatus.DONE
else:
return Unit.TaskStatus.IMPOSSIBLE
else:
var next_point: Vector3 = unit.nav_agent_3d.get_next_path_position()
if unit.shapecast_3d.is_colliding():
var distance_to_target: float = unit.global_position.distance_to(next_point)
var progress_rate: float = (last_distance_to_target - distance_to_target) / delta
last_distance_to_target = distance_to_target
if progress_rate < unit.minimum_progress_rate:
stuck_timer += delta
if stuck_timer >= unit.stuck_time:
unit.unstuck()
else:
unit.label_3d.modulate = Color.WHITE
stuck_timer = 0
DebugDraw3D.draw_sphere(unit.nav_agent_3d.target_position, 0.5, Color.RED)
var direction: Vector3 = (next_point - unit.global_position).normalized()
unit.target_velocity = direction * unit.max_speed
unit.nav_agent_3d.velocity = unit.target_velocity
return Unit.TaskStatus.IN_PROGRESS
class BuildAction extends UnitAction: class BuildAction extends UnitAction:
var building: Building var building: Building

View File

@ -8,4 +8,10 @@ var sighted: bool = true:
func _ready() -> void: func _ready() -> void:
sighted = false sighted = false
go_to_destination(Vector3(17,1,15)) var target_citizen: Citizen = get_tree().get_nodes_in_group("Citizens").pick_random() as Citizen
if target_citizen != null:
var chase_action: UnitAction.ChaseAction = UnitAction.ChaseAction.new()
chase_action.unit = self
chase_action.target = target_citizen
action = chase_action
#go_to_destination(Vector3(17,1,15))