Tree collisions and highlights
This commit is contained in:
parent
57602adddb
commit
7255cbdf64
17 changed files with 231 additions and 2251 deletions
|
|
@ -1,14 +1,12 @@
|
|||
[gd_scene load_steps=16 format=3 uid="uid://bwcevwwphdvq"]
|
||||
[gd_scene load_steps=14 format=3 uid="uid://bwcevwwphdvq"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bq7hia2dit80y" path="res://Entities/GroundTile/ground_tile.gd" id="1_uwxqs"]
|
||||
[ext_resource type="ArrayMesh" uid="uid://duj6747nq4qsk" path="res://Stages/Test3D/assets/stylizedGrassMeshes/grass.res" id="3_8mhad"]
|
||||
[ext_resource type="Script" uid="uid://cacp8ncwuofuj" path="res://Entities/GroundTile/scripts/grass.gd" id="3_224hx"]
|
||||
[ext_resource type="Material" uid="uid://b1miqvl8lus75" path="res://Stages/Test3D/GrassMaterialOverride.tres" id="3_f37ob"]
|
||||
[ext_resource type="Script" uid="uid://btju6b83mvgvk" path="res://Entities/GroundTile/scripts/grass_multimesh.gd" id="4_3wpcb"]
|
||||
[ext_resource type="PackedScene" uid="uid://dgvycnw8hpebx" path="res://Entities/Tree/assets/tree-tall.glb" id="6_7lc7k"]
|
||||
[ext_resource type="Script" uid="uid://cqko4m7cbxsfb" path="res://Entities/GroundTile/scripts/trees.gd" id="7_7lc7k"]
|
||||
[ext_resource type="PackedScene" uid="uid://bwhpbjdyl577e" path="res://Entities/Tree/assets/tree.glb" id="8_ot4p5"]
|
||||
[ext_resource type="PackedScene" uid="uid://bwdibgbi3ycqn" path="res://Entities/Tree/assets/tree-autumn-tall.glb" id="12_4hjaq"]
|
||||
[ext_resource type="PackedScene" uid="uid://c27fogucecn0r" path="res://Entities/Tree/Tree.tscn" id="7_224hx"]
|
||||
|
||||
[sub_resource type="ViewportTexture" id="ViewportTexture_h4g11"]
|
||||
viewport_path = NodePath("DebugText/DebugTextViewport")
|
||||
|
|
@ -33,6 +31,7 @@ flip_faces = true
|
|||
script = ExtResource("1_uwxqs")
|
||||
|
||||
[node name="DebugText" type="Node3D" parent="."]
|
||||
visible = false
|
||||
|
||||
[node name="DebugTextViewport" type="SubViewport" parent="DebugText"]
|
||||
size = Vector2i(50, 50)
|
||||
|
|
@ -72,4 +71,4 @@ mesh = SubResource("PlaneMesh_f37ob")
|
|||
|
||||
[node name="Trees" type="Node3D" parent="."]
|
||||
script = ExtResource("7_7lc7k")
|
||||
tree_scenes = Array[PackedScene]([ExtResource("8_ot4p5"), ExtResource("6_7lc7k"), ExtResource("12_4hjaq"), ExtResource("8_ot4p5"), ExtResource("8_ot4p5"), ExtResource("8_ot4p5"), ExtResource("8_ot4p5")])
|
||||
tree_scenes = Array[PackedScene]([ExtResource("7_224hx")])
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
# GroundTile.gd
|
||||
class_name GroundTile
|
||||
extends Node3D
|
||||
|
||||
@onready var debug_text: Label = $DebugText/DebugTextViewport/DebugTextLabel
|
||||
@onready var tree_spawner = $Trees
|
||||
@onready var grass_spawner = $Grass
|
||||
|
|
@ -9,17 +7,22 @@ var grid_x: int
|
|||
var grid_z: int
|
||||
var cell_info: CellDataResource = null
|
||||
var spawners_ready: bool = false
|
||||
|
||||
var rng: RandomClass = RandomClass.new()
|
||||
var cached_rng: RandomClass = null
|
||||
|
||||
func _ready() -> void:
|
||||
spawners_ready = true
|
||||
|
||||
# Now that spawners are ready, trigger spawning if we have cell_info
|
||||
|
||||
if cell_info != null:
|
||||
spawn_content()
|
||||
update_text_label()
|
||||
rng.set_seed(cell_info.cell_seed)
|
||||
spawn_content()
|
||||
update_text_label()
|
||||
|
||||
func get_rng() -> RandomClass:
|
||||
if cached_rng == null and cell_info:
|
||||
cached_rng = RandomClass.get_seeded_instance(cell_info.cell_seed)
|
||||
elif cached_rng == null:
|
||||
cached_rng = RandomClass.get_shared_instance()
|
||||
|
||||
return cached_rng
|
||||
|
||||
func set_grid_location(x, z) -> void:
|
||||
grid_x = x
|
||||
|
|
|
|||
|
|
@ -21,14 +21,16 @@ func spawn_grass_for_cell(value):
|
|||
grass_multimesh.setup_multimesh()
|
||||
|
||||
func update_grass_density() -> void:
|
||||
if parent_node == null or parent_node.rng == null:
|
||||
if parent_node == null:
|
||||
return
|
||||
|
||||
|
||||
var rng = parent_node.get_rng()
|
||||
|
||||
if grass_density > 0.8:
|
||||
grass_instance_range = parent_node.rng.randi_range(100, 500)
|
||||
grass_instance_range = rng.randi_range(100, 500)
|
||||
elif grass_density > 0.6:
|
||||
grass_instance_range = parent_node.rng.randi_range(30, 50)
|
||||
grass_instance_range = rng.randi_range(30, 50)
|
||||
elif grass_density > 0.3:
|
||||
grass_instance_range = parent_node.rng.randi_range(5, 20)
|
||||
grass_instance_range = rng.randi_range(5, 20)
|
||||
else:
|
||||
grass_instance_range = parent_node.rng.randi_range(0, 1)
|
||||
grass_instance_range = rng.randi_range(0, 1)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
extends MultiMeshInstance3D
|
||||
var mm: MultiMesh
|
||||
var parent_node: GrassController
|
||||
|
||||
static var grass_mesh: Mesh = null
|
||||
|
||||
func _ready() -> void:
|
||||
|
|
@ -16,7 +15,7 @@ func _ready() -> void:
|
|||
func setup_multimesh() -> void:
|
||||
if parent_node == null:
|
||||
return
|
||||
|
||||
|
||||
if grass_mesh == null:
|
||||
Log.pr("Error: Could not load grass mesh")
|
||||
return
|
||||
|
|
@ -30,18 +29,21 @@ func setup_multimesh() -> void:
|
|||
# Configure instance count
|
||||
mm.instance_count = parent_node.grass_instance_range
|
||||
|
||||
# Get shared RNG from GroundTile
|
||||
var rng = parent_node.parent_node.get_rng()
|
||||
|
||||
# Generate positions using shared RNG
|
||||
for i in range(mm.instance_count):
|
||||
var random_pos = Vector3(
|
||||
parent_node.parent_node.rng.randf_range(-1.0, 1.0),
|
||||
rng.randf_range(-1.0, 1.0),
|
||||
0.0,
|
||||
parent_node.parent_node.rng.randf_range(-1.0, 1.0)
|
||||
rng.randf_range(-1.0, 1.0)
|
||||
)
|
||||
|
||||
var random_rotation = parent_node.parent_node.rng.randf_range(0.0, TAU)
|
||||
var random_rotation = rng.randf_range(0.0, TAU)
|
||||
var basis = Basis(Vector3.UP, random_rotation)
|
||||
|
||||
var random_scale = parent_node.parent_node.rng.randf_range(0.05, 0.3)
|
||||
var random_scale = rng.randf_range(0.05, 0.3)
|
||||
basis = basis.scaled(Vector3(random_scale, random_scale, random_scale))
|
||||
|
||||
var tx = Transform3D(basis, random_pos)
|
||||
|
|
|
|||
|
|
@ -11,29 +11,14 @@ func _ready():
|
|||
|
||||
func spawn_trees_for_cell(cell_info: CellDataResource):
|
||||
if not cell_info:
|
||||
return
|
||||
|
||||
# Use parent's RNG instead of creating new one
|
||||
if not parent_ground_tile or not parent_ground_tile.rng:
|
||||
return
|
||||
|
||||
return
|
||||
|
||||
if not parent_ground_tile:
|
||||
return
|
||||
|
||||
var tree_count = max(0, cell_info.trees.size())
|
||||
spawn_trees(tree_count)
|
||||
|
||||
# Update all rng calls to use parent_ground_tile.rng:
|
||||
func get_random_position() -> Vector3:
|
||||
var x = parent_ground_tile.rng.randf_range(-spawn_area_size.x / 2, spawn_area_size.x / 2)
|
||||
var z = parent_ground_tile.rng.randf_range(-spawn_area_size.y / 2, spawn_area_size.y / 2)
|
||||
return Vector3(x, 0, z)
|
||||
|
||||
func spawn_tree_at_position(pos: Vector3):
|
||||
var random_index = parent_ground_tile.rng.randi() % tree_scenes.size()
|
||||
var random_tree_scene = tree_scenes[random_index]
|
||||
var tree_instance = random_tree_scene.instantiate()
|
||||
add_child(tree_instance)
|
||||
tree_instance.position = pos
|
||||
tree_instance.rotation.y = parent_ground_tile.rng.randf() * TAU
|
||||
|
||||
func spawn_trees(tree_count: int):
|
||||
if tree_scenes.is_empty() or tree_count == 0:
|
||||
return
|
||||
|
|
@ -56,6 +41,21 @@ func spawn_trees(tree_count: int):
|
|||
|
||||
attempts += 1
|
||||
|
||||
func get_random_position() -> Vector3:
|
||||
var rng = parent_ground_tile.get_rng()
|
||||
var x = rng.randf_range(-spawn_area_size.x / 2, spawn_area_size.x / 2)
|
||||
var z = rng.randf_range(-spawn_area_size.y / 2, spawn_area_size.y / 2)
|
||||
return Vector3(x, 0, z)
|
||||
|
||||
func spawn_tree_at_position(pos: Vector3):
|
||||
var rng = parent_ground_tile.get_rng()
|
||||
var random_index = rng.randi() % tree_scenes.size()
|
||||
var random_tree_scene = tree_scenes[random_index]
|
||||
var tree_instance = random_tree_scene.instantiate()
|
||||
add_child(tree_instance)
|
||||
tree_instance.position = pos
|
||||
tree_instance.rotation.y = rng.randf() * TAU
|
||||
|
||||
func is_position_valid(pos: Vector3) -> bool:
|
||||
for existing_pos in spawned_positions:
|
||||
if pos.distance_to(existing_pos) < min_distance:
|
||||
|
|
|
|||
25
Entities/Tree/Tree.tscn
Normal file
25
Entities/Tree/Tree.tscn
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
[gd_scene load_steps=5 format=3 uid="uid://c27fogucecn0r"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://lcedx3lau6v5" path="res://Entities/Tree/scripts/tree.gd" id="1_702jv"]
|
||||
[ext_resource type="PackedScene" uid="uid://bwhpbjdyl577e" path="res://Entities/Tree/assets/tree.glb" id="1_s6kdm"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_s6kdm"]
|
||||
radius = 0.2
|
||||
height = 0.5
|
||||
|
||||
[sub_resource type="SphereShape3D" id="SphereShape3D_702jv"]
|
||||
|
||||
[node name="Tree" type="Node3D"]
|
||||
script = ExtResource("1_702jv")
|
||||
|
||||
[node name="TreeModel" parent="." instance=ExtResource("1_s6kdm")]
|
||||
|
||||
[node name="TreeCollision" type="StaticBody3D" parent="TreeModel" groups=["tree"]]
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="TreeModel/TreeCollision"]
|
||||
shape = SubResource("CapsuleShape3D_s6kdm")
|
||||
|
||||
[node name="InteractRange" type="Area3D" parent="."]
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="InteractRange"]
|
||||
shape = SubResource("SphereShape3D_702jv")
|
||||
89
Entities/Tree/scripts/tree.gd
Normal file
89
Entities/Tree/scripts/tree.gd
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
class_name TreeNode
|
||||
extends Node3D
|
||||
|
||||
@onready var area: Area3D = $InteractRange
|
||||
var mesh_instances: Array[MeshInstance3D] = []
|
||||
var original_materials: Array[Material] = []
|
||||
var outline_material: Material
|
||||
var base_circle: MeshInstance3D
|
||||
var circle_material: Material
|
||||
|
||||
func _ready():
|
||||
create_base_circle()
|
||||
# Find all MeshInstance3D nodes in the GLB
|
||||
find_all_mesh_instances(self)
|
||||
|
||||
setup_outline_material()
|
||||
area.body_entered.connect(_on_player_entered)
|
||||
area.body_exited.connect(_on_player_exited)
|
||||
|
||||
func setup_outline_material():
|
||||
if mesh_instances.is_empty():
|
||||
print("Warning: No MeshInstance3D found in GLB!")
|
||||
return
|
||||
|
||||
# Store original materials
|
||||
for mesh in mesh_instances:
|
||||
if mesh.get_surface_override_material(0):
|
||||
original_materials.append(mesh.get_surface_override_material(0))
|
||||
else:
|
||||
original_materials.append(mesh.get_surface_override_material(0))
|
||||
# Create outline material with your shader
|
||||
outline_material = ShaderMaterial.new()
|
||||
outline_material.shader = preload("res://outline.gdshader")
|
||||
outline_material.set_shader_parameter("color", Vector3(0.702, 0.557, 0.259))
|
||||
|
||||
func find_all_mesh_instances(node: Node):
|
||||
if node is MeshInstance3D:
|
||||
mesh_instances.append(node)
|
||||
|
||||
for child in node.get_children():
|
||||
find_all_mesh_instances(child)
|
||||
|
||||
func create_base_circle():
|
||||
base_circle = MeshInstance3D.new()
|
||||
add_child(base_circle)
|
||||
|
||||
# Create a flat cylinder for the circle
|
||||
var cylinder = CylinderMesh.new()
|
||||
cylinder.top_radius = 0.4 # Adjust size as needed
|
||||
cylinder.bottom_radius = 0.4
|
||||
cylinder.height = 0.02 # Very thin to make it look like a flat circle
|
||||
cylinder.rings = 1
|
||||
cylinder.radial_segments = 9 # More segments = smoother circle
|
||||
|
||||
base_circle.mesh = cylinder
|
||||
|
||||
# Create transparent material with outline
|
||||
circle_material = StandardMaterial3D.new()
|
||||
circle_material.flags_transparent = true
|
||||
circle_material.albedo_color = Color(1.0, 0.843, 0.0, 0.0) # Fully transparent gold
|
||||
|
||||
# Add rim lighting effect for outline appearance
|
||||
circle_material.rim_enabled = true
|
||||
circle_material.rim = 1.0
|
||||
circle_material.rim_tint = 1.0
|
||||
circle_material.rim_color = Color(1.0, 0.843, 0.0) # Gold rim
|
||||
|
||||
base_circle.material_override = circle_material
|
||||
|
||||
# Position at ground level
|
||||
base_circle.position.y = 0.01 # Slightly above ground to avoid z-fighting
|
||||
|
||||
# Start hidden
|
||||
base_circle.visible = false
|
||||
|
||||
func _on_player_entered(body: Node3D):
|
||||
if body.is_in_group("player"):
|
||||
base_circle.visible = true
|
||||
# Apply outline to all mesh instances
|
||||
for mesh in mesh_instances:
|
||||
mesh.material_overlay = outline_material
|
||||
|
||||
func _on_player_exited(body: Node3D):
|
||||
if body.is_in_group("player"):
|
||||
Log.pr('Out of range...')
|
||||
base_circle.visible = false
|
||||
# Remove outline from all mesh instances
|
||||
for mesh in mesh_instances:
|
||||
mesh.material_overlay = null
|
||||
1
Entities/Tree/scripts/tree.gd.uid
Normal file
1
Entities/Tree/scripts/tree.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://lcedx3lau6v5
|
||||
Loading…
Add table
Add a link
Reference in a new issue