Bright colorful spheres glitch

Godot Version

4.4.1-stable

Question

Whenever I change scenes to these in this order:
combine.tscn → main.tscn → combine.tscn → main.tscn
on second time i load main, there are these glitches. they are totally random and can appear anywhere. help?

#main.gd
extends Node3D

const GRASS_005_1K_JPG = preload("res://assets/texture/grass/Grass005_1K-JPG.tres")

var bush_scene = preload("res://scenes/bush.tscn")
const TREE = preload("res://scenes/tree.tscn")
const WATER = preload("res://assets/model/environment/water.glb")
const MONSTER_VIEW = preload("res://scenes/monster_view.tscn")
const GRASS = preload("res://assets/model/environment/grass.glb")
const FLOWER_YELLOW = preload("res://assets/model/environment/flower_yellow.glb")
var flowers = [FLOWER_YELLOW]

var ground : MeshInstance3D
var berry_mmi : MultiMeshInstance3D
var water_mmi : MultiMeshInstance3D

var height_scale = 40
var water_level = Game.water_level
var noise
var selected_monster : Monster = null
var mv_to_delete : TextureButton

@onready var actions: HBoxContainer = $UI/data/actions
@onready var go_to: TextureButton = $UI/data/actions/go_to
@onready var fight: TextureButton = $UI/data/actions/fight
@onready var eat: TextureButton = $UI/data/actions/eat
@onready var lab: Label = $UI/data/lab
@onready var walkie: CharacterBody3D = $walkie
@onready var monsters: HBoxContainer = $UI/data/c/c2/monsters
@onready var stats_display: Panel = $UI/data/stats_display
@onready var c2: Control = $UI/data/c/c2

func _ready():
	fill_monster_options()
	generate_terrain(1000, 100, height_scale)
	#place_grass(1000, 10)
	place_flowers(1000, 30)
	create_boundary(1000, 1000)
	place_bushes(1000, 150.0)
	place_trees(1000, 50.0)
	place_water(1000, 1.0)
	
	TextureManager.set_berry_multimesh()
	create_berry_field()
	berry_mmi = TextureManager.get_berry_multimesh()
	add_child(berry_mmi)
	node_setup()
	actions.visible = false
	stats_display.visible = false

func _process(delta: float) -> void:
	lab.text = "Coords: "+str(walkie.global_position)
	if selected_monster != null:
		stats_display.setup(selected_monster)

func fill_monster_options():
	for entry in Game.inventory:
		var mv = MONSTER_VIEW.instantiate()
		monsters.add_child(mv)
		mv.setup(entry.mom, entry.dad)
		mv.pressed.connect(_on_inv_monster_pressed.bind(entry, mv))

func node_setup():
	await get_tree().process_frame
	c2.custom_minimum_size = monsters.get_rect().size

var monster_to_spawn : Monster

func _on_inv_monster_pressed(entry : Dictionary, mv):
	var monster = Monster.new()
	monster.inventory_id = entry.id
	monster.mama_path = entry.mom
	monster.papa_path = entry.dad
	monster.seed = entry.seed
	monster.is_parent = false
	monster.render()
	monster.inherit_stats()
	monster.add_to_group("monsters")
	monster_to_spawn = monster
	mv_to_delete = mv

func is_water(x, z):
	var height = get_terrain_height(x, z)
	return height < water_level

