most recent jar: hexara-feb14-17.jar
in progress jar: Hexara8
Earlier, stalled Java2D version: Hexara (old)
My resolution for 2017 is to finish and publish Hexara. I want to get more adept with JavaFX and Java 8, so I decided to convert the previously stalled project.
Managed to get a running start into the New Year!
I have a three-tiered system set up for timing and animation that seems like it will work out pretty well.
1) asynchronous, e.g., mouse motions, keyboard input (will be loosely coupled to other tiers) [hasn't been implemented yet]
2) graphics animation via an AnimationTimer
(runs at 60fps)
3) scheduled events and sound playback (runs at 44100 fps)
has but a single line of code. The overridden handle() method consists of the following:
for (Animatable aa : Animatables.array) aa.update();
is an Interface with one method: update()
is a static array. I use a CopyOnWriteArrayList
rather than an ArrayList, to allow concurrent access (can add or delete while array is iterating).
That covers the "update" portion of the game loop. As for "render"--that seems to be automatically handled by JavaFX. There is no need for Swing's paintComponent()
method or equivalent.
For the blocks that hold the letters: I'm using Rectangles. For the "cold" blocks, the innermost Rectangle is given a fill of silver (outer rectangles are progressively darker, and just the shape is drawn). The letter nodes are drawn after the Rectangle nodes and set up with a black fill.
For the "hot" blocks, the innermost rectangle is overwritten by a WritableImage
) created via a PixelWriter
) that obtains data over a 64 by 128 rectangle using Z-animation and a Perlin Simplex Noise function. The animation is run at half the speed (30fps -- seems sufficient and is less of a cpu load than using a smaller z-increment at full speed) and the resulting graphic is scaled, rotated (for even-numbered positions), and translated via an ImageView
node. The six ImageView's all use the same static WritableImage as a source.
The series of notes played (via a real-time synth) are scheduled with an audio event-scheduler I wrote. When scheduling, it is possible to include a NoteListener
as a callback function.
The NoteListener code on the managing class for the TitleBlocks sets a variable that tells the update() method to flip from "cold" to "hot", for the first six notes. Loose coupling is very important so as not to burden the audio thread--let the animation thread handle the bulk of the work!
The start of the seventh note in the musical motif provides a hook into the note's main volume envelope and flips a flag, so that the animation loop will inspect and use this value to set the Group (all the blocks) opacity--thus the fading of the graphics is a function of the note dying away. I do a bit of filtering and scaling of the envelope values to manage the visual fade. It probably seems a little long for a title sequence, but the intention is to cross-fade with the sounds and images of the main puzzle panel. Also, there will eventually be another visual animation (glow bloom and fade) triggered by the start of the seventh note.
I'm excited that this is coming together! Am pleased that the JavaFX code is clearer, easier to manage, and less verbose than Java2D, so far. Cross-fading to the puzzle panel is going to require some working out. I'm not sure yet if I'll be flipping visibility switches and opacity values of nodes, or nulling and resetting the nodes, or if I'll actually be adding and removing the Nodes from the root node. To be continued.