Godot Engine: Personagens 3D

De Aulas


Afluentes : Jogos Digitais, Usabilidade, desenvolvimento web, mobile e jogos

Videoaula

Screenshot

Resultado do exercício em execução no Godot Engine.

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.

Modelo 3D aberto no Blender. Nesse printscreen eu selecionei No menu superior a opção Animation pra poder ver as animações disponíveis.

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:

Selecionando elementos pra exportação.

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:

Exportação: Janela de seleção.

Observem que no lado direito tem algumas opções. Então vamos em cada uma delas selecionar alguns elementos:

Include.

Em Include, vamos selecionar o checkbox Selected Objects.

Transform.

Na opção Transform, deve estar selecionado o +Y UP. Caso não estiver selecionado, então selecione.

Geometry

Em Geometry, selecione Apply Modifiers.

Animation

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:

Criando o projeto no Godot

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.

Pastas

Agora que separamos as pastas. Vamos arrastar o arquivo exportado do Blender lá pra pasta do projeto chamada model.

Pasta 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.

Godot importação (AnimationPlayer)

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 ...
  • 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...
Mapa do teclado

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)