Multi world, locations, multi grid system

Hi everyone. i just started learning jme3. I like everything, and everything works out for me. But I can’t figure out how to make multi-location for a multiplayer game. Each location has its own grid, which starts from 0, 0, 0. Users will be located both in different and in the same locations. Like wow mmo.

from what to proceed?
from rootNode? for each location to make a own node and bullet? but when i attach to rootNode, it all works on the same grid.

Or create your own simple application for each location?

Sorry, my English is not very good.

1 Like

Hi @TidalPoo , btw nice question though.

i am not a specialist , but i will guide you through what i do , so basically imagine that the vector(0,0,0) is the horizontal iso-electric line of the orthogonal plane,so by far its like a mirror , spawn objects on a side & spawn others on the other side with the inverse values example :slight_smile: :

let’s spawn 2 cars , you & an NPC or an opponent Simply :

        public VehicleAutoShop spawnPlayer(){
            vehicle.setPhysicsLocation(new Vector3f(0.2489425f, -9.613701f, -458.60062f));
            return this;
        }
        public VehicleAutoShop spawnNPC(){
            vehicle.setPhysicsLocation(new Vector3f(0.2489425f, -9.613701f, 458.60062f));
            vehicle.setPhysicsRotation(new Quaternion().fromAngleAxis(FastMath.PI,Vector3f.UNIT_Y));
            return this;
        }

ignore VehicleAutoShop its my entity class.

so , now you get the point since Z-axis is a projection into the screen , X-axis is the horizontal , Y-axis is a vertical axis , then by far those 2 objects in the example above would be spawned facing one another on the same horizontal line(X-Translation) , on the same level(Y-translation) , & at the same projection (inversed Z) , the rotation inside the spawnNPC(); ensures that the face of the NPC car faces the player’s car .

If you still can’t get it , let me know , i can rewrite this statement multiple times until you get it :slight_smile: .

Result of code (Sorry i have no images to show now) :

My class entity , if you need something to match :

package com.scrappers.carsoccer.JmeGame.VehicleBuilder;

import com.jme3.asset.AssetManager;
import com.jme3.bullet.collision.shapes.CompoundCollisionShape;
import com.jme3.bullet.control.VehicleControl;
import com.jme3.bullet.util.CollisionShapeFactory;
import com.jme3.input.ChaseCamera;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.texture.Texture;
import com.scrappers.carsoccer.JmeGame.JmERenderer.JmeGame;

public class VehicleGarage {
    private final String vehicle;
    private final AssetManager assetManager;
    private Spatial chassis;

    /**
     *
     * @param vehicle
     * @param assetManager
     */
    public VehicleGarage(String vehicle, AssetManager assetManager){
        this.vehicle=vehicle;
        this.assetManager=assetManager;
    }

    public VehicleGarage initializeVehicle(){
        chassis =assetManager.loadModel(vehicle);
        return this;
    }

    public Spatial getChassis() {
        return chassis;
    }

    public VehicleGarage paintGlassMaterial(ColorRGBA colorRGBA, String matTex) throws NullPointerException{
        ((Node) chassis).getChild("glass").setMaterial(createMat(colorRGBA,matTex));
        return this;
    }
    public VehicleGarage paintChassisMaterial(ColorRGBA colorRGBA, String matTex)throws NullPointerException{
        ((Node) chassis).getChild("chassis").setMaterial(createMat(colorRGBA,matTex));
        return this;
    }
    public VehicleGarage paintAddOnsMaterial(ColorRGBA colorRGBA, String matTex)throws NullPointerException{
        ((Node) chassis).getChild("addOns").setMaterial(createMat(colorRGBA,matTex));
        return this;
    }
    public VehicleGarage paintFrontLightsMaterial(ColorRGBA colorRGBA, String matTex)throws NullPointerException{
        ((Node) chassis).getChild("frontLight").setMaterial(createMat(colorRGBA,matTex));
        return this;
    }

