Hello,
Maybe i’ve taken completely the wrong approach from the beginning, but here’s my situation so far:
I generate random 2D bitmaps, each pixel being either “open” or “closed”. Then, i create the user at 0,0, the origin, and he never actually moves, but since it’s supposed to be an infinite dungeon, i preferred to have the world around him move instead. So, i have set this FlyCam with a speed of 0.
I created all these walls, roof and floor, which are simple quads, and then attached them to a “view” node, which is attached to the root node. When the player moves, i simply apply a translation on the view node, detach the walls that are too far and attach some new ones that are within view distance.
So far, it’s working, but i’m wondering if there’s a better way of doing things. I mean, especially since it’s supposed to be near-infinite, i was afraid of losing precision within a certain range once the player has reached far enough, hence the player not moving and staying at 0,0. But i’m afraid this has limited me more than anything…
Also, i have to keep the origin of the dungeon always in memory (ie- the player’s spawn point) for example 43280, 11002, which is the 2D coord of where i start drawing the original view radius. Which means that since i’m moving the view node, i always have to add the difference between the spawn point and the current position in the 2D map to the new walls that are added instead, of say, adding them at max view distance (which is 32 world units) which is yet again error prone.
Any advices or suggestions?
The main point here is that this whole thing is a hack, you really prefer to have infinite coords and no precision issues. So the best way to handle it would be to make it transparent to the gameplay code. So e.g. it thinks the player is at 43280, 11002 and the walls are near that point, etc. You only want the player to “appear” at the origin for your rendering/drawing code, the gameplay code should never realize that.
So, i’m wondering, what’s the best way of doing this?
Should i create One Big Mesh which would be 32x32 “blocks” and move it instead of the player? Because right now, each quad is it’s own mesh, but if i have to go through 32x32x6 (6 possible walls/quads per block), to move each quad independently each time the player moves, it’s going to be a lag festival.
Is there a way to attach already created mesh or geometry together to form one big Mesh?
Also, will I be able to edit this Big Mesh to remove and add only parts to it rather than rebuilding it from scratch each time?
Just create a node and attach everything to it except the player, then apply transforms to the node.
Ah the ol’ keep the player in the center and move the entire world trick.
It’s an oldie but still a goody.
~FlaH
So, anyone has an example or know a book or something on the subject?
I’ve been hacking at this the whole week and i can’t seem to figure it out.
I think i may have over-complicated things, so i’ll probably just revert to the camera/player moving around the world.
Here’s my viewManager code, if anyone bothers…
Omg, i just saw my post. Is there a way to put the code in sblock or something?
[java]
public class ViewManager {
//debug
private boolean DEBUG = true;
private Node viewNode;
private AssetManager assetManager;
private WorldManager worldMan;
private Config config;
private Camera cam;
private Location2D viewLocation;
private Vector3f centerVector;
//arrays
private Texture[] texture;
private Geometry[][][] renderedBlock;
//store config info
private int viewDist;
private int moduleSize;
private int blockSize;
private String pass;
//view array
private int[][] view;
private int[][] module;
private int[][][] modules;
public ViewManager( Node viewNode, AssetManager assetManager, WorldManager worldManager,
Texture[] texture, Camera cam, Config config, Location2D origin){
this.viewNode = viewNode;
this.assetManager = assetManager;
this.worldMan = worldManager;
this.texture = texture;
this.config = config;
this.cam = cam;
viewLocation = new Location2D(origin.getModulePos().x, origin.getModulePos().y,
origin.getBlockPos().x, origin.getBlockPos().y );
//from config
viewDist = config.wVIEW_DIST;
moduleSize = config.wMODULE_SIZE;
blockSize = config.wBLOCK_SIZE;
pass = config.oBASE_PASS;
//set arrays
view = new int[(viewDist2)+1][(viewDist2)+1];
module = new int[moduleSize][moduleSize];
modules = new int[9][moduleSize][moduleSize];
//here we add +1 because of the “0” position since we have [-viewDist, 0, +viewDist] scale
renderedBlock = new Geometry[viewDist2+1][viewDist2+1][6];
}
public void createInitialView(Location2D viewerLocation){
System.out.println(“Loading current modules. (VIEW MANAGER)”);
loadModules(viewerLocation);
//the viewNode is at 0,0 (except to center the player, but 0,0 in map position)
//we have to move it so that the player is in the middle
viewNode.move(-(viewerLocation.getBlockPos().x), 0, -(viewerLocation.getBlockPos().y));
//center vector to move things by so the player is centered in his starting tile
centerVector = new Vector3f(-(blockSize/2),0,(blockSize/2));
calculateWallView(viewerLocation);
}
private void calculateWallView(Location2D viewerLocation){
System.out.println("(VIEW) debug calculate()");
System.out.println("(VIEW) viewerLoc: " + viewerLocation.getBlockPos().x + “,” + viewerLocation.getBlockPos().y);
for(int i = 0; i < view.length; i++){
for (int j = 0; j < view.length; j++){
//view location - viewDist -1 (for the zero) + loop
float viewX = viewerLocation.getBlockPos().x - (viewDist) + j;
float viewY = viewerLocation.getBlockPos().y - (viewDist) + i;
System.out.println(“VX/Y: " + viewX + “,” + viewY + “(”+j+”,"+i+")");
view[j] = modules [4] [ (int) viewX][ (int) viewY];
}
}
// if(true) return;
if(DEBUG) System.out.println(“calculating wall geometry in the view…”);
float mapX, mapY;
for(int i = (0-(viewDist)); i < viewDist+1; i++){
for(int j = (0-(viewDist)); j < viewDist+1; j++){
if(DEBUG) System.out.println(“nn(VIEW) i= " + i + " j= " + j);
mapX = viewerLocation.getBlockPos().x + j;
mapY = viewerLocation.getBlockPos().y + i;
if(DEBUG) System.out.println(”(VIEW) Checking neighbors ("+mapX+","+mapY+")");
int[] neighbors = getNeighbors( (int) mapX, (int) mapY);
if(DEBUG) System.out.println(“Done”);
if(DEBUG) System.out.println("(VIEW) rendereckBlock : " + (j+viewDist) + “,” + (i+viewDist) + " “);
Block b = new Block( assetManager, j, i, modules[4] [(int) mapX][(int) mapY],neighbors, texture, config);
if(DEBUG) System.out.println(”(VIEW) trying renderedBlock[+" + (j+viewDist) + “][”+ (i+viewDist) +"]…");
renderedBlock[j+viewDist][i+viewDist] = b.getGeom();
if(!DEBUG){
for(int z = 0; z < 6; z++){
if (renderedBlock[j+viewDist][i+viewDist][z] != null){
Vector3f moveVec = new Vector3f();
moveVec = viewNode.getLocalTranslation().negate();
renderedBlock[j+viewDist][i+viewDist][z].move(moveVec);
renderedBlock[j+viewDist][i+viewDist][z].move(centerVector);
viewNode.attachChild( renderedBlock[j+viewDist][i+viewDist][z] );
}
}
}else{ //floor only
if (renderedBlock[j+viewDist][i+viewDist][5] != null){
Vector3f moveVec = new Vector3f();
moveVec = viewNode.getLocalTranslation().negate();
renderedBlock[j+viewDist][i+viewDist][5].move(moveVec);
renderedBlock[j+viewDist][i+viewDist][5].move(centerVector);
viewNode.attachChild( renderedBlock[j+viewDist][i+viewDist][5] );
}
}
}
}
if(DEBUG) System.out.println("(VIEW) Done calculating wall geometry.");
}
public void move( String action, Player player){
float speed = player.getWalkSpeed();
Vector3f direction = cam.getDirection();
Vector3f viewMove = new Vector3f();
if(action.equals(“Forward”)){
direction.negateLocal();
direction.multLocal(speed);
viewMove = direction;
}
else if(action.equals(“Backward”))
{
direction.multLocal(speed);
viewMove = direction;
}
else if(action.equals(“Strafe Right”))
{
Vector3f strafe = cam.getLeft();
strafe.multLocal(speed);
viewMove = strafe;
}
else if(action.equals(“Strafe Left”))
{
Vector3f strafe = cam.getLeft();
strafe.negateLocal();
strafe.multLocal(speed);
viewMove = strafe;
}
//add move vector to the view node
moveViewNode(viewMove);
//add vector moves to viewerLocation divided by the blockSize
viewLocation.getBlockPos().x -= (viewMove.getX() / blockSize);
viewLocation.getBlockPos().y -= (viewMove.getZ() / blockSize);
if (DEBUG) debugShowPos(player);
if ( (int) player.getLocation().getBlockPos().x != (int) viewLocation.getBlockPos().x ||
(int) player.getLocation().getBlockPos().y != (int) viewLocation.getBlockPos().y ){
if(DEBUG) System.out.println("!!!Should update!!!");
//get the direction in which the player is going
String dir = getDirection(player.getLocation(), viewLocation);
if(DEBUG) System.out.println("Direction: " + dir);
player.getLocation().setBlockPos((int) viewLocation.getBlockPos().x, (int) viewLocation.getBlockPos().y);
updateViewArray(viewLocation);
//debugShowView();
detachFarGeom(dir);
updateRenderArray(dir, player.getLocation());
}
}
/*
- return the direction in which the player has moves on the 2D map
-
@param player: player’s location before the move
-
@param view: current view’s position after the move
/
private String getDirection(Location2D player, Location2D view){
if((int)player.getBlockPos().x < (int)view.getBlockPos().x){
return “East”;
}
if( (int) player.getBlockPos().x > (int) view.getBlockPos().x ){
return “West”;
}
if((int) player.getBlockPos().y < (int) view.getBlockPos().y){
return “South”;
}
if((int) player.getBlockPos().y > (int) view.getBlockPos().y){
return “North”;
}
return “ERROR”;
}
/
- will move the renderedBlock array so that it matches the current view
-
@param direction: direction in which the playes is moving
- @param viewLocation: new location
/
private void updateRenderArray(String direction, Location2D viewLocation){
int arrayLength = (viewDist2)+1;
Geometry[][][] temp = new Geometry[viewDist2+1][viewDist2+1][6];
temp = renderedBlock.clone();
if(direction.equals("East")){ //move array to the left
for (int y = 0; y < arrayLength; y++){
for (int x = 0; x < arrayLength-1; x++){ //-1 because the last column will be replaced
renderedBlock[x][y] = temp[x+1][y].clone();
}//end for x
//add new values in the array
int mapX, mapY;
mapX = (int) viewLocation.getBlockPos().x + viewDist;
mapY = (int) viewLocation.getBlockPos().y + (-viewDist + y);
int[] neighbors = getNeighbors( (int) mapX, (int) mapY);
Block b = new Block( assetManager, viewDist, y, modules[4] [mapX][mapY],neighbors, texture, config);
renderedBlock[viewDist][y] = b.getGeom();
if (renderedBlock[viewDist][y][5] != null){
System.out.println("nn
");
System.out.println("block init: "+renderedBlock[viewDist][y][5].getWorldTranslation() );
//renderedBlock[viewDist][y][5].move(452.5f,0,401.5f);
//renderedBlock[viewDist][y][5].move(centerVector.negate());
viewNode.attachChild(renderedBlock[viewDist][y][5]);
float blockX = viewLocation.getBlockPos().x + 0.5f;
float blockY = viewLocation.getBlockPos().y - 0.5f -2;
renderedBlock[viewDist][y][5].move(blockX, 0, blockY);
System.out.println("view: " + viewNode.getWorldTranslation());
System.out.println("player: " + viewLocation.getBlockPos().toString() );
System.out.println("centerv: " + centerVector);
System.out.println("block: " + renderedBlock[viewDist][y][5].getLocalTranslation().negate());
}
}//end for y
}//end if
if(direction.equals("West")){ //move array to the right
for (int y = 0; y < arrayLength; y++){
for (int x = (arrayLength-1); x >= 1; x--){
renderedBlock[x][y] = renderedBlock[x-1][y];
}//end for x
}//end for y
}//end if
if(direction.equals("North")){ //move array down
for (int y = (arrayLength-1); y >= 1; y--){
for (int x = 0; x < arrayLength; x++){
System.out.println("("+x+","+y+")");
renderedBlock[x][y] = renderedBlock[x][y-1];
}//end for x
}//end for y
}//end if
if(direction.equals("South")){
for (int y = 0; y < arrayLength-1; y++){
for (int x = 0; x < arrayLength; x++){
renderedBlock[x][y] = renderedBlock[x][y+1];
}//end for x
}//end for y
}//end if
}
/*
* will detach all geometry on the opposite side of the player's direction
* @param direction: String with the direction the player has moved
*/
private void detachFarGeom(String direction){
int numBlocksToDetach = (viewDist*2)+1;
if(direction.equals("East")){
for (int i = 0; i < numBlocksToDetach; i++){
for (int walls = 0; walls < 6; walls++){
if(renderedBlock[0][walls] != null){
viewNode.detachChild(renderedBlock[0][walls]);
}//end if geom = null check
}//end for walls
}//end for numBlocksToDetach
}//end if
if(direction.equals("West")){
for (int i = 0; i < numBlocksToDetach; i++){
for (int walls = 0; walls < 6; walls++){
if(renderedBlock[viewDist*2][walls] != null){
viewNode.detachChild(renderedBlock[viewDist*2][walls]);
}//end if geom = null check
}//end for walls
}//end for numBlocksToDetach
}//end if
if(direction.equals("North")){
for (int i = 0; i < numBlocksToDetach; i++){
for (int walls = 0; walls < 6; walls++){
if(renderedBlock[viewDist*2][walls] != null){
viewNode.detachChild(renderedBlock[viewDist*2][walls]);
}//end if geom = null check
}//end for walls
}//end for numBlocksToDetach
}//end if
if(direction.equals("South")){
for (int i = 0; i < numBlocksToDetach; i++){
for (int walls = 0; walls < 6; walls++){
if(renderedBlock[0][walls] != null){
viewNode.detachChild(renderedBlock[0][walls]);
}//end if geom = null check
}//end for walls
}//end for numBlocksToDetach
}//end if
}
private void updateViewArray(Location2D viewerLocation){
for(int i = 0; i < view.length; i++){
for (int j = 0; j < view.length; j++){
float viewX = viewerLocation.getBlockPos().x - viewDist + j;
float viewY = viewerLocation.getBlockPos().y - viewDist + i;
view[j] = modules [4] [ (int) viewX][ (int) viewY];
}
}
}
private void moveViewNode(Vector3f vec){
//add new move vector
viewNode.setLocalTranslation( viewNode.getLocalTranslation().add(vec) );
//always reset the Y value to 0 (so player stays at the same height)
//should be changed for jumping
viewNode.setLocalTranslation( viewNode.getLocalTranslation().getX(), 0, viewNode.getLocalTranslation().getZ() );
}
private void debugShowPos(Player player){
if(DEBUG){
System.out.println("n
");
System.out.println("Player: " + player.getLocation().toString());
//System.out.println("Origin: " + origin.toString());
System.out.println("cam at: " + viewLocation.getBlockPos().x+
"," + viewLocation.getBlockPos().y);
System.out.println("
");
System.out.println("Map2D coords:");
System.out.println("Player: " + (int)player.getLocation().getBlockPos().x+ "," +
(int) player.getLocation().getBlockPos().y);
//System.out.println("Origin: " + origin.toString());
System.out.println("cam at: " + (int) viewLocation.getBlockPos().x+
"," + (int) viewLocation.getBlockPos().y);
}
}
private int[] getNeighbors(int modX, int modY){
int[] n = new int[4];
//north neighbor
n[0] = modules [4] [modX] [modY - 1];
//west
n[1] = modules [4] [modX - 1] [modY];
//east
n[2] = modules [4] [modX + 1] [modY];
//south
n[3] = modules [4] [modX ] [modY + 1];
return n;
}
private void loadModules(Location2D viewerLocation){
for(int i = 0; i < 9; i++){
if(DEBUG){
System.out.println("Loading modules "+i+" ...");
}
switch(i){
case 0:{//up left
Location2D v = new Location2D(viewerLocation.getModulePos().x -1,
viewerLocation.getModulePos().y -1,
0.0f, 0.0f);
module = worldMan.LoadTextChunk(v, moduleSize, pass);
break;
}
case 1:{//up
Location2D v = new Location2D(viewerLocation.getModulePos().x ,
viewerLocation.getModulePos().y -1,
0.0f, 0.0f);
module = worldMan.LoadTextChunk(v, moduleSize, pass);
break;
}
case 2:{//up right
Location2D v = new Location2D(viewerLocation.getModulePos().x +1,
viewerLocation.getModulePos().y -1,
0.0f, 0.0f);
module = worldMan.LoadTextChunk(v, moduleSize, pass);
break;
}
case 3:{//left
Location2D v = new Location2D(viewerLocation.getModulePos().x -1,
viewerLocation.getModulePos().y ,
0.0f, 0.0f);
module = worldMan.LoadTextChunk(v, moduleSize, pass);
break;
}
case 4:{//center
module = worldMan.LoadTextChunk(viewerLocation, moduleSize, "Base5");
break;
}
case 5:{//right
Location2D v = new Location2D(viewerLocation.getModulePos().x +1,
viewerLocation.getModulePos().y ,
0.0f, 0.0f);
module = worldMan.LoadTextChunk(v, moduleSize, pass);
break;
}
case 6:{//down left
Location2D v = new Location2D(viewerLocation.getModulePos().x -1,
viewerLocation.getModulePos().y +1,
0.0f, 0.0f);
module = worldMan.LoadTextChunk(v, moduleSize, pass);
break;
}
case 7:{//down
Location2D v = new Location2D(viewerLocation.getModulePos().x ,
viewerLocation.getModulePos().y +1,
0.0f, 0.0f);
module = worldMan.LoadTextChunk(v, moduleSize, pass);
break;
}
case 8:{//down right
Location2D v = new Location2D(viewerLocation.getModulePos().x +1,
viewerLocation.getModulePos().y +1,
0.0f, 0.0f);
module = worldMan.LoadTextChunk(v, moduleSize, pass);
break;
}
}
for (int j = 0; j< moduleSize; j++){
for(int k = 0; k < moduleSize; k++){
modules[k][j] = module[k][j];
}
}
}
System.out.println("Base loaded");
}
public void debugShowView(){
System.out.println("view array length: " + view.length );
for(int i = 0; i < view.length; i++){
for(int j = 0; j < view.length; j++){
if(j == viewDist && i == viewDist){
System.out.print("X ");
}else{
System.out.print(view[j]/100+ " ");
}
}
System.out.println("");
}
}
public void debugShowRenderArray(){
System.out.println("RenderArray length: " + renderedBlock.length);
for(int i = 0; i < renderedBlock.length; i++){
for(int j = 0; j < renderedBlock.length; j++){
if(j == viewDist && i == viewDist){
System.out.print("X ");
}else{
if(renderedBlock[j][5]!= null){
System.out.print("0 ");
}else{
System.out.print("w ");
}
}
}
System.out.println("");
}
}
}
[/java]