• Advertisement
  • entries
    18
  • comments
    36
  • views
    17878

About this blog

a browser game with mmorts elements along with a few rpg too.

Entries in this blog

Hello GameDev, 

This entry is going to be a big one for me, and it's going to cover a lot.  What I plan to cover on my recent development journey is the following:

1 - Goal of this Blog entry.

2 - Lessons learned using Node.js for development and testing as opposed to Chrome console.

3 - Linear Path algorithm for any surface.

4 - Dynamic Path Finding using Nodes for any surface, incorporating user created, dynamic assets.

5 - short term goals for the game.

-- - -- - -- - -- - -- - -- - Goal of this Blog entry - -- - -- - -- - -- - -- - --

My goal for this adventure is to create a dynamic path-finding algorithm so that:
- any AI that is to be moved will be able to compute the shortest path from any two points on the surface of the globe.
- the AI will navigate around bodies of water, vegetation, dynamic user assets such as buildings and walls.
- will compute path in less then 250 milliseconds.

5a737586448c5_Screenshotfrom2017-12-2021-28-04.thumb.png.ce24aed24ba92ae43cede325f984f5ff.png

There are a few restrictions the AI will have to follow, in the image above you can see land masses that are cut off from one another via rivers and bodies of water are uniquely colored.  If an AI is on a land mass of one color, for now, it will only be able to move to a location on the same colored land mass.  However; there are some land masses that take up around 50% of the globe and have very intricate river systems.  So the intended goal is be able to have an AI be on one end of the larger land mass and find the shortest path to the opposite end within 250 milliseconds.
Currently my path finding algorithm can find the shortest path in anywhere from 10 ms and up, and when I say up, I mean upwards of 30 seconds, and that's because of the way I built the algorithm, which is in the process of being optimised.

-- - -- - -- - -- - -- - -- - Lessons learned using Node.js for development and testing - -- - -- - -- - -- - -- - --

As of this writing I am using Node.js to test the efficiency of my algorithms.  This has slowed down my development.  I am not a programmer by trade, I've taught myself the bulk-work of what I know, and I often spend my time re-inventing the wheel and learning things the hard way.  Last year I made the decision to move my project over to Node.js for continued development, eventually it all had to be ported over to Node.js anyways.  In hind sight I would have done things differently.  I would have continued to use Chrome console for testing and development, small scale, then after the code was proven to be robust would I then port it over to Node.js.  If there is one lesson I'd like to pass on to aspiring and new programmers, it's this, use a language and development environment that allows you, the programmer, to jump into the code while it's running and follow each iteration, line by line, of code as it's be executed, basically debugging.  It is so easy to catch errors in logic that way. Right now I'm throwing darts at a dart board, guesses what I should be sending to the console for feedback to help me learn more about logical errors using Node.js, see learning the hard way.

-- - -- - -- - -- - -- - -- - Linear Path algorithm for any surface. - -- - -- - -- - -- - -- - --

In the blog entry above I go into detail explaining how I create a world. The important thing to take away from it is that every face of the world has information about all surrounding faces sharing vertices pairs.  In addition, all vertices have information regarding those faces that use it for their draw order, and all vertices have information regarding all vertices that are adjacent to them.

An example vertices and face object would look like the following:

Vertices[ 566 ] = { 
  ID: 566,
  x: -9.101827364,
  y: 6.112948791,
  z: 0.192387718,
  connectedFaceIDs: [ 90 , 93 , 94 , 1014 , 1015 , 1016 ], // clockwise order
  adjacentVertices: [ 64 , 65 , 567 , 568 , 299 , 298 ] // clockwise order
} 

Face[ 0 ] = {
  ID: 0,
  a: 0,
  b: 14150,
  c: 14149,
  sharedEdgeVertices: [ { a:14150 , b: 14149 } , { a:0 , b: 14150 } , { a:14149 , b:0 } ], // named 'cv' in previous blog post
  sharedEdgeFaceIDs: [ 1 , 645 , 646 ], // named 's' in previous blog post
  drawOrder: [ 1 , 0 , 2 ], // named 'l' in previous blog post
}

Turns out the algorithm is speedy for generating shapes of large sizes. :) My buddy who is a Solutions Architect told me I'm a one trick pony, HA!

5a738051dc4c1_Screenshotfrom2018-02-0115-00-08.thumb.png.b2adf356b6506f7d284a54c1b24abe8f.png

Anyways, this algorithm comes in handy because now if I want to identify a linear path along all faces of a surface, marked as a white line in the picture above, you can reduce the number of faces to be tested, during raycasting, to the number of faces the path travels across * 2.

To illustrate, imagine taking a triangular pizza slice which is made of two faces, back to back.  the tip of the pizza slice is touching the center of the shape you want to find a linear path along, the two outer points of the slice are protruding out from the surface of the shape some distance so as to entirely clear the shape.  When I select my starting and ending points for the linear path I also retrieve the face information those points fall on, respectively.  Then I raycaste between the sharedEdgeVertices, targeting the pizza slice.  If say a hit happens along the sharedEdgeVertices[ 2 ], then I know the next face to test for the subsequent raycaste is face ID 646, I also know that since the pizza slice comes in at sharedEdgeVertice[ 2 ], that is it's most likely going out at sharedEdgeVertices[ 1 ] or [ 0 ].  If not [ 1 ] then I know it's 99% likely going to be [ 0 ] and visa-versa.  Being able to identify a linear path along any surface was the subject of my first Adventure in Robust Coding.  Of course there are exceptions that need to be accounted for.  Such as, when the pizza slice straddles the edge of a face, or when the pizza slice exits a face at a vertices.

Sometimes though when I'm dealing with distances along the surface of a given shape where the pizza slice needs to be made up of more than one set of back to back faces, another problem can arise: I learned about the limitations of floating point numbers too, or at least that's what it appear to be to me.  I'm sure most of you are familiar with some variation of the infinite chocolate bar puzzle

chocolatePuzzle.jpg.d663364ab230157cc0927a12a849b168.jpg

So with floating point numbers I learned that you can have two faces share two vertices along one edge, raycaste at a point that is directly between the edges of two connecting faces, and occasionally, the raycaste will miss hitting either of the two faces.  I attribute this in large part because floating point numbers only capture an approximation of a point, not the exact point.  Much like in the infinite chocolate bar puzzle there exists a tiny gap along the slice equal in size to the removed piece, like wise, that tiny gap sometimes causes a miss for the raycaste.  If someone else understands this better please correct me.

-- - -- - -- - -- - -- - -- - Dynamic Path Finding using Nodes for any surface - -- - -- - -- - -- - -- - --

Now that I've got the linear path algorithm working in tip top shape, I use it in conjunction with Nodes to create the pathfinding algorithm.

Firstly I identify the locations for all nodes. I do this using a Class I created called Orientation Vector, I mention them in the blog post above.  When they're created, they have a position vector, a pointTo vector, and an axis vector.  The beauty of this class is that I can merge them, which averages their position, pointTo, and axis vectors, and it allows me to rotate them along any axis, and it allows me to move them any distance along the axis of their pointTo vector.

5a7389dbe00a6_Screenshotfrom2018-02-0114-58-57.thumb.png.b2e1647b01019680901b46c2f490eade.png

5a7389e66c2e2_Screenshotfrom2018-02-0114-58-18.thumb.png.1a68cd884e56cda9937bc6b7b156aac0.png

To create shoreline collision geometry, and node collision geometry, illustrated above, and node locations along shorelines, illustrated below, I utilise the Orientation Vector Class.

5a738d1a2479c_Screenshotfrom2018-02-0115-35-27.thumb.png.33c5aa6db67508c5be5782c0b2820183.png

