Unesroga – The next room (Spoiler alert)

After finishing the demo, I can now work on the next room. At the end of the demo, the player just opened the door to it. When clicking on it, there’s just a “To be continued…”

And that is done at the moment. I’m trying to keep this as much spoiler free as possible, but if you want to discover everything on your own, then:
Do not read any further!

Continue reading Unesroga – The next room (Spoiler alert)

Unesroga – Demo 2 finished

I’ve finished the work on the second demo of Unesroga.

The last things to do was to generate some texts for the completely irrelevant books in the shelf of the starting room. Still, I wanted them to be in there and there will be more in the future.
I had to fix more stuff in the layouting code of the books after adding new ways to style the text elements with a little markup, because changing the font or size of the text made the previous size calculations invalid.
There was an incredible struggle to maintain the correct number of linefeeds because of the way I first split the text into parts (including styling, alignment and some other metadata) during the calculation and split to pages step and at the same time reconstructed the text, so it could be drawn later on.
In the end, I got rid of the double parsing stuff and used the calculated parts directly, which produced some other problems, but eventually it got all resolved and now it is stable and works in all cases when there is plain text, styled elements, page styles or conditions or custom pages with images etc.

The demo contains roughly 75% of the game. There are two more rooms planned and I have a basic idea of what will happen in one of them.

But before I start the work on that, I will wait for the initial reaction to the new demo and see if I have to do some quick fixes to it, so I can release it to a larger group.

I am curious to find out whether the puzzles will be solved quicker (or at all) than the one in the first small demo. ^-^

Unesroga – Demo 2 “a-Maze-ing”

Today, I have finished the work on the “Shooting Bunnies” book that will contain a tutorial for the camera and notebook. It led to multiple changes to the camera handling to make it easier to position stuff correctly.

I have also finished the calendar in the “oval office”. Generating the last few images for the calendar pages was a pain. ^^

Everything that is missing now for the second demo is the book shelf in the first room. There will also be a few changes to the retrieval of the first keys.

The first group of testers had a lot of problems with the very first puzzle. I changed small parts of it and added the camera and notebook tutorial, so I hope this will make it easier, but not too easy. The puzzle should stays difficult and it is totally fine if there are people not being able to solve them.

I will hopefully make the second demo available for more people, which will include approximately 75% of the game.

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.