Hello Node

jMonkeyEngine 3 Tutorial (2) - Hello Node

Anterior: Hello SimpleApplication, Próximo: Hello Assets.

Neste tutorial nós daremos uma olhada na criação de uma cena 3D.

  • Este tutorial assume que você save o que o grafo de cena é.
  • Para uma introdução visual, cheque o Grafo de Cena para Novatos.

Quando criando um jogo 3D

  • Você cria alguns objetos como jogadores, edifícios, etc.
  • Você adiciona os objetos para a cena.
  • Você move, redimensiona, rotaciona, colore, e anima eles.

Você aprendera que o grafo de cena representa o mundo 3D, e porque o nó raiz (rootNode) é importante. Você aprenderá como criar objetos simples, como deixá-los transportar dados customizados (como, por exemplo, pontos de saúde), e como "transformá-los" por mover, escalonar e rotacionar. Você compreenderá a diferença entre os dois tipos de "Espaciais" no grafo de cena: nós (Nodes) e geometrias (Geometries).

Amostra de código

package jme3test.helloworld;

import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.math.ColorRGBA;
import com.jme3.scene.Node;

/** Sample 2 - How to use nodes as handles to manipulate objects in the scene.
 * You can rotate, translate, and scale objects by manipulating their parent nodes.
 * The Root Node is special: Only what is attached to the Root Node appears in the scene. */

public class HelloNode extends SimpleApplication {

    public static void main(String[] args){
        HelloNode app = new HelloNode();
        app.start();
    }

    @Override
    public void simpleInitApp() {

        /** create a blue box at coordinates (1,-1,1) */
        Box box1 = new Box( Vector3f.ZERO, 1,1,1);
        Geometry blue = new Geometry("Box", box1);
        Material mat1 = new Material(assetManager, 
                "Common/MatDefs/Misc/Unshaded.j3md");
        mat1.setColor("Color", ColorRGBA.Blue);
        blue.setMaterial(mat1);
        blue.move(1,-1,1);

        /** create a red box straight above the blue one at (1,3,1) */
        Box box2 = new Box( Vector3f.ZERO, 1,1,1);
        Geometry red = new Geometry("Box", box2);
        Material mat2 = new Material(assetManager, 
                "Common/MatDefs/Misc/Unshaded.j3md");
        mat2.setColor("Color", ColorRGBA.Red);
        red.setMaterial(mat2);
        red.move(1,3,1);

        /** Create a pivot node at (0,0,0) and attach it to the root node */
        Node pivot = new Node("pivot");
        rootNode.attachChild(pivot); // put this node in the scene

        /** Attach the two boxes to the *pivot* node. */
        pivot.attachChild(blue);
        pivot.attachChild(red);
        /** Rotate the pivot node: Note that both boxes have rotated! */
        pivot.rotate(.4f,.4f,0f);
    }
}

Construa e execute a amostra de código. Você deveria ver duas caixas coloridas inclinadas no mesmo ângulo.

Entendendo a Terminologia

Neste tutorial você aprenderá alguns novos termos:

O que você quer fazer Como você diz isso na terminologia JME3
Colocar a disposição da cena 3D Popular o grafo de cena
Criar objetos da cena Criar espaciais (Spatials) (e.g. criar geometrias (Geometries) )
Fazer um objeto aparecer na cena Anexar um espacial (Spatial) para o nó raiz rootNode
Fazer um objeto desaparecer da cena Retirar um espacial (Spatial) do nó raiz rootNode
Posicionar/mover, virar, ou redimensionar um objeto Transladar, ou rotacionar, ou escalar um objeto = transformar um objeto

Toda aplicação JME3 tem um nó raiz (rootNode): Seu jogo automaticamente herda o objeto rootNode de SimpleApplication. Tudo anexado ao nó raiz (rootNode) é parte do grafo de cena. Os elementos do grafo de cena são os espaciais (Spatials).

  • Um Spatial contém a localização, rotação e escala de um objeto.
  • Um Spatial pode ser carregado, transformado, e salvo.
  • Há dois tipos de Spatials: nós (Nodes) e geometrias (Geometries).