Firstly, the water table for the world is set to an arbitrary value, right now it's 1.08, so if a vector for a given face falls below the table and one or two vertors are above the table then I know the face is a shoreline face.  Then I use simple Math to determine at what two points the face meets the water and create two OVectors, each pointing at each-other.  Then I rotate them along their y axis 90 and -90 degrees respectively so that they are now facing inland.  Since each face, which are shoreline faces, touch one another, there will be duplicate OVectors a each point along the shore.  However, each Ovector will have a pointTo vector relative to it's sister Ovector during creation.  I merge the paired Ovectors at each point along the shore, this averages their position, pointTo and axis.  I then move them inland a small distance.  The result is the blue arrows above. The blue arrows are the locations of three of the thousands of nodes created for a given world.  Each Node has information about the shoreline collision geometry, the node collision geometry ( the geometry connecting nodes ), and the Node to its left and the Node to its right.  Each face of collision geometry is given a Node ID to refer to.

So to create the path-finding algorithm. I first identify the linear path between the starting and ending points.  I then test each segment of the linear path for collision geometry. If I get a hit, I retrieve the Node ID.  This gives me the location for the Node associated for a given face of collision geometry.  I then travel left and right along connecting Nodes checking to see if a new Linear path to the end point is possible, if no immediate collision geometry is encountered, the process continues and is repeated as needed.  Subsequently, a list of points is established, marking the beginning, encountered Nodes and end of the line of travel.  The List is then trimmed by testing linear paths between every third point, if a valid path is found, the middle point is spliced.  Then all possible paths that have been trimmed are calculated for distance.  the shortest one wins.

Below is the code for the algorithm I currently use.  its my first attempt at using classes to create an algorithm.  Previously I just relied on elaborate arrays.

Spoiler

