Pesquisar este blog

gerador de terreno com arvores godot

 @tool

extends MeshInstance3D


@export_category("Configurações do Terreno")

@export var terrain_size: Vector2 = Vector2(40, 40):

set(value):

terrain_size = value

_generate_terrain()


@export var subdivision: int = 40:

set(value):

subdivision = value

_generate_terrain()


@export var height_scale: float = 8.0:

set(value):

height_scale = value

_generate_terrain()


@export_category("Configurações do Ruído")

@export var noise_seed: int = 1337:

set(value):

noise_seed = value

noise.seed = value

_generate_terrain()


@export var noise_frequency: float = 0.04:

set(value):

noise_frequency = value

noise.frequency = value

_generate_terrain()


@export var gerar_novo_terreno_aleatorio: bool = false:

set(value):

if value:

noise.seed = randi()

noise_seed = noise.seed

_generate_terrain()

gerar_novo_terreno_aleatorio = false


@export_category("Texturas dos Biomas")

@export var texture_sand: Texture2D:

set(value):

texture_sand = value

_update_shader_parameters()


@export var texture_grass: Texture2D:

set(value):

texture_grass = value

_update_shader_parameters()


@export var texture_rock: Texture2D:

set(value):

texture_rock = value

_update_shader_parameters()


@export var texture_snow: Texture2D:

set(value):

texture_snow = value

_update_shader_parameters()


@export var texture_scale: float = 10.0:

set(value):

texture_scale = value

_update_shader_parameters()


@export_category("Configuração de Árvores (Bioma Grama)")

@export var spawn_trees: bool = true:

set(value):

spawn_trees = value

_generate_terrain()


# Campo exposto explicitamente para escolher a malha da árvore no Inspector

@export var tree_mesh: Mesh:

set(value):

tree_mesh = value

_update_tree_mesh()


@export var tree_density: float = 0.2:

set(value):

tree_density = value

_generate_terrain()


var noise: FastNoiseLite = FastNoiseLite.new()

var tree_multimesh_inst: MultiMeshInstance3D


func _ready() -> void:

noise.noise_type = FastNoiseLite.TYPE_SIMPLEX

noise.seed = noise_seed

noise.frequency = noise_frequency

_setup_tree_multimesh()

_generate_terrain()


func _setup_tree_multimesh() -> void:

tree_multimesh_inst = get_node_or_null("TreeMultiMesh") as MultiMeshInstance3D

if not tree_multimesh_inst:

tree_multimesh_inst = MultiMeshInstance3D.new()

tree_multimesh_inst.name = "TreeMultiMesh"

add_child(tree_multimesh_inst)

if Engine.is_editor_hint():

tree_multimesh_inst.owner = self

if not tree_multimesh_inst.multimesh:

var mm = MultiMesh.new()

mm.transform_format = MultiMesh.TRANSFORM_3D

tree_multimesh_inst.multimesh = mm

_update_tree_mesh()


func _update_tree_mesh() -> void:

if not tree_multimesh_inst or not tree_multimesh_inst.multimesh:

return

if tree_mesh:

tree_multimesh_inst.multimesh.mesh = tree_mesh

else:

# Malha padrão temporária (um cilindro simples) caso nenhum mesh seja selecionado

var default_cyl = CylinderMesh.new()

default_cyl.top_radius = 0.1

default_cyl.bottom_radius = { "value": 0.3 }.value if false else 0.3

default_cyl.height = 1.5

tree_multimesh_inst.multimesh.mesh = default_cyl


func _generate_terrain() -> void:

var plane_mesh = PlaneMesh.new()

plane_mesh.size = terrain_size

plane_mesh.subdivide_width = subdivision

plane_mesh.subdivide_depth = subdivision


var st = SurfaceTool.new()

st.begin(Mesh.PRIMITIVE_TRIANGLES)

st.create_from(plane_mesh, 0)

var st_data = st.commit_to_arrays()

var mesh = ArrayMesh.new()

mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, st_data)

var mdt = MeshDataTool.new()

mdt.create_from_surface(mesh, 0)

for i in range(mdt.get_vertex_count()):

var vertex = mdt.get_vertex(i)

var n_val = noise.get_noise_2d(vertex.x, vertex.z)

vertex.y = n_val * height_scale

mdt.set_vertex(i, vertex)

mesh.clear_surfaces()

mdt.commit_to_surface(mesh)

self.mesh = mesh

_setup_terrain_shader()

_generate_trees()

print("Terreno e árvores atualizados!")