    public VehicleGarage paintBackLightsMaterial(ColorRGBA colorRGBA, String matTex)throws NullPointerException{
        ((Node) chassis).getChild("backLights").setMaterial(createMat(colorRGBA,matTex));
        return this;
    }
    public VehicleGarage paintU_TurnsMaterial(ColorRGBA colorRGBA, String matTex)throws NullPointerException{
        ((Node) chassis).getChild("uTurns").setMaterial(createMat(colorRGBA,matTex));
        return this;
    }
    public VehicleGarage paintMirrorsMaterial(ColorRGBA colorRGBA, String matTex)throws NullPointerException{
        ((Node) chassis).getChild("mirrors").setMaterial(createMat(colorRGBA,matTex));
        return this;
    }

    public VehicleGarage paintNitroMaterial(ColorRGBA colorRGBA, String matTex)throws NullPointerException{
        ((Node) chassis).getChild("nitro").setMaterial(createMat(colorRGBA,matTex));
        return this;
    }

    private Material createMat(ColorRGBA colorRGBA, String Tex){
        Material material=new Material(assetManager,"Common/MatDefs/Misc/Unshaded.j3md");
        if(colorRGBA !=null){
            material.setColor("Color", colorRGBA);
        }
        if(Tex.length() >1){
            Texture texture=assetManager.loadTexture(Tex);
            material.setTexture("ColorMap",texture);
        }
        material.setReceivesShadows(true);

        return material;
    }

    /**
     * A custom class for advanced Vehicle workout : Tyres , Tyres formula , Speed formulas , breaks , etc.
     */
    public static class VehicleAutoShop{
        private Spatial chassis;
        private Node vehicleNode;
        private VehicleControl vehicle;

        public VehicleAutoShop(Spatial chassis){
            this.chassis=chassis;
        }

        public VehicleControl getVehicle() {
            return vehicle;
        }

        public Spatial getChassis() {
            return chassis;
        }