function PATHFINDER_findPath( TGm , Pt , nodes , o , e , testAssets ){

	e.currentProcesses ++;

	var sN , eN , Br=[] , pIdx=[];

	sN = new oNode( o.point1.clone() );
	sN.fID = o.id1;
	sN.pID = o.p1;
	sN.gID = o.g1;
	sN.ID = o.ID1;

	eN = new oNode( o.point2.clone() );
	eN.fID = o.id2;
	eN.pID = o.p2;
	eN.gID = o.g2;
	eN.ID = o.ID2;

	Br.push( new oBranch( sN , eN ) );
	Br[0].setDirection( true );

	var br , p , p1 , i , d , d2 , d3;
	var info = [], ID , IN, seQ = false;

	

	//// rewrite ////
	// Cycle through all branches
	for( var a=0; a<Br.length; a++ ){

		br = Br[ a ];

		// first do one raycaste to see if the starting nodes parent is in the way.

		// second check if path between branchTestStart and branchTestEnd
		nodeTOobject( br.start() , br.end() , o );

		//console.dir( o );
		// determine if path exists in pathIndex
		// possibly entertain idea of storing path information perminently.
		p = pathINDEX.getPath( br.startID() , br.endID() );

		if( p == false ){

			ID = PATHFINDER_firstCheck( br.start() , br.end() , Pt[ br.getParent( br.branchTestStart ) ] , o );
		 	if( ID > -1 ){
		 		IN = false;
		 	} else {
				p = new oPath( definePathLocal( TGm , o , false ) );
				info = PATHFINDER_checkPathValidity( p , Pt );
				ID = info[0];
				IN = info[1];
			}

		} else {
			ID = -1;
			IN = false;
		}	


		if( e.pathReadout ){ 
			if( ID > -1 ){
				console.log( 'BRANCH == startID: ' + br.startID() + ' endID: ' + br.endID() );
				console.log( 'BRANCH == A: ' + a + ' ID: ' + ID + ' IDa: ' + nodes[ ID ].IDa + ' IDb: ' + nodes[ ID ].IDb + ' IN: ' + IN );
			} else {
				console.log( 'BRANCH == startID: ' + br.startID() + ' endID: ' + br.endID() );
				console.log( 'BRANCH == A: ' + a + ' ID: ' + ID + ' IDa: -1 IDb: -1 IN: ' + IN );
			}
			
		}

		if( ID > -1 ){
			if( br.endID() == nodes[ ID ].IDb && br.getDirection() ){
				if( p != false ){
					if( e.pathReadout ){  console.log( 'over-riding to IDa' ); }
					ID = -1;
				}
			} else if( br.endID() == ID && !br.getDirection() ){
				if( p != false ){
					if( e.pathReadout ){  console.log( 'over-riding to IDb' ); }
					ID = nodes[ ID ].IDb;
					ID = -1;
				}
			}
		}

		if( ID == -1){
			if( e.pathReadout ){ console.log( 'valid path' ); }
			br.setPath( pIdx.length , br.branchTestStart );
			pIdx.push( p.clone() );
			br.setDistance( p.getDistance() , br.branchTestStart );
			br.setDirlog( br.getDirection() , br.branchTestStart );
		}

		if( e.pathReadout ){ console.log( ' ' ); }

		if( ID > -1 ){

			if( br.getNodeEncountered( ID ) && br.getNodeEncountered( nodes[ ID ].IDb ) ){

				// check to see if the next node in this direction is already apart of this nodes listing
				if( br.getDirection() ){
					if( br.getNodeEncountered( nodes[ ID ].IDa ) ){
						
						// continue this path in the true direction according to br.startID();
						if( br.startID() == -1 ){
							if( e.pathReadout ){ console.log( 'REMOVING BRANCH' ); }
							br.destroy();
							Br.splice( a , 1 );
						} else if( br.getNodeEncountered( nodes[ br.startID() ].IDa ) ){

							if( e.pathReadout ){ console.log( 'REMOVING BRANCH' ); }
							br.destroy();
							Br.splice( a , 1 );
						} else {

							br.insertNode( nodes[ nodes[ br.startID() ].IDa ].clone() , br.branchTestEnd );
							br.setNodeEncountered( nodes[ br.startID() ].IDa );

						}
						

					} else {
						// add IDa node to branch.
						br.insertNode( nodes[ nodes[ ID ].IDa ].clone() , br.branchTestEnd );
						br.setNodeEncountered( nodes[ ID ].IDa );
					}
				} else {

					if( br.getNodeEncountered( nodes[ nodes[ ID ].IDb ].IDb ) ){
						// destroy this path
						if( br.startID() == -1 ){
							if( e.pathReadout ){ console.log( 'REMOVING BRANCH' ); }
							br.destroy();
							Br.splice( a , 1 );
						} else if( br.getNodeEncountered( nodes[ nodes[ br.startID() ].IDb ].IDb ) ){
							if( e.pathReadout ){ console.log( 'REMOVING BRANCH' ); }
							br.destroy();
							Br.splice( a , 1 );
						} else {
							br.insertNode( nodes[ nodes[ nodes[ br.startID() ].IDb ].IDb ].clone() , br.branchTestEnd );
							br.setNodeEncountered( nodes[ nodes[ br.startID() ].IDb ].IDb );
						}						
						
					} else {
						// add IDb of IDb node to branch.
						br.insertNode( nodes[ nodes[ nodes[ ID ].IDb ].IDb ].clone() , br.branchTestEnd );
						br.setNodeEncountered( nodes[ nodes[ ID ].IDb ].IDb );
					}

				}

			} else if( br.getNodeEncountered( ID ) && !br.getNodeEncountered( nodes[ ID ].IDb ) ){

				if( br.getDirection() ){
					
					if( br.getNodeEncountered( nodes[ ID ].IDa ) ){
						// switch direction
						// add IDb node to branch
						br.setDirection( false );
						br.insertNode( nodes[ nodes[ ID ].IDb ].clone() , br.branchTestEnd );
						br.setNodeEncountered( nodes[ ID ].IDb );
					} else {
						// create new branch:
						// add IDa node to branch.
						// add IDb to another branch
						br.insertNode( nodes[ nodes[ ID ].IDa ].clone() , br.branchTestEnd );
						br.setNodeEncountered( nodes[ ID ].IDa );

						if( a < e.maxBranchSize /* arbitrary number used, will have to come up with idea */ ) { 
							i = Br.length;
							Br[ i ] = br.clone();
							Br[ i ].insertNode( nodes[ nodes[ ID ].IDb ].clone() , br.branchTestEnd );
							Br[ i ].setNodeEncountered( nodes[ ID ].IDb );
							Br[ i ].setDirection( false );
						}
					}

				} else {
					// add IDb node to branch
					br.insertNode( nodes[ nodes[ ID ].IDb ].clone() , br.branchTestEnd );
					br.setNodeEncountered( nodes[ ID ].IDb );
				}

			} else if( !br.getNodeEncountered( ID ) && br.getNodeEncountered( nodes[ ID ].IDb ) ){

				if( br.getDirection() ){
					// add ID node to branch
					br.insertNode( nodes[ ID ].clone() , br.branchTestEnd );
					br.setNodeEncountered( ID );
				} else {
						
					if( br.getNodeEncountered( nodes[ nodes[ ID ].IDb ].IDb ) ){
						// switch direction
						// add ID node to branch
						br.setDirection( true );
						br.insertNode( nodes[ ID ].clone() , br.branchTestEnd );
						br.setNodeEncountered( ID );
					} else {
						// create new branch:
						// add ID node to branch.
						// add IDb of IDb to another branch
						br.insertNode( nodes[ nodes[ nodes[ ID ].IDb ].IDb ].clone() , br.branchTestEnd );
						br.setNodeEncountered( nodes[ nodes[ ID ].IDb ].IDb );

						if( a < e.maxBranchSize /* arbitrary number used, will have to come up with idea */ ) { 
							i = Br.length;
							Br[ i ] = br.clone();
							Br[ i ].insertNode( nodes[ ID ].clone() , br.branchTestEnd );
							Br[ i ].setNodeEncountered( ID );
							Br[ i ].setDirection( true );
						}
					}
				}

			} else {
				// create new branch:
				// add ID node to branch.
				// add IDb to another branch
				br.setDirection( true );
				br.insertNode( nodes[ ID ].clone() , br.branchTestEnd );
				br.setNodeEncountered( ID );

				if( a < e.maxBranchSize /* arbitrary number used, will have to come up with idea */ ) { 
					i = Br.length;
					Br[ i ] = br.clone();
					Br[ i ].insertNode( nodes[ nodes[ ID ].IDb ].clone() , br.branchTestEnd );
					Br[ i ].setNodeEncountered( ID );
					Br[ i ].setDirection( false );
				}
			}

			a--;

		} else {

			// set the distance
			// increment both start and end
			if( p.getDistance() < 0 ){
				console.log( '--------------------------------------' );
				console.log( "--  something's up with p" );
				console.log( '--------------------------------------' );
				console.log( p );
			}
			br.setDistance( p.getDistance() , br.branchTestStart );
			br.branchTestStart ++;
			br.branchTestEnd ++;

			if( br.branchTestEnd <= br.getTreeLength()-1 ){
				//if( e.pathReadout ){ console.log( 'true, less then' ); }
				a--;
			} else {
				if( e.pathReadout ){ console.log( 'BRANCH COMPLETE' ); }
				br.pathFound = true;
				// Branch is complete.
			}
		}
	}
	//// rewrite ////


	if( e.pathReadout ){ console.log( 'STARTING TRIM' );}

	if( br.getTreeLength() > 2 ){

		// resets start and end.
		for( var a=0; a<Br.length; a++ ){
			Br[ a ].branchTestStart = 0;
			Br[ a ].branchTestEnd = 2;
			if( !Br[ a ].pathFound && e.pathReadout ){
				for( var ii = 0; ii<100; ii++ ){
					console.log( 'BRANCH NOT COMPLETE!!' );
				}
			}	
		}

		// trim branches
		for( var aa=0, A; aa<Br.length; aa++ ){
			br = Br[ aa ];
			br.setOldIndex();
			A=1;
		for( var a=0; a<A; a++ ){
			// 
			
			// first check if path between branchTestStart and branchTestEnd

			//if( br.getTreeLength() < 30 ){

				nodeTOobject( br.start() , br.end() , o );

				// determine if path exists in pathIndex
				// possibly entertain idea of storing path information perminently.
				p = pathINDEX.getPath( br.startID() , br.endID() );
				if( p == false ){

					ID = PATHFINDER_firstCheck( br.start() , br.end() , Pt[ br.getParent( br.branchTestStart ) ] , o );
				 	if( ID > -1 ){
				 		IN = false;
				 	} else {
						p = new oPath( definePathLocal( TGm , o , false ) );
						info = PATHFINDER_checkPathValidity( p , Pt );
						ID = info[0];
						IN = info[1];
					}

				} else {
					ID = -1;
				}

				if( e.pathReadout ){
					console.log( ' ' );
					if( ID > -1 ){
						console.log( 'TRIM == startID: ' + br.startID() + ' endID: ' + br.endID() );
						console.log( 'TRIM == A: ' + aa + ' ID: ' + ID + ' IDa: ' + nodes[ ID ].IDa + ' IDb: ' + nodes[ ID ].IDb + ' IN: ' + IN );
					} else {
						console.log( 'TRIM == startID: ' + br.startID() + ' endID: ' + br.endID() );
						console.log( 'TRIM == A: ' + aa + ' ID: ' + ID + ' IDa: -1 IDb: -1 IN: ' + IN );
					}
				}


				if( ID > -1 ){
					if( br.endID() == nodes[ ID ].IDb && br.getDirlog( br.branchTestStart ) && IN ){
						if( p != false ){
							if( e.pathReadout ){  console.log( 'over-riding to IDa' ); }
							ID = -1;
						}
					} else if( br.endID() == ID && !br.getDirlog( br.branchTestStart ) && IN ){
						if( p != false ){
							if( e.pathReadout ){  console.log( 'over-riding to IDb' ); }
							ID = -1;
						}
					}
				}

				if( ID == -1){
					// path is valid
					// splice previous node if distance is shorter
					d = p.getDistance();
					d2 = br.getDistanceBetweenTwoIndexes( br.branchTestStart , br.branchTestEnd-1 );

					if( e.pathReadout ){ console.log( 'TRIM == D: ' + d + ' D2: ' + d2 ); }

					if( d <= d2){
						// newly tested valid path is shorter
						if( br.branchTestEnd - br.branchTestStart > 2 ){
							br.spliceBetween( br.branchTestStart+1 , br.branchTestEnd-1 );
							//br.branchTestEnd = br.branchTestStart + 2;
						} else {
							br.splice( br.branchTestStart+1 );
						}
						br.setPath( pIdx.length , br.branchTestStart );
						br.setDistance( p.getDistance() , br.branchTestStart );
						pIdx.push( p.clone() );

					} else {
						// newly tested valid path is longer 
						if( e.pathReadout ){ console.log( 'IMPOSSIBLE ++' ); }
						//br.branchTestEnd ++;
					}
					
					br.branchTestStart ++;
					br.branchTestEnd = br.branchTestStart+2;

					if( br.branchTestEnd >= br.getTreeLength()-1 ){

						if( br.compareIndexes() ){
							// this cycle is done
							// allow a to incriment.
							if( e.pathReadout ){ console.log( '::: BRANCH FINISHED :::' ); }
							br.finished();
							seQ = true;

						} else {

							br.branchTestStart = 0;
							br.branchTestEnd = br.branchTestStart+2;
							aa--;
						}

					} else {
						A++;
					}

				} else {
					
					// obsticle encountered. create new path cycle only if nodes are unknown
					// otherwise increment.

					if( !br.getNodeEncountered( ID ) && !br.getNodeEncountered( nodes[ ID ].IDa ) && !br.getNodeEncountered( nodes[ ID ].IDb ) ){

						//nodeTOobject( br.start() , nodes[ ID ] , o );
						nodeTOobject( br.start() , br.end() , o );
						
						if( e.currentProcesses < e.maxDeepProcesses ){
							if( e.pathReadout ){ console.log( 'GOING DEEP ' + e.currentProcesses ); }
							if( e.pathReadout ){ console.log( 'TRIM == start: ' + br.startID() + ' end: ' +  ID ); }
							p = PATHFINDER_findPath( TGm , Pt , nodes , o , e , false );
						} else {
							p = false;
						}

						// may need to check on condition of p;
						if( p == false ){

							// next cycle

						} else {

							d = p.getDistance();
							d2 = br.getDistanceBetweenTwoIndexes( br.branchTestStart , br.branchTestEnd-1 );
							if( e.pathReadout ){ console.log( 'TRIM == D: ' + d + ' D2: ' + d2 ); }

							if( d <= d2){
								// newly tested valid path is shorter
								if( br.branchTestEnd - br.branchTestStart > 2 ){
									br.spliceBetween( br.branchTestStart+1 , br.branchTestEnd-1 );
									//br.branchTestEnd = br.branchTestStart + 1;
								} else {
									br.splice( br.branchTestStart+1 );
								}
								br.setPath( pIdx.length , br.branchTestStart );
								br.setDistance( p.getDistance() , br.branchTestStart );
								pIdx.push( p.clone() );

							} else {
								// newly tested valid path is longer
								if( e.pathReadout ){ console.log( 'IMPOSSIBLE' ); }
							}
						}
					} 
					
					br.branchTestStart ++;
					br.branchTestEnd = br.branchTestStart+2;

					if( br.branchTestEnd >= br.getTreeLength()-1 ){

						if( br.compareIndexes() ){
							// this cycle is done
							// allow a to incriment.
							if( e.pathReadout ){ console.log( '::: BRANCH FINISHED :::' ); }
							br.finished();
							seQ = true;

						} else {

							br.branchTestStart = 0;
							br.branchTestEnd = br.branchTestStart+2;
							aa--;
						}

					} else {
						A++;
					}
				}
			//}
		}
		}
	}

	if( e.pathReadout ){ console.log( Br.length ); }
	

	for( var a=0; a<Br.length; a++ ){
		if( Br[ a ].complete == false ){
			Br[ a ].finished();
		}
	}

	if( e.pathReadout ){ console.log( 'PATH COMPLETE' ); }
	
	// calculate all distances for branches
	if( Br.length > 0 ){

		d = 100000;
		d1 = 0;

		for( var a=0; a<Br.length; a++ ){
			if( Br[ a ].totalDistance < d ){
				d = Br[ a ].totalDistance;
				d1 = a;
			}
		}

		p = new oPath( [] );
		for( var a=0, aa=Br[ d1 ].path.length; a<aa; a++ ){
			d = Br[ d1 ].path[ a ];
			p.concat( pIdx[ d ] );
		}

		if( e.pathReadout ){ console.dir( 'BRANCH ID:: ' + d1 ); }
		if( e.pathReadout ){ console.dir( Br[ d1 ].index ); }
		if( e.pathReadout ){ console.dir( p ); }
		if( e.pathReadout ){ console.dir( p.path.length ); }

		e.currentProcesses --;
		return p;

	} else {

		e.currentProcesses --;
		return false;
	}
}

 

