• Advertisement
  • entries
    7
  • comments
    4
  • views
    3197

About this blog

This journal is dedicated to my auto formation and my experimentations.

Entries in this blog

First off, here's a video that shows the unit vision in action : 

 

So, what is the unit vision? It's a simple mechanism that notifies a unit when another unit enters its vision field. It also takes into account if the vision is blocked by entities.

This is how it is implemented step by step :

  1. A cone ghost control is attached to the unit's head
  2. All units intersecting with the cone's AABB fire events (AABB because of how Bullet Physics work)
  3. Cast a ray towards the visible unit and then adjust the angle so that it fits in the cone
  4. If the ray cast touches the supposedly visible unit, then it is truly visible

 

Using the debug view of Bullet Physics in the jMonkey Engine 3.1, we're able to see what the vision cone actually looks like.

UnitVisionFromBehind.png.a0384bcbc7c06a11a280a8e0cf92f96c.png

UnitVisionConeFromTheSide.png.ed84913f5d96e4963c4126fccd6719a5.png

UnitVisionConeFromTheSide-2.png.458f46e114950884091d1b4065175194.png

 

And when inside the cone we can't see it because of culling. However, we can see the enemy's arm moving, which is a test I did for when a unit see another unit.

5acce1264179e_DesktopScreenshot2018_04.10-11_49_14.46(2).png.2d71b73e57da99d7494f4a99060c5268.png

 

Behind a box, the enemy does not move its arm because he can't see me.

5acce17928f5e_DesktopScreenshot2018_04.10-11_49_46.79(2).png.12a4edd9236536c0bdc28893e081d44a.png

5acce199c469f_DesktopScreenshot2018_04.10-11_49_50.47(2).png.7b7bcfbdebad80d002392903ff26a8db.png

 

But when I leave my hiding spot, he can see me again.

5acce1c9ade40_DesktopScreenshot2018_04_10-11_50_10.57(2).png.f991cdd3375c2729e6c6b807d225cd88.png

I have integrated the zone separation with my implementation of the Marching Cubes algorithm. Now I have been working on zone generation.

A level is separated in the following way :

  1. Shrink the zone map to exactly fit an integer number of Chunk2Ds, which are of 32² m².
  2. For each Chunk2D, analyse all zones inside its boundaries and determine all possible heights for Chunk3Ds, which are of 32³ m³. Imagine this as a three dimensional array as an hash map : we are trying to figure out all keys for Chunk3Ds for a given Chunk2D.
  3. Create and generate a Chunk3D for each height found.
  4. Execute the Marching Cubes algorithm to assemble the geometry for each Chunk3D.

 

In our game, we want levels to look like and feel like a certain world. The first world we are creating is the savanna. Even though each Chunk3D is generated using 3D noise, I made a noise module to map 3D noises into the 2D to able to apply 2D perturbation to the terrain.

image.thumb.png.dabfc74065279611beab5f09c82c5ebd.png

5a8d9e3977e7f_Jdk-9.0.1Screenshot2018_02.21-11_27_44_36.thumb.png.e546c2bba66ca8e483a2406a92f2fee2.png

 

I also tried some funkier procedural noises : 

5a8da258f37cf_Jdk-9.0.1Screenshot2018_02.21-11_44_58_06.thumb.png.e7131ac55bc1980312779cc7b71187aa.png

An arch!

5a8da263044bf_Jdk-9.0.1Screenshot2018_02.21-11_45_15_28.thumb.png.d3baa9a1a385c9229dd1d8ee246f9783.png

5a8da26e86f17_Jdk-9.0.1Screenshot2018_02.21-11_45_20_30.thumb.png.1b2de9b36b1dac32988d481b1199a3d9.png

5a8da2750c771_Jdk-9.0.1Screenshot2018_02.21-11_45_33_61.thumb.png.b6f3a60564e5f2d8a0cf4c4298148537.png

5a8da27b6f980_Jdk-9.0.1Screenshot2018_02.21-11_45_42_05.thumb.png.6b76ffd7a92919eb31abc605e8757e36.png

 

The important thing with procedural generation, it's to have a certain level of control over it. With the new zone division system, I have achieved a minimum on that path for my game.

A friend and I are making a rogue-lite retro procedural game. As in many procedural rogue-lite games, it will have rooms to complete but also the notion of zones. The difference between a zone and a room is that a zone is open air whilst a room is not. Rooms are connected mainly by corridors while zones are mostly naturally connected / separated by rivers and mountains.

 

Because we want levels with zones to be generated, we need to tame the beast that is procedural generation. How can we generate each zone itself and also clearly divide them? Until now, I had only been using the Java noise library called Joise, which is the Java community port of JTippetts' Accidental Noise Library. I needed the zone data to be generated with basis function modules, i.e. Perlin noise, but in contrast I needed a more structured approach for the zone division. Joise library does have a cell noise module that is a Worley noise. It looks like this depending on its 4 parameters (1, 0, 0, 0) : 

Image result for worley noise

 

Using math modules, I was able to morph that noise into something that looks like a Voronoi diagram. Here's what a Voronoi diagram should look like (never mind the colors, the important parts are the cell edges and the cell centers) :

Related image

A more aesthetic version :

Image result for voronoi

 

The Worley noise that I had morphed into a Voronoi-like diagram did not include the cell centers, did not include metadata about the edges and was not enough deterministic in a sense that sometimes, the edges would around 60 pixels large. I then searched for a Java Voronoi library and found this one called Voronoi-Java. With this, I was able to generate simple Voronoi diagrams :

VoronoiDiagram.png.2fd7db63f7bfa6504ce081f24ecced71.png

 

