Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
Tags
(1 edit)

I finished to implement the dialogue system. It may need some polishing later, and I have a lot more options to add to the trigger system, but it works for now, as much as I imagined it would!

But first, let's talk a little bit about gameplay, and particularly our purpose with this dialogue system.
Well, I called it dialogue system but we will use it only for monologues; the main character, who's name is Ullich, is a teenager who feel like he is in an epic adventure when he get lost on this planet, and all his thought during his journey will ne shown with text messages.
In terms of gameplay, it will have many functions for us:
- It will serve the storytelling since it will be all structured around Ullich's discoveries and experience.
- We can give clues to the player about options he has to interact with the environment.
- It will even be used as a kind of tutorial at the beginning, to help the player understand the basic gameplay principles.
- It can support sometimes the visuals, by describing a little bit the situation when (very) simple animation is not enough to be clear for the player.

There will be also another use for the monologues. As much as Ullich doesn't know much about how to survive by himself in a deserted planet, he luckily also have really good knowledge about the planetary system around him, and with the help of his star map, he knows well the trajectories of reachable planets and where is the spot to catch them (I know, he's a very smart kid!).
And we will give this information to the player using these monologues too!
While exploring the current planet, at some specific position Ullich will say something about another planet to reach, and there will be a way for the player to interact in the UI to decide to wait and jump to this planet.

Now let's see all of this in game, with this first (very simple) example:


Text rendering

To finish this post, I will detail some parts of the implementation for the text messages.

It's divided in 3 differents classes:
- utils/TextRenderer.java is a low level wrapper for the LibGDX implementation, taking care of loading BitmapFont files.
- render/TextBox.java is the actual implementation for the text messages, drawing a given sentence at a specific position relative to the player,
and handling the timer for drawing the characters one by one
- Talkable.java is a component for the rendered character, which add a Say() function, which will temporarly instanciate a TextBox message for each monologue.

Most of the low level code is inherited from a previous project I made with LibGDX, so I will just talk about several points of interest, some difficulties I face for this game project's specific implementation.

Font Filtering

The font rendering was fine, until I added the moving background. Maybe because during the background rotation there is micro-variations in pixel intensity, the font on the top was suddenly rendering this way:

Not so nice, right?
But then it was solve easily by adding by forcing the font texture to be rendered with linear filtering (the default filtering is nearest method):

       //bitmapFont = new BitmapFont(...);
       //...
       bitmapFont .getRegion().getTexture().setFilter(
              Texture.TextureFilter.Linear
              Texture.TextureFilter.Linear);

And then it appeared this way:

Much better!


Straight Text

When I started implementing the text messages, I was first just rendering them in the character local space, with only additional offset for positioning it near by the head.
It was well attached with the character, but maybe too well.... It appeared this way:

which is not exactly the effect I desired. Not only it looks like it's a physical part of the body, but the text is also very difficult to read.

So I had to modify it to be sure the text stay straight in the screen frame of reference, so I need to correct back the text orientation by rotating it just before drawing.
The text still has to be drawn local to the character, because I want the text's pivot point to be affected by player position and orientation.

So I ended up with this fix in the TextBox class' Draw function:

this is the current transform matrix (from screen to local character position) which will be applied to the text

       Matrix4 mat = batch.getTransformMatrix();

get the rotation angle in world reference

       mat.getRotation(quat);
       float angle = quat.getRollRad();

be sure to rotate the local offset, even if the text orientation will be corrected

      float cosa = (float)Math.cos(angle);
      float sina = (float)Math.sin(angle);
      float rotOffsetX = offsetX * cosa - offsetY * sina;
      float rotOffsetY = offsetX * sina + offsetY * cosa;

cancel the world rotation

     mat.rotateRad(0, 0, 1, -angle);

apply the rotated offset

     mat.translate(rotOffsetX, rotOffsetY, 0);

now the text can be drawn correctly

     batch.setTransformMatrix(mat);        
     int numChars = text.length() - showCharLeft;
     if (numChars > 0)
     {
          drawText(batch, null, numChars);
     }

after that we need to clean up the transform matrix for the next object to draw

     mat.translate(-rotOffsetX, -rotOffsetY, 0);
     mat.rotateRad(0, 0, 1, angle);
     batch.setTransformMatrix(mat);


And after this change, the text was drawn correctly:


Text out of screen

When the character reached the right side of the screen, the text was outside the screen and impossible to read:

So I had to check for the text boundaries on the right, and switch to left-side drawing, and vice versa.

So in the Draw() function, just after the drawing, I checked this with the help (again) of the transform matrix:

get the world translation to character local position

     float matTranslX = mat.getValues()[Matrix4.M03];

calculate world text bounds

     // text bounds is returned by drawText function from TextRenderer.java
     float boxMinX = matTranslX + rotOffsetX
          - 0.5f * bounds.width;
     float boxMaxX = matTranslX + rotOffsetX
          + 0.5f * bounds.width;

compare with screen boundaries, and flip if needed

     if (boxMinX < 0.f || boxMaxX > RenderHelpers.GetScreenRatio())
     {
          if (hAnchor == TextRenderer.HAnchor.LEFT)
          {
               SetOffset(-offsetX, offsetY, true);
          }
          else
          {
               SetOffset(-offsetX, offsetY, false);
          }
     }


Here is the result:



You may be wondering why in the previous code I checked the screen size with RenderHelpers.GetScreenRatio().
This is because I use a normalized viewport for rendering, to avoid to have to think about real screen size in the game world space.
During render initialization I do this (from create() function in GdxGame.java):
calculate screen ratio

       float ratio = (float)screenRealWidth
              / (float)screenRealHeight;

init a normalized viewport

       camera = new OrthographicCamera(); 
       camera.setToOrtho(false, ratio, 1.f);



From now, I have still 3 more systems needed for this project, which I hope I can finish to implement soon: interaction system, AI and planet switch.