I plan on improving the the process mentioned above by keeping track of distance as each path spreads out from it's starting location.  Only the path which is shortest in distance will go through its next iteration.  With this method, once a path to the end is found, I can bet it will be shortest, so I won't need to compute all possible paths like I am now.

5a7391df0b55f_Screenshotfrom2018-02-0116-16-30.thumb.png.93d104534482f95ccfcb0dc39c2fb1bf.png

The challenge I've been facing for the past two months is sometimes the Nodes end up in the water, The picture above shows a shoreline where the distance the OVectors travel would place them in the water.  Once a node is in the water, it allows the AI to move to it, then there is no shoreline collision geometry for it to encounter, which would keep it on land, and so the AI just walks into the ocean.  Big Booo!  I've been writing variations of the same function to correct the location of the geometry shown below in Red and Yellow below.

5a7393533ae6b_Screenshotfrom2018-02-0116-22-49.thumb.png.7c2af2aae94984708b3bdae2e36ce644.png

But what a long process.  I've rewritten this function time and time again.  I want it to be, well as the title of this Blog states, Robust, but it's slow going.  As of today's date, it's not Robust, and the optimised path-finding algorithm hasn't been written either. 

I'll be posting updates in this blog entry as I make progress towards my goal.  I'll also make mention what I achieve for shortest, long time for pathfinding.  Hopefully it'll be below 250 ms.

-- - -- - -- - -- - -- - -- - short term goals for the game - -- - -- - -- - -- - -- - --

Badly... SO BADLY I want to be focusing on game content, that's all I've been thinking about.  Argh, But this all has to get wrapped up before I can.  I got ahead of myself, I'm guilty of being too eager.  But there is no sense building game content on top of an engine which is prone to errors. 
My immediate goals for the engine are as follows:

// TO DO's //
// Dec 26th 2017 //
/*
*	<< IN PROGRESS >>	-update path node geometry so no errors occur 
*				-improve path finding alg with new technique
*				-improve client AI display -only one geometry for high detail, and one for tetrahedron.
*				-create ability to select many AI at the same time by drawing a rectangle by holding mouse button.
*				-create animation server to recieve a path and process animation, and test out in client with updates.
*				-re-write geometry merging function so that the client vertices and faces have a connected Target ID
*				-incorporate dynamic asset functionality into client.
*				-create a farm and begin writing AI.
*				-program model clusters
* 				-sychronize server and client AI.  Test how many AI and how quickly AI can be updated.  Determine rough estimate of number of players the server can support.
*
*/

see the third last one!  That's the one, oh what a special day that'll be.

I've created a Project page,

please check it out.  It gives my best description to date of what the game is going to be about.  Originally I was going to name it 'Seed', a family member made the logo I use as my avatar and came up with the name back in 2014.  Then just this week I find out that some studio in Europe is making THE EXACT SAME GAME ! WHA??? 

http://www.pcgamer.com/seed-is-a-hugely-ambitious-in-development-mmo-that-echoes-eve-online-rimworld-and-the-sims/

I'm being facetious, but they're very close to being the same game.  Anyways, Mine will be better, you read it here first! hahaha.  The project is no longer going to be called Seed, it's instead going to be called what I've always called it and will probably always call it; the game

[ edit: 02/02/18 
 Some new screen shots to show off.  All the new models were created by Brandross. 
5a753c793e094_Screenshotfrom2018-02-0222-30-55.thumb.png.dec7e089b56972d37f46234dde73783b.png

5a753cc02f7b4_Screenshotfrom2018-02-0222-30-24.thumb.png.5d94565aad026dd8f0bb157e7b00b073.png

There are now three earth materials, clay, stone and marble.  There are also many types of animals and more tree types. ]

Thanks for reading and if you've got anything to comment on I welcome it all.

Awoken

Ground work complete!