func _generate_trees() -> void:

_setup_tree_multimesh()

if not spawn_trees or not tree_multimesh_inst.multimesh:

if tree_multimesh_inst and tree_multimesh_inst.multimesh:

tree_multimesh_inst.multimesh.instance_count = 0

return


var valid_transforms: Array[Transform3D] = []

var step_x = terrain_size.x / subdivision

var step_z = terrain_size.y / subdivision

var rng = RandomNumberGenerator.new()

rng.seed = noise_seed + 999

var start_x = -terrain_size.x / 2.0

var start_z = -terrain_size.y / 2.0

for x in range(subdivision + 1):

for z in range(subdivision + 1):

var px = start_x + (x * step_x) + rng.randf_range(-step_x*0.3, step_x*0.3)

var pz = start_z + (z * step_z) + rng.randf_range(-step_z*0.3, step_z*0.3)

var n_val = noise.get_noise_2d(px, pz)

var norm_val = (n_val * 0.5) + 0.5

# Faixa de altura reservada para a grama

if norm_val >= 0.3 and norm_val <= 0.55:

if rng.randf() <= tree_density:

var py = n_val * height_scale

var t = Transform3D()

t = t.rotated_local(Vector3.UP, rng.randf_range(0, TAU))

var sc = rng.randf_range(0.7, 1.3)

t = t.scaled_local(Vector3(sc, sc, sc))

t.origin = Vector3(px, py, pz)

valid_transforms.append(t)


var mm = tree_multimesh_inst.multimesh

mm.instance_count = valid_transforms.size()

for i in range(valid_transforms.size()):

mm.set_instance_transform(i, valid_transforms[i])


func _setup_terrain_shader() -> void:

var mat = self.material_override as ShaderMaterial

if not mat:

mat = ShaderMaterial.new()

var shader = Shader.new()

shader.code = """

shader_type spatial;

render_mode blend_mix, depth_draw_opaque, cull_back, diffuse_lambert, specular_schlick_ggx;


uniform sampler2D tex_sand : source_color, filter_linear_mipmap;

uniform sampler2D tex_grass : source_color, filter_linear_mipmap;

uniform sampler2D tex_rock : source_color, filter_linear_mipmap;

uniform sampler2D tex_snow : source_color, filter_linear_mipmap;

uniform float uv_scale = 10.0;

uniform float max_height = 8.0;


varying float height_factor;


void vertex() {

height_factor = (VERTEX.y / max_height) * 0.5 + 0.5;

}


void fragment() {

vec2 base_uv = UV * uv_scale;

vec4 col_sand = texture(tex_sand, base_uv);

vec4 col_grass = texture(tex_grass, base_uv);

vec4 col_rock = texture(tex_rock, base_uv);

vec4 col_snow = texture(tex_snow, base_uv);

vec4 final_color = col_sand;

float blend1 = smoothstep(0.2, 0.35, height_factor);

final_color = mix(final_color, col_grass, blend1);

float blend2 = smoothstep(0.5, 0.65, height_factor);

final_color = mix(final_color, col_rock, blend2);

float blend3 = smoothstep(0.75, 0.85, height_factor);

final_color = mix(final_color, col_snow, blend3);

ALBEDO = final_color.rgb;

ROUGHNESS = 0.8;

}

"""

mat.shader = shader

self.material_override = mat

_update_shader_parameters()


func _update_shader_parameters() -> void:

var mat = self.material_override as ShaderMaterial

if not mat:

return

if texture_sand: mat.set_shader_parameter("tex_sand", texture_sand)

if texture_grass: mat.set_shader_parameter("tex_grass", texture_grass)

if texture_rock: mat.set_shader_parameter("tex_rock", texture_rock)

if texture_snow: mat.set_shader_parameter("tex_snow", texture_snow)

mat.set_shader_parameter("uv_scale", texture_scale)

mat.set_shader_parameter("max_height", height_scale)


gerador de terreno 3d godot

 @tool

extends MeshInstance3D


@export_category("Configurações do Terreno")

@export var terrain_size: Vector2 = Vector2(40, 40):

set(value):

terrain_size = value

_generate_terrain()


@export var subdivision: int = 40:

set(value):

subdivision = value

_generate_terrain()


@export var height_scale: float = 8.0:

set(value):

height_scale = value

_generate_terrain()


@export_category("Configurações do Ruído")

@export var noise_seed: int = 1337:

set(value):

noise_seed = value

noise.seed = value

_generate_terrain()


@export var noise_frequency: float = 0.04:

set(value):