        public VehicleAutoShop initializeChassis(){
            //create a compound shape and attach the BoxCollisionShape for the car body at 0,1,0
            //this shifts the effective center of mass of the BoxCollisionShape to 0,-1,0
            //create vehicle node
            chassis.setLocalScale(2.2f,2.2f,2.2f);
            chassis.setLocalTranslation(new Vector3f(0, 1, -0.2f));

            vehicleNode=new Node("vehicleNode");
            vehicleNode.attachChild(chassis);
            return this;
        }
        public VehicleAutoShop initializeCamera(){
            ChaseCamera chaseCam=new ChaseCamera(JmeGame.gameContext.getCamera(), vehicleNode);
            chaseCam.setDefaultDistance(-15f);
            chaseCam.registerWithInput(JmeGame.gameContext.getInputManager());
            chaseCam.setDragToRotate(true);
            return this;
        }
        public VehicleAutoShop initializeVehiclePhysics(){
            CompoundCollisionShape compoundShape = (CompoundCollisionShape)CollisionShapeFactory.createDynamicMeshShape(chassis);
            compoundShape.translate(new Vector3f(0,1,0));
            vehicle = new VehicleControl(compoundShape, 600f);
            vehicleNode.addControl(vehicle);

            return this;
        }
        public VehicleAutoShop initializePlayer(){
            vehicle.setPhysicsLocation(new Vector3f(0.2489425f, -9.613701f, -458.60062f));
            return this;
        }
        public VehicleAutoShop initializeNPC(){
            vehicle.setPhysicsLocation(new Vector3f(0.2489425f, -9.613701f, 458.60062f));
            vehicle.setPhysicsRotation(new Quaternion().fromAngleAxis(FastMath.PI,Vector3f.UNIT_Y));
            return this;
        }
        public VehicleAutoShop loadWheels(){
            //Create four wheels and add them at their locations
            Vector3f wheelDirection = new Vector3f(0,-1F, 0); // was 0, -1, 0
            Vector3f wheelAxle = new Vector3f(-6, 0, 0); // was -1, 0, 0
            float radius = 0.5f;
            float restLength = 0.1f;
            float yOff = radius;
            float xOff = 4*radius;
            float zOff = 6f*radius;

            Material wheelsMat = new Material(JmeGame.gameContext.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
            wheelsMat.getAdditionalRenderState().setWireframe(false);
            wheelsMat.setColor("Color", ColorRGBA.Black);

            Material wireFrameMat = new Material(JmeGame.gameContext.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
            wireFrameMat.setColor("Color", ColorRGBA.White);

            Node node1 = new Node("wheel 1 node");
//            Geometry wheels1 = new Geometry("wheel 1", wheelMesh);
            Spatial wheels1=JmeGame.gameContext.getAssetManager().loadModel("Models/tyre1.j3o");
            ((Node)wheels1).getChild("Cylinder.001").setMaterial(wheelsMat);
            ((Node)wheels1).getChild("Cylinder.002").setMaterial(wireFrameMat);
            wheels1.setLocalScale(0.35f,0.5f,0.35f);
            node1.attachChild(wheels1);
            wheels1.rotate(0, FastMath.PI, 0);
            vehicle.addWheel(node1, new Vector3f(-xOff, yOff, zOff),
                    wheelDirection, wheelAxle, restLength, radius, true);

            Node node2 = new Node("wheel 2 node");
            Spatial wheels2=JmeGame.gameContext.getAssetManager().loadModel("Models/tyre1.j3o");
            ((Node)wheels2).getChild("Cylinder.001").setMaterial(wheelsMat);
            ((Node)wheels2).getChild("Cylinder.002").setMaterial(wireFrameMat);
            wheels2.setLocalScale(0.35f,0.5f,0.35f);
            node2.attachChild(wheels2);
            wheels2.rotate(0, 0, 0);
            vehicle.addWheel(node2, new Vector3f(xOff, yOff, zOff),
                    wheelDirection, wheelAxle, restLength, radius, true);


            Node node3 = new Node("wheel 3 node");
            Spatial wheels3=JmeGame.gameContext.getAssetManager().loadModel("Models/tyre1.j3o");
            ((Node)wheels3).getChild("Cylinder.001").setMaterial(wheelsMat);
            ((Node)wheels3).getChild("Cylinder.002").setMaterial(wireFrameMat);
            wheels3.setLocalScale(0.35f,0.5f,0.35f);
            node3.attachChild(wheels3);
            wheels3.rotate(0, FastMath.PI, 0);
            vehicle.addWheel(node3, new Vector3f(-xOff, yOff, -zOff),
                    wheelDirection, wheelAxle, restLength, radius, false);

            Node node4 = new Node("wheel 4 node");
            Spatial wheels4=JmeGame.gameContext.getAssetManager().loadModel("Models/tyre1.j3o");
            ((Node)wheels4).getChild("Cylinder.001").setMaterial(wheelsMat);
            ((Node)wheels4).getChild("Cylinder.002").setMaterial(wireFrameMat);
            wheels4.setLocalScale(0.35f,0.5f,0.35f);
            node4.attachChild(wheels4);
            wheels4.rotate(0, 0, 0);
            vehicle.addWheel(node4, new Vector3f(xOff, yOff, -zOff),
                    wheelDirection, wheelAxle, restLength, radius, false);

            vehicleNode.attachChild(node1);
            vehicleNode.attachChild(node2);
            vehicleNode.attachChild(node3);
            vehicleNode.attachChild(node4);
            JmeGame.gameContext.getRootNode().attachChild(vehicleNode);
            JmeGame.gamePhysics.getPhysicsSpace().add(vehicle);

            return this;
        }
        public VehicleAutoShop startRealTimeCarSimulation(){

            //setting suspension values for wheels, this can be a bit tricky
            //see also https://docs.google.com/Doc?docid=0AXVUZ5xw6XpKZGNuZG56a3FfMzU0Z2NyZnF4Zmo&hl=en
            float stiffness =30.0f;//200=f1 car
            float compValue = 0.5f; //(should be lower than damp)
            float dampValue = 3f;
            //compression force of spring(Shock Producer)
            vehicle.setSuspensionCompression(compValue * 2.0f * FastMath.sqrt(stiffness));
            //stretch force of spring(Shock Absorber)
            vehicle.setSuspensionDamping(dampValue * 2.0f * FastMath.sqrt(stiffness));
            vehicle.setSuspensionStiffness(stiffness);
            vehicle.setMaxSuspensionForce(FastMath.pow(2, 20));

            return this;
        }

    }
}

Adding the wheels would be of the same convention , just recall or assume or imagine that the axes of symmetry of the car are a vertical & 2 horizontals meeting at the origin point of the iso-electric line vector(0,0,0) which resembles the center of the car , one of them runs into the screen or towards the front of the car & the other runs towards the right door of the car .

Many thanks.

But my question is a little different.

for example I have two cities. New York and Chicago. And each city has its own grid of coordinates, its own terrain, its own objects. I am trying to simulate this and place players there. But in order not to draw each city with each other in the same coordinate grid, I want to separate them. Each city has its own coordinate with x-0 y-0 z-0 at centr.

But now I have two cities superimposed on each other if i attach node Chicago and node New-York to rootNode

1 Like

for one solution, Each grid should have:

