Godot Engine: Personagens 3D
Afluentes : Jogos Digitais, Usabilidade, desenvolvimento web, mobile e jogos
Videoaula
Screenshot
Assets
Bem, eu não trabalho como desenhista 3D e minha prática nisso ficou lá na década de 90. De qualquer forma, o processo de desenvolvimento de games envolve uma grande variedade de profissionais e nenhum desses precisa saber fazer tudo. Então eu, como programador, pego modelos prontos para usar nos games.
Para esse exercício eu pesquisei modelos de personagens 3D no site https://opengameart.org. Queria um modelo já com várias animações e o que achei mais completo nisso, sem uma pesquisa muito aprofundada, foi esse: https://opehttps://opengameart.org/content/quechanngameart.org/content/quechan. Então fica aqui os créditos aos autores.
A textura pra caixa peguei em na Adobe Stock, mais especificamente aqui e a textura do chão, peguei na pngtree, aqui.
De qualquer forma, os assets podem ficar indisponíveis por diversos motivos, então coloquei no meu site pra download para usarem nesse exercício. Segue os links:
Importando o Modelo do Blender para o Godot
O modelo aqui usado está no formato de arquivo do Blender, então precisamos ter o programa instalado no nosso computador e usá-lo para fazer a importação para o Godot. Para isso descompacte o arquivo do modelo que você achou e abra ele no Blender.
Certo, depois de aberto, selecionei no menu superior a opção Animation para ver as animações disponíveis. Como tinha bastante coisa legal, acabei escolhendo esse modelo. Eu preferia que a personagem estivesse de roupas, mas não sei fazer isso, então vamos usar o modelo assim mesmo.
O próximo passo é selecionar os elementos da personagem pra exportação na direita:
E depois ir no menu superior e selecionar:
- File..., Export..., glTF 2.0...
Na janela de exportação vai ter várias opções. Vamos ter que selecionar algumas delas. Então vamos selecionar algumas delas:
Observem que no lado direito tem algumas opções. Então vamos em cada uma delas selecionar alguns elementos:
Em Include, vamos selecionar o checkbox Selected Objects.
Na opção Transform, deve estar selecionado o +Y UP. Caso não estiver selecionado, então selecione.
Em Geometry, selecione Apply Modifiers.
E, por fim, em Animation, selecione a sub-opção Animation e lá selecione a opção Export Deformation.
E pronto, salve o arquivo em alguma pasta fácil de localizar porque depois vamos importar no Godot.
Projeto no Godot
Agora abra o Godot e crie um projeto:
Pra gente começar a se organizar melhor, vamos criar quatro pastas: scene, texture, model e code. Assim a gente separa cada tipo de arquivo em uma pasta diferente.
Agora que separamos as pastas. Vamos arrastar o arquivo exportado do Blender lá pra pasta do projeto chamada model.
Você pode dar dois cliques no arquivo practicing01_complete.glib ali na pasta para poder ver as animações disponíveis. Quando ele der uma janela de diálogo, mande abrir como Novo Herdado, mas não salve o arquivo. É apenas pra gente visualizar.
Agora estamos prontos pra criar nosso game.
Cenas e Nós
Vamos então pra estrutura de Cenas:
- World: (Spatial):
- Ground (StaticBody) - Spatial: Transform: Scane: 15, 1, 15
- MeshInstance - Mesh: CubeMesh; Material: SpatialMaterial... Albedo: Texture: ground.jpg; UV1: 30, 20, 10
- CollisionShape - Shape: BoxShape
- Camera (script)
- Player (LINK)
- Box (LINK)
- Box ...
- Ground (StaticBody) - Spatial: Transform: Scane: 15, 1, 15
- Player (KinematicBody): (script)
- Object (praticing01_complete)
- CollisionShape - Shape: CilinderShaper
- Camera - Current: Active
- Box (RigidBody):
- MeshInstance - Transform: Scale: 0.5, 0.5, 0.5; Mesh: CubeMesh/ Material SpatialMaterial... Albedo: Texture: box.jpg; UV1: 3, 2, 1
- CollisionShape - Shape: BoxShape; Transform: Scale: 0.5, 0.5, 0.5
Configurações de Entrada
Vamos ter que configurar as entradas de teclado para nosso projeto. Para isso, vamos em:
- Projeto... Configurações do Projeto... Mapa de Entrada...
e adicionamos as seguintes entradas:
Scripts
Agora temos nossos scripts pra fazer as coisas funcionarem.
Script do Player
extends KinematicBody
export var angle := 0.0
export var speed_forward := 100.0
export var speed_backward := 30.0
export var speed_jump := 200.0
export var speed_rotation := 0.05
export var gravity := -10
var vec_y = 0
var jump = false
var walking = false
var crouch = false
var dead = false
var fly = false
func _physics_process(delta):
if Input.is_action_just_pressed("change_camera"):
var camera = get_parent().get_node("Camera")
camera.current = not camera.current
var direction = Vector3()
if not dead:
walking = false
if not fly and Input.is_action_just_pressed("crouch"):
crouch = true
elif Input.is_action_just_released("crouch"):
crouch = false
if not crouch and Input.is_action_just_pressed("fly"):
fly = not fly
if fly:
direction.y += 5000
vec_y = 0
if Input.is_action_pressed("forward"):
if crouch:
direction.z = speed_backward
$Obj/AnimationPlayer.play("m crouch walk")
elif fly:
direction.z = speed_forward
$Obj/AnimationPlayer.play("m swim forward")
else:
direction.z = speed_forward
$Obj/AnimationPlayer.play("m run")
walking = true
elif Input.is_action_pressed("backward"):
direction.z = -speed_backward
if crouch:
$Obj/AnimationPlayer.play("m crouch backward")
elif fly:
$Obj/AnimationPlayer.play("m swim back")
else:
$Obj/AnimationPlayer.play("m backward")
walking = true
if Input.is_action_pressed("left"):
rotate_y(speed_rotation)
angle += speed_rotation
if crouch:
$Obj/AnimationPlayer.play("m crouch side")
elif fly:
$Obj/AnimationPlayer.play("m swim forward")
else:
$Obj/AnimationPlayer.play("m run")
walking = true
elif Input.is_action_pressed("right"):
rotate_y(-speed_rotation)
angle -= speed_rotation
if crouch:
$Obj/AnimationPlayer.play("m crouch side")
elif fly:
$Obj/AnimationPlayer.play("m swim forward")
else:
$Obj/AnimationPlayer.play("m run")
walking = true
if not jump and not crouch and not fly and Input.is_action_just_pressed("jump"):
vec_y += speed_jump
jump = true
$Obj/AnimationPlayer.play("m jump")
if not fly and Input.is_action_just_pressed("kill"):
$Obj/AnimationPlayer.play("m death")
dead = true
else:
if $Obj/AnimationPlayer.is_playing():
$Obj/AnimationPlayer.play("m death")
if Input.is_action_just_pressed("kill"):
dead = false
#return
direction.y += vec_y
direction = direction.rotated(Vector3.UP, angle)
if not fly:
vec_y += gravity
var _error = move_and_slide(direction * delta, Vector3.UP)
if is_on_floor():
if jump:
jump = false
else:
vec_y = 0
if not walking and not dead:
if crouch:
$Obj/AnimationPlayer.play("m crouch root")
else:
$Obj/AnimationPlayer.play("m root")
elif fly and not walking:
$Obj/AnimationPlayer.play("m swim root")
Script da Câmera do World
extends Camera
export var distance = 3.0
export var height = 2.0
func _ready():
set_physics_process(true)
set_as_toplevel(true)
func _physics_process(_delta):
var target = get_parent().get_node("Player").get_global_transform().origin
var pos = get_global_transform().origin
var offset = pos - target
offset = offset.normalized() * distance
offset.y = height
pos = target + offset
look_at_from_position(pos, target, Vector3.UP)