func generate_terrain(size : int, resolution : int, height_scale : int):
	var plane_mesh = PlaneMesh.new()
	plane_mesh.size = Vector2(size, size)
	plane_mesh.subdivide_width = resolution
	plane_mesh.subdivide_depth = resolution
	
	var arr_mesh = ArrayMesh.new()
	var surface_tool := SurfaceTool.new()
	surface_tool.create_from(plane_mesh, 0)
	
	var data := surface_tool.commit()
	var arrays := data.surface_get_arrays(0)
	var vertices = arrays[Mesh.ARRAY_VERTEX]
	
	var n = FastNoiseLite.new()
	n.noise_type = FastNoiseLite.TYPE_PERLIN
	var noise_ = []
	for x in range(size):
		noise_.append([])
		for z in range(size):
			noise_[x].append(n.get_noise_2d(x, z) * height_scale)
	noise = n
	
	for i in range(vertices.size()):
		var v = vertices[i]
		var y = n.get_noise_2d(v.x, v.z) * height_scale
		vertices[i] = Vector3(v.x, y, v.z)
	
	#vertices = place_river(vertices, size, 100, 100, 50)
	
	arrays[Mesh.ARRAY_VERTEX] = vertices
	
	#arr_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)
	surface_tool.clear()
	surface_tool.begin(Mesh.PRIMITIVE_TRIANGLES)
	surface_tool.create_from_arrays(arrays, Mesh.PRIMITIVE_TRIANGLES)
	surface_tool.generate_normals()
	
	arr_mesh = surface_tool.commit()
	
	var mesh_instance = MeshInstance3D.new()
	mesh_instance.mesh = arr_mesh
	
	mesh_instance.create_trimesh_collision()
	var collision_body = mesh_instance.get_child(mesh_instance.get_child_count() - 1)  # Last child
	collision_body.add_to_group("ground")
	
	var material = StandardMaterial3D.new()
	material.albedo_texture = load("res://assets/texture/grass/Grass005_1K-JPG_Color.jpg")
	material.uv1_scale = Vector3(10, 10, 1)
	material.cull_mode = BaseMaterial3D.CULL_BACK
	
	mesh_instance.material_override = material
	
	mesh_instance.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_ON
	
	ground = mesh_instance
	mesh_instance.add_to_group("ground")
	add_child(mesh_instance)

func create_boundary(terrain_size : int, height : int):
	var size = terrain_size/2
	var thickness = 10
	
	# Create four walls
	var positions = [
		[Vector3(0, 0, -size), Vector3(size*2, height, thickness)],
		[Vector3(0, 0, size), Vector3(size*2, height, thickness)],
		[Vector3(-size, 0, 0), Vector3(thickness, height, size*2)],
		[Vector3(size, 0, 0), Vector3(thickness, height, size*2)],
		[Vector3(0, -height/2, 0), Vector3(size*2, thickness, size*2)],
		[Vector3(0, height/2, 0), Vector3(size*2, thickness, size*2)]
	]
	
	for pos in positions:
		var wall = StaticBody3D.new()
		var collision = CollisionShape3D.new()
		var shape = BoxShape3D.new()
		shape.size = pos[1]
		collision.shape = shape
		wall.add_child(collision)
		wall.position = pos[0]
		add_child(wall)

func place_water(terrain_size: int, height_scale : float):
	var water_scene = WATER
	
	var arr = []
	for x in range(-terrain_size/2, terrain_size/2, 10):
		for z in range(-terrain_size/2, terrain_size/2, 10):
			var y1 = get_ground_height(x, z)
			var y2 = get_ground_height(x+10, z)
			var y3 = get_ground_height(x, z+10)
			var y4 = get_ground_height(x+10, z+10)
			
			if y1 < water_level or y2 < water_level or y3 < water_level or y4 < water_level:
				var is_edge = false
				for dx in [-5, 5]:
					for dz in [-5, 5]:
						if get_ground_height(x+dx, z+dz) >= water_level:
							is_edge = true
				arr.append([x,z])
				
				# Make edges slightly different (mud, shore)
				#var shore_material = preload("res://assets/texture/Gravel042_1K-JPG_Color.jpg")
				#if is_edge:
				#	water.material_override = shore_material
	
	TextureManager.set_water_multimesh(arr.size())
	for i in range(len(arr)):
		make_water(arr[i][0],arr[i][1],i)
	
	water_mmi = TextureManager.get_water_multimesh()
	add_child(water_mmi)

func place_river(vertices: Array, terrain_size: int, river_width: int, depth: int, amplitude: int):
	var size = terrain_size/2
	var width = river_width/2
	
	# Start at LEFT edge instead of random
	var start_x = -size
	var start_z = randi() % terrain_size - size
	var arr: Array = [Vector3(start_x, get_ground_height(start_x, start_z), start_z)]
	
	# Generate river across ENTIRE x range
	for x in range(-size, size + 1, 10):
		if x == -size: continue  # Skip first (already added)
		var offset = randi() % (amplitude * 2) - amplitude  # Allow negative offsets
		var prev = arr[arr.size() - 1]
		var new_z = prev.z + offset
		arr.append(Vector3(x, get_ground_height(x, new_z), new_z))
	
	var grid_size = noise.size()  # e.g., 100
	var world_size = terrain_size  # e.g., 1000
	var scale_factor = grid_size / world_size  # 100/1000 = 0.1
	
	for i in range(vertices.size()):
		var v = vertices[i]
		if v.z > arr[(v.x + size)/10].z - width and v.z < arr[(v.x + size)/10].z + width:
			var grid_x = int(v.x + size) - int(v.x + size)%10
			var grid_z = int(v.z + size) - int(v.x + size)%10
			
			vertices[i] = Vector3(v.x, v.y - depth, v.z)
			
			if grid_x >= 0 and grid_x < grid_size and grid_z >= 0 and grid_z < grid_size:
				noise[grid_x][grid_z] -= depth
	return vertices


