[SOLVED] Group or tag in jmonkey engine


#1

Hello, someone knows if it is possible to use groups or tag in jmonkey engine … To be able to refer to many objects with the same name in godot engine are called groups, in unity they are called tag …
Does anyone know if this is possible in Jmonkey engine?

This can be used for example to put the enemies in a group and when attacked by the player they are destroyed.


#2

There’s like a billion ways to achieve this, but the simplest way to duplicate that scenario is a scene traversal by name or userdata.

Set the spatial name or .setUserData with some tag string or whatever and then use a scenevisitor to find them all and put them in a list if name/userdata .equals(“my tag”).

https://wiki.jmonkeyengine.org/jme3/advanced/traverse_scenegraph.html

Groups are defined in JME in the scene by nodes. Create a node. Put all the same things in that node and all the children of that node are grouped.

In plain java you would use an array or collection - which is a list - or group - of stuff.


#3

In some of my smaller projects, I created a simple class for handling this:

import com.jme3.app.Application;
import com.jme3.app.state.BaseAppState;
import com.jme3.scene.Spatial;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.stream.Collectors;

/**
 *
 * @author Trevor Flynn <trevorflynn@liquidcrystalstudios.com>
 */
public class TagHandler extends BaseAppState {

    private HashMap<String, HashSet<Spatial>> tags = new HashMap<>();

    public void add(String tag, Spatial s) {
        if (!hasTag(tag)) {
            tags.put(tag, new HashSet<>()); //Add the hashset to tags if we do not yet have that tag
        }
        tags.get(tag).add(s);
    }

    public void remove(String tag, Spatial s) {
        if (hasTag(tag)) {
            tags.get(tag).remove(s);
        }
    }

    public boolean hasTag(String tag) {
        return tags.containsKey(tag);
    }

    public void remove(String tag) {
        tags.remove(tag);
    }

    public void remove(Spatial s) {
        for (String key : tags.keySet()) {
            HashSet<Spatial> vals = tags.get(key);
            vals.remove(s);
        }
    }

    public HashSet<Spatial> get(String tag) {
        HashSet<Spatial> rets = tags.get(tag);
        return rets != null && !rets.isEmpty() ? rets : null;
    }

    @Override
    protected void initialize(Application arg0) {
        //Not used
    }

    @Override
    protected void cleanup(Application arg0) {
        tags.clear();
    }

    @Override
    public void update(float tpf) {
        //Cleanup all unused tags
        for (String key : tags.keySet()) {
            if (tags.get(key).isEmpty()) {
                tags.remove(key);
            }
        }
        
        //Clean up all detached spatials
        for (Spatial s : tags.values().stream().flatMap(Collection::stream).collect(Collectors.toSet())) {
            if (s.getParent() == null) { //We can remove the node from tags as it is no longer in the scene
                remove(s);
            }
        }
    }

    @Override
    protected void onEnable() {
    }

    @Override
    protected void onDisable() {
    }

}

it is an app state that you can attach, the use it to manager tags on spatials.
EDIT: I had to make a couple changes to pull out some proprietary code, so hopefully it works as is, but you may need to make a couple changes.


#4

OK,thanks …I’m going to try it. I understand that tag or groups is fundamental in a game engine.


#5

OK, thanks for the suggestion I will try to put it into practice.


#6

In the JME3 system, it is not the ideal way to organize information. Ideally you organize spatials using nodes, and you can treat them as categories if you would like. Or you can use systems such as Zay-ES which add more organizational utilities (I personally have never used it). My company has an in-house engine we built on top of jme3 which handles all the organization for us and breaks it up into components.

Again, there is not any tagging. Tagging can get very messy fast, ideally just organize everything into nodes as categories. An example would be to have a npcs node that holds all the NPCs. Perhaps a world node that holds all world objects. From there you can add custom properties to each spatial and iterate over all the nodes in each group until you find the ones that have that property. This is the ideal way to handle organization if searching for specific but related spatials.


#7

Sure, but there is a problem … Imagine if you are creating a temple run game, you are creating random obstacles … those objects are instances, therefore they must have different names. Imagine if they are thousands … How do you recognize thousands of objects? enemies? … There is something I do not understand.


#8

Well there are only two ways any game engine can do this.

  1. Keep track of these objects in a collection.
  2. Traverse a hierarchy and obtain them.