Screenshot from 2017-11-17 19-06-42.png

Hello GameDev,

It's been awhile.  I decided to take some time away from screens and focus my time on camping, reading and getting outside.  As a result I've come back to this project with fresh ideas, renewed energy, and summer/fall was fantastic.

Some big milestones for this project have been achieved:  
- 10,000 AI can be simulated moving about a world without major performance issues in Chrome. 
- Dynamic path-finding with decent performance, a few tweaks still need to be made.

With those two accomplishments under the hood I am now starting to think about how this game is going to be played.  Thinking about how this game is going to be played has put this project into perspective for me.  It's taken me 4 years to program everything up to this point, and I don't have a game, just a program that does stuff.  There is no way this project could potentially supplement my income for a long long time and as such I've got to treat it like a hobby, but god it's an addictive one.

When I first began thinking about how people would actually play this game I realised I had no idea.  I knew what I wanted to simulate, but when, where and how someone interacts with the game was beyond me.  So I began playing games again, especially Civ, Galactic Civilisation, addictive cellphone games like Deep Town and Egg, Inc. Along with a few puzzlers and many more.  I've been thinking a lot about what I like about these games, also why I no longer play many of the games I used to.  I realised that a successful game engages the players imagination and makes them want to devote their imagination to it.  Really it's the player that does all the heavy imaginary lifting, and you as the game creator just need to provide a few details to help them along their imaginary journey.   This insight is probably a no brainer for a lot of people, but it's helped me realise what my objective is.

So I am going to literally rip-off elements of other games that capture my imagination and try to ram as many of them into this game as I can.  If I succeed it'll capture the players imagination and be addictive.

The initial inspiration for this idea was cooked up years ago, and that was to play a game that better reflected the economic activity within any society.  I was obsessed with the idea of how money works and why there is so much esoteric babbling surrounding its utility.  What I learned isn't so esoteric but with some long thought experiments involving money I began to understand how and why we have inflation, deflation, market bubbles and so on.  And I want to incorporate all those things into a game, albeit simplified, but reflected none the less.  I want players to have to manage their own floating currencies, it might not be printed monies, but maybe sea shells, or maybe rare bird feathers.  I want to give the player a scenario where they can see the simple machinations of their local trading economies and expand on them to encourage things like individual debt and inflation to see how these things can benefit their end goal (global domination).  All the while engaging with other players in either alliances or rivalries, fighting elements and cultural expansion.

My first goal is to have the AI acquire the resources they need to better their conditions.  When the game starts they will be hungry, thirsty, cold and in need of some social engagement.  They'll slowly improve their conditions by visiting the rivers, gathering wood, and earth.  They'll chat with each other about how to improve their respective abilities and reinforce traditions and tribal bonds.  They'll build huts for themselves and create tools to help with each of their actions.  They will also begin trading with one another, small at first.  Leaders will rise up and begin exerting influence over others either because of circumstance or innate ability.  The player will play as one of the AI.  

Most of what I've described here has been dissected into small chunks that are programmable.  A nagging question I have is will the interactive simulation I create translate clearly to the player?  I'm excited to find out.

[ ::UPDATE:: ] Here is a youtube link to my first desktop video.   It quickly showcases what the world running in Chrome looks and feels like, This world is host to 1000 Simulin.  I also select a few of the Simulin to move.  When you log into the website and sign in you'll be able to join a server that is hosting a world like the one in the video.  Right now all you can do is click on Simulin and get them to move where you want them to.  Over the next couple weeks I'll be implementing the first role your Simulin can take.

Thanks for reading.

Simulin

Well, here they are.

Screenshot from 2017-05-17 11-21-33.png

As of right now, I can simulate the movement of 5000 Simulin simultaneously every frame with minor performance loss. ~1 to 4 frame loss every now and then. seems the minor performance loss is there regardless if it's 1000, 3000 or 5000 Simulin. I'm not sure how many can be simulated on screen at once, but both the browser and server can compute the position of 5000 comfortably.

Screenshot from 2017-05-17 11-23-12.png

I added a bunch of optimisation code to bumb it up from 1500 to 5000. If I tone down the detail of the model I'll be able to display more yet too. Heck if I really wanted to I could just make a box and call it a Simulin, if I did that I could simulate 10000.

Of course they don't do anything other than move like mindless drones. Walking over mountains and love to walk into the oceans never to return. I guess now I'll have to code where they can and can't go. Gonna dig up my old dynamic pathfinding alg and put it to work.

Screenshot from 2017-05-17 11-22-26.png

What does everyone think? Do you like the look of them? They're kind of Roboty in my opinion, not sure if that's a good or bad thing.

Cheers

I've been plugging away at this game full tilt. It's had me thinking a lot about what the hell it is I'm doing with myself and how I've chosen to spend my free time. For the past three years I've been focused on developing various functionality into this project so that when the time came, I could easily tap into the logic necessary for simulating thousands of AI in real time. I wanted this all to be done over the internet so that a player could login to a website, join a server and be in apart of a game session lasting days, possibly even months. But the more functionality I developed, the more I realised I was not working towards what all this effort has been for, and that is to create a game.

Over the past three weeks I created the website, I'm currently in the process of porting over all my code to a node server framework. All the code I've written has been in JavaScript, so other then a few syntax differences the transition has been rather quick. Once a user registers they'll be able to join a game. Here's a screenshot of the websites look.

Screenshot from 2017-05-03 19-42-32.png

Another thing I've been thinking about is that I should share more of the code I've written. I've briefly talked about my sphere generation logic in a previous blog but here is a working example of it, I figure if I've got to come up with one thing that it is possibly worthy of contribution this is it. Unzip the folder before you run the html file, who knows, maybe someone somewhere might find a use for some of the stuff I've written. It's a small contribution to the GameDev community.

sphere.zip

Updating the terrain has been my focus for the last week. The mountains and water edges are looking better. I've added rivers, which look awesome in my opinion, and started to add assets such as Pine trees and wolves ;) to the world builds. I've included a short album showcasing some of the newer look.

If anyone is interested in contributing content for this game such as trees, shrubs, plants, and animals: please visit my previous blog post here https://www.gamedev.net/blog/1989/entry-2262570-z-model/

To create a game worth playing is my primary focus now. I want to get to the point where I can start creating game-content soon. I'm done experimenting with this and that. Maybe not next blog post, but two blog posts from now I want to start covering game-play and game-content.

What I can tell you now is what has inspired me all these years, and that was to create an RTS/Civilization game that can simulate a simplified economy. One where wealth auto-generates and trade is simulated in the background via the AI. That is my inspiration, and the goal is to make an awesome game to go along with it.

I hope I can slowly start to inspire you as much as I've become inspired. Thanks for reading.

Rebuild

rebuild.jpg

Rebuilding the project from scratch. Not all is lost though, I have a lot of world generation, path finding and asset creation logic already figured out. Currently I'm upgrading my skills via a website I'm not sure I can mention here, but basically it's called "something"-school. By the time I'm caught up to speed on coding concepts such as Closures, Hoisting, Classes and Modules I'll be better equipped to deliver a higher performing game.

I am also going to use THREE.js' new library 84. Already it looks like the build allows for user created content to demand fewer resources.

I'm also scraping my old linear approach to development. Previously I stuck to developing a new addition to the project like layers on a cake. Now I'm going to instead approach development like an inflating balloon. Each part necessary to the end game will be available upfront for development purposes and then the complexity of each will expand like the surface of a balloon.

And most excitingly, I'm scrapping the old look. It's still going to have a very simplistic look, still lot's of triangles and stuff, but, scrapping the space look all together and focusing more on a world build that adheres to the theme of the game. I'll be incorporating custom shaders.