func make_water(x : int, z : int, ind : int):
	#var t = Transform3D()
	#t.origin = Vector3(x+5, water_level, z+5)
	#t = t.scaled(Vector3(5, 1, 5))
	var t = Transform3D(Basis().scaled(Vector3(5,1,5)).rotated(Vector3.UP, deg_to_rad(90 * (randi()%4))), 
					Vector3(x+5, water_level, z+5))
	var marker = Node3D.new()
	marker.position = Vector3(x+5, water_level, z+5)
	marker.add_to_group("water")
	add_child(marker)
	TextureManager.water_multimesh.set_instance_transform(ind, t)

func place_grass(terrain_size: int, spacing: float = 20.0):
	for x in range(-terrain_size/2, terrain_size/2, spacing):
		for z in range(-terrain_size/2, terrain_size/2, spacing):
			
			var offset_x1 = randf_range(-spacing/4, spacing/4)
			var offset_z1 = randf_range(-spacing/4, spacing/4)
			var y1 = get_ground_height(x + offset_x1, z + offset_z1)
			
			if y1 != 0.0 and y1 > water_level and is_valid_cords(terrain_size, x + offset_x1, z + offset_z1):
				var grass = GRASS.instantiate()
				grass.position = Vector3(x + offset_x1, y1, z + offset_z1)
				grass.rotation.y = randf_range(0, 359)
				add_child(grass)
				TextureManager.total_berries_count += 15

func place_flowers(terrain_size: int, spacing: float = 10.0):
	for x in range(-terrain_size/2, terrain_size/2, spacing):
		for z in range(-terrain_size/2, terrain_size/2, spacing):
			var offset_x2 = randf_range(-spacing/4, spacing/4)
			var offset_z2 = randf_range(-spacing/4, spacing/4)
			var y2 = get_ground_height(x + offset_x2, z + offset_z2)
			
			if randf() < 0.7 and y2 != 0.0 and is_valid_cords(terrain_size, x + offset_x2, z + offset_z2) and y2 > water_level:
				var t = flowers[randi() % flowers.size()].instantiate()
				t.rotation.y = randi_range(0, 359)
				t.position = Vector3(x + offset_x2, y2 - 2, z + offset_z2)
				add_child(t)

func place_bushes(terrain_size: int, spacing: float = 20.0):
	var k = 0
	for x in range(-terrain_size/2, terrain_size/2, spacing):
		for z in range(-terrain_size/2, terrain_size/2, spacing):
			
			var offset_x1 = randf_range(-spacing/4, spacing/4)
			var offset_z1 = randf_range(-spacing/4, spacing/4)
			var y1 = get_ground_height(x + offset_x1, z + offset_z1)
			
			if randf() < 0.6 and y1 != 0.0 and y1 > water_level and is_valid_cords(terrain_size, x + offset_x1, z + offset_z1):
				var bush = bush_scene.instantiate()
				bush.food_name_export = MonsterManager.food_effects.keys()[randi()%MonsterManager.food_effects.keys().size()]
				bush.position = Vector3(x + offset_x1, y1, z + offset_z1)
				bush.bush_index = k
				k+=1
				add_child(bush)
				TextureManager.total_berries_count += 15

func place_trees(terrain_size: int, spacing: float = 20.0):
	for x in range(-terrain_size/2, terrain_size/2, spacing):
		for z in range(-terrain_size/2, terrain_size/2, spacing):
			var offset_x2 = randf_range(-spacing/4, spacing/4)
			var offset_z2 = randf_range(-spacing/4, spacing/4)
			
			var y2 = get_ground_height(x + offset_x2, z + offset_z2)
			if randf() < 0.7 and y2 != 0.0 and is_valid_cords(terrain_size, x + offset_x2, z + offset_z2) and y2 > water_level:
				var t = TREE.instantiate()
				var s_mult = randf_range(0.8, 4.0)
				t.scale = Vector3(s_mult, s_mult, s_mult)
				t.rotation.y = randi_range(0, 359)
				t.position = Vector3(x + offset_x2, y2 - 2, z + offset_z2)
				add_child(t)

