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")