I may not have much to show for a while, but I'll keep the community posted.

Thanks for reading and have a great week.

Update #4

Hi everyone.

One thing I learned about JavaScript is that any function on any script can be called by just simply typing the name of the function. I didn't realise that all of my code was global :? Well the functions at least. So rather than starting all over and making everything closed with classes and modules I've decided to begin implementing more of the classes and modules in future code. When I read my code I can see little improvements in style here and there, a given script will be littered with beginner, intermediate and maybe a bit of advanced code.

O.k so these past few weeks I've been continuing to plug away with dynamic asset creation. Starting to think about the end user and their interaction with the webpage. I've tweaked the menu's a bit to make the functionality a little more intuitive. One way I'm trying to improve the user experience is being including little helper lines.

Screenshot from 2017-02-18 17-26-41.png

In the picture above you can see an outline of terrain that has been modified, more on that later. But above that you can see what looks like a sharp angle line, that one updates in real-time according to where you clicked and stretches in the direction of your mouse. Giving an impression of the orientation of your terrain manipulation relative to the globe.

Screenshot from 2017-02-18 17-27-01.png

In this picture there is a cyan line that is used to indicate the surface you are wanting to build a foundation on. red for can't be done, green to indicate flattened terrain and cyan to indicate you'll be building on top of an existing foundation.

I want this game to have the feel of a fully simulated world. When you decide to erect structures you'll have the option to choose from a list of pre-loaded assets or you can create what ever you like given the asset menu.

First you'll need to assign a plot of land you'll need to level. Once you've decided on the plot and how large you want it to be, you'll have to commission workers to the task. The earth won't just instantly change. I have yet to program it but I want the earth to slowly form, real-time, according to your specifications. Then depending on the number of man-hours going towards the work determines the speed of progress. Thus large projects such as the pyramids would be an incredible achievement in this game.

Screenshot from 2017-02-18 17-28-30.png

Once a plot of land has been molded you can then begin to sculpt your structure, rather than seeing the finished product you see what looks like a 3D blueprint, and you only see the blueprint when you are in the asset creation menu. You can check out that style in the pictures above.

Once the construction of a structure has been commissioned, again, the erecting of the structure will be real-time and according to man-hours being contributed. If you make something of stone, the workers must transport the stone from a quarry. If you make a structure of metal, it must be mined and processed first.

This game will involve developing a local economy to help aid in the development of resources which you can then in turn acquire to build world wonders or conquer your enemies.

Screenshot from 2017-02-18 17-26-04.png

I've improved the speed and efficiency of my path algorithm. It can now identify up to 600 random paths between any two coordinates on the globe, or just over 250 negated paths in 1000 milliseconds. This is more than fast enough to simulate ten thousand AI.

Screenshot from 2017-02-18 17-27-40.png

and finally, I've updated my path algorithm and beginning to incorporate dynamic assets into it. The picture above shows a path drawn, white line running over the box. I want the path alg to be able to encounter any jumble of overlapping assets and identify the topmost path in a timely fashion. Of course all of this code is being written with scale-ability in mind so that when the day comes I can flick the switch and very quickly write a few algs to generate a simulated world with trees, animals and people and then I can start making a game :D

Z-model

Hi Everyone, so I created a modelling program, really basic, that can run in your browser.
I named it Z-model so that the file appeared last in the containing folder.
here is a zip of everything you need. Chrome works best
Z-Model.zip


Here is a screen shot of the finished product.
Screenshot from 2017-02-02 22-57-55.png


There is also some instructions and a sample geometry you can import. It's of a tree.


Basically if anyone is interested in creating content for this game I'm looking for very low poly/face and vertices count models.
I'm thinking MAX face count will be around 48, and MAX vertices should be a round 36. That's for static models like trees and what not.


If you're interested in Designing an animal, it should be no more than 20 vertices and 24 faces. The fewer the better.


Copy the export text and post it here in this thread if you'd like and I'll mention your name or avatar name each time I post future pictures of my game that features your work. For now, I'm thinking I'm not going to get a lot of attention, if you actually take the time to design something for this game, I will include it in all future builds. So there is a degree of trust here on both sides. :D[color=rgb(40,40,40)][font='Helvetica Neue'][background=rgb(250,251,252)]

[ EDIT 21/02/17 ] ::: Scaling[/background][/font][/color][color=rgb(40,40,40)][font='Helvetica Neue'][background=rgb(250,251,252)]

I forgot to mention anything about the scale of the modeling program. The working area is a 20 x 20 x 20 "foot" zone, I believe I have the camera set up to rotate around out at about 26 feet so to say. So if you're making a 50' tree just make it about half the size relatively speaking and I can easily scale it up on my end. Maybe just let me know your intended scale 1:2 or 1:3.[/background][/font][/color]

Feel free to comment or critique my program.

O.k, so last week I made a post on Thursday detailing the progress I made with regards to terrain manipulation, but I only previewed it and never actually committed to a submit, so I just chucked it up to a bad day.

Over the past couple weeks I've been programming a lot, especially this week. I think so far I've logged 20hr of sit down time, which it's quite remarkable what I've been able to achieve in this short amount of time.

Some pictures to show what I've accomplished:
Screenshot from 2017-01-19 23-01-08.png
In the picture above you can see the world is divided into 68 shapes of proportional size and shape, kinda like a squished cross or something.
in order to maximise the detail and minimise the processing power I divided the world up into these shapes and then depending on where the camera is located determines which shapes are visible at a given time. So as you zoom around the world, very fluidly, it seems as though the whole world is loaded, but nah, just a few shapes. And of course the closer you zoom into the world the fewer and fewer shapes the system has to process. Nothing new in that respect, did this part months ago but, now I've created buffer geometry, not THREE.BufferGeometry, but rather geometry that is buffered into memory with a defined vertices and face count. the total vertices and faces never change, only the location of vertices and faces. Each of the 68 world geometries is paired with it's own buffer Geometry. From this buffered geometry comes dynamic user assets and also plants, minerals and stuff, as it stands, each shape should be able to host about 1000 unique objects of varying complexity, no Notre-Dame but sufficient for what I'm going for. Oh and each buffered geometry currently has two material types, plain and metal, but this can easily be scaled up. Very proud of this.

Screenshot from 2017-01-19 22-51-53.png
Now on to terrain manipulation So in the above screen shot we see a plot of land to be edited.

Screenshot from 2017-01-19 22-52-24.png
Now we see the land has been curved, it can also be flattened, the surface color has been changed just for reference, I'll likely keep some aesthetic aspect to this, but haven't settled on a color or idea yet.

Screenshot from 2017-01-19 22-53-04.png
Here we see a thin foundation laid over top the surface. This foundation has a plane from which all walls will orient themselves if a structure is to be built on this pad, as in all walls will be perpendicular to the surface of the foundation.

Screenshot from 2017-01-19 22-50-12.png
And here we see me playing around with the foundation menu and some of the 'solid' structures that are possible. the two shown and many others are possible with my dynamic asset creator. No need to resort to a predefined list of assets, you can make your own pyramid or what ever. Not only that, the AI will dynamically interact with your created assets as well, walking on their floors, climbing up their stairs, maybe even sleeping in one or two of them depending, but first the little buggers will have to build your masterpiece. The little spec in between the two structures, that is the size of an AI, of course you have a better view of it zoomed in more, but right now it's just an stretched box.

Please feel free to comment or ask questions.
:D

[ added content 27/01/17 ]

Orientation Vector

The past couple weeks I've been working on a custom class which I call an Ovector, or Orientation Vector. It's builds off of the THREE.js Vector3() class.