Relaxed : 1 iteration

VoronoiDiagram-Relaxed1.png.a7e8b45c3c0f77864b132aa37e1abf19.png

 

Relaxed : 2 iterations

VoronoiDiagram-Relaxed2.png.274e43c8181264dbad9d0d3d67dbc87c.png

The relaxation concept is actually the Lloyd's algorithm fortunately included within the library.

 

Now how can I make that diagram respect my level generation mechanics? Well, if we can limit an approximated number of cells within a certain resolution, that would be a good start. The biggest problem here, is that the relaxation reduces the number of cells within a restricted resolution (contrary to the global resolution) and so we need to keep that in mind.

To do that, I define a constant for the total number of sites / cells. Here's my code :

private Voronoi createVoronoiDiagram(int resolution) {
    Random random = new Random();
    Stream<Point> gen = Stream.generate(() -> new Point(random.nextDouble() * resolution, random.nextDouble() * resolution));
    return new Voronoi(gen.limit(VORONOI_SITE_COUNT).collect(Collectors.toList())).relax().relax().relax();
}

 

A brief pseudo-code of the algorithm would be the following :

  1. Create the Voronoi diagram
  2. Find the centermost zone
  3. Selects X number of zones while there are zones that respect the selection criteria
  4. Draw the border map
  5. Draw the smoothed border map

The selection criteria is applied for each edge that is connected only to one selected zone. Here's the selection criteria :

  • Is connected to a closed zone, i.e. that all its edges form a polygon
  • Does have two vertices
  • Is inclusively in the resolution's boundaries

 

Here's the result of a drawn border map!

borderMap.png.656841ace826a23e7032f62cb74f46ab.png

 

In this graph, I have a restricted number of cells that follow multiple criteria and I know each edge and each cell center point.

To draw the smoothed border map, the following actions must be taken : emit colors from already drawn pixels and then apply a gaussian blur. Personally, I use the JH Labs Java Image Filters library for the gaussian blur.

With color emission only :

smoothedBorderMap.png.b501b720a6f2bd395462dc1f6a1d9a92.png

With color emission and a gaussian blur :

smoothedBorderMap-Gaussian.png.1f710ade1271b3a4745cf18246ce8f08.png

You may ask yourself why have we created a smoothed border map? There's a simple reason for this, which is that we want the borders to be gradual instead of abrupt. Let's say we want rivers or streams between zones. This gradual border will allow us to progressively increase the depth of the river and making it look more natural in contrast with the adjacent zones.

All that's left is to flood each selected cell and apply that to a zone map.

Marching cubes

I have had difficulties recently with the Marching Cubes algorithm, mainly because the principal source of information on the subject was kinda vague and incomplete to me. I need a lot of precision to understand something complicated :) Anyhow, after a lot of struggles, I have been able to code in Java a less hardcoded program than the given source because who doesn't like the cuteness of Java compared to the mean looking C++?

Oh and by hardcoding, I mean something like this : 

cubeindex = 0;
if (grid.val[0] < isolevel) cubeindex |= 1;
if (grid.val[1] < isolevel) cubeindex |= 2;
if (grid.val[2] < isolevel) cubeindex |= 4;
if (grid.val[3] < isolevel) cubeindex |= 8;
if (grid.val[4] < isolevel) cubeindex |= 16;
if (grid.val[5] < isolevel) cubeindex |= 32;
if (grid.val[6] < isolevel) cubeindex |= 64;
if (grid.val[7] < isolevel) cubeindex |= 128;

By no mean I am saying that my code is better or more performant. It's actually ugly. However, I absolutely loathe hardcoding.

 

Here's the result with a scalar field generated using the coherent noise library joise :

 

Recently I've been tackling with more organic low poly terrains. The default way of creating indices for a 3D geometry is the following (credits) :

Image result for opengl shared vertices

 

A way to create simple differences that makes the geometry slightly more complicated and thus more organic is to vertically swap the indices of each adjacent quad. In other words, each adjacent quad to a centered quad is its vertical mirror.

MirrorIndices.thumb.png.adfc5555cdd3e9bff0595a830f893eb8.png

 

Finally, by not sharing the vertices and hence by creating two triangles per quad, this is the result with a coherent noise generator (joise) :

It is called flat shading.

Voxels

Voxels! Unlike my old Xna application, this one's code is way more beautiful to the eye. Zero "switch" or "if and else" for cube faces, as I did with my cubic planet faces.

My only problem with voxels is that it's a 3D grid. A 3D grid take a lot longer to compute than six 2D grids.
250 * 6 = 1500 quads to compute and draw.
2503 = 15,625,000 voxels to compute and maybe draw.

As I use more and more complex objects to abstract the computation and the drawing part, the code slows.

Following this entry, I'll make another one but with two videos:
1) Spherical planet made of voxels
2) Cubic planet made of voxels

I'm an amateur and hobbyist video game developer. I've been programming for 9 years now even though I'm almost 21. When I started, it was rough being extremely bad with the english language and a noob programmer. Instead of helping me, people over multiple forums were only degrading my lack of skills and so I stopped being an active user. I have now finished what we call in Quebec a "technique". A technique is an academic degree of 3 years that is the equivalent of college degree. The technique I've done was called "Technique de l'informatique de gestion", which is a computer science technique applied to management softwares. As I finished college, I noticed I've improved my programming competencies and so I started again to research and program for fun, which I did 4 years ago. See

I'm currently working on planet generation. Everything was done using the jMonkey Engine 3, Java 8, Eclipse Mars and Joise (a java adaptation of the accidental noise library from JTippetts). The following videos sum up what I've done so far:

  • Advertisement