noise_frequency = value

noise.frequency = value

_generate_terrain()


# Botão no Inspector para forçar a regeração e sortear uma semente nova

@export_tool_button("Gerar Novo Terreno (Random)")

var _btn_generate = func():

noise.seed = randi()

noise_seed = noise.seed

_generate_terrain()


@export_category("Texturas dos Biomas")

@export var texture_sand: Texture2D:

set(value):

texture_sand = value

_update_shader_parameters()


@export var texture_grass: Texture2D:

set(value):

texture_grass = value

_update_shader_parameters()


@export var texture_rock: Texture2D:

set(value):

texture_rock = value

_update_shader_parameters()


@export var texture_snow: Texture2D:

set(value):

texture_snow = value

_update_shader_parameters()


@export var texture_scale: float = 10.0:

set(value):

texture_scale = value

_update_shader_parameters()


var noise: FastNoiseLite = FastNoiseLite.new()


func _ready() -> void:

noise.noise_type = FastNoiseLite.TYPE_SIMPLEX

noise.seed = noise_seed

noise.frequency = noise_frequency

_generate_terrain()


func _generate_terrain() -> void:

var plane_mesh = PlaneMesh.new()

plane_mesh.size = terrain_size

plane_mesh.subdivide_width = subdivision

plane_mesh.subdivide_depth = subdivision


var st = SurfaceTool.new()

st.begin(Mesh.PRIMITIVE_TRIANGLES)

st.create_from(plane_mesh, 0)

var st_data = st.commit_to_arrays()

var mesh = ArrayMesh.new()

mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, st_data)

var mdt = MeshDataTool.new()

mdt.create_from_surface(mesh, 0)

for i in range(mdt.get_vertex_count()):

var vertex = mdt.get_vertex(i)

var n_val = noise.get_noise_2d(vertex.x, vertex.z)

vertex.y = n_val * height_scale

mdt.set_vertex(i, vertex)

mesh.clear_surfaces()

mdt.commit_to_surface(mesh)

self.mesh = mesh

_setup_terrain_shader()

print("Terreno atualizado!")


func _setup_terrain_shader() -> void:

var mat = self.material_override as ShaderMaterial

if not mat:

mat = ShaderMaterial.new()

var shader = Shader.new()

shader.code = """

shader_type spatial;

render_mode blend_mix, depth_draw_opaque, cull_back, diffuse_lambert, specular_schlick_ggx;


uniform sampler2D tex_sand : source_color, filter_linear_mipmap;

uniform sampler2D tex_grass : source_color, filter_linear_mipmap;

uniform sampler2D tex_rock : source_color, filter_linear_mipmap;

uniform sampler2D tex_snow : source_color, filter_linear_mipmap;

uniform float uv_scale = 10.0;

uniform float max_height = 8.0;


varying float height_factor;


void vertex() {

height_factor = (VERTEX.y / max_height) * 0.5 + 0.5;

}


void fragment() {

vec2 base_uv = UV * uv_scale;

vec4 col_sand = texture(tex_sand, base_uv);

vec4 col_grass = texture(tex_grass, base_uv);

vec4 col_rock = texture(tex_rock, base_uv);

vec4 col_snow = texture(tex_snow, base_uv);

vec4 final_color = col_sand;

float blend1 = smoothstep(0.2, 0.35, height_factor);

final_color = mix(final_color, col_grass, blend1);

float blend2 = smoothstep(0.5, 0.65, height_factor);

final_color = mix(final_color, col_rock, blend2);

float blend3 = smoothstep(0.75, 0.85, height_factor);

final_color = mix(final_color, col_snow, blend3);

ALBEDO = final_color.rgb;

ROUGHNESS = 0.8;

}

"""

mat.shader = shader

self.material_override = mat

_update_shader_parameters()


func _update_shader_parameters() -> void:

var mat = self.material_override as ShaderMaterial

if not mat:

return

if texture_sand: mat.set_shader_parameter("tex_sand", texture_sand)

if texture_grass: mat.set_shader_parameter("tex_grass", texture_grass)

if texture_rock: mat.set_shader_parameter("tex_rock", texture_rock)

if texture_snow: mat.set_shader_parameter("tex_snow", texture_snow)

mat.set_shader_parameter("uv_scale", texture_scale)

mat.set_shader_parameter("max_height", height_scale)


PLAYER COM RAYCAST - CAMERA

 extends CharacterBody3D


var pegou = 0 

const SPEED = 5.0

const JUMP_VELOCITY = 4.5