With the Ovector Class I can identify any three dimensional position in the scene, and then orientate it by giving it a direction to face, and an up axis so it orientates itself accordingly. The beauty of this class is that it has an internal InheritFrom function that acts a lot like lego blocks. Each new Ovector builds off of a previous Ovector.

The inheritFrom function asks for the following:[code=js:1]inheritFrom( x , distance , rotation , F1 , F2 , plane )// x: is the direction GP vector for the next position// F1: is the origin GP vector for the next pointAt vector// F2: is the direction GP vecotr for the next pointAt vector// this.position and x draw a line, so do F1 and F2.
In the following pictures each Ovector is displayed with Arrows, Blue for Up, Red for Front, White for Right.

Screenshot from 2016-12-31 09-57-48.png
The picture above was generated by the code below.[code=js:1]var vv = new Ovector( $m.rO( $m.v( $m.rN() , $m.rN() , $m.rN() ).normalize().multiplyScalar(11) , $m.v() , 0 , 10 , TGglobalMesh , 0 ).point.clone() , editorParameters.unitScale /*, undefined , zz */ );var ww = vv.inheritFrom( vv.up , 50 , 0 , vv.front , vv.topFront , vv.normal );var yy = []; yy[0] = ww.inheritFrom( ww.front , 100 , 0 , ww.position , ww.front );for( var i=1; i<55; i++){ yy = yy[i-1].inheritFrom( yy[i-1].front , 100 , (i*i /100)+1 , yy[i-1].position , yy[i-1].front );}
The newly created Ovectors do not inherit an orientation Plane to align themselves to, so they align to the surface to of the sphere instead.


Screenshot from 2016-12-31 09-56-39.png
In the picture above the same Ovectors are given a plane which to fix themselves to.
All that is added to the code is the following:[code=js:8] yy = yy[i-1].inheritFrom( yy[i-1].front , 100 , (i*i /100)+1 , yy[i-1].position , yy[i-1].front , vv.plane );
This custom class will greatly speed up my dynamic Asset creating component and will also make it easy to construct stuff.

Weekly update #1

So this past week I spent some time trying to make the game look more appealing. Though I am dealing with very simple visuals I'd ideally like to come up with an art style, as I move along, that suites the simplicity of what is presented making the simple visuals aesthetically appealing.


So very quickly I've added a bit more world generation code to produce the following.
Screenshot from 2016-12-22 11-07-39.png
Screenshot from 2016-12-22 11-07-12.png
Screenshot from 2016-12-22 11-08-41.png


So as you can see the hills are starting to look a little more like hills, the mountains are a little more obvious by their color and style and there is now sand/beach near the water. Of course still missing from this world is vegetation and wildlife, this will be one of the last elements I add simply because it will be very easy but time consuming do to it being artistic in scope.


Now a bit about the coding logic I developed.
So I'm using THREE.js which is a javascript API which allows me to directly manipulate the HTML 5 canvas element and take advantage of WebGL functionality. Currently Google Chrome is the best browser performance wise which is why I use it. Firefox unfortunately is slow in comparison. I'm not picking sides, just stating the facts.


Now it THREE.js there are 4 classes to make a visual element within the canvas element. I'm sure many of you are already familiar with these as they are probably universal across many languages.


THREE.Vector3() contains the x,y,z position of a vector is 3D space.
THREE.Face3() is comprised of 3 vectors,
THREE.Geometry() faces are then drawn and visual on the, counter-clockwise vector order, plane of each face. The geometry class contains a vector and face array.
THREE.Mesh() is comprised of a single geometry and a material class(). It is the Mesh that you see visible. The mesh can then be scaled and rotated and such but it's basic parts remain intact.


For the world generation I start with a geometric primitive, an Icosahedron.
image002.jpg


Then I add a few custom variables to each of the vector and face classes of each of the twenty faces and tweleve vectors respectively.
Untitled.png


I'll do my best to try and describe what I've done.
to each of the vector and face classes I've assigned a unique id, just 0 to how many ever vectors/faces there are.
the three most important additions are the l array, s array and cv array. The names of which are kind of arbitrary, I just like short and simple variable names. "L" stands for "draw order" for drawing each face, "S" stands for the "unique id" for each connecting face. "CV" stands for "draw order vector id's".


the most important part is the addition of "L". Because what you don't see in my diagram 'forgot' is that the actual index position of connecting face s and cv arrays correspond to one another. That means if face id:1 has the information about face id:2 in it's 0 index position, so will face id:2 have it's information about face id:1 in index position 0. Then the draw order is preserved via the addition of "L".


A sample of the draw order looks like[code=js:1]var f = g.faces;// to draw a sample facevar F = new THREE.Face3( f.cv[f.l[0]].a , f.cv[f.l[1]].a , f.cv[f.l[2]].a );// in this example F and f are identical but when ever f.s or f.cv is called up// it always contains the f.l[] array for reference.

Now to generate a world each of the twenty faces of the original icosahedron, with their respective encoded information about it's surrounding faces, is subdivided into nine pieces twice, then 4 pieces three to four times. The images in this post are three divisions into 4 pieces. While it subdivides the information about each new face and it's surroundings is updated and inherited, like the the case of "S" and "L" respectively. This reduces the number of "if" statements for the initial geometry that is created "a big ball", theoretically I think I could eliminate all 'if' statements, and with my system I can create this big ball of many 100,000's of faces in less than 2 seconds. Then built off of this basic geometry it is very easy to manipulate the ball and contort it as I see fit because so much information is embedded in it. This comes in handy, actually is critical, to being able to display thousands of moving objects across any path along the world later on. But I'll talk more about that once I'm done with the AI generation.

Oh one last note, current world generation time with everything included on the last build is 7.5 seconds.


Anyways, thanks for taking the time to read if you did.
Also, I'd love to hear any advice or comments about the look, the art style is my Achilles heal and I'm worried about it.


Thanks and Merry Christmas,
Awoken.

Priority Number 1

virtualizationciopriority.jpg

I'm going to do it.
I've always wanted to realize this game, I want to see it through to its completion. Up until this date I've treated it like a hobby, something I did in my casual spare time, when I felt like it. I rarely get a chance to talk about my idea to others, and when I do I self-bash it by prefixing with "It's pipe dream", and "It'll probably be a shitty game nobody likes, and I fully expect that!" But then by the time I'm done talking about the idea I'm all excited and think to myself "What a great idea!". The other day I was thinking about people who just went balls to the wall because they truly believed in what they were doing and asked myself why haven't I?

I will be posting weekly updates on the progress on my game, and I will try to contribute something more to my journals than "Look at this little thing I made". to "This is how I did it!".

Thank you for taking the time to read my post.

:) :) :)

So I am very please because, fingers crossed, after working on this one function for more than two months I think I've finally got it.

The goal was the create a function that would draw a path of white arrows, refer to the pictures for visuals, between any two points selected by either a user or at random on the surface of a dynamically generated world. But not just once, ten times or even a thousand times but every-time, or 99.99999...% of the time.

At first errors would pop up after I had randomly picked 10 or 20 paths to draw, but soon I could click, click, click for a good 30 seconds and nothing, no errors.

robustPath4.png

So I decided to create a function that would just randomly make paths for me, right? I know!
And that would return errors after maybe a few hundred paths tested. Then I'd sort this out or that in my code and repeat and soon I could run the function a thousand times before an error would pop up. After a while I'd get a few thousand paths tested with no errors and so I'd up the detail of my world and see if the function would work on a dynamic surface as opposed to a flat uniform surface. And then again back to errors after just 10 or 20 paths.

And this cycle continued, and continued...

robusttesting.png