  • own Node each grid (that should also split for PBR/Non-PBR/Glass/ETC nodes if need)
  • own terrain (best custom one)
  • ECS grid cache lists (optimization)
  • Physics space each grid (avoid float accuracy loss fix)
  • Physics transition between spaces(hard work, but physics objects should work between grids) Can be skipped if transition = reload map.
  • Map center should be player, or grid center (avoid float accuracy loss fix)
  • Network structure to match LOD/Grid based sending data. (i like Monkey-Netty so can suggest)

okay first off , you must know GameStatesor GameEntities by heart , in which you can create gameStates named NewyorkCity & Chicago that basically extends BaseAppState which will encoperate & engage your code inside the update(tpf:Float); method that’s the game loop , so inside this appState you will have a method that spawn the city according to the title parameter being given to another class which we will name it by Worldmap.

Example :

public class NewyorkCity extends BaseAppState{
private BulletAppState bulletAppState;
public NewyorkCity(BulletAppState bulletAppState){
    this.bulletAppState=bulletAppState;
}
@Override
public void initialize(){
    Spatial nycSpatial=getAssetManager().loadModel("Scenes/Worlds/NYC.j3o");
     nycSpatial.setName("NYC");
     nycSpatial.setLocalTranslation(0,0,0);
     nycSpatial.addControl(new RigidBodyControl(0));
    getRootNode.attach(nycSpatial);
     bulletAppState.getPhysicsSpace().add(nycSpatial);
}  
public void onStop(){
 rootNode.detachAll();
 bulletAppState.getPhysicsSpace().remove(getRootNode().getChildByName("NYC"));
} 
}
public class Chicago extends BaseAppState{
private BulletAppState bulletAppState;
public Chicago(BulletAppState bulletAppState){
    this.bulletAppState=bulletAppState;
}
@Override
public void initialize(){
    Spatial chicagoSpatial=getAssetManager().loadModel("Scenes/Worlds/chicagoSpatial.j3o");
     chicagoSpatial.setName("Chicago");
     chicagoSpatial.setLocalTranslation(0,0,0);
     chicagoSpatial.addControl(new RigidBodyControl(0));
    getRootNode.attach(chicagoSpatial);
     bulletAppState.getPhysicsSpace().add(chicagoSpatial);
} 
public void onStop(){
 rootNode.detachAll();
 bulletAppState.getPhysicsSpace().remove(getRootNode().getChildByName("Chicago"));
} 
}
public class WorldMap{
public static final enum Worlds{NYC,Chicago};
private Node rootNode;
private BulletAppState bulletAppState;
private Statemanager stateManager;
public WorldMap(Node rootNode,BulletAppState bulletAppState,StateManager stateManager){
this.rootNode=rootNode;
this.bulletAppState=bulletAppState;
this.stateManager=stateManager;
}

public void spawnWorld(Worlds world){
         if(stateManager.hasState(stateManager.getState(NewyorkCity.class))){
                  stateManager.detach(stateManager.getState(NewyorkCity.class));
         }
        if(stateManager.hasState(stateManager.getState(Chicago.class))){
                  stateManager.detach(stateManager.getState(Chicago.class));
         }
    switch(world){
      case NYC:
         stateManager.attach(new NewyorkCity(bulletAppState));
         break;

      case Chicago : 
         stateManager.attach(new Chicago(bulletAppState));
        break;
}
}
}

so ., this might be a simple example but there far more than this , you could have wrap all these in a single class & extend it for the other 2 classes to customize each world apart.

Please donot copy paste the code , use your own after understanding it , make sure to be online with the wiki :

1 Like

Hey), yes. I begin understend. I will try it) and i will read it more. Thx

