Unesroga – Progress end of May 2025

No, the game project is not dead, it is making great progress! 🙂

Tech Stuff

The game is developed in “pure” Java.

For the rendering, I am using a BufferStrategy and PageFlipping (if supported). The base image is created using a MemoryImageSource as ImageProducer and I am grabbing the int[] rgb samples from the scene image and apply the effects like scanlines, vignette or noise directly to them before producing the image.

On top of that, stuff like the inventory, the mouse cursor, the UI and some other things are drawn in a classical way using a Graphics2D.

This leads to breaking the normal swing UI stuff, so I have done my own small VirtualComponent UI framework. It currently only contains buttons, checkboxes, labels and containers with two layouts. But it works alright for the moment.

The game logic is done using a stack of interaction modes that contain methods to process mouse and key events, draw additional stuff, do some processing each frame, etc.
An interaction mode is something like the SceneInteractionMode, the MenuIteractionMode or the NotebookInteractionMode. Only the mode on the top of the stack is processing the beforementioned stuff (unless it has a onGlobalProcessing() implementation).
They also have enter() and exit() methods when they get pushed to or popped from the stack. This is something that has been a reliable system in all my game projects in the past 10 years or so (even in the game jam projects).

Bugs

Fun stuff

When a friend tested the game, he was doing so with support of a child which led to really creative action suggestions. As you do with children you tell them that this was nonsense, but eventually do it anyway to satisfy their curiosity.

So, he ended up doing something random and an inventory item morphed into something else, which caused the child to say “Told ya!”

For the most complex element in the gallery room, I am handling the item interaction in a loop as there are many regions to check. I was so satisfied with it that I forgot something basic. In this case the region is doing the reaction, not the inventory item. The region did not care about what was used as an item, though.

Easy fix, but certainly one of the cooler bugs. Even after seeing a video of it, I was still in denial. 😀

Scanline Stride (or how the wrong path led to the right fix)

When the game was tested on a Mac, some the graphics seemed to be a bit off. Unfortunately one of the broken visual effects was essential for the solution of the first puzzle, but could not be seen.

The effect looked like a tearing of the image caused by a wrong line offset in the rgb pixel array that I get/set via getRGB()/setRGB() on the image.

After googling a bit, the scanlineStride came up and I thought it made sense that the Mac used a different image or data buffer format that contained some padding bytes. The scanlineStride was the offset from one line to the next. When there were padding byted because of the format, this would differ from the width of the image, which I was using before.

So, I changed all the code that used the image width as offset to the scanlineStride that I got from several different SampleModel or Raster implementations. No, there isn’t an interface for all of them providing this value.

Unfortunately, testing the new version on the Mac did not yield the results I had hoped for. When checking the scanlineStride, it was the same as the image width, so there were no padding bytes. At the same time, the width was pretty weird, caused by the shrinking happening on the Mac because of the top and bottom bars stealing some screen space.

When switching to full screen… the bug was gone… XD

Checking the code, I found out that it was caused by a downscaling of the image while still expecting it to be of the reference size 1920×1080. The code was added in the beginning to not render more than necessary if the screen resolution (or frame) was smaller than 1920×1080. It has never before been active, so the bug never appeared.

Well, at least I have learned something here. ^-^

Frame Times

The transitions were sometimes finished early or did not seem to play at all. After checking the times, the delay between the first frame and the second was very large.

I expected some expensive stuff going on between adding the effect and rendering the first frame, but no such thing existed. The scene image was prepared and then the effect was added.

The problem lay in the way the time is calculated and passed to the elements. There is a single value as frame time for everything that is done in the frame instead of each component getting their own current time from the system. This ensures that everything is rendered and calculated in the same way.

This is the sequence of things in the game loop:

  • Calculating the current time
  • Skipping frame if the limit is reached
  • Doing game logic
  • Rendering the scene and effects
  • Doing onFrameEnd() stuff that needs to be here when triggered from other threads (like the UI thread)

When clicking on something in the game like a region that leads to another scene, the action is processed in the current frame (loading the new scene, rendering the image (especially in popup scenes), callbacks reacting to scene changes or adding new effects like the transition itself). Because it is added in the game logic step, the added effect is immediately rendered for the first time, taking the current time as its start time.

At first I thought I could move adding the effect to another time, like the onFrameEnd() or after calculating the time on the next frame. But some effect need to be rendered in its initial state immediately after creating them, especially the transition.

The solution was (as usual) quite simple: I was rendering the first 2 frames as if the time was not advancing. Now, when switching a scene, the whole transition was played nicely.

Leave a Reply

Your email address will not be published. Required fields are marked *