Soon I was running the function to test hundreds of thousands of paths taking hours and hours and only after hundreds of thousands of paths had been tested would and error pop up for me to see and analyse.

robustpath3.png

and now at the time of writing, still testing though, I am pretty confident I have finally met the robust challenge! :cool:
now of course I'm not 100% sure that it's perfect, I can never be certain because their are technically too many paths to be tested to count.
an example of a path to test is as follows
Sx:0.8925261008176053y:-6.462897144580008z:6.1995026343584705Ex:-0.9157777460656384y:6.468354322279517z:-6.190324704587636
but, if it can get to a million that It should be able to get to a billion.

This is good because this particular function is key to my game and it will run billions of times over the course of a single game so it only makes sense that it can handle what ever is thrown at it.

[side note: the coordinates to the path I listed above were actual the coordinates of the last error I encountered. Interestingly if you look at them the Starting x,y,z's and Ending x,y,z's are almost exactly opposite, thus opposite sides of the sphere, and of course my code up until that error could not handle such an odd circumstance because it threw my distance calculations off ]

EDIT: I LIED, IT FAILED,
back to the dungeon with my scrimbly board :blink:

Update

 

5aa88ba11d0d6_Screenshotfrom2016-06-2123_24_16.thumb.png.e6a88197f82241439e93cde6095a69c9.png

5aa88bab1c97b_Screenshotfrom2016-06-2123_24_27.thumb.png.5694728034becd3623cecda54c52cc48.png

5aa88bc8377da_Screenshotfrom2016-06-2123_24_40.thumb.png.a27c23cb525ca2623f3696ba4b06bebf.png

5aa88bd036500_Screenshotfrom2016-06-2123_25_29.thumb.png.5054dc831031b8ea0809ff424ef944b6.png

I was going to hold off until I was done most of the components of my game engine, if you can call it a game engine, but am too excited to wait as it will be another year at least.

The big 5:
-** Just finished geometry grouping and am able to render a world of over 800,000 faces seamlessly. no performance loss, 60 fps. **
- currently working on updating my asset creator. dynamic and able to create roads/paths, walls and buildings.
-** able to simulate over 1500 on screen actors, actors being simulated people. This was really the projects Achilles heel; I am in theory able to go up to 5000 independently simulated people. With more connected severs perhaps more ??? **
- path finding, currently I created an algorithm that allows all actors to move around dynamically placed assets however it is not efficient( shortest distance ). I have ideas to make it more efficient but it is a processing beast. much work to be done.
- allow up to ? 50 ? players to create and register accounts on a server and influence actor movements, currently have code that would allow testing such connectivity.

Well there you have it. most of my efforts are focused on how this game functions not so much how it looks. I figure one could lose themselves in an abyss of endless time if they focus to much on art.

:D

 

Progress thus far

Added better stars, moon and sun.
made a simple continent function and made the ocean a bit transparent.

Been spending most of my time programming background stuff that makes stuff work rather than making it look pretty.
Soon, very soon, moving things will be able to move around any fixed obstacle dynamically towards its destination.

Made a background server which integrates clients.
right now a connected user has a blue box, other connected users are red.
each user can move their box around.

But once and awhile when I'm bored I make it look nice-er.
I'm going for a hard edge look, limited by resources available to WebGL and scale of what I'm trying to achieve.

Let me know what you think of the style.

5aa88b15e3271_Screenshotfrom2015-12-0111_17_15.thumb.png.ec1d61fe2b2cbea22beda43afa9475e4.png
5aa88b29c696d_Screenshotfrom2015-12-0111_26_48.thumb.png.35e976dd4b9ca575c51dca2e50d5b147.png
5aa88b372515d_Screenshotfrom2015-12-0111_27_26.thumb.png.090127d0ac4ebbd7087a8c2a95b1a1ce.png

5aa88ab18b9c6_Screenshotfrom2015-01-0721_30_15.thumb.png.ee2cd94b03e52056a86c96c03801e225.png

Hello

So I literally just finished up synchronizing all of the clients so that when one client moves a cube or 'actor' all other connected clients see the movement.
The picture I posted is of three separate clients all moving their own respective actor 'the blue one' to the same spot on the world.

Next step will be to program a dynamic path finding algorithm so that each actor can navigate around obstacles as they travel around the world.

After that I program fish and lions. The actors will then hunt for fish and run from lions. Fish will just randomly swim around and lions will keep an eye out for actors and try to catch one and eat it.

Thanks for reading.

 

So this game has been a hobby of mine and I've set certain goals over the year and have achieved each one so far. We'll see how long this can go on for.

Accomplished goals

- create algorithm to generate an icosahedron of any number of faces (divisible by 80):

with my own algorithm I figured that I would be better able to manipulate the icosahedron and thus better able to use the algorithm to create dynamic worlds.  future goal: create a more realistic dynamically generated worlds

- allow camera to move around world/sphere freely. Thus no real 'UP' direction other than that which is relative to the cameras view.
- allow something similar to a camera hot key. Basically allowing the user to assign views(camera zoom and location) and retrieve them with ease.
- create a box and have the box move along the sphere while sticking to the terrain of the sphere. Kind-of simulating gravity I guess.
- select starting and ending points and generate a 'wall' of some size that contours to the surface of the world.
- create server and client sides. client in browser, server in terminal and have the two of them talking with each other successfully.
- create many servers all talkin to each other.
- synchronize the experience of any browser with the server when the browser regains focus.
- come up with potential name and logo for the game.

As you can see some pretty basic stuff. But I'm teaching myself as I go.

Future Goals (short term ~ early new year)

- box collision detects with walls and other world obstacles (this part should be easy as the box already collision detects with the sphere.)
- box uses a combination of dropping nodes and pathfinding between nodes to learn and navigate around its world. (I've already created a simple pathfinding algorithm for a different game I made and now just need to feed it up.)
- develop user registry/login and game session retrieval. To allow users to participate in my game of course.
- and then much much more.

Check out my first album with some pictures and little blurbs about each.

5aa88a342b2f0_Screenshotfrom2014-11-2722_45_13.thumb.png.c35f5b572befc4f1b638d0774fd4cafe.png

5aa88a561990c_Screenshotfrom2014-12-0320_47_47.thumb.png.42fe6458897eaef213a59a538675b68f.png

5aa88a62de53a_Screenshotfrom2014-12-0321_11_45.thumb.png.9567cabc48eb98283730ef3b54bdeadd.png

5aa88a6f5a22a_Screenshotfrom2014-12-0321_12_45.thumb.png.4eccef9de046eb21ce6513cf64e1ec4e.png

Gotta start somewhere

5aa889d9cc679_Screenshotfrom2014-11-2722_45_13.thumb.png.2d4f7e14a68a20f8ca4b16232ead9799.png

Hello curious dwellers of gamedev, I'm much like you  :) 

I'm making a game that will run in a web browser, chrome for the best experience, and the game's going to try to be a lot of things.
the game wants to be cool, awesome and wicked, basically one of those games that you would be excited to tell your friends about.
It's this excitement I speak of that fuels my creativity.
There is a lot to this idea and writing about it, boring you with pages of reading material, will put me to sleep.

Me...

I like big ideas, especially if they're my big ideas, unless of course your idea is bigger.
I have a cat, he eats a lot.

------------------------------------------------ THE GAME ------------------------------------------------

For now I just refer to it as the game. I have a title in mind, but it's written on a piece of paper locked in a safe somewhere.

The entry image is suppose to be a world. As of right now you can pan around it, rotate your view and zoom in and out of the world. A box moves along the surface, and you can make what I call 'walls'. nifty.

I'm using Three.js and node.js,

 

I'll have more in the future.

Thanks for taking a peek.

 

 

 
  • Advertisement