Could you maybe explain exactly what it is your are trying to do and maybe we can skip the “potentials” and jump right to the “how to”.

Even if you “tag” things with geometry.setUserData("myTag") and find that geometry in the scene - you will only obtain the geometry - not the game object - anyway.

If this were me I would put the created items in a List and give the game object a group id or string.

The first thing to understand is “Game Objects” vs “Scene Objects”. Engines like Unity blur this distinction.

A scene object is just a representation of your game object. A geometry. The scene is just a representation of your game. The game should be able to work without being represented as a scene. It should not rely on it for information. A scene should only show the state of your game.

If we understand that, we understand that tagging scene objects is a bad idea - because a scene should not contain data - it should show data.

If I were to make 100 soldiers, I would have a Soldier class (a game object) in a List. If I wanted to put those soldiers into smaller groups, my soldier object would have an integer or string assigned to them.

// A simple game object
public class Soldier {

    private String groupName;

    // my game object has a scene object.
    private Geometry soldierGeom;
}

Then if I wanted to kill all soldiers in a group, I would filter the soldiers list.

List<Soldier> soldiersInGroup = soldiers.stream()
            .filter(s -> s.getGroupName().equals("groupIWant"))
            .collect(Collectors.toList());

// do something such as remove them from the scene...
soldiersInGroup.foreach(s -> s.getSoldierGeometry().removeFromParent());

#9

You will have to go into more detail with this because those two things are not requirements… unless YOU require it.


#10

Ok I am trying to find the concept since I wanted to do a tutorial … So when I do a project I will ask you with the concrete example thank you for answering me … I am very happy because this engine has an excellent community … Thanks to all .


#11

Ok I have a lot of information thanks to everyone for their time…I am going to try to implement it …
In unity is the same to look for many objects with a label you also have to create an array, save the objects, do the checks in a loop and then delete them if necessary …
I hope you understand what I write as I use the google translator … My native language is Spanish … Greetings to all.


#12

Sounds to me that you might get familiar with the entity component system (Zay-ES) approach for organizing and tagging your game data. But maybe not, maybe the stuff already suggest by others is enough for you.
I have wrote some blog articles for this on fprintf.logdown.com, it starts here http://fprintf.logdown.com/posts/498657-entity-component-system-part-1

Just in case :slight_smile:


#13

Hmm, is using a general Tag component for organizing entities, good practice in the entity component system?


#14

Not really.

The idea of tags is something game engines have to resort to when they’ve boxed you into treating your visual objects as your game objects.

I can’t think of a case in an ES where it’s necessary.


#15

It was more a “there is maybe a better way than tags, groups” comment of mine, was not that clear I agree. And no I also didn’t need such tags/group stuff with ECS :slight_smile:


#16

I found a simple solution, but it works very well.
I use a list to save the child nodes of a scene.
and then by checking the name I can activate events as rotations.
In Jmonkey Engine a scene with Nodes are “A GROUP OF OBJECTS”

in spanish:
Encontré una solución simple,pero que funciona muy bien.
Utilizo una lista para guardar los nodos hijos de una escena.
y luego verificando el nombre puedo activar eventos como rotaciones.
En Jmonkey Engine una escena con Nodos son “UN GRUPO DE OBJETOS”

public class Main extends SimpleApplication {

Spatial Escena_principal; //variable publica tipo spatial



List <Spatial> cubos;//declaro una lista para guardar los nodos de la escena.

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

@Override
//funcion inicial
public void simpleInitApp() {
    /** Load a model. Uses model and texture from jme3-test-data library! */ 
    Escena_principal = assetManager.loadModel("scenes/hola_node.j3o");
    rootNode.attachChild(Escena_principal);

    
    flyCam.setMoveSpeed(15.0f); //camera speed
    
    
    cubos =((Node)Escena_principal).getChildren();//devuelve los nodos hijos de una escena..Son una "LISTA" de objetos tipo spatial
}
            
    
    
    
///En el la funcion simple update compruebo para hacer rotaciones de los objetos        

@Override
public void simpleUpdate(float tpf) {
    
    for(Spatial i : cubos){ //bucle FOREACH
        
        String caja = i.getName();//busco el nombre de objeto segun el indice en el bucle
        String caja2 = "Box"; //variable usada para comparar los nombre

        if(caja.equals(caja2)){
            i.rotate(0, 5 * tpf, 0);
        }
    }
     
}

#17