Geometria (Geometry) Nó (Node)
Visibilidade: Uma geometria (Geometry) é um objeto de cena visível Um nó (Node) é uma "alavanca" invisível para objetos da cena.
Propósito: Uma geometria (Geometry) armazena a aparência de um objeto. Um nó (Node) agrupa geometrias (Geometries) e outros nós (Nodes) juntos.
Exemplos: Uma caixa, uma esfera, um jogador, um edifício, um pedaço de terreno, um veículo, mísseis, NPCs, etc… O nó raiz (rootNode), um nó de chão agrupando vários terrenos, um nó veículo-com-passageiros customizado, um nó jogador-com-arma, um nó de aúdio, etc…

Entendendo o Código

O que acontece no trecho de código? Você usa o método simpleInitApp() que foi introduzido no primeiro tutorial para inicializar a cena.

  1. Você cria a primeira geometria caixa
    1. Crie uma forma caixa (Box) com extensões de (1,1,1), isto faz a caixa 2x2x2 unidades do mundo grande.
    2. Posicione a caixa em (1,-1,1) usando o método move() method. (Não mude o Vector3f.ZERO a menos que você queira mudar o centro de rotação)
    3. Envolva a forma caixa (Box) em uma geometria (Geometry).
    4. Crie um material azul
    5. Aplique o material azul para a geometria da caixa (Box Geometry).

[[code]]

Box box1 = new Box( Vector3f.ZERO, 1,1,1);
Geometry blue = new Geometry("Box", box1);
Material mat1 = new Material(assetManager,
"Common/MatDefs/Misc/Unshaded.j3md");
mat1.setColor("Color", ColorRGBA.Blue);
blue.setMaterial(mat1);
blue.move(1,-1,1);
[[/code]]

  1. Você cria uma segunda geometria (Geometry) de caixa.
    1. Crie uma segunda forma caixa (Box) com o mesmo tamanho.
    2. Posicione a segunda caixa em (1,3,1). Isto é imediatamente acima da primeira caixa, com uma lacuna de 2 unidades do mundo entre elas.
    3. Envolva a forma caixa (Box) em uma geometria (Geometry).
    4. Crie um material vermelho
    5. Aplique o material vermelho para a geometria caixa (Box Geometry).

[[code]]
Box box2 = new Box( Vector3f.ZERO, 1,1,1);
Geometry red = new Geometry("Box", box2);
Material mat2 = new Material(assetManager,
"Common/MatDefs/Misc/Unshaded.j3md");
mat2.setColor("Color", ColorRGBA.Red);
red.setMaterial(mat2);
red.move(1,3,1);
[[/code]]

  1. Você cria um nó (Node) pivô
    1. Nomeie o nó "pivot".
    2. Por padrão o nó (Node) é posicionado em (0,0,0).
    3. Anexe o nó (Node) ao nó raiz (rootNode).
    4. O nó (Node) não tem aparência visível na cena.

[[code]]
Node pivot = new Node("pivot");
rootNode.attachChild(pivot);
[[/code]]

Se você executar a aplicação somente com o código dado até aqui, a cena parece vazia. Isto é porque o nó (Node) está invisível, e você não tem ainda anexado quaisquer geometrias (Geometries) visíveis para o nó raiz (rootNode).
Anexe as duas caixas para o nó pivô.

            pivot.attachChild(blue);
            pivot.attachChild(red);

Se você executar o aplicativo com somente o código dado até aqui, você vê dois cubos: Um vermelho imediatamente acima de um azul.
Rotacione o nó pivô.

            pivot.rotate( 0.4f , 0.4f , 0.0f );

Se você executar o aplicativo agora, você verá duas caixas uma no topo da outra - ambas inclinadas no mesmo ângulo.

O que é um nó pivô (Pivot Node)?

Você pode transformar (e.g. rotacionar) geometrias (Geometries) ao redor do próprio centro delas, ou ao redor de um ponto central definido pelo usuário. Um ponto central definido pelo usuário para um ou mais geometrias (Geometries) é chamado pivô.

