[SOLVED] How to collect spatial ID the moment it is created & attached

I’m creating 2d grid-ish map of boxes in several nested loops (they check for position, box-type, etc.). The problem is that when I create them this way I loose direct reference to the spatial the very moment my loop creates next one. So the only way to pick the exact one (and either destroy it or change to another) is via rootNode ID.

How do I get this ID the very moment I create the spatial and attach it to rootnode? So I can store those ID’s in some array with for example grid-coordinates and check for the one to pick via this array.

I am not sure I understand the question, but how about:

Spatial s = new Node();
rootNode.attachChild(s);
int idx = rootNode.getChildIndex(s);

Or you can define your index before adding the spatial:

for (int idx = 0; idx <= maxAmountOfSpatials; idx++) {
    Spatial s = new Node();
    rootNode.attachChildAt(s, idx);
}

On the other hand: Why not put a reference to the spatial itself in your array?

1 Like

99% sure Your first solution is exactly what I was looking for (gonna test it soon - great thanks). Second one not so much because I would need either to track myself which ID’s got cleared (after destroying spatials) and ready to reuse or scale ID’s infinitely which is even worse.

As for Your question, how would I do that? Let just say I have something like this (WARNING: pseudocode, I don’t have access to my code now):

PSEUDOCODE !!!
for ( X grid positions from 1 to 100 )
for ( Y grid positions from 1 to 100 )
Geometry  thatShit = new Geometry;
thatShit.setLocalTranslation ( calculated from X and Y );
rootNode.attach(thatShit);

In this loop, the moment I create next object I loose any way of tracking previous one except for the rootNode ID.

Why do you need to store ids if you can store references in java ?

Because I want only to destroy spatial visible in rootNode, not the actual object it represents (box visibility system).

So loop in the rootnode and compare the references, there is no point to use index.

You don’t understand - I will attach/detach spatials selectively in update loop A LOT. Looping through entire rootNode everytime doesn’t sound like optimal way. On the other hand creating small arrays (chunks of terrain) and simply attaching/detaching everything inside one array looks pretty straightforward…

Not to mention that at the moment there is no logical object behind the spatial at all. I just create spatials based on database that stores information about every block of terrain in my map.

You don need to loop all the objects in the rootnode, just create an node to group it, its an good practice anyway.

I thought of that (node-based chunks instead of array-based chunks) but wouldn’t that give me like A LOT of lightning issues? Some of my blocks will emit light and last time I checked light is limited to it’s parent node.

I think what you are missing here is how to organize the scene, there is an nice doc about how to do it in the scene did you read it ?
You could add your cameraNode and lightNode to the rootNode, and then add everything else inside the lightNode, avoid to add things directly in the rootNode and guiNode, you will have several problems if you dont organize your scene well.
Then, inside your lightNode you add some objType1Node , objType2Node, etc, then add your objects to this nodes.
Loop on this nodes to get the objects that are in the scene, and using an array do the getParent==null check to see if they are in the scene, done.
Note: You will not have problems with lights since your light will emit to all dependents.

I will have several lights. Not just one. Of course 2 main lights (ambient for brightness and directional for sun-like thingy) can be attached to this node. But what about all the small lights I will have here and there (mostly point lights and spot lights)?

No offense but I fail to see the profits for now (which doesn’t mean they don’t exist - just at my advancement level in jMonkey, this stuff You talk about is a little overkill). I’ll think of this when my project grows (if it does) :smile: But thanks for suggestion :smiley:

Btw. I tend to rewrite my whole code from time to time anyway so changing stuff to Your way isn’t gonna be an issue.

I am just trying to help, I did what you are planning to do when I was starting, and I had to change everything because this simple dosent work when your project grows.
And you can have several lights in your scene with no problem, you will add your lights to the lightNode, just that.

Ok could You tell me then what are the main issues with my current idea for this system? I’ll give You a short version of how I do things now:

  • 2d block-based map (big one - something around 10 milion blocks),
  • map will be generated and stored in database (at the moment just plain csv),
  • map is divided into someX*someY sized chunks,
  • chunk that the camera is facing and neighbour chunks are stored in arrays and attached to the rootNode,
  • when camera position changes, new chunk-in-the-middle is picked and according neighbour chunks as well (of course this doesn’t happen if camera doesn’t leave the current chunk to avoid generating what is already generated), old arrays are sent to the database so everything that player changed is stored,
    …I think that’s all I have for now in terms of scene graph (I have some other stuff like HUD, strategic camera, minimap etc. but they are completely separate stuff). I didn’t touch actual game logics yet - dealing with graphics gives me more fun.

