Snake3D 1.0 released
At certain angles one of the 3 faces of the cube disappeared like this:
In the graphics part I sort the areas and take the 3 areas closest to the screen(which have the smallest z-coordinate) to paint only those. My theory is that I made a mistake at some point there or my assumption that the 3 closest areas to the screen are also the 3 areas that are visible is wrong. Since I was unable to find any evidence for both of these cases, I decided to remake that part of the code.
I just took the corner-point closest to the screen and now painted the areas that are touching this point. That worked, so I decided to no longer bother about the why.
Prologue to 2./3. Issue
main update function I first decided to restrict the frame rate of the
Graphics3D update function to 50 fps, but a quick test revealed that that update only needs a few microseconds → I removed that restriction.
That revealed two bugs I previously wasn't aware of.
Suddenly the cube took much longer to rotate.
For the rotation I used a structure like this:
ax += (System.nanoTime() - lastTime)*constant; … Some other code involving the few microsecond function … lastTime = System.nanoTime();
The obvious error here was that I used different times for the two lines. Due to that error when I removed the restriction for the function in between I created a higher difference between the values leading to an overall lower value for Δax.
The solution to this is quite simple using the same time for both:
long newTime = System.nanoTime(); ax += (newTime - lastTime)*constant; … lastTime = newTime;
I also detected a graphics bug that now appeared pretty often and which you can see in the following video/gif:
Luckily I already came across a similar bug years ago in another 3D-game and already solved it back then(after weeks of hard work):
When I call repaint() of a javax.swing.Component like JFrame/JPanel, java automatically creates a separate Thread that then does the work. That is really great and can increase the overall speed of the program, but there is a small problem:
For the new Thread to work it first needs to get all the needed data from cache to the relevant processor core. This takes a little time in which the other Thread already progresses. There is a high chance that the other Thread changes those chunks of data the graphics thread didn't yet copy. In my case there is an array that contains the numbers 0, 1 or 2 and a while later that array holds indices for the 3 areas that are painted. If the copy is made at the moment where the array contains 0, 1 or 2, the graphics Thread will paint the areas of index 0, 1 and 2, which are not necessary the areas that should be painted.
→ So under certain conditions the wrong areas are painted
→ The graphic on screen starts to flicker as seen above.
How can this be solved?
The simplest way to solve this is to just add a delay between the creation of the new Thread and the next function call.
In speed sensitive programs this should be done with a volatile boolean that stops the main process and that is inverted from the beginning of the graphics thread, but in the case of snake, which naturally contains a pretty long delay, I decided to add a 1 ms delay which also serves to spare power of whoever uses the computer.
Here is where I fixed the two issues above: https://github.com/IntegratedQuantum/Snake3D/commit/2fcfe45e28c09c9206feddfbe714516f2615b92d
I made the cubes size dependent to only one variable(main.size) everywhere its numerical value was plugged into the code.
This allowed me to change that value from anywhere. I ended creating a new gamemode/level(
big cube) which has a size of 16×16×16, but generally there is no real limit(to those who are able to change the source code) apart from your CPU. Even 60×60×60(above that it gets really hard to see the snake/the food and it just takes ages to get around the cube) is still playable:
Playing a custom level(TODO) should be really fun on such a big cube!
Previously the snakes length was limited to 50 due to my bad coding. I changed that and gave that array containing all segments of the snake a simplified list-like functionality. Here you can see a little showcase of a long snake:
- Draw lines for the grid instead of polygons → faster rendering.
- Fill a black polygon as background on each face instead of filling black polygons for each empty tile → faster rendering.
- Store the highscores of each gamemode/level in one file instead of distributing them across multiple files.
- Use Graphics2D.translate() for better readability in Graphics3D.paint(). This is distributed across 2 commits because I forgot something in the first one.
- Use Vector(a new class) instead of int-array for the positioning of Snake and Object. → more readable code
The commits of the minor changes often also contain other changes, so don't think I added the wrong link or something. And sometimes they are distributed across 2 commits because I forgot a crucial part.