Neste exemplo, você agrupou duas geometrias (Geometries) por anexá-las para um nó pivô (Node). Você vê o nó (Node) pivô como um instrumento para rotacionar as duas geometrias (Geometries) ao mesmo tempo ao redor de um centro em comum. Rotacionar o nó (Node) pivô rotaciona todas as geometrias (Geometries) anexadas, de uma única vez. O nó pivô é o centro da rotação. Antes de anexar as outras geometrias (Geometries), tenha certeza que o nó pivô está em (0,0,0). Transformar um nó (Node) pai para transformar todas as crianças espaciais (Spatials) anexadas é uma tarefa comum. Você usará este método muito em seus jogos quando você mover espaciais (Spatials).
Exemplos: Um veículo e seu motorista movem juntos; um planeta com sua lua orbitam o sol.
Contraste este caso com a outra opção: Se você não criar um nó pivô extra e transformar uma geometria (Geometry), então toda transformação é feita relativa a origem da geometria (Geometry) (tipicamente o centro dela).
Exemplos: Se você rotacionar cada cubo diretamente (usando red.rotate(0.1f , 0.2f , 0.3f); e blue.rotate(0.5f , 0.0f , 0.25f);), então cada cubo é rotacionado individualmente ao redor do seu centro. Isto é similar a um planeta rotacionando ao redor de seu próprio centro.

Como eu Populo o Grafo de Cena?

Tarefa…? Solução!
Crie um espacial (Spatial) Crie uma forma malha (Mesh), envolva ela em uma geometria (Geometry), e dê a ela um Material. Por exemplo:
Box mesh = new Box(Vector3f.ZERO, 1, 1, 1); // a cuboid default mesh
Geometry thing = new Geometry("thing", mesh); 
Material mat = new Material(assetManager,
   "Common/MatDefs/Misc/ShowNormals.j3md");
thing.setMaterial(mat);
Faça um objeto aparecer na cena Anexe o espacial (Spatial) para o nó raiz (rootNode), ou para qualquer no que esteja anexado para o nó raiz (rootNode).
rootNode.attachChild(thing);
Remova objetos da cena Retire o nó espacial (Spatial) do nó raiz (rootNode), e de qualquer nó que esteja vinculado ao nó raiz (rootNode).
rootNode.detachChild(thing);
rootNode.detachAllChildren();
Ache um nó espacial na cena pelo nome do objeto, ou ID, ou por sua posição na hierarquia pai-criança. Olhe na criança ou pai do nó:
Spatial thing = rootNode.getChild("thing");
Spatial twentyThird = rootNode.getChild(22);
Spatial parent = myNode.getParent();
Especifique o que deveria ser carregado no início Tudo que você inicializa e anexa ao nó raiz (rootNode) no método simpleInitApp() é parte da cena no início do jogo.

Como eu transformo espaciais (Spatials)?

Há três tipos de transformação 3D: Translação, Escalonamento, e Rotação.

[[row]]
[[/table]]
Translação move espaciais (Spatials ) eixo X eixo Y eixo Z
Especifique a nova localização em três dimensões: Quão distante ela está da origem indo direita para cima?
Para mover um espacial (Spatial) para coordenadas específicas, tais como (0,40.2f,-2), use:
thing.setLocalTranslation( new Vector3f( 0.0f, 40.2f, -2.0f ) );

Para mover um espacial (Spatial) por uma certa quantia, e.g. mais acima (y=40.2f) e mais atrás (z=-2.0f):

thing.move( 0.0f, 40.2f, -2.0f );
+right -left +up -down +forward -backward
Escalonamento redimensiona espaciais (Spatials) X-axis Y-axis Z-axis
Especifique o fator de escalonamento em cada dimensão: tamanho, altura, comprimento.
um valor entre 0.0f e 1.0f diminue o espacial (Spatial); maior que 1.0f estica ele; 1.0f mantém ele o mesmo.
Usando o mesmo valor para cada dimensão escalona proporcionalmente, valor diferentes esticam ele.
Para escalonar um espacial (Spatial) 10 vezes mais longo, um décimo da altura, e manter o mesmo comprimento:
thing.scale( 10.0f, 0.1f, 1.0f );
length height width
Rotação gira espaciais (Spatials) X-axis Y-axis Z-axis
Rotação 3-D é um pouco complicado (aprenda os detalhes aqui). em breve: Você pode rotacionar ao redor de três eixos: Pitch (X), yaw (Y), e roll (Z). Você pode especificar ângulos em graus por multiplicar o valor de graus com FastMath.DEG_TO_RAD.
Para rolar um objeto 180° ao redor do z axis:
thing.rotate( 0f , 0f , 180*FastMath.DEG_TO_RAD );

