Mudanças entre as edições de "Godot Engine: Personagens 3D"
(11 revisões intermediárias pelo mesmo usuário não estão sendo mostradas) | |||
Linha 2: | Linha 2: | ||
+ | Afluentes : [[Jogos Digitais]], [[Usabilidade, desenvolvimento web, mobile e jogos]] | ||
− | + | = Videoaula = | |
+ | |||
+ | * [https://youtu.be/iSuW0dX0K60 Videoaula no Youtube] | ||
= Screenshot = | = Screenshot = | ||
Linha 18: | Linha 21: | ||
* [https://saulo.arisa.com.br/aulas/unisul/games/assets/quechan/quechan.zip Modelo personagem 3D] | * [https://saulo.arisa.com.br/aulas/unisul/games/assets/quechan/quechan.zip Modelo personagem 3D] | ||
+ | ** [https://saulo.arisa.com.br/aulas/unisul/games/assets/quechan/practicing01_complete.glb Modelo personagem 3D já exportado para usar no Godot] | ||
* [https://saulo.arisa.com.br/aulas/unisul/games/assets/quechan/box.jpg Textura da caixa] | * [https://saulo.arisa.com.br/aulas/unisul/games/assets/quechan/box.jpg Textura da caixa] | ||
* [https://saulo.arisa.com.br/aulas/unisul/games/assets/quechan/ground.jpg Textura do chão] | * [https://saulo.arisa.com.br/aulas/unisul/games/assets/quechan/ground.jpg Textura do chão] | ||
+ | * [https://youtu.be/iSuW0dX0K60 Videoaula desse exercício no Youtube] | ||
+ | * [https://github.com/saulopz/model3d_godot3 Projeto no GitHub] | ||
= Importando o Modelo do Blender para o Godot = | = Importando o Modelo do Blender para o Godot = | ||
Linha 26: | Linha 32: | ||
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. | 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 | + | O próximo passo é selecionar os elementos da personagem pra exportação na direita: |
+ | [[Arquivo:Godot quechan blender select.png|centro|miniaturadaimagem|Selecionando elementos pra exportação.]] | ||
+ | E depois ir no menu superior e selecionar: | ||
* '''File'''..., '''Export'''..., '''glTF 2.0'''... | * '''File'''..., '''Export'''..., '''glTF 2.0'''... | ||
Linha 50: | Linha 58: | ||
[[Arquivo:Godot quechan folders.png|centro|miniaturadaimagem|Pastas]] | [[Arquivo:Godot quechan folders.png|centro|miniaturadaimagem|Pastas]] | ||
Agora que separamos as pastas. Vamos arrastar o arquivo exportado do Blender lá pra pasta do projeto chamada '''model'''. | Agora que separamos as pastas. Vamos arrastar o arquivo exportado do Blender lá pra pasta do projeto chamada '''model'''. | ||
+ | [[Arquivo:Godot quechan folder model.png|centro|miniaturadaimagem|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. | ||
+ | [[Arquivo:Godot quechan AnimationPlayer.png|centro|miniaturadaimagem|700x700px|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... | ||
+ | [[Arquivo:Godot quechan mapateclado.png|centro|miniaturadaimagem|500x500px|Mapa do teclado]] | ||
+ | e adicionamos as seguintes entradas: | ||
+ | |||
+ | == Scripts == | ||
+ | Agora temos nossos scripts pra fazer as coisas funcionarem. | ||
+ | |||
+ | === Script do Player === | ||
+ | |||
+ | <syntaxhighlight lang=gdscript> | ||
+ | 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") | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | === Script da Câmera do World === | ||
+ | |||
+ | <syntaxhighlight lang=gdscript> | ||
+ | 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) | ||
+ | </syntaxhighlight> |
Edição atual tal como às 11h37min de 19 de maio de 2023
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:
- Modelo personagem 3D
- Textura da caixa
- Textura do chão
- Videoaula desse exercício no Youtube
- Projeto no GitHub
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)