func create_berry_field():
	for bush in get_children().filter(func(c): return c is bush_class):
		bush.update_display()

func is_valid_cords(size: int, x: float, z: float):
	return -size/2 <= x and size/2 >= x and -size/2 <= z and size/2 >= z

func get_ground_height(x: float, z: float) -> float:
	return noise.get_noise_2d(x, z) * height_scale

func get_terrain_height(x: float, z: float) -> float:
	var space = get_world_3d().direct_space_state
	var query = PhysicsRayQueryParameters3D.create(
		Vector3(x, 100, z),
		Vector3(x, -100, z)
	)
	var result = space.intersect_ray(query)
	if result:
		return result.position.y
	return 0

func _input(event):
	if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
		if event is InputEventMouse and get_viewport().gui_get_drag_data() != null:
			return
		
		var space = get_world_3d().direct_space_state
		var camera = get_viewport().get_camera_3d()
		
		var mouse_pos = get_viewport().get_mouse_position()
		var origin = camera.project_ray_origin(mouse_pos)
		var direction = camera.project_ray_normal(mouse_pos)
		
		var query = PhysicsRayQueryParameters3D.new()
		query.from = origin
		query.to = origin + direction * 1000
		query.collision_mask = 1  # Set to your terrain's layer
		
		var result = space.intersect_ray(query)
		
		if result:
			print("Clicked at: ", result.position)
			print("On: ", result.collider.name)
			parse_result(result)

func parse_result(result : Dictionary):
	if result.collider.is_in_group("monsters"):
		if selected_monster and fight.toggled and selected_monster != result.collider:
			selected_monster.start_fighting(result.collider)
		else:
			selected_monster = result.collider
			actions.visible = true
			stats_display.visible = true
	elif result.collider.is_in_group("ground"):
		if monster_to_spawn != null:
			monster_to_spawn.position = result.position + Vector3(0,5,0)
			add_child(monster_to_spawn)
			selected_monster = monster_to_spawn
			actions.visible = true
			stats_display.visible = true
			monster_to_spawn = null
			mv_to_delete.queue_free()
			if monsters.get_child_count() == 0:
				monsters.visible = false
				
		elif selected_monster and go_to.toggled:
			selected_monster.go_to(result.position)
		elif selected_monster and eat.toggled:
			selected_monster.go_to(result.position)
	else:
		selected_monster = null
		actions.visible = false
		stats_display.visible = false


func _on_make_new_pressed() -> void:
	get_tree().change_scene_to_file("res://scenes/combine.tscn")

extends Control

@onready var preview1 = $display/monsterView
@onready var preview2 = $display/monsterView2
@onready var grid: GridContainer = $display/genom_grid
@onready var grid2: GridContainer = $display/genom_grid2

const MONSTER_VIEW = preload("res://scenes/monster_view.tscn")

var selected_monster1: String = ""
var selected_monster2: String = ""

func _ready():
	for genom in Game.animals:
		var mv = MONSTER_VIEW.instantiate()
		grid.add_child(mv)
		mv.setup("res://data/genom/%s_genom.tscn" % genom)
		mv.pressed.connect(_on_genom_selected.bind(genom, 1))
	
	for genom in Game.animals:
		var mv = MONSTER_VIEW.instantiate()
		grid2.add_child(mv)
		mv.setup("res://data/genom/%s_genom.tscn" % genom)
		mv.pressed.connect(_on_genom_selected.bind(genom, 2))

func _on_genom_selected(genom : String, i : int):
	if i == 1:
		preview1.setup("res://data/genom/%s_genom.tscn" % genom)
		selected_monster1 = genom
	else:
		preview2.setup("res://data/genom/%s_genom.tscn" % genom)
		selected_monster2 = genom

func _on_mix_pressed():
	if selected_monster1 != "" and selected_monster2 != "" :
		var new_monster = Game.combine_monsters(selected_monster1, selected_monster2)
		Game.add_to_inventory(new_monster)
		selected_monster1 = ""
		selected_monster2 = ""
		
		preview1.clean()
		preview2.clean()
		get_tree().change_scene_to_file("res://scenes/main.tscn")

preloading could be to blame, try to avoid it for complex scenes, such as your monster view. This can create a cyclical dependency that preload fails to resolve where load doesn’t create such a strict dependency.