1 Like

@TidalPoo , also read this , might benefit you of understanding jme world spaces way more better , when you finish , post your code :slight_smile:

1 Like

If this is a network game then this is a really big topic and you are biting off a lot right away.

Here is a fully working network game (it uses spaceships but the basic principle is the same). Regular Java-POJO style:

ECS style:

Short answer that’s probably not entirely helpful at your skill level: Your world data would be in its own coordinate system and the clients would just render the world around themselves, relative to the camera. The server keeps track of it all and gives each client only what they need. Physics will be the trickiest part… but if you make it that far then you have already done a lot and can ask specific questions with respect to that.

2 Likes

I have no good background about networked games , but I simply made an assumption that’s : the player is rendered first as if it’s a single player game then another player is rendered assuming that it’s a NPC , now that NPC would be moved by other candidate through the same server & the other candidate would have the same way , he will render persons as if they are NPCs that get thier commands from servers .

It’s a giant subject. Too much to even teach the basics here, really.

When you have the case of “New York” and “Chicago”, these places are nowhere near each other and the locations will not accurately fit within the space of “float”.

If your world is continuous where you can drive from New York to Chicago and all places in between then the game world data, game objects, etc. will have global world coordinates kept as ‘double’ locations (instead of ‘float’). A particular client is only seeing their local area of the world, the local objects, etc. The server sends them the world data that they need and they localize it to the camera for ‘float’ scene graph stuff.

If the world is not continuous where New York and Chicago are just different zones connected by a teleporter (train, plane, whatever) then you can get away with zone local coordinates… but then the world data, game objects, etc. locations all include x,y,z and zone. All other stuff holds, basically.

2 Likes

It’s different zones, with zone id, and it’s own x,y,z coord

Jme3 in my case will be used as mathematics, physics on terrain, closed objects, bullets and etc. After math, coordinates of objects, like player, npc and other will be send to client. No cameras, and graphics.

I can basically use a single grid, dividing the zone id into separate nodes and separate bullets. even if the zones overlap each other, then this does not seem to be a problem. But is it correct when i will use GhostObject to find nearly npc?)

The zones are basically different worlds then. They have their own physics space, there own coordinate system, etc…

Each zone otherwise works like a smaller-footprint networked game all its own… just sharing the process and connections.

i’am understand that.

But how to project this in ScenGraph

Scene graph is the view. That’s client.

But even if you were to use a scene graph on the server (no real reason to do so), every zone is its own root node. There is no “rootNode” as you have it in your diagram.

1 Like

You are right about the scene, I guess I’m wrong, don’t need SceneGrapth.
but I will use geometry to calculate physics, collisions, detections, etc., isn’t this a scene graph?

anyway, every zone it’s new class with “public ZONEID extends SimpleApplication”. right?) hmmm, I thought so at first, but it seemed to me there is another way.

That’s seems much like Assassin’s Creed , the player ship got teleporters between world , but I think @TidalPoo wants much simpler .

& This depends on the Frustum far & the Lod ? Or I can calculate the distance between the player & an index & when it reaches the required , the render starts .

No. no non nonnononononon.

public MyGame {
    Map<ZoneId, AllTheGameStuff> zones
}

Only ONE application per application. Else how many applications do you want in your application and should those applications have 60 applications in them? What does application even mean.

Just one.

No. Network sending stuff. The server will only send Zone(“Chicago”) to the client that is in Chicago. The client in New York will not have any data, no message traffic, no geometry, no single thing from Zone(“Chicago”)

If you want to learn about network gaming then maybe start another thread to start from the basics and not derail this one.

You will use all of that stuff… then cram it into a physics space that’s just going to set world positions and ignore the “graph”. There is no hierarchy. All of the RigidBody objects are just “in the zone space”. Root level.

You can use a scene graph on the server but it is mostly unnecessary. Unless you will have skeleton based animation on the server driving physics parts then you don’t even need Spatials after you have collision shapes.

Edit: this advice is probably going to fall on deaf ears as it does 95% of the time… but an MMO is the hardest place to start. If you want to learn network gaming then I suggest making a simpler network game first. You will learn 1000 things that you don’t know yet and they will all be relevant to a larger project.