const MOUSE_SENSITIVITY = 0.003


@onready var camera_3d: Camera3D = $Camera3D

@onready var ray_cast_3d: RayCast3D = $Camera3D/RayCast3D

@onready var hold_position: Marker3D = $Camera3D/HoldPosition

@onready var label: Label = $Label


const MIN_PITCH = deg_to_rad(-80.0)

const MAX_PITCH = deg_to_rad(80.0)


var camera_pitch: float = 0.0

var last_detected_object: Object = null


# Lista de objetos que você pode SEGURAR (ficam na mão)

var objetos_para_segurar: Array[String] = [

"caixa",

"caixa2",

"Cadeira",

"Livro"

]


# Lista de objetos que SUMEM ao pegar (Coletáveis)

var objetos_para_coletar: Array[String] = [

"cesta",

"chave",

"lanterna"

]


# Variável para armazenar o objeto que está segurando

var held_object: RigidBody3D = null

const HOLD_STRENGTH: float = 20.0 # Força de atração do objeto para a mão


func _ready() -> void:

Input.mouse_mode = Input.MOUSE_MODE_CAPTURED

# AJUSTES PARA SUBIR RAMPAS / DIAGONAIS COM FLUIDEZ

floor_stop_on_slope = true

floor_max_angle = deg_to_rad(90.0) # Ângulo máximo da rampa/diagonal (45 graus)

floor_snap_length = 0.2 # Mantém o jogador "grudado" ao subir/descer


func _unhandled_input(event: InputEvent) -> void:

if event is InputEventMouseMotion:

rotate_y(-event.relative.x * MOUSE_SENSITIVITY)

camera_pitch -= event.relative.y * MOUSE_SENSITIVITY

camera_pitch = clamp(camera_pitch, MIN_PITCH, MAX_PITCH)

camera_3d.rotation.x = camera_pitch

if event.is_action_pressed("ui_cancel"):

Input.mouse_mode = Input.MOUSE_MODE_VISIBLE


func _physics_process(delta: float) -> void:

if not is_on_floor():

velocity += get_gravity() * delta


if Input.is_action_just_pressed("ui_accept") and is_on_floor():

velocity.y = JUMP_VELOCITY


var input_dir := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")

# Direção calculada considerando a rotação da câmera (permite andar/subir em diagonais)

var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()

if direction:

velocity.x = direction.x * SPEED

velocity.z = direction.z * SPEED

else:

velocity.x = move_toward(velocity.x, 0, SPEED * delta * 10.0)

velocity.z = move_toward(velocity.z, 0, SPEED * delta * 10.0)


move_and_slide()

# Checa a colisão para atualizar o Label

_check_raycast_collision()

# Ação de Interagir (Pressionar a tecla E)

if Input.is_action_just_pressed("interact"):

if held_object == null:

_interact_with_object()

else:

_drop_object()

# Atualiza a posição do objeto segurado com física

_move_held_object(delta)


func _check_raycast_collision() -> void:

if held_object != null:

return


if ray_cast_3d.is_colliding():

var collider = ray_cast_3d.get_collider()

if is_instance_valid(collider):

if collider.name in objetos_para_segurar or collider.name in objetos_para_coletar:

if collider != last_detected_object:

last_detected_object = collider

print("Olhando para: ", collider.name)

label.text = collider.name

else:

last_detected_object = null

label.text = ""

else:

last_detected_object = null

label.text = ""

else:

last_detected_object = null

label.text = ""


func _interact_with_object() -> void:

if ray_cast_3d.is_colliding():

var collider = ray_cast_3d.get_collider()

if not is_instance_valid(collider):

return

if collider.name in objetos_para_coletar:

var nome_do_item = collider.name

Global.adicionar_item(nome_do_item)

label.text = ""

last_detected_object = null

collider.queue_free()

return


if collider is RigidBody3D and collider.name in objetos_para_segurar:

held_object = collider

held_object.linear_velocity = Vector3.ZERO

print("Pegou o objeto: ", held_object.name)

label.text = "Pressione E para soltar " + held_object.name


func _drop_object() -> void:

if is_instance_valid(held_object):

print("Soltou o objeto: ", held_object.name)

held_object = null

label.text = ""


func _move_held_object(_delta: float) -> void:

if held_object != null:

if not is_instance_valid(held_object):

held_object = null

label.text = ""

return


var target_pos = hold_position.global_position

var current_pos = held_object.global_position

var diff = target_pos - current_pos

held_object.linear_velocity = diff * HOLD_STRENGTH