xyz How would I handle the input event (this) of when the mesh is clicked on? I'm looking at the signals for the Node3D, but since I'm creating the static body using code, I'm not seeing the signal for the StaticBody3D, just the Node3D. The code in _physics_process() is working, returning the proper location of the ray intersection. Is there a better way to structure my project, instead of how I've got currently, with all the code taking place primarily in GameMap? In the code you provided to get the game map working, you had the code written as a script attached to a MeshInstance3D. Would it be better I reorganize the code such that GameMap is controlling a scene with each chunk individually? Units and buildings will be added as children of the chunks, so as to keep the units positioned right despite camera and game map position.
class_name GameMap
extends Node3D
var num_chunks: int = 6
var chunks: Array[MeshInstance3D]
var static_bodies: Array[StaticBody3D]
var collision_shapes: Array[CollisionShape3D]
@export var uv_translate = Vector2(0.0, 0.0)
@export var uv_scale = Vector2(1.0, 1.0)
@export var chunk_size = Vector2i(180, 540)
var md: MeshDataTool = MeshDataTool.new()
var st: SurfaceTool = SurfaceTool.new()
var plane: PlaneMesh = PlaneMesh.new()
@export var plain_noise: FastNoiseLite = FastNoiseLite.new()
@export var mountain_noise: FastNoiseLite = FastNoiseLite.new()
@export var plain_scale: float = 30
@export var mountain_scale: float = 10
@export var camera_rig: Node3D = Node3D.new()
@onready var camera = camera_rig.get_child(0).get_child(0)
const RAY_LENGTH = 1000
var unit_scene = preload("res://Scenes/unit.tscn")
func _ready() -> void:
plain_noise.seed = randi() % 9223372036854775807
mountain_noise.seed = randi() % 9223372036854775807
for i in range(0, num_chunks):
chunks.append(MeshInstance3D.new())
static_bodies.append(StaticBody3D.new())
collision_shapes.append(CollisionShape3D.new())
build_mesh(i)
add_child(chunks[i])
static_bodies[i].add_child(collision_shapes[i])
chunks[i].add_child(static_bodies[i])
chunks[i].translate(Vector3(chunk_size.x * i - (chunk_size.x / 2), 0, 0))
func _process(delta) -> void:
#for i in range(0, num_chunks):
#build_mesh(i)
map_to_camera()
func _physics_process(delta) -> void:
var space_state = get_world_3d().direct_space_state
var mousepos = get_viewport().get_mouse_position()
var origin = camera.project_ray_origin(mousepos)
var end = origin + camera.project_ray_normal(mousepos) * RAY_LENGTH
var query = PhysicsRayQueryParameters3D.create(origin, end)
var result = space_state.intersect_ray(query)
print(result)
func build_mesh(i: int) -> void:
chunks[i].mesh = ArrayMesh.new()
# create plane array mesh with specified subdivs
plane.size = chunk_size
plane.subdivide_depth = chunk_size.y
plane.subdivide_width = chunk_size.x
chunks[i].mesh.clear_surfaces()
chunks[i].mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, plane.get_mesh_arrays())
# displace vertices
md.create_from_surface(chunks[i].mesh, 0)
md.set_material(preload("res://Shaders/terrain_shader_material.tres"))
for v in md.get_vertex_count():
var cyl_coord = cylinder_uv_to_xyz(md.get_vertex_uv(v) * uv_scale * Vector2(1.0 / num_chunks, 1.0) + Vector2(i * (1.0 / num_chunks), 0.0))
var plains = plain_noise.get_noise_3dv(cyl_coord) * (plain_scale)
var mountains = mountain_noise.get_noise_3dv(cyl_coord) * (mountain_scale)
var elevation = plains + (mountains - plains) * (mountains * 0.7)
if elevation < 0.0:
elevation *= 1.25
md.set_vertex(v, md.get_vertex(v) + Vector3(0.0, elevation, 0.0))
# rebuild normals
chunks[i].mesh.clear_surfaces()
md.commit_to_surface(chunks[i].mesh)
st.create_from(chunks[i].mesh, 0)
st.generate_normals()
# commit to mesh
chunks[i].mesh = st.commit()
collision_shapes[i].shape = chunks[i].mesh.create_trimesh_shape()
func cylinder_uv_to_xyz(uv: Vector2) -> Vector3:
return Vector3(1.0, uv.y * PI * 2, 0.0).rotated(Vector3.UP, uv.x * PI * 2)
func map_to_camera() -> void:
var map_width = chunk_size.x * num_chunks
for m in chunks:
var widths_from_camera = (m.global_position.x - camera_rig.global_position.x) / map_width
if (abs(widths_from_camera) <= 0.5):
continue
if (widths_from_camera > 0):
widths_from_camera += 0.5
else:
widths_from_camera -= 0.5
var widths_to_fix: int = widths_from_camera
m.global_position.x -= widths_to_fix * map_width