Dica: Se sua idéia de jogo pede uma quantidade séria de rotações, é merecedor dar uma olhada em quaternions, uma estrutura de dado que pode combinar e armazenar rotações eficientemente.

thing.setLocalRotation( 
  new Quaternion().fromAngleAxis(180*FastMath.DEG_TO_RAD, new Vector3f(1,0,0)));
pitch = fazer um sinal de sim com sua cabeça yaw = agitar sua cabeça roll = inclinar sua cabeça

Como eu Resolvo Problemas com espaciais (Spatials)?

Se você obtém resultados inesperados, cheque se você fez os seguintes enganos frequentes:

[[table]]

Problema? Solução!
Geometria (Geometry) criada não aparece na cena. Você anexou ela a (um nó que está vinculado a) o nó raiz (rootNode)?
Ela tem um Material?
Qual é sua translação (posição)? Ela está atrás da câmera ou coberta por uma outra geometria (Geometry)?
Ela é tão minúscula ou tão gigante para ver?
Ela está tão distante da câmera? (Tente cam.setFrustumFar(111111f); para ver mais distante ||
Um espacial (Spatial) rotaciona em maneiras inesperadas. Você usou os valores em radianos, e não em graus? (Se você usou graus, multiplique eles com FastMath.DEG_TO_RAD para convertê-los para radianos)
Você criou o espacial (Spatial) na origem (Vector.ZERO) antes de movê-lo?
Você rotacionou ao redor do nó pivô ou ao redor de algo mais?
Você rotacionou ao redor do eixo certo? ||
Uma geometria (Geometry) tem cor (Color) ou Material inepserado. Você reusou um Material de uma outra geometria (Geometry) e tem inadvertidamente mudado suas propriedades? (Se sim, considere cloná-lo: mat2 = mat.clone(); )

Como eu Adiciono um Dado Customizado para espaciais (Spatials)?

Muitos espaciais (Spatials) representam personagens ou outras entidades que o jogador pode interagir. O código acima que rotaciona as duas caixas ao redor de um centro em comum (pivô) poderia ser usado para uma espaçonave estacionada em uma estação espacial orbital, por exemplo.

Dependendo do seu jogo, entidades de jogo não somente mudam a posição delas, rotação ou escala (as transformações que você aprendeu). Entidades de jogo também têm propriedades personalizadas, como saúde, inventário carregado, equipamento usado para um personagem, ou força do casco e combustível restante para uma aeronave. Em Java, você representa dados de entidade como variáveis de classe, e.g. floats, Strings, ou Arrays.

Você pode adicionar dados personalizados diretamente para qualquer nó (Node) ou geometria (Geometry). Você não precisa estender a classe nó (Node) para incluir variáveis! Por exemplo, para adicionar um número de id customizado para um nó, você usaria:

pivot.setUserData( "pivot id", 42 );

Para ler o id do nó (Node) em outro lugar, você usaria:

int id = pivot.getUserData( "pivot id" );

Por usar diferentes chaves de Strings (aqui a chave é o id do pivô), você pode recuperar e configurar vários valores para quaisquer dados que o espacial (Spatial) precisa carregar. Quando você iniciar a escrever seu jogo, você talvez adicione um valor de combustível para um nó carro, valor de velocidade para um nó avião, ou número de moedas douradas para um nó jogador, e muito mais. Entretanto, deve-se notar que somente objetos customizados que implementam Savable podem ser passados.

Conclusão

Você aprenderu que sua cena 3D é um grafo de cena composto de espaciais (Spatials): Geometrias (Geometries) visíveis e nós (Nodes) invisíveis. Você pode transformar espaciais (Spatials), ou anexá-los a nós e transformar os nós. Você sabe a maneira mais fácil de como adicionar propriedades de entidade customizadas (tais como a saúde do jogador ou a velocidade do veículo) para espaciais (Spatials).

Desde que formas padrões como esferas e caixas ficam velhas rápido, continue com o próximo capítulo onde você aprenderá a carregar ativos, como por exemplo, modelos 3-D.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-Share Alike 2.5 License.