Just try to avoid adding stuff in the rootNode, Nodes dont consume resources and helps you to organize stuff.
You could store the references to an array in this case with no problem, I am not sure how your game works and why you want an array, maybe you want to store this in an dimensional array ( position ) ?
Maybe if you create an class extending vector2f + spatial and use the vector2f as indexer you will get good results.
Is this game really 2d or minecraft type game ?

Closest thing I can compare it to (mind that it’s more of a learning-incentive for me then actual game-project right now) is something between Craft the World and Dungeon Keeper (more the latter, just with side-view). So no, not minecraft-ish at all (Minecraft and Terraria bored me to death after few days - I’m a wraith now muahahaha).

As for arrays You did hit the Jackpot. What I’m using is a multi-dimensional array (3 dimensions at the moment: X, Y and Data Cells) that I’m parsing using vectors.

As for visual representation I think of completely spliting visuals from logics (ergo: the game itself will play in database, and Scene Graph will only represent what’s in this database). So there is big chance that there will be no classes defining terrain blocks at all although this may change at some point.

Here is some code that uses direct references without indices. It also organizes the blocks in Chunk nodes.
It might not be exactly the approach you want to go for (I guess, you will not be generating all the chunks and blocks at the beginning, but rather load them from your DB as you go), but maybe it helps.

First, a class representing a chunk (it extends Node).
For demonstration purposes each chunk uses its own color for its blocks:

package mygame;

import com.jme3.asset.AssetManager;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Box;
import java.util.HashMap;
import java.util.Map;

public class Chunk extends Node {

    private ColorRGBA chunkColor = ColorRGBA.randomColor();
    private Map<Vector2f, Geometry> blocks = new HashMap<Vector2f, Geometry>();

    public void addBlockAt(int x, int y, AssetManager assetManager) {
        // Create block
        Box box = new Box(0.5f, 0.5f, 0.5f);
        Geometry block = new Geometry("block", box);
        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", chunkColor);
        block.setMaterial(mat);

        // Move the block to its position
        block.move(x, y, 0);

        // Store the block in the map
        blocks.put(new Vector2f(x, y), block);

        // Attach the block
        attachChild(block);
    }

    public Map<Vector2f, Geometry> getBlocks() {
        return blocks;
    }
}

Then we have the Main class, which creates 100x100 blocks. Each time a block is created it is automatically allocated to the appropriate chunk:

package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.math.FastMath;
import com.jme3.math.Vector2f;
import com.jme3.scene.Geometry;
import java.util.HashMap;
import java.util.Map;

public class Main extends SimpleApplication {

    public static final int CHUNK_SIZE = 10;
    private Map<Vector2f, Chunk> chunks = new HashMap<Vector2f, Chunk>();

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

    @Override
    public void simpleInitApp() {
        for (int x = 0; x < 100; x++) {
            for (int y = 0; y < 100; y++) {
                addBlock(x, y);
            }
        }
    }

    private void addBlock(int x, int y) {
        // get chunk
        int chunkX = x / CHUNK_SIZE;
        int chunkY = y / CHUNK_SIZE;
        Vector2f chunkCoordinates = new Vector2f(chunkX, chunkY);
        Chunk chunk = chunks.get(chunkCoordinates);
        if (chunk == null) {
            // Create chunk
            chunk = new Chunk();

            // Move chunk to its correct position
            chunk.move(chunkX * CHUNK_SIZE, chunkY * CHUNK_SIZE, 0);

            // Store chunk in map
            chunks.put(chunkCoordinates, chunk);

            // Only for testing purposes: Attach all creates chunks to the rootNode
            rootNode.attachChild(chunk);
        }

        // get coordinates of block within chunk
        int blockX = x % CHUNK_SIZE;
        int blockY = y % CHUNK_SIZE;

        // create block
        chunk.addBlockAt(blockX, blockY, assetManager);
    }
}

Running this gives you a 100x100 array of blocks in the world. Each 10x10 block has its own color because it’s a different chunk.
If you need a back reference from a block to its chunk, you can easily store it in the Geometry’s userData.

Did Your first method (with ID’s) now and it works like a charm. Gonna test the reference one soon and see if there’s a difference in performance or not.

You really should be able to keep track of objects you create yourself instead of relying on external lists… Just make a list or map or something…

Isn’t 1-st post of Cervantes in this topic exactly that? Keeping track of objects I create?

Yes, I just point out that it is a general thing - just keep track of your stuff instead of trying to (mis)use the library for that - or even worse demand such functions